Archived
Merge from vscode 313ede61cbad8f9dc748907b3384e059ddddb79a (#7436)
* Merge from vscode 313ede61cbad8f9dc748907b3384e059ddddb79a * fix strict null checks
This commit is contained in:
Vendored
+10
-8
@@ -21,7 +21,6 @@ process.on('SIGPIPE', () => {
|
||||
//#endregion
|
||||
|
||||
//#region Add support for redirecting the loading of node modules
|
||||
|
||||
exports.injectNodeModuleLookupPath = function (injectPath) {
|
||||
if (!injectPath) {
|
||||
throw new Error('Missing injectPath');
|
||||
@@ -37,8 +36,10 @@ exports.injectNodeModuleLookupPath = function (injectPath) {
|
||||
const originalResolveLookupPaths = Module._resolveLookupPaths;
|
||||
|
||||
// @ts-ignore
|
||||
Module._resolveLookupPaths = function (moduleName, parent) {
|
||||
const paths = originalResolveLookupPaths(moduleName, parent);
|
||||
Module._resolveLookupPaths = function (moduleName, parent, newReturn) {
|
||||
const result = originalResolveLookupPaths(moduleName, parent, newReturn);
|
||||
|
||||
const paths = newReturn ? result : result[1];
|
||||
for (let i = 0, len = paths.length; i < len; i++) {
|
||||
if (paths[i] === nodeModulesPath) {
|
||||
paths.splice(i, 0, injectPath);
|
||||
@@ -46,7 +47,7 @@ exports.injectNodeModuleLookupPath = function (injectPath) {
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
return result;
|
||||
};
|
||||
};
|
||||
//#endregion
|
||||
@@ -70,10 +71,11 @@ exports.enableASARSupport = function (nodeModulesPath) {
|
||||
|
||||
// @ts-ignore
|
||||
const originalResolveLookupPaths = Module._resolveLookupPaths;
|
||||
|
||||
// @ts-ignore
|
||||
Module._resolveLookupPaths = function (request, parent) {
|
||||
const paths = originalResolveLookupPaths(request, parent);
|
||||
Module._resolveLookupPaths = function (request, parent, newReturn) {
|
||||
const result = originalResolveLookupPaths(request, parent, newReturn);
|
||||
|
||||
const paths = newReturn ? result : result[1];
|
||||
for (let i = 0, len = paths.length; i < len; i++) {
|
||||
if (paths[i] === NODE_MODULES_PATH) {
|
||||
paths.splice(i, 0, NODE_MODULES_ASAR_PATH);
|
||||
@@ -81,7 +83,7 @@ exports.enableASARSupport = function (nodeModulesPath) {
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
return result;
|
||||
};
|
||||
};
|
||||
//#endregion
|
||||
|
||||
+1
-6
@@ -17,7 +17,7 @@ const paths = require('./paths');
|
||||
// @ts-ignore
|
||||
const product = require('../product.json');
|
||||
// @ts-ignore
|
||||
const { app, protocol } = require('electron');
|
||||
const app = require('electron').app;
|
||||
|
||||
// Enable portable support
|
||||
const portable = bootstrap.configurePortable();
|
||||
@@ -33,11 +33,6 @@ app.setPath('userData', userDataPath);
|
||||
// Update cwd based on environment and platform
|
||||
setCurrentWorkingDirectory();
|
||||
|
||||
// Register custom schemes with privileges
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
{ scheme: 'vscode-resource', privileges: { secure: true, supportFetchAPI: true, corsEnabled: true } }
|
||||
]);
|
||||
|
||||
// Global app listeners
|
||||
registerListeners();
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AbstractEnablePreviewFeatures } from 'sql/workbench/common/enablePreviewFeatures';
|
||||
|
||||
export class BrowserEnablePreviewFeatures extends AbstractEnablePreviewFeatures {
|
||||
protected async getWindowCount(): Promise<number> {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
|
||||
export class EnablePreviewFeatures implements IWorkbenchContribution {
|
||||
export abstract class AbstractEnablePreviewFeatures implements IWorkbenchContribution {
|
||||
|
||||
private static ENABLE_PREVIEW_FEATURES_SHOWN = 'workbench.enablePreviewFeaturesShown';
|
||||
|
||||
@@ -22,12 +22,12 @@ export class EnablePreviewFeatures implements IWorkbenchContribution {
|
||||
@IConfigurationService configurationService: IConfigurationService
|
||||
) {
|
||||
let previewFeaturesEnabled = configurationService.getValue('workbench')['enablePreviewFeatures'];
|
||||
if (previewFeaturesEnabled || storageService.get(EnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, StorageScope.GLOBAL)) {
|
||||
if (previewFeaturesEnabled || storageService.get(AbstractEnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, StorageScope.GLOBAL)) {
|
||||
return;
|
||||
}
|
||||
Promise.all([
|
||||
hostService.hasFocus,
|
||||
hostService.windowCount
|
||||
this.getWindowCount()
|
||||
]).then(([focused, count]) => {
|
||||
if (!focused && count > 1) {
|
||||
return null;
|
||||
@@ -42,7 +42,7 @@ export class EnablePreviewFeatures implements IWorkbenchContribution {
|
||||
label: localize('enablePreviewFeatures.yes', "Yes"),
|
||||
run: () => {
|
||||
configurationService.updateValue('workbench.enablePreviewFeatures', true);
|
||||
storageService.store(EnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, true, StorageScope.GLOBAL);
|
||||
storageService.store(AbstractEnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, true, StorageScope.GLOBAL);
|
||||
}
|
||||
}, {
|
||||
label: localize('enablePreviewFeatures.no', "No"),
|
||||
@@ -53,7 +53,7 @@ export class EnablePreviewFeatures implements IWorkbenchContribution {
|
||||
label: localize('enablePreviewFeatures.never', "No, don't show again"),
|
||||
run: () => {
|
||||
configurationService.updateValue('workbench.enablePreviewFeatures', false);
|
||||
storageService.store(EnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, true, StorageScope.GLOBAL);
|
||||
storageService.store(AbstractEnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, true, StorageScope.GLOBAL);
|
||||
},
|
||||
isSecondary: true
|
||||
}]
|
||||
@@ -61,4 +61,6 @@ export class EnablePreviewFeatures implements IWorkbenchContribution {
|
||||
})
|
||||
.then(null, onUnexpectedError);
|
||||
}
|
||||
|
||||
protected abstract getWindowCount(): Promise<number>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AbstractEnablePreviewFeatures } from 'sql/workbench/common/enablePreviewFeatures';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IElectronService } from 'vs/platform/electron/node/electron';
|
||||
|
||||
export class NativeEnablePreviewFeatures extends AbstractEnablePreviewFeatures {
|
||||
|
||||
constructor(
|
||||
@IStorageService storageService: IStorageService,
|
||||
@INotificationService notificationService: INotificationService,
|
||||
@IHostService hostService: IHostService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IElectronService private readonly electronService: IElectronService
|
||||
) {
|
||||
super(storageService, notificationService, hostService, configurationService);
|
||||
}
|
||||
protected getWindowCount(): Promise<number> {
|
||||
return this.electronService.getWindowCount();
|
||||
}
|
||||
}
|
||||
@@ -138,7 +138,7 @@ registerAction({
|
||||
await workspaceEditingService.addFolders(folders.map(folder => ({ uri: folder })));
|
||||
await viewletService.openViewlet(viewletService.getDefaultViewletId(), true);
|
||||
if (options.forceNewWindow) {
|
||||
return hostService.openInWindow([{ folderUri: folders[0] }], { forceNewWindow: options.forceNewWindow });
|
||||
return hostService.openWindow([{ folderUri: folders[0] }], { forceNewWindow: options.forceNewWindow });
|
||||
}
|
||||
else {
|
||||
return hostService.reload();
|
||||
|
||||
+2
-2
@@ -4,10 +4,10 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { OpenWelcomePageInBrowser } from './openWebsite';
|
||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { BrowserEnablePreviewFeatures } from 'sql/workbench/browser/enablePreviewFeatures';
|
||||
|
||||
Registry
|
||||
.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
|
||||
.registerWorkbenchContribution(OpenWelcomePageInBrowser, LifecyclePhase.Restored);
|
||||
.registerWorkbenchContribution(BrowserEnablePreviewFeatures, LifecyclePhase.Eventually);
|
||||
+13
@@ -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.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { NativeEnablePreviewFeatures } from 'sql/workbench/electron-browser/enablePreviewFeatures';
|
||||
|
||||
Registry
|
||||
.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
|
||||
.registerWorkbenchContribution(NativeEnablePreviewFeatures, LifecyclePhase.Eventually);
|
||||
@@ -14,7 +14,7 @@
|
||||
"./sql/azdata.d.ts",
|
||||
"./sql/azdata.proposed.d.ts",
|
||||
"./vs/base/**/*.ts",
|
||||
"./vs/platform/**/*.ts",
|
||||
// "./vs/platform/**/*.ts",
|
||||
"./sql/base/**/*.ts",
|
||||
"./sql/editor/**/*.ts",
|
||||
"./sql/platform/angularEventing/**/*.ts",
|
||||
|
||||
Vendored
+446
-1291
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { IMarkdownString, parseHrefAndDimensions, removeMarkdownEscapes } from 'vs/base/common/htmlContent';
|
||||
import { defaultGenerator } from 'vs/base/common/idGenerator';
|
||||
import * as marked from 'vs/base/common/marked/marked';
|
||||
import * as insane from 'vs/base/common/insane/insane';
|
||||
import { insane } from 'vs/base/common/insane/insane';
|
||||
import { parse } from 'vs/base/common/marshalling';
|
||||
import { cloneAndChange } from 'vs/base/common/objects';
|
||||
import { escape } from 'vs/base/common/strings';
|
||||
|
||||
@@ -152,34 +152,48 @@ export class StandardWheelEvent {
|
||||
this.deltaX = deltaX;
|
||||
|
||||
if (e) {
|
||||
let e1 = <IWebKitMouseWheelEvent><any>e;
|
||||
let e2 = <IGeckoMouseWheelEvent><any>e;
|
||||
if (e.type === 'wheel') {
|
||||
|
||||
// vertical delta scroll
|
||||
if (typeof e1.wheelDeltaY !== 'undefined') {
|
||||
this.deltaY = e1.wheelDeltaY / 120;
|
||||
} else if (typeof e2.VERTICAL_AXIS !== 'undefined' && e2.axis === e2.VERTICAL_AXIS) {
|
||||
this.deltaY = -e2.detail / 3;
|
||||
} else {
|
||||
this.deltaY = -e.deltaY / 40;
|
||||
}
|
||||
// Modern wheel event
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent
|
||||
const ev = <WheelEvent><unknown>e;
|
||||
|
||||
// horizontal delta scroll
|
||||
if (typeof e1.wheelDeltaX !== 'undefined') {
|
||||
if (browser.isSafari && platform.isWindows) {
|
||||
this.deltaX = - (e1.wheelDeltaX / 120);
|
||||
if (ev.deltaMode === ev.DOM_DELTA_LINE) {
|
||||
// the deltas are expressed in lines
|
||||
this.deltaY = -e.deltaY;
|
||||
this.deltaX = -e.deltaX;
|
||||
} else {
|
||||
this.deltaX = e1.wheelDeltaX / 120;
|
||||
this.deltaY = -e.deltaY / 40;
|
||||
this.deltaX = -e.deltaX / 40;
|
||||
}
|
||||
} else if (typeof e2.HORIZONTAL_AXIS !== 'undefined' && e2.axis === e2.HORIZONTAL_AXIS) {
|
||||
this.deltaX = -e.detail / 3;
|
||||
} else {
|
||||
this.deltaX = -e.deltaX / 40;
|
||||
}
|
||||
|
||||
// Assume a vertical scroll if nothing else worked
|
||||
if (this.deltaY === 0 && this.deltaX === 0 && e.wheelDelta) {
|
||||
this.deltaY = e.wheelDelta / 120;
|
||||
} else {
|
||||
// Old (deprecated) wheel events
|
||||
let e1 = <IWebKitMouseWheelEvent><any>e;
|
||||
let e2 = <IGeckoMouseWheelEvent><any>e;
|
||||
|
||||
// vertical delta scroll
|
||||
if (typeof e1.wheelDeltaY !== 'undefined') {
|
||||
this.deltaY = e1.wheelDeltaY / 120;
|
||||
} else if (typeof e2.VERTICAL_AXIS !== 'undefined' && e2.axis === e2.VERTICAL_AXIS) {
|
||||
this.deltaY = -e2.detail / 3;
|
||||
}
|
||||
|
||||
// horizontal delta scroll
|
||||
if (typeof e1.wheelDeltaX !== 'undefined') {
|
||||
if (browser.isSafari && platform.isWindows) {
|
||||
this.deltaX = - (e1.wheelDeltaX / 120);
|
||||
} else {
|
||||
this.deltaX = e1.wheelDeltaX / 120;
|
||||
}
|
||||
} else if (typeof e2.HORIZONTAL_AXIS !== 'undefined' && e2.axis === e2.HORIZONTAL_AXIS) {
|
||||
this.deltaX = -e.detail / 3;
|
||||
}
|
||||
|
||||
// Assume a vertical scroll if nothing else worked
|
||||
if (this.deltaY === 0 && this.deltaX === 0 && e.wheelDelta) {
|
||||
this.deltaY = e.wheelDelta / 120;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,15 +86,21 @@ export class Gesture extends Disposable {
|
||||
this._register(DomUtils.addDisposableListener(document, 'touchmove', (e: TouchEvent) => this.onTouchMove(e)));
|
||||
}
|
||||
|
||||
public static addTarget(element: HTMLElement): void {
|
||||
public static addTarget(element: HTMLElement): IDisposable {
|
||||
if (!Gesture.isTouchDevice()) {
|
||||
return;
|
||||
return Disposable.None;
|
||||
}
|
||||
if (!Gesture.INSTANCE) {
|
||||
Gesture.INSTANCE = new Gesture();
|
||||
}
|
||||
|
||||
Gesture.INSTANCE.targets.push(element);
|
||||
|
||||
return {
|
||||
dispose: () => {
|
||||
Gesture.INSTANCE.targets = Gesture.INSTANCE.targets.filter(t => t !== element);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@memoize
|
||||
|
||||
@@ -103,7 +103,7 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
|
||||
|
||||
render(container: HTMLElement): void {
|
||||
this.element = container;
|
||||
Gesture.addTarget(container);
|
||||
this._register(Gesture.addTarget(container));
|
||||
|
||||
const enableDragging = this.options && this.options.draggable;
|
||||
if (enableDragging) {
|
||||
|
||||
@@ -63,7 +63,7 @@ export class Button extends Disposable {
|
||||
|
||||
container.appendChild(this._element);
|
||||
|
||||
Gesture.addTarget(this._element);
|
||||
this._register(Gesture.addTarget(this._element));
|
||||
|
||||
[DOM.EventType.CLICK, EventType.Tap].forEach(eventType => {
|
||||
this._register(DOM.addDisposableListener(this._element, eventType, e => {
|
||||
|
||||
@@ -83,7 +83,7 @@ export class BaseDropdown extends ActionRunner {
|
||||
this._register(cleanupFn);
|
||||
}
|
||||
|
||||
Gesture.addTarget(this._label);
|
||||
this._register(Gesture.addTarget(this._label));
|
||||
}
|
||||
|
||||
get element(): HTMLElement {
|
||||
|
||||
@@ -236,7 +236,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
|
||||
this.rowsContainer = document.createElement('div');
|
||||
this.rowsContainer.className = 'monaco-list-rows';
|
||||
Gesture.addTarget(this.rowsContainer);
|
||||
this.disposables.add(Gesture.addTarget(this.rowsContainer));
|
||||
|
||||
this.scrollableElement = this.disposables.add(new ScrollableElement(this.rowsContainer, {
|
||||
alwaysConsumeMouseWheel: true,
|
||||
|
||||
@@ -542,7 +542,7 @@ export class MouseController<T> implements IDisposable {
|
||||
list.onContextMenu(this.onContextMenu, this, this.disposables);
|
||||
list.onMouseDblClick(this.onDoubleClick, this, this.disposables);
|
||||
list.onTouchStart(this.onMouseDown, this, this.disposables);
|
||||
Gesture.addTarget(list.getHTMLElement());
|
||||
this.disposables.add(Gesture.addTarget(list.getHTMLElement()));
|
||||
}
|
||||
|
||||
list.onMouseClick(this.onPointer, this, this.disposables);
|
||||
|
||||
@@ -398,7 +398,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
EventHelper.stop(e, true);
|
||||
this.onClick(e);
|
||||
}));
|
||||
}, 50);
|
||||
}, 100);
|
||||
|
||||
this._register(this.runOnceToEnableMouseUp);
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ export class MenuBar extends Disposable {
|
||||
}
|
||||
}));
|
||||
|
||||
Gesture.addTarget(buttonElement);
|
||||
this._register(Gesture.addTarget(buttonElement));
|
||||
this._register(DOM.addDisposableListener(buttonElement, EventType.Tap, (e: GestureEvent) => {
|
||||
// Ignore this touch if the menu is touched
|
||||
if (this.isOpen && this.focusedMenu && this.focusedMenu.holder && DOM.isAncestor(e.initialTarget as HTMLElement, this.focusedMenu.holder)) {
|
||||
@@ -322,7 +322,7 @@ export class MenuBar extends Disposable {
|
||||
}
|
||||
}));
|
||||
|
||||
Gesture.addTarget(buttonElement);
|
||||
this._register(Gesture.addTarget(buttonElement));
|
||||
this._register(DOM.addDisposableListener(buttonElement, EventType.Tap, (e: GestureEvent) => {
|
||||
// Ignore this touch if the menu is touched
|
||||
if (this.isOpen && this.focusedMenu && this.focusedMenu.holder && DOM.isAncestor(e.initialTarget as HTMLElement, this.focusedMenu.holder)) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@font-face {
|
||||
font-family: "octicons";
|
||||
src: url("./octicons.ttf?628f71ee09945d25ba5fceb0c17f7b0f") format("truetype");
|
||||
src: url("./octicons.ttf?1829db8570ee0fa5a4bef3bb41d5f62e") format("truetype");
|
||||
}
|
||||
|
||||
.octicon, .mega-octicon {
|
||||
|
||||
Binary file not shown.
@@ -139,7 +139,7 @@ export class Sash extends Disposable {
|
||||
this._register(domEvent(this.el, 'mousedown')(this.onMouseDown, this));
|
||||
this._register(domEvent(this.el, 'dblclick')(this.onMouseDoubleClick, this));
|
||||
|
||||
Gesture.addTarget(this.el);
|
||||
this._register(Gesture.addTarget(this.el));
|
||||
this._register(domEvent(this.el, EventType.Start)(this.onTouchStart, this));
|
||||
|
||||
if (isIPad) {
|
||||
|
||||
@@ -23,7 +23,10 @@ export class MarkdownString implements IMarkdownString {
|
||||
|
||||
appendText(value: string): MarkdownString {
|
||||
// escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
|
||||
this.value += value.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&');
|
||||
this.value += value
|
||||
.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&')
|
||||
.replace('\n', '\n\n');
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+1
-7
@@ -3,11 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export as namespace insane;
|
||||
|
||||
export = insane;
|
||||
|
||||
declare function insane(
|
||||
export function insane(
|
||||
html: string,
|
||||
options?: {
|
||||
readonly allowedSchemes?: readonly string[],
|
||||
@@ -16,5 +12,3 @@ declare function insane(
|
||||
},
|
||||
strict?: boolean,
|
||||
): string;
|
||||
|
||||
declare namespace insane { }
|
||||
|
||||
@@ -21,11 +21,7 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// ESM-comment-begin
|
||||
let __insane_exports;
|
||||
// ESM-comment-end
|
||||
|
||||
|
||||
let __insane_func;
|
||||
|
||||
(function () { function r(e, n, t) { function o(i, f) { if (!n[i]) { if (!e[i]) { var c = "function" == typeof require && require; if (!f && c) return c(i, !0); if (u) return u(i, !0); var a = new Error("Cannot find module '" + i + "'"); throw a.code = "MODULE_NOT_FOUND", a } var p = n[i] = { exports: {} }; e[i][0].call(p.exports, function (r) { var n = e[i][1][r]; return o(n || r) }, p, p.exports, r, e, n, t) } return n[i].exports } for (var u = "function" == typeof require && require, i = 0; i < t.length; i++)o(t[i]); return o } return r })()({
|
||||
1: [function (require, module, exports) {
|
||||
@@ -92,7 +88,7 @@ let __insane_exports;
|
||||
|
||||
insane.defaults = defaults;
|
||||
module.exports = insane;
|
||||
__insane_exports = insane;
|
||||
__insane_func = insane;
|
||||
|
||||
}, { "./defaults": 2, "./parser": 7, "./sanitizer": 8, "assignment": 6, "he": 9 }], 5: [function (require, module, exports) {
|
||||
'use strict';
|
||||
@@ -469,10 +465,10 @@ let __insane_exports;
|
||||
}, {}]
|
||||
}, {}, [4]);
|
||||
|
||||
// BEGIN MONACOCHANGE
|
||||
// __marked_exports = marked;
|
||||
// }).call(this);
|
||||
|
||||
// ESM-comment-begin
|
||||
define(function() { return __insane_exports; });
|
||||
define(function() { return { insane: __insane_func }; });
|
||||
// ESM-comment-end
|
||||
|
||||
// ESM-uncomment-begin
|
||||
// export var insane = __insane_func;
|
||||
// ESM-uncomment-end
|
||||
|
||||
@@ -92,7 +92,10 @@ class RemoteAuthoritiesImpl {
|
||||
return this._delegate(uri);
|
||||
}
|
||||
const authority = uri.authority;
|
||||
const host = this._hosts[authority];
|
||||
let host = this._hosts[authority];
|
||||
if (host.indexOf(':') !== -1) {
|
||||
host = `[${host}]`;
|
||||
}
|
||||
const port = this._ports[authority];
|
||||
const connectionToken = this._connectionTokens[authority];
|
||||
return URI.from({
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Menu, MenuItem, BrowserWindow, ipcMain, IpcMainEvent } from 'electron';
|
||||
import { Menu, MenuItem, BrowserWindow, ipcMain, Event as IpcMainEvent } from 'electron';
|
||||
import { ISerializableContextMenuItem, CONTEXT_MENU_CLOSE_CHANNEL, CONTEXT_MENU_CHANNEL, IPopupOptions } from 'vs/base/parts/contextmenu/common/contextmenu';
|
||||
|
||||
export function registerContextMenuListener(): void {
|
||||
|
||||
@@ -437,6 +437,7 @@ export class TreeView extends HeightMap {
|
||||
private shouldInvalidateDropReaction: boolean;
|
||||
private currentDropTargets: ViewItem[] | null = null;
|
||||
private currentDropDisposable: Lifecycle.IDisposable = Lifecycle.Disposable.None;
|
||||
private gestureDisposable: Lifecycle.IDisposable = Lifecycle.Disposable.None;
|
||||
private dragAndDropScrollInterval: number | null = null;
|
||||
private dragAndDropScrollTimeout: number | null = null;
|
||||
private dragAndDropMouseY: number | null = null;
|
||||
@@ -523,7 +524,7 @@ export class TreeView extends HeightMap {
|
||||
this.wrapper.style.msTouchAction = 'none';
|
||||
this.wrapper.style.msContentZooming = 'none';
|
||||
} else {
|
||||
Touch.Gesture.addTarget(this.wrapper);
|
||||
this.gestureDisposable = Touch.Gesture.addTarget(this.wrapper);
|
||||
}
|
||||
|
||||
this.rowsContainer = document.createElement('div');
|
||||
@@ -1681,6 +1682,7 @@ export class TreeView extends HeightMap {
|
||||
if (this.context.cache) {
|
||||
this.context.cache.dispose();
|
||||
}
|
||||
this.gestureDisposable.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
suite('markdownString', () => {
|
||||
|
||||
test('escape', () => {
|
||||
|
||||
const mds = new MarkdownString();
|
||||
|
||||
mds.appendText('# foo\n*bar*');
|
||||
|
||||
assert.equal(mds.value, '\\# foo\n\n\\*bar\\*');
|
||||
});
|
||||
});
|
||||
@@ -27,6 +27,7 @@ function getWorker(workerId: string, label: string): Worker | Promise<Worker> {
|
||||
throw new Error(`You must define a function MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker`);
|
||||
}
|
||||
|
||||
// ESM-comment-begin
|
||||
export function getWorkerBootstrapUrl(scriptPath: string, label: string): string {
|
||||
if (/^(http:)|(https:)|(file:)/.test(scriptPath)) {
|
||||
const currentUrl = String(window.location);
|
||||
@@ -43,6 +44,7 @@ export function getWorkerBootstrapUrl(scriptPath: string, label: string): string
|
||||
}
|
||||
return scriptPath + '#' + label;
|
||||
}
|
||||
// ESM-comment-end
|
||||
|
||||
function isPromiseLike<T>(obj: any): obj is PromiseLike<T> {
|
||||
if (typeof obj.then === 'function') {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { app, ipcMain as ipc, systemPreferences, shell, Event, contentTracing, protocol, powerMonitor, IpcMainEvent } from 'electron';
|
||||
import { app, ipcMain as ipc, systemPreferences, shell, Event, contentTracing, protocol, powerMonitor, Event as IpcMainEvent, BrowserWindow } from 'electron';
|
||||
import { IProcessEnvironment, isWindows, isMacintosh } from 'vs/base/common/platform';
|
||||
import { WindowsManager } from 'vs/code/electron-main/windows';
|
||||
import { OpenContext, IWindowOpenable } from 'vs/platform/windows/common/windows';
|
||||
@@ -78,6 +78,8 @@ import { IElectronService } from 'vs/platform/electron/node/electron';
|
||||
import { ElectronMainService } from 'vs/platform/electron/electron-main/electronMainService';
|
||||
import { ISharedProcessMainService, SharedProcessMainService } from 'vs/platform/ipc/electron-main/sharedProcessMainService';
|
||||
import { assign } from 'vs/base/common/objects';
|
||||
import { IDialogMainService, DialogMainService } from 'vs/platform/dialogs/electron-main/dialogs';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
|
||||
export class CodeApplication extends Disposable {
|
||||
|
||||
@@ -85,6 +87,7 @@ export class CodeApplication extends Disposable {
|
||||
private static readonly TRUE_MACHINE_ID_KEY = 'telemetry.trueMachineId';
|
||||
|
||||
private windowsMainService: IWindowsMainService | undefined;
|
||||
private dialogMainService: IDialogMainService | undefined;
|
||||
|
||||
constructor(
|
||||
private readonly mainIpcServer: Server,
|
||||
@@ -381,8 +384,7 @@ export class CodeApplication extends Disposable {
|
||||
}
|
||||
|
||||
// Setup Auth Handler
|
||||
const authHandler = appInstantiationService.createInstance(ProxyAuthHandler);
|
||||
this._register(authHandler);
|
||||
this._register(new ProxyAuthHandler());
|
||||
|
||||
// Open Windows
|
||||
const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, electronIpcServer, sharedProcessClient));
|
||||
@@ -449,6 +451,7 @@ export class CodeApplication extends Disposable {
|
||||
}
|
||||
|
||||
services.set(IWindowsMainService, new SyncDescriptor(WindowsManager, [machineId, this.userEnv]));
|
||||
services.set(IDialogMainService, new SyncDescriptor(DialogMainService));
|
||||
services.set(ISharedProcessMainService, new SyncDescriptor(SharedProcessMainService, [sharedProcess]));
|
||||
services.set(ILaunchMainService, new SyncDescriptor(LaunchMainService));
|
||||
|
||||
@@ -503,13 +506,13 @@ export class CodeApplication extends Disposable {
|
||||
|
||||
contentTracing.stopRecording(join(homedir(), `${product.applicationName}-${Math.random().toString(16).slice(-4)}.trace.txt`), path => {
|
||||
if (!timeout) {
|
||||
if (this.windowsMainService) {
|
||||
this.windowsMainService.showMessageBox({
|
||||
if (this.dialogMainService) {
|
||||
this.dialogMainService.showMessageBox({
|
||||
type: 'info',
|
||||
message: localize('trace.message', "Successfully created trace."),
|
||||
detail: localize('trace.detail', "Please create an issue and manually attach the following file:\n{0}", path),
|
||||
buttons: [localize('trace.ok', "Ok")]
|
||||
}, this.windowsMainService.getLastActiveWindow());
|
||||
}, withNullAsUndefined(BrowserWindow.getFocusedWindow()));
|
||||
}
|
||||
} else {
|
||||
this.logService.info(`Tracing: data recorded (after 30s timeout) to ${path}`);
|
||||
@@ -580,6 +583,7 @@ export class CodeApplication extends Disposable {
|
||||
|
||||
// Propagate to clients
|
||||
const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService);
|
||||
this.dialogMainService = accessor.get(IDialogMainService);
|
||||
|
||||
// Create a URL handler to open file URIs in the active window
|
||||
const environmentService = accessor.get(IEnvironmentService);
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { BrowserWindow, app, AuthInfo, WebContents, Event as ElectronEvent } from 'electron';
|
||||
|
||||
@@ -22,18 +21,21 @@ type Credentials = {
|
||||
password: string;
|
||||
};
|
||||
|
||||
export class ProxyAuthHandler {
|
||||
export class ProxyAuthHandler extends Disposable {
|
||||
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private retryCount = 0;
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
@IWindowsMainService private readonly windowsMainService: IWindowsMainService
|
||||
) {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
const onLogin = Event.fromNodeEventEmitter<LoginEvent>(app, 'login', (event, webContents, req, authInfo, cb) => ({ event, webContents, req, authInfo, cb }));
|
||||
onLogin(this.onLogin, this, this.disposables);
|
||||
this._register(onLogin(this.onLogin, this));
|
||||
}
|
||||
|
||||
private onLogin({ event, authInfo, cb }: LoginEvent): void {
|
||||
@@ -61,10 +63,9 @@ export class ProxyAuthHandler {
|
||||
}
|
||||
};
|
||||
|
||||
const focusedWindow = this.windowsMainService.getFocusedWindow();
|
||||
|
||||
const focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow) {
|
||||
opts.parent = focusedWindow.win;
|
||||
opts.parent = focusedWindow;
|
||||
opts.modal = true;
|
||||
}
|
||||
|
||||
@@ -89,8 +90,4 @@ export class ProxyAuthHandler {
|
||||
win.close();
|
||||
});
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { assign } from 'vs/base/common/objects';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { BrowserWindow, ipcMain } from 'electron';
|
||||
import { ISharedProcess } from 'vs/platform/windows/electron-main/windows';
|
||||
import { ISharedProcess } from 'vs/platform/ipc/electron-main/sharedProcessMainService';
|
||||
import { Barrier } from 'vs/base/common/async';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
|
||||
|
||||
@@ -561,7 +561,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
autoDetectHighContrast = false;
|
||||
}
|
||||
windowConfiguration.highContrast = isWindows && autoDetectHighContrast && systemPreferences.isInvertedColorScheme();
|
||||
windowConfiguration.accessibilitySupport = app.accessibilitySupportEnabled;
|
||||
windowConfiguration.accessibilitySupport = app.isAccessibilitySupportEnabled();
|
||||
|
||||
// Title style related
|
||||
windowConfiguration.maximized = this._win.isMaximized();
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as fs from 'fs';
|
||||
import { basename, normalize, join, dirname } from 'vs/base/common/path';
|
||||
import { basename, normalize, join, } from 'vs/base/common/path';
|
||||
import { localize } from 'vs/nls';
|
||||
import * as arrays from 'vs/base/common/arrays';
|
||||
import { assign, mixin } from 'vs/base/common/objects';
|
||||
@@ -13,34 +13,36 @@ import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup';
|
||||
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||
import { IStateService } from 'vs/platform/state/node/state';
|
||||
import { CodeWindow, defaultWindowState } from 'vs/code/electron-main/window';
|
||||
import { ipcMain as ipc, screen, BrowserWindow, dialog, systemPreferences, FileFilter, shell, MessageBoxReturnValue, MessageBoxOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue, Display } from 'electron';
|
||||
import { ipcMain as ipc, screen, BrowserWindow, systemPreferences, MessageBoxOptions, Display } from 'electron';
|
||||
import { parseLineAndColumnAware } from 'vs/code/node/paths';
|
||||
import { ILifecycleMainService, UnloadReason, LifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, IPathsToWaitFor, isFileToOpen, isWorkspaceToOpen, isFolderToOpen, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows';
|
||||
import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, IPathsToWaitFor, isFileToOpen, isWorkspaceToOpen, isFolderToOpen, IWindowOpenable, IOpenEmptyWindowOptions, IAddFoldersRequest } from 'vs/platform/windows/common/windows';
|
||||
import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs';
|
||||
import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnWorkspace, findWindowOnExtensionDevelopmentPath, findWindowOnWorkspaceOrFolderUri } from 'vs/code/node/windowsFinder';
|
||||
import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnWorkspace, findWindowOnExtensionDevelopmentPath, findWindowOnWorkspaceOrFolderUri } from 'vs/platform/windows/node/window';
|
||||
import { Event as CommonEvent, Emitter } from 'vs/base/common/event';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { ITelemetryService, ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IWindowsMainService, IOpenConfiguration, IWindowsCountChangedEvent, ICodeWindow, IWindowState as ISingleWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows';
|
||||
import { IWorkspacesHistoryMainService } from 'vs/platform/workspaces/electron-main/workspacesHistoryMainService';
|
||||
import { IProcessEnvironment, isMacintosh, isWindows } from 'vs/base/common/platform';
|
||||
import { IWorkspaceIdentifier, WORKSPACE_FILTER, isSingleFolderWorkspaceIdentifier, hasWorkspaceFileExtension, IEnterWorkspaceResult, IRecent } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { IWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, hasWorkspaceFileExtension, IRecent } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { normalizeNFC } from 'vs/base/common/normalization';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Queue } from 'vs/base/common/async';
|
||||
import { exists, dirExists } from 'vs/base/node/pfs';
|
||||
import { getComparisonKey, isEqual, normalizePath, basename as resourcesBasename, originalFSPath, hasTrailingPathSeparator, removeTrailingPathSeparator } from 'vs/base/common/resources';
|
||||
import { dirExists } from 'vs/base/node/pfs';
|
||||
import { getComparisonKey, isEqual, normalizePath, originalFSPath, hasTrailingPathSeparator, removeTrailingPathSeparator } from 'vs/base/common/resources';
|
||||
import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { restoreWindowsState, WindowsStateStorageData, getWindowsStateStoreData } from 'vs/code/electron-main/windowsStateStorage';
|
||||
import { getWorkspaceIdentifier, IWorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService';
|
||||
import { once } from 'vs/base/common/functional';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { isWindowsDriveLetter, toSlashes } from 'vs/base/common/extpath';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
|
||||
const enum WindowError {
|
||||
UNRESPONSIVE = 1,
|
||||
@@ -167,9 +169,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
private readonly windowsState: IWindowsState;
|
||||
private lastClosedWindowState?: IWindowState;
|
||||
|
||||
private readonly dialogs: Dialogs;
|
||||
private readonly workspacesManager: WorkspacesManager;
|
||||
|
||||
private readonly _onWindowReady = this._register(new Emitter<ICodeWindow>());
|
||||
readonly onWindowReady: CommonEvent<ICodeWindow> = this._onWindowReady.event;
|
||||
|
||||
@@ -194,7 +193,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IWorkspacesHistoryMainService private readonly workspacesHistoryMainService: IWorkspacesHistoryMainService,
|
||||
@IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IDialogMainService private readonly dialogMainService: IDialogMainService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -203,9 +203,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
this.windowsState.openedWindows = [];
|
||||
}
|
||||
|
||||
this.dialogs = new Dialogs(stateService, this);
|
||||
this.workspacesManager = new WorkspacesManager(workspacesMainService, backupMainService, this);
|
||||
|
||||
this.lifecycleMainService.when(LifecycleMainPhase.Ready).then(() => this.registerListeners());
|
||||
this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.installWindowsMutex());
|
||||
}
|
||||
@@ -260,6 +257,11 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
this.lastClosedWindowState = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
// Signal a window is ready after having entered a workspace
|
||||
this._register(this.workspacesMainService.onWorkspaceEntered(event => {
|
||||
this._onWindowReady.fire(event.window);
|
||||
}));
|
||||
}
|
||||
|
||||
// Note that onBeforeShutdown() and onBeforeWindowClose() are fired in different order depending on the OS:
|
||||
@@ -380,12 +382,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
};
|
||||
}
|
||||
|
||||
async openExternal(url: string): Promise<boolean> {
|
||||
shell.openExternal(url);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
open(openConfig: IOpenConfiguration): ICodeWindow[] {
|
||||
this.logService.trace('windowsManager#open');
|
||||
openConfig = this.validateOpenConfig(openConfig);
|
||||
@@ -776,7 +772,9 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
private doAddFoldersToExistingWindow(window: ICodeWindow, foldersToAdd: URI[]): ICodeWindow {
|
||||
window.focus(); // make sure window has focus
|
||||
|
||||
window.sendWhenReady('vscode:addFolders', { foldersToAdd });
|
||||
const request: IAddFoldersRequest = { foldersToAdd };
|
||||
|
||||
window.sendWhenReady('vscode:addFolders', request);
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -862,7 +860,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
path.label = pathToOpen.label;
|
||||
pathsToOpen.push(path);
|
||||
} else {
|
||||
const uri = resourceFromURIToOpen(pathToOpen);
|
||||
const uri = this.resourceFromURIToOpen(pathToOpen);
|
||||
|
||||
// Warn about the invalid URI or path
|
||||
let message, detail;
|
||||
if (uri.scheme === Schemas.file) {
|
||||
@@ -881,7 +880,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
noLink: true
|
||||
};
|
||||
|
||||
this.dialogs.showMessageBox(options, this.getFocusedWindow());
|
||||
this.dialogMainService.showMessageBox(options, withNullAsUndefined(BrowserWindow.getFocusedWindow()));
|
||||
}
|
||||
}
|
||||
return pathsToOpen;
|
||||
@@ -1011,10 +1010,12 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
this.logService.error(`Invalid URI input string, scheme missing: ${arg}`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return uri;
|
||||
} catch (e) {
|
||||
this.logService.error(`Invalid URI input string: ${arg}, ${e.message}`);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -1023,7 +1024,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let uri = resourceFromURIToOpen(toOpen);
|
||||
let uri = this.resourceFromURIToOpen(toOpen);
|
||||
if (uri.scheme === Schemas.file) {
|
||||
return this.parsePath(uri.fsPath, options, isFileToOpen(toOpen));
|
||||
}
|
||||
@@ -1050,6 +1051,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
remoteAuthority
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
fileUri: uri,
|
||||
remoteAuthority
|
||||
@@ -1071,6 +1073,18 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
};
|
||||
}
|
||||
|
||||
private resourceFromURIToOpen(openable: IWindowOpenable): URI {
|
||||
if (isWorkspaceToOpen(openable)) {
|
||||
return openable.workspaceUri;
|
||||
}
|
||||
|
||||
if (isFolderToOpen(openable)) {
|
||||
return openable.folderUri;
|
||||
}
|
||||
|
||||
return openable.fileUri;
|
||||
}
|
||||
|
||||
private parsePath(anyPath: string, options: IPathParseOptions, forceOpenWorkspaceAsFile?: boolean): IPathToOpen | undefined {
|
||||
if (!anyPath) {
|
||||
return undefined;
|
||||
@@ -1086,11 +1100,36 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
anyPath = parsedPath.path;
|
||||
}
|
||||
|
||||
// open remote if either specified in the cli even if it is a local file. TODO@aeschli: Future idea: resolve in remote host context.
|
||||
// open remote if either specified in the cli even if it is a local file.
|
||||
const remoteAuthority = options.remoteAuthority;
|
||||
|
||||
const candidate = normalize(anyPath);
|
||||
if (remoteAuthority) {
|
||||
// assume it's a folder or workspace file
|
||||
|
||||
const first = anyPath.charCodeAt(0);
|
||||
// make absolute
|
||||
if (first !== CharCode.Slash) {
|
||||
if (isWindowsDriveLetter(first) && anyPath.charCodeAt(anyPath.charCodeAt(1)) === CharCode.Colon) {
|
||||
anyPath = toSlashes(anyPath);
|
||||
}
|
||||
anyPath = '/' + anyPath;
|
||||
}
|
||||
|
||||
const uri = URI.from({ scheme: Schemas.vscodeRemote, authority: remoteAuthority, path: anyPath });
|
||||
|
||||
if (hasWorkspaceFileExtension(anyPath)) {
|
||||
if (forceOpenWorkspaceAsFile) {
|
||||
return { fileUri: uri, remoteAuthority };
|
||||
}
|
||||
return { workspace: getWorkspaceIdentifier(uri), remoteAuthority };
|
||||
}
|
||||
return { folderUri: uri, remoteAuthority };
|
||||
}
|
||||
|
||||
let candidate = normalize(anyPath);
|
||||
|
||||
try {
|
||||
|
||||
const candidateStat = fs.statSync(candidate);
|
||||
if (candidateStat.isFile()) {
|
||||
|
||||
@@ -1185,7 +1224,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
return { openFolderInNewWindow: !!openFolderInNewWindow, openFilesInNewWindow };
|
||||
}
|
||||
|
||||
openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): void {
|
||||
openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): ICodeWindow[] {
|
||||
|
||||
// Reload an existing extension development host window on the same path
|
||||
// We currently do not allow more than one extension development window
|
||||
@@ -1195,7 +1234,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
this.reload(existingWindow, openConfig.cli);
|
||||
existingWindow.focus(); // make sure it gets focus and is restored
|
||||
|
||||
return;
|
||||
return [existingWindow];
|
||||
}
|
||||
let folderUris = openConfig.cli['folder-uri'] || [];
|
||||
let fileUris = openConfig.cli['file-uri'] || [];
|
||||
@@ -1286,7 +1325,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
noRecentEntry: true,
|
||||
waitMarkerFileURI: openConfig.waitMarkerFileURI
|
||||
};
|
||||
this.open(openArgs);
|
||||
|
||||
return this.open(openArgs);
|
||||
}
|
||||
|
||||
private openInBrowserWindow(options: IOpenBrowserWindowOptions): ICodeWindow {
|
||||
@@ -1580,23 +1620,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
});
|
||||
}
|
||||
|
||||
async enterWorkspace(win: ICodeWindow, path: URI): Promise<IEnterWorkspaceResult | undefined> {
|
||||
const result = await this.workspacesManager.enterWorkspace(win, path);
|
||||
|
||||
return result ? this.doEnterWorkspace(win, result) : undefined;
|
||||
}
|
||||
|
||||
private doEnterWorkspace(win: ICodeWindow, result: IEnterWorkspaceResult): IEnterWorkspaceResult {
|
||||
|
||||
// Mark as recently opened
|
||||
this.workspacesHistoryMainService.addRecentlyOpened([{ workspace: result.workspace }]);
|
||||
|
||||
// Trigger Eevent to indicate load of workspace into window
|
||||
this._onWindowReady.fire(win);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
focusLastActive(cli: ParsedArgs, context: OpenContext): ICodeWindow {
|
||||
const lastActive = this.getLastActiveWindow();
|
||||
if (lastActive) {
|
||||
@@ -1613,7 +1636,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
return getLastActiveWindow(WindowsManager.WINDOWS);
|
||||
}
|
||||
|
||||
getLastActiveWindowForAuthority(remoteAuthority: string | undefined): ICodeWindow | undefined {
|
||||
private getLastActiveWindowForAuthority(remoteAuthority: string | undefined): ICodeWindow | undefined {
|
||||
return getLastActiveWindow(WindowsManager.WINDOWS.filter(window => window.remoteAuthority === remoteAuthority));
|
||||
}
|
||||
|
||||
@@ -1623,13 +1646,11 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
if (cli && (cli.remote !== remote)) {
|
||||
cli = { ...cli, remote };
|
||||
}
|
||||
const forceReuseWindow = options && options.reuse;
|
||||
const forceNewWindow = !forceReuseWindow;
|
||||
return this.open({ context, cli, forceEmpty: true, forceNewWindow, forceReuseWindow });
|
||||
}
|
||||
|
||||
openNewTabbedWindow(context: OpenContext): ICodeWindow[] {
|
||||
return this.open({ context, cli: this.environmentService.args, forceNewTabbedWindow: true, forceEmpty: true });
|
||||
const forceReuseWindow = options && options.forceReuseWindow;
|
||||
const forceNewWindow = !forceReuseWindow;
|
||||
|
||||
return this.open({ context, cli, forceEmpty: true, forceNewWindow, forceReuseWindow });
|
||||
}
|
||||
|
||||
waitForWindowCloseOrLoad(windowId: number): Promise<void> {
|
||||
@@ -1666,7 +1687,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
}
|
||||
}
|
||||
|
||||
getFocusedWindow(): ICodeWindow | undefined {
|
||||
private getFocusedWindow(): ICodeWindow | undefined {
|
||||
const win = BrowserWindow.getFocusedWindow();
|
||||
if (win) {
|
||||
return this.getWindowById(win.id);
|
||||
@@ -1710,14 +1731,14 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
}
|
||||
|
||||
// Show Dialog
|
||||
this.dialogs.showMessageBox({
|
||||
this.dialogMainService.showMessageBox({
|
||||
title: product.nameLong,
|
||||
type: 'warning',
|
||||
buttons: [mnemonicButtonLabel(localize({ key: 'reopen', comment: ['&& denotes a mnemonic'] }, "&&Reopen")), mnemonicButtonLabel(localize({ key: 'wait', comment: ['&& denotes a mnemonic'] }, "&&Keep Waiting")), mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))],
|
||||
message: localize('appStalled', "The window is no longer responding"),
|
||||
detail: localize('appStalledDetail', "You can reopen or close the window or keep waiting."),
|
||||
noLink: true
|
||||
}, window).then(result => {
|
||||
}, window.win).then(result => {
|
||||
if (!window.win) {
|
||||
return; // Return early if the window has been going down already
|
||||
}
|
||||
@@ -1733,14 +1754,14 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
|
||||
// Crashed
|
||||
else {
|
||||
this.dialogs.showMessageBox({
|
||||
this.dialogMainService.showMessageBox({
|
||||
title: product.nameLong,
|
||||
type: 'warning',
|
||||
buttons: [mnemonicButtonLabel(localize({ key: 'reopen', comment: ['&& denotes a mnemonic'] }, "&&Reopen")), mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))],
|
||||
message: localize('appCrashed', "The window has crashed"),
|
||||
detail: localize('appCrashedDetail', "We are sorry for the inconvenience! You can reopen the window to continue where you left off."),
|
||||
noLink: true
|
||||
}, window).then(result => {
|
||||
}, window.win).then(result => {
|
||||
if (!window.win) {
|
||||
return; // Return early if the window has been going down already
|
||||
}
|
||||
@@ -1770,8 +1791,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
}
|
||||
|
||||
async pickFileFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void> {
|
||||
const title = localize('open', "Open");
|
||||
const paths = await this.dialogs.pick({ ...options, pickFolders: true, pickFiles: true, title });
|
||||
const paths = await this.dialogMainService.pickFileFolder(options);
|
||||
if (paths) {
|
||||
this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFileFolder', options.telemetryExtraData);
|
||||
const urisToOpen = await Promise.all(paths.map(async path => {
|
||||
@@ -1790,8 +1810,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
}
|
||||
|
||||
async pickFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void> {
|
||||
const title = localize('openFolder', "Open Folder");
|
||||
const paths = await this.dialogs.pick({ ...options, pickFolders: true, title });
|
||||
const paths = await this.dialogMainService.pickFolder(options);
|
||||
if (paths) {
|
||||
this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFolder', options.telemetryExtraData);
|
||||
this.open({
|
||||
@@ -1805,8 +1824,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
}
|
||||
|
||||
async pickFileAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void> {
|
||||
const title = localize('openFile', "Open File");
|
||||
const paths = await this.dialogs.pick({ ...options, pickFiles: true, title });
|
||||
const paths = await this.dialogMainService.pickFile(options);
|
||||
if (paths) {
|
||||
this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFile', options.telemetryExtraData);
|
||||
this.open({
|
||||
@@ -1820,10 +1838,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
}
|
||||
|
||||
async pickWorkspaceAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void> {
|
||||
const title = localize('openWorkspaceTitle', "Open Workspace");
|
||||
const buttonLabel = mnemonicButtonLabel(localize({ key: 'openWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Open"));
|
||||
const filters = WORKSPACE_FILTER;
|
||||
const paths = await this.dialogs.pick({ ...options, pickFiles: true, title, filters, buttonLabel });
|
||||
const paths = await this.dialogMainService.pickWorkspace(options);
|
||||
if (paths) {
|
||||
this.sendPickerTelemetry(paths, options.telemetryEventName || 'openWorkspace', options.telemetryExtraData);
|
||||
this.open({
|
||||
@@ -1838,7 +1853,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
}
|
||||
|
||||
private sendPickerTelemetry(paths: string[], telemetryEventName: string, telemetryExtraData?: ITelemetryData) {
|
||||
|
||||
const numberOfPaths = paths ? paths.length : 0;
|
||||
|
||||
// Telemetry
|
||||
@@ -1850,18 +1864,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
});
|
||||
}
|
||||
|
||||
showMessageBox(options: MessageBoxOptions, win?: ICodeWindow): Promise<MessageBoxReturnValue> {
|
||||
return this.dialogs.showMessageBox(options, win);
|
||||
}
|
||||
|
||||
showSaveDialog(options: SaveDialogOptions, win?: ICodeWindow): Promise<SaveDialogReturnValue> {
|
||||
return this.dialogs.showSaveDialog(options, win);
|
||||
}
|
||||
|
||||
showOpenDialog(options: OpenDialogOptions, win?: ICodeWindow): Promise<OpenDialogReturnValue> {
|
||||
return this.dialogs.showOpenDialog(options, win);
|
||||
}
|
||||
|
||||
quit(): void {
|
||||
|
||||
// If the user selected to exit from an extension development host window, do not quit, but just
|
||||
@@ -1879,240 +1881,3 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface IInternalNativeOpenDialogOptions extends INativeOpenDialogOptions {
|
||||
|
||||
pickFolders?: boolean;
|
||||
pickFiles?: boolean;
|
||||
|
||||
title: string;
|
||||
buttonLabel?: string;
|
||||
filters?: FileFilter[];
|
||||
}
|
||||
|
||||
class Dialogs {
|
||||
|
||||
private static readonly workingDirPickerStorageKey = 'pickerWorkingDir';
|
||||
|
||||
private readonly mapWindowToDialogQueue: Map<number, Queue<void>>;
|
||||
private readonly noWindowDialogQueue: Queue<void>;
|
||||
|
||||
constructor(
|
||||
private readonly stateService: IStateService,
|
||||
private readonly windowsMainService: IWindowsMainService
|
||||
) {
|
||||
this.mapWindowToDialogQueue = new Map<number, Queue<void>>();
|
||||
this.noWindowDialogQueue = new Queue<void>();
|
||||
}
|
||||
|
||||
async pick(options: IInternalNativeOpenDialogOptions, win?: ICodeWindow): Promise<string[] | undefined> {
|
||||
|
||||
// Ensure dialog options
|
||||
const dialogOptions: OpenDialogOptions = {
|
||||
title: options.title,
|
||||
buttonLabel: options.buttonLabel,
|
||||
filters: options.filters
|
||||
};
|
||||
|
||||
// Ensure defaultPath
|
||||
dialogOptions.defaultPath = options.defaultPath || this.stateService.getItem<string>(Dialogs.workingDirPickerStorageKey);
|
||||
|
||||
|
||||
// Ensure properties
|
||||
if (typeof options.pickFiles === 'boolean' || typeof options.pickFolders === 'boolean') {
|
||||
dialogOptions.properties = undefined; // let it override based on the booleans
|
||||
|
||||
if (options.pickFiles && options.pickFolders) {
|
||||
dialogOptions.properties = ['multiSelections', 'openDirectory', 'openFile', 'createDirectory'];
|
||||
}
|
||||
}
|
||||
|
||||
if (!dialogOptions.properties) {
|
||||
dialogOptions.properties = ['multiSelections', options.pickFolders ? 'openDirectory' : 'openFile', 'createDirectory'];
|
||||
}
|
||||
|
||||
if (isMacintosh) {
|
||||
dialogOptions.properties.push('treatPackageAsDirectory'); // always drill into .app files
|
||||
}
|
||||
|
||||
// Show Dialog
|
||||
const windowToUse = win || this.windowsMainService.getFocusedWindow();
|
||||
|
||||
const result = await this.showOpenDialog(dialogOptions, windowToUse);
|
||||
if (result && result.filePaths && result.filePaths.length > 0) {
|
||||
|
||||
// Remember path in storage for next time
|
||||
this.stateService.setItem(Dialogs.workingDirPickerStorageKey, dirname(result.filePaths[0]));
|
||||
|
||||
return result.filePaths;
|
||||
}
|
||||
|
||||
return undefined; // {{SQL CARBON EDIT}} @anthonydresser strict-null-check
|
||||
}
|
||||
|
||||
private getDialogQueue(window?: ICodeWindow): Queue<any> {
|
||||
if (!window) {
|
||||
return this.noWindowDialogQueue;
|
||||
}
|
||||
|
||||
let windowDialogQueue = this.mapWindowToDialogQueue.get(window.id);
|
||||
if (!windowDialogQueue) {
|
||||
windowDialogQueue = new Queue<any>();
|
||||
this.mapWindowToDialogQueue.set(window.id, windowDialogQueue);
|
||||
}
|
||||
|
||||
return windowDialogQueue;
|
||||
}
|
||||
|
||||
showMessageBox(options: MessageBoxOptions, window?: ICodeWindow): Promise<MessageBoxReturnValue> {
|
||||
return this.getDialogQueue(window).queue(async () => {
|
||||
if (window) {
|
||||
return dialog.showMessageBox(window.win, options);
|
||||
}
|
||||
|
||||
return dialog.showMessageBox(options);
|
||||
});
|
||||
}
|
||||
|
||||
showSaveDialog(options: SaveDialogOptions, window?: ICodeWindow): Promise<SaveDialogReturnValue> {
|
||||
|
||||
function normalizePath(path: string | undefined): string | undefined {
|
||||
if (path && isMacintosh) {
|
||||
path = normalizeNFC(path); // normalize paths returned from the OS
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
return this.getDialogQueue(window).queue(async () => {
|
||||
let result: SaveDialogReturnValue;
|
||||
if (window) {
|
||||
result = await dialog.showSaveDialog(window.win, options);
|
||||
} else {
|
||||
result = await dialog.showSaveDialog(options);
|
||||
}
|
||||
|
||||
result.filePath = normalizePath(result.filePath);
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
showOpenDialog(options: OpenDialogOptions, window?: ICodeWindow): Promise<OpenDialogReturnValue> {
|
||||
|
||||
function normalizePaths(paths: string[] | undefined): string[] | undefined {
|
||||
if (paths && paths.length > 0 && isMacintosh) {
|
||||
paths = paths.map(path => normalizeNFC(path)); // normalize paths returned from the OS
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
return this.getDialogQueue(window).queue(async () => {
|
||||
|
||||
// Ensure the path exists (if provided)
|
||||
if (options.defaultPath) {
|
||||
const pathExists = await exists(options.defaultPath);
|
||||
if (!pathExists) {
|
||||
options.defaultPath = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Show dialog
|
||||
let result: OpenDialogReturnValue;
|
||||
if (window) {
|
||||
result = await dialog.showOpenDialog(window.win, options);
|
||||
} else {
|
||||
result = await dialog.showOpenDialog(options);
|
||||
}
|
||||
|
||||
result.filePaths = normalizePaths(result.filePaths);
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class WorkspacesManager {
|
||||
|
||||
constructor(
|
||||
private readonly workspacesMainService: IWorkspacesMainService,
|
||||
private readonly backupMainService: IBackupMainService,
|
||||
private readonly windowsMainService: IWindowsMainService,
|
||||
) { }
|
||||
|
||||
async enterWorkspace(window: ICodeWindow, path: URI): Promise<IEnterWorkspaceResult | null> {
|
||||
if (!window || !window.win || !window.isReady) {
|
||||
return null; // return early if the window is not ready or disposed
|
||||
}
|
||||
|
||||
const isValid = await this.isValidTargetWorkspacePath(window, path);
|
||||
if (!isValid) {
|
||||
return null; // return early if the workspace is not valid
|
||||
}
|
||||
|
||||
return this.doOpenWorkspace(window, getWorkspaceIdentifier(path));
|
||||
}
|
||||
|
||||
private async isValidTargetWorkspacePath(window: ICodeWindow, path?: URI): Promise<boolean> {
|
||||
if (!path) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (window.openedWorkspace && isEqual(window.openedWorkspace.configPath, path)) {
|
||||
return false; // window is already opened on a workspace with that path
|
||||
}
|
||||
|
||||
// Prevent overwriting a workspace that is currently opened in another window
|
||||
if (findWindowOnWorkspace(this.windowsMainService.getWindows(), getWorkspaceIdentifier(path))) {
|
||||
const options: MessageBoxOptions = {
|
||||
title: product.nameLong,
|
||||
type: 'info',
|
||||
buttons: [localize('ok', "OK")],
|
||||
message: localize('workspaceOpenedMessage', "Unable to save workspace '{0}'", resourcesBasename(path)),
|
||||
detail: localize('workspaceOpenedDetail', "The workspace is already opened in another window. Please close that window first and then try again."),
|
||||
noLink: true
|
||||
};
|
||||
|
||||
await this.windowsMainService.showMessageBox(options, this.windowsMainService.getFocusedWindow());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true; // OK
|
||||
}
|
||||
|
||||
private doOpenWorkspace(window: ICodeWindow, workspace: IWorkspaceIdentifier): IEnterWorkspaceResult {
|
||||
window.focus();
|
||||
|
||||
// Register window for backups and migrate current backups over
|
||||
let backupPath: string | undefined;
|
||||
if (!window.config.extensionDevelopmentPath) {
|
||||
backupPath = this.backupMainService.registerWorkspaceBackupSync({ workspace, remoteAuthority: window.remoteAuthority }, window.config.backupPath);
|
||||
}
|
||||
|
||||
// if the window was opened on an untitled workspace, delete it.
|
||||
if (window.openedWorkspace && this.workspacesMainService.isUntitledWorkspace(window.openedWorkspace)) {
|
||||
this.workspacesMainService.deleteUntitledWorkspaceSync(window.openedWorkspace);
|
||||
}
|
||||
|
||||
// Update window configuration properly based on transition to workspace
|
||||
window.config.folderUri = undefined;
|
||||
window.config.workspace = workspace;
|
||||
window.config.backupPath = backupPath;
|
||||
|
||||
return { workspace, backupPath };
|
||||
}
|
||||
}
|
||||
|
||||
function resourceFromURIToOpen(openable: IWindowOpenable): URI {
|
||||
if (isWorkspaceToOpen(openable)) {
|
||||
return openable.workspaceUri;
|
||||
}
|
||||
|
||||
if (isFolderToOpen(openable)) {
|
||||
return openable.folderUri;
|
||||
}
|
||||
|
||||
return openable.fileUri;
|
||||
}
|
||||
|
||||
@@ -35,12 +35,15 @@ export function restoreWindowsState(data: WindowsStateStorageData | undefined):
|
||||
if (windowsState.lastActiveWindow) {
|
||||
result.lastActiveWindow = restoreWindowState(windowsState.lastActiveWindow);
|
||||
}
|
||||
|
||||
if (windowsState.lastPluginDevelopmentHostWindow) {
|
||||
result.lastPluginDevelopmentHostWindow = restoreWindowState(windowsState.lastPluginDevelopmentHostWindow);
|
||||
}
|
||||
|
||||
if (Array.isArray(windowsState.openedWindows)) {
|
||||
result.openedWindows = windowsState.openedWindows.map(windowState => restoreWindowState(windowState));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -49,9 +52,11 @@ function restoreWindowState(windowState: ISerializedWindowState): IWindowState {
|
||||
if (windowState.backupPath) {
|
||||
result.backupPath = windowState.backupPath;
|
||||
}
|
||||
|
||||
if (windowState.remoteAuthority) {
|
||||
result.remoteAuthority = windowState.remoteAuthority;
|
||||
}
|
||||
|
||||
if (windowState.folder) {
|
||||
result.folderUri = URI.parse(windowState.folder);
|
||||
} else if (windowState.folderUri) {
|
||||
@@ -59,11 +64,13 @@ function restoreWindowState(windowState: ISerializedWindowState): IWindowState {
|
||||
} else if (windowState.folderPath) {
|
||||
result.folderUri = URI.file(windowState.folderPath);
|
||||
}
|
||||
|
||||
if (windowState.workspaceIdentifier) {
|
||||
result.workspace = { id: windowState.workspaceIdentifier.id, configPath: URI.parse(windowState.workspaceIdentifier.configURIPath) };
|
||||
} else if (windowState.workspace) {
|
||||
result.workspace = { id: windowState.workspace.id, configPath: URI.file(windowState.workspace.configPath) };
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,19 +3,18 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as os from 'os';
|
||||
import * as fs from 'fs';
|
||||
import { spawn, ChildProcess, SpawnOptions } from 'child_process';
|
||||
import { buildHelpMessage, buildVersionMessage, addArg, createWaitMarkerFile, OPTIONS } from 'vs/platform/environment/node/argv';
|
||||
import { parseCLIProcessArgv } from 'vs/platform/environment/node/argvHelper';
|
||||
import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import * as paths from 'vs/base/common/path';
|
||||
import * as os from 'os';
|
||||
import * as fs from 'fs';
|
||||
import { whenDeleted, writeFileSync } from 'vs/base/node/pfs';
|
||||
import { findFreePort, randomPort } from 'vs/base/node/ports';
|
||||
import { resolveTerminalEncoding } from 'vs/base/node/encoding';
|
||||
import * as iconv from 'iconv-lite';
|
||||
import { isWindows, isLinux } from 'vs/base/common/platform';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { ProfilingSession, Target } from 'v8-inspect-profiler';
|
||||
import { isString } from 'vs/base/common/types';
|
||||
|
||||
@@ -179,7 +178,8 @@ export async function main(argv: string[]): Promise<any> {
|
||||
if (!stdinFileError) {
|
||||
|
||||
// Pipe into tmp file using terminals encoding
|
||||
resolveTerminalEncoding(verbose).then(encoding => {
|
||||
resolveTerminalEncoding(verbose).then(async encoding => {
|
||||
const iconv = await import('iconv-lite');
|
||||
const converterStream = iconv.decodeStream(encoding);
|
||||
process.stdin.pipe(converterStream).pipe(stdinFileStream);
|
||||
});
|
||||
@@ -360,10 +360,6 @@ export async function main(argv: string[]): Promise<any> {
|
||||
options['stdio'] = 'ignore';
|
||||
}
|
||||
|
||||
if (isLinux) {
|
||||
addArg(argv, '--no-sandbox'); // Electron 6 introduces a chrome-sandbox that requires root to run. This can fail. Disable sandbox via --no-sandbox
|
||||
}
|
||||
|
||||
const child = spawn(process.execPath, argv.slice(2), options);
|
||||
|
||||
if (args.wait && waitMarkerFilePath) {
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as extpath from 'vs/base/common/extpath';
|
||||
import { OpenContext } from 'vs/platform/windows/common/windows';
|
||||
import { IWorkspaceIdentifier, IResolvedWorkspace, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { isEqual, isEqualOrParent } from 'vs/base/common/resources';
|
||||
|
||||
export interface ISimpleWindow {
|
||||
openedWorkspace?: IWorkspaceIdentifier;
|
||||
openedFolderUri?: URI;
|
||||
|
||||
extensionDevelopmentPath?: string[];
|
||||
lastFocusTime: number;
|
||||
}
|
||||
|
||||
export interface IBestWindowOrFolderOptions<W extends ISimpleWindow> {
|
||||
windows: W[];
|
||||
newWindow: boolean;
|
||||
context: OpenContext;
|
||||
fileUri?: URI;
|
||||
userHome?: string;
|
||||
codeSettingsFolder?: string;
|
||||
localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null;
|
||||
}
|
||||
|
||||
export function findBestWindowOrFolderForFile<W extends ISimpleWindow>({ windows, newWindow, context, fileUri, localWorkspaceResolver: workspaceResolver }: IBestWindowOrFolderOptions<W>): W | undefined {
|
||||
if (!newWindow && fileUri && (context === OpenContext.DESKTOP || context === OpenContext.CLI || context === OpenContext.DOCK)) {
|
||||
const windowOnFilePath = findWindowOnFilePath(windows, fileUri, workspaceResolver);
|
||||
if (windowOnFilePath) {
|
||||
return windowOnFilePath;
|
||||
}
|
||||
}
|
||||
return !newWindow ? getLastActiveWindow(windows) : undefined;
|
||||
}
|
||||
|
||||
function findWindowOnFilePath<W extends ISimpleWindow>(windows: W[], fileUri: URI, localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null): W | null {
|
||||
|
||||
// First check for windows with workspaces that have a parent folder of the provided path opened
|
||||
for (const window of windows) {
|
||||
const workspace = window.openedWorkspace;
|
||||
if (workspace) {
|
||||
const resolvedWorkspace = localWorkspaceResolver(workspace);
|
||||
if (resolvedWorkspace) {
|
||||
// workspace could be resolved: It's in the local file system
|
||||
if (resolvedWorkspace.folders.some(folder => isEqualOrParent(fileUri, folder.uri))) {
|
||||
return window;
|
||||
}
|
||||
} else {
|
||||
// use the config path instead
|
||||
if (isEqualOrParent(fileUri, workspace.configPath)) {
|
||||
return window;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then go with single folder windows that are parent of the provided file path
|
||||
const singleFolderWindowsOnFilePath = windows.filter(window => window.openedFolderUri && isEqualOrParent(fileUri, window.openedFolderUri));
|
||||
if (singleFolderWindowsOnFilePath.length) {
|
||||
return singleFolderWindowsOnFilePath.sort((a, b) => -(a.openedFolderUri!.path.length - b.openedFolderUri!.path.length))[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getLastActiveWindow<W extends ISimpleWindow>(windows: W[]): W | undefined {
|
||||
const lastFocusedDate = Math.max.apply(Math, windows.map(window => window.lastFocusTime));
|
||||
|
||||
return windows.filter(window => window.lastFocusTime === lastFocusedDate)[0];
|
||||
}
|
||||
|
||||
export function findWindowOnWorkspace<W extends ISimpleWindow>(windows: W[], workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier)): W | null {
|
||||
if (isSingleFolderWorkspaceIdentifier(workspace)) {
|
||||
for (const window of windows) {
|
||||
// match on folder
|
||||
if (isSingleFolderWorkspaceIdentifier(workspace)) {
|
||||
if (window.openedFolderUri && isEqual(window.openedFolderUri, workspace)) {
|
||||
return window;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isWorkspaceIdentifier(workspace)) {
|
||||
for (const window of windows) {
|
||||
// match on workspace
|
||||
if (window.openedWorkspace && window.openedWorkspace.id === workspace.id) {
|
||||
return window;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function findWindowOnExtensionDevelopmentPath<W extends ISimpleWindow>(windows: W[], extensionDevelopmentPaths: string[]): W | null {
|
||||
|
||||
const matches = (uriString: string): boolean => {
|
||||
return extensionDevelopmentPaths.some(p => extpath.isEqual(p, uriString, !platform.isLinux /* ignorecase */));
|
||||
};
|
||||
|
||||
for (const window of windows) {
|
||||
// match on extension development path. The path can be one or more paths or uri strings, using paths.isEqual is not 100% correct but good enough
|
||||
const currPaths = window.extensionDevelopmentPath;
|
||||
if (currPaths && currPaths.some(p => matches(p))) {
|
||||
return window;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function findWindowOnWorkspaceOrFolderUri<W extends ISimpleWindow>(windows: W[], uri: URI | undefined): W | null {
|
||||
if (!uri) {
|
||||
return null;
|
||||
}
|
||||
for (const window of windows) {
|
||||
// check for workspace config path
|
||||
if (window.openedWorkspace && isEqual(window.openedWorkspace.configPath, uri)) {
|
||||
return window;
|
||||
}
|
||||
|
||||
// check for folder path
|
||||
if (window.openedFolderUri && isEqual(window.openedFolderUri, uri)) {
|
||||
return window;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{}
|
||||
@@ -11,7 +11,7 @@ import * as platform from 'vs/base/common/platform';
|
||||
import { CharWidthRequest, CharWidthRequestType, readCharWidths } from 'vs/editor/browser/config/charWidthReader';
|
||||
import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';
|
||||
import { CommonEditorConfiguration, IEnvConfiguration } from 'vs/editor/common/config/commonEditorConfig';
|
||||
import { IEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { EditorOption, IEditorConstructionOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo';
|
||||
import { IDimension } from 'vs/editor/common/editorCommon';
|
||||
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
|
||||
@@ -310,13 +310,13 @@ export class Configuration extends CommonEditorConfiguration {
|
||||
|
||||
constructor(
|
||||
isSimpleWidget: boolean,
|
||||
options: IEditorOptions,
|
||||
options: IEditorConstructionOptions,
|
||||
referenceDomElement: HTMLElement | null = null,
|
||||
private readonly accessibilityService: IAccessibilityService
|
||||
) {
|
||||
super(isSimpleWidget, options);
|
||||
|
||||
this._elementSizeObserver = this._register(new ElementSizeObserver(referenceDomElement, () => this._onReferenceDomElementSizeChanged()));
|
||||
this._elementSizeObserver = this._register(new ElementSizeObserver(referenceDomElement, options.dimension, () => this._onReferenceDomElementSizeChanged()));
|
||||
|
||||
this._register(CSSBasedConfiguration.INSTANCE.onDidChange(() => this._onCSSBasedConfigurationChanged()));
|
||||
|
||||
|
||||
@@ -14,14 +14,14 @@ export class ElementSizeObserver extends Disposable {
|
||||
private width: number;
|
||||
private height: number;
|
||||
|
||||
constructor(referenceDomElement: HTMLElement | null, changeCallback: () => void) {
|
||||
constructor(referenceDomElement: HTMLElement | null, dimension: IDimension | undefined, changeCallback: () => void) {
|
||||
super();
|
||||
this.referenceDomElement = referenceDomElement;
|
||||
this.changeCallback = changeCallback;
|
||||
this.measureReferenceDomElementToken = -1;
|
||||
this.width = -1;
|
||||
this.height = -1;
|
||||
this.measureReferenceDomElement(false);
|
||||
this.measureReferenceDomElement(false, dimension);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
@@ -75,4 +75,4 @@ export class ElementSizeObserver extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ class TouchHandler extends MouseHandler {
|
||||
constructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) {
|
||||
super(context, viewController, viewHelper);
|
||||
|
||||
Gesture.addTarget(this.viewHelper.linesContentDomNode);
|
||||
this._register(Gesture.addTarget(this.viewHelper.linesContentDomNode));
|
||||
|
||||
this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Tap, (e) => this.onTap(e)));
|
||||
this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Change, (e) => this.onChange(e)));
|
||||
|
||||
@@ -152,6 +152,10 @@ export class TextAreaHandler extends ViewPart {
|
||||
this.textArea.setAttribute('aria-haspopup', 'false');
|
||||
this.textArea.setAttribute('aria-autocomplete', 'both');
|
||||
|
||||
if (platform.isWeb && options.get(EditorOption.readOnly)) {
|
||||
this.textArea.setAttribute('readonly', 'true');
|
||||
}
|
||||
|
||||
this.textAreaCover = createFastDomNode(document.createElement('div'));
|
||||
this.textAreaCover.setPosition('absolute');
|
||||
|
||||
@@ -395,6 +399,14 @@ export class TextAreaHandler extends ViewPart {
|
||||
this._copyWithSyntaxHighlighting = options.get(EditorOption.copyWithSyntaxHighlighting);
|
||||
this.textArea.setAttribute('aria-label', this._getAriaLabel(options));
|
||||
|
||||
if (platform.isWeb && e.hasChanged(EditorOption.readOnly)) {
|
||||
if (options.get(EditorOption.readOnly)) {
|
||||
this.textArea.setAttribute('readonly', 'true');
|
||||
} else {
|
||||
this.textArea.removeAttribute('readonly');
|
||||
}
|
||||
}
|
||||
|
||||
if (e.hasChanged(EditorOption.accessibilitySupport)) {
|
||||
this._textAreaInput.writeScreenReaderContent('strategy changed');
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import { registerThemingParticipant } from 'vs/platform/theme/common/themeServic
|
||||
import { ModelDecorationMinimapOptions } from 'vs/editor/common/model/textModel';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { GestureEvent, EventType, Gesture } from 'vs/base/browser/touch';
|
||||
|
||||
function getMinimapLineHeight(renderMinimap: RenderMinimap): number {
|
||||
if (renderMinimap === RenderMinimap.Large) {
|
||||
@@ -208,6 +209,10 @@ class MinimapLayout {
|
||||
return Math.round(desiredSliderPosition / this._computedSliderRatio);
|
||||
}
|
||||
|
||||
public getDesiredScrollTopFromTouchLocation(pageY: number): number {
|
||||
return Math.round((pageY - this.sliderHeight / 2) / this._computedSliderRatio);
|
||||
}
|
||||
|
||||
public static create(
|
||||
options: MinimapOptions,
|
||||
viewportStartLineNumber: number,
|
||||
@@ -451,12 +456,17 @@ export class Minimap extends ViewPart {
|
||||
private readonly _mouseDownListener: IDisposable;
|
||||
private readonly _sliderMouseMoveMonitor: GlobalMouseMoveMonitor<IStandardMouseMoveEventData>;
|
||||
private readonly _sliderMouseDownListener: IDisposable;
|
||||
private readonly _gestureDisposable: IDisposable;
|
||||
private readonly _sliderTouchStartListener: IDisposable;
|
||||
private readonly _sliderTouchMoveListener: IDisposable;
|
||||
private readonly _sliderTouchEndListener: IDisposable;
|
||||
|
||||
private _options: MinimapOptions;
|
||||
private _lastRenderData: RenderData | null;
|
||||
private _selections: Selection[] = [];
|
||||
private _selectionColor: Color | undefined;
|
||||
private _renderDecorations: boolean = false;
|
||||
private _gestureInProgress: boolean = false;
|
||||
private _buffers: MinimapBuffers | null;
|
||||
|
||||
constructor(context: ViewContext) {
|
||||
@@ -566,12 +576,50 @@ export class Minimap extends ViewPart {
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
this._gestureDisposable = Gesture.addTarget(this._domNode.domNode);
|
||||
this._sliderTouchStartListener = dom.addDisposableListener(this._domNode.domNode, EventType.Start, (e: GestureEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (this._lastRenderData) {
|
||||
this._slider.toggleClassName('active', true);
|
||||
this._gestureInProgress = true;
|
||||
this.scrollDueToTouchEvent(e);
|
||||
}
|
||||
});
|
||||
|
||||
this._sliderTouchMoveListener = dom.addStandardDisposableListener(this._domNode.domNode, EventType.Change, (e: GestureEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (this._lastRenderData && this._gestureInProgress) {
|
||||
this.scrollDueToTouchEvent(e);
|
||||
}
|
||||
});
|
||||
|
||||
this._sliderTouchEndListener = dom.addStandardDisposableListener(this._domNode.domNode, EventType.End, (e: GestureEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this._gestureInProgress = false;
|
||||
this._slider.toggleClassName('active', false);
|
||||
});
|
||||
}
|
||||
|
||||
private scrollDueToTouchEvent(touch: GestureEvent) {
|
||||
const startY = this._domNode.domNode.getBoundingClientRect().top;
|
||||
const scrollTop = this._lastRenderData!.renderedLayout.getDesiredScrollTopFromTouchLocation(touch.pageY - startY);
|
||||
this._context.viewLayout.setScrollPositionNow({
|
||||
scrollTop: scrollTop
|
||||
});
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._mouseDownListener.dispose();
|
||||
this._sliderMouseMoveMonitor.dispose();
|
||||
this._sliderMouseDownListener.dispose();
|
||||
this._gestureDisposable.dispose();
|
||||
this._sliderTouchStartListener.dispose();
|
||||
this._sliderTouchMoveListener.dispose();
|
||||
this._sliderTouchEndListener.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService
|
||||
import { ICommandDelegate } from 'vs/editor/browser/view/viewController';
|
||||
import { IContentWidgetData, IOverlayWidgetData, View } from 'vs/editor/browser/view/viewImpl';
|
||||
import { ViewOutgoingEvents } from 'vs/editor/browser/view/viewOutgoingEvents';
|
||||
import { ConfigurationChangedEvent, EditorLayoutInfo, IEditorOptions, EditorOption, IComputedEditorOptions, FindComputedEditorOptionValueById } from 'vs/editor/common/config/editorOptions';
|
||||
import { ConfigurationChangedEvent, EditorLayoutInfo, IEditorOptions, EditorOption, IComputedEditorOptions, FindComputedEditorOptionValueById, IEditorConstructionOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { Cursor, CursorStateChangedEvent } from 'vs/editor/common/controller/cursor';
|
||||
import { CursorColumns, ICursors } from 'vs/editor/common/controller/cursorCommon';
|
||||
import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
@@ -236,7 +236,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
||||
|
||||
constructor(
|
||||
domElement: HTMLElement,
|
||||
options: IEditorOptions,
|
||||
options: IEditorConstructionOptions,
|
||||
codeEditorWidgetOptions: ICodeEditorWidgetOptions,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@ICodeEditorService codeEditorService: ICodeEditorService,
|
||||
@@ -329,7 +329,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
||||
this._codeEditorService.addCodeEditor(this);
|
||||
}
|
||||
|
||||
protected _createConfiguration(options: IEditorOptions, accessibilityService: IAccessibilityService): editorCommon.IConfiguration {
|
||||
protected _createConfiguration(options: IEditorConstructionOptions, accessibilityService: IAccessibilityService): editorCommon.IConfiguration {
|
||||
return new Configuration(this.isSimpleWidget, options, this._domElement, accessibilityService);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import { USUAL_WORD_SEPARATORS } from 'vs/editor/common/model/wordHelper';
|
||||
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { isObject } from 'vs/base/common/types';
|
||||
import { IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IDimension } from 'vs/editor/common/editorCommon';
|
||||
|
||||
//#region typed options
|
||||
|
||||
@@ -516,6 +517,13 @@ export interface IEditorOptions {
|
||||
showUnused?: boolean;
|
||||
}
|
||||
|
||||
export interface IEditorConstructionOptions extends IEditorOptions {
|
||||
/**
|
||||
* The initial editor dimension (to avoid measuring the container).
|
||||
*/
|
||||
dimension?: IDimension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration options for the diff editor.
|
||||
*/
|
||||
|
||||
@@ -280,6 +280,8 @@ export interface IEditor {
|
||||
/**
|
||||
* Instructs the editor to remeasure its container. This method should
|
||||
* be called when the container of the editor gets resized.
|
||||
*
|
||||
* If a dimension is passed in, the passed in value will be used.
|
||||
*/
|
||||
layout(dimension?: IDimension): void;
|
||||
|
||||
|
||||
@@ -922,7 +922,7 @@ export interface DocumentSymbol {
|
||||
|
||||
/**
|
||||
* The document symbol provider interface defines the contract between extensions and
|
||||
* the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_goto-symbol)-feature.
|
||||
* the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-symbol)-feature.
|
||||
*/
|
||||
export interface DocumentSymbolProvider {
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import { ScrollType, IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { registerEditorAction, registerEditorContribution, ServicesAccessor, EditorAction, registerInstantiatedEditorAction } from 'vs/editor/browser/editorExtensions';
|
||||
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
|
||||
import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateForMatchingLines, setCollapseStateForType } from 'vs/editor/contrib/folding/foldingModel';
|
||||
import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateForMatchingLines, setCollapseStateForType, toggleCollapseState } from 'vs/editor/contrib/folding/foldingModel';
|
||||
import { FoldingDecorationProvider } from './foldingDecorations';
|
||||
import { FoldingRegions, FoldingRegion } from './foldingRanges';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
@@ -656,6 +656,30 @@ class FoldAction extends FoldingAction<FoldingArguments> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ToggleFoldAction extends FoldingAction<void> {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.toggleFold',
|
||||
label: nls.localize('toggleFoldAction.label', "Toggle Fold"),
|
||||
alias: 'Toggle Fold',
|
||||
precondition: CONTEXT_FOLDING_ENABLED,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.editorTextFocus,
|
||||
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_K),
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
invoke(_foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void {
|
||||
let selectedLines = this.getSelectedLines(editor);
|
||||
toggleCollapseState(foldingModel, 1, selectedLines);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class FoldRecursivelyAction extends FoldingAction<void> {
|
||||
|
||||
constructor() {
|
||||
@@ -842,6 +866,7 @@ registerEditorAction(UnfoldAllAction);
|
||||
registerEditorAction(FoldAllBlockCommentsAction);
|
||||
registerEditorAction(FoldAllRegionsAction);
|
||||
registerEditorAction(UnfoldAllRegionsAction);
|
||||
registerEditorAction(ToggleFoldAction);
|
||||
|
||||
for (let i = 1; i <= 7; i++) {
|
||||
registerInstantiatedEditorAction(
|
||||
|
||||
@@ -242,6 +242,26 @@ export class FoldingModel {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse or expand the regions at the given locations
|
||||
* @param levels The number of levels. Use 1 to only impact the regions at the location, use Number.MAX_VALUE for all levels.
|
||||
* @param lineNumbers the location of the regions to collapse or expand, or if not set, all regions in the model.
|
||||
*/
|
||||
export function toggleCollapseState(foldingModel: FoldingModel, levels: number, lineNumbers: number[]) {
|
||||
let toToggle: FoldingRegion[] = [];
|
||||
for (let lineNumber of lineNumbers) {
|
||||
let region = foldingModel.getRegionAtLine(lineNumber);
|
||||
if (region) {
|
||||
const doCollapse = !region.isCollapsed;
|
||||
toToggle.push(region);
|
||||
if (levels > 1) {
|
||||
let regionsInside = foldingModel.getRegionsInside(region, (r, level: number) => r.isCollapsed !== doCollapse && level < levels);
|
||||
toToggle.push(...regionsInside);
|
||||
}
|
||||
}
|
||||
}
|
||||
foldingModel.toggleCollapseState(toToggle);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.monaco-editor-hover p > code {
|
||||
.monaco-editor-hover code {
|
||||
font-family: var(--monaco-monospace-font);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget > .details p > code {
|
||||
.monaco-editor .suggest-widget > .details p code {
|
||||
font-family: var(--monaco-monospace-font);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { ToggleTabFocusModeAction } from 'vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode';
|
||||
import { IEditorConstructionOptions } from 'vs/editor/standalone/browser/standaloneCodeEditor';
|
||||
import { IStandaloneEditorConstructionOptions } from 'vs/editor/standalone/browser/standaloneCodeEditor';
|
||||
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
@@ -164,7 +164,7 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget {
|
||||
if (e.equals(KeyMod.CtrlCmd | KeyCode.KEY_H)) {
|
||||
alert(AccessibilityHelpNLS.openingDocs);
|
||||
|
||||
let url = (<IEditorConstructionOptions>this._editor.getRawOptions()).accessibilityHelpUrl;
|
||||
let url = (<IStandaloneEditorConstructionOptions>this._editor.getRawOptions()).accessibilityHelpUrl;
|
||||
if (typeof url === 'undefined') {
|
||||
url = 'https://go.microsoft.com/fwlink/?linkid=852450';
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget';
|
||||
import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { IDiffEditorOptions, IEditorOptions, IEditorConstructionOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { InternalEditorAction } from 'vs/editor/common/editorAction';
|
||||
import { IModelChangedEvent } from 'vs/editor/common/editorCommon';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
@@ -79,7 +79,7 @@ export interface IActionDescriptor {
|
||||
/**
|
||||
* The options to create an editor.
|
||||
*/
|
||||
export interface IEditorConstructionOptions extends IEditorOptions {
|
||||
export interface IStandaloneEditorConstructionOptions extends IEditorConstructionOptions {
|
||||
/**
|
||||
* The initial model associated with this code editor.
|
||||
*/
|
||||
@@ -158,7 +158,7 @@ export class StandaloneCodeEditor extends CodeEditorWidget implements IStandalon
|
||||
|
||||
constructor(
|
||||
domElement: HTMLElement,
|
||||
options: IEditorConstructionOptions,
|
||||
options: IStandaloneEditorConstructionOptions,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@ICodeEditorService codeEditorService: ICodeEditorService,
|
||||
@ICommandService commandService: ICommandService,
|
||||
@@ -287,7 +287,7 @@ export class StandaloneEditor extends StandaloneCodeEditor implements IStandalon
|
||||
|
||||
constructor(
|
||||
domElement: HTMLElement,
|
||||
options: IEditorConstructionOptions | undefined,
|
||||
options: IStandaloneEditorConstructionOptions | undefined,
|
||||
toDispose: IDisposable,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@ICodeEditorService codeEditorService: ICodeEditorService,
|
||||
|
||||
@@ -24,7 +24,7 @@ import { IWebWorkerOptions, MonacoWebWorker, createWebWorker as actualCreateWebW
|
||||
import * as standaloneEnums from 'vs/editor/common/standalone/standaloneEnums';
|
||||
import { Colorizer, IColorizerElementOptions, IColorizerOptions } from 'vs/editor/standalone/browser/colorizer';
|
||||
import { SimpleEditorModelResolverService } from 'vs/editor/standalone/browser/simpleServices';
|
||||
import { IDiffEditorConstructionOptions, IEditorConstructionOptions, IStandaloneCodeEditor, IStandaloneDiffEditor, StandaloneDiffEditor, StandaloneEditor } from 'vs/editor/standalone/browser/standaloneCodeEditor';
|
||||
import { IDiffEditorConstructionOptions, IStandaloneEditorConstructionOptions, IStandaloneCodeEditor, IStandaloneDiffEditor, StandaloneDiffEditor, StandaloneEditor } from 'vs/editor/standalone/browser/standaloneCodeEditor';
|
||||
import { DynamicStandaloneServices, IEditorOverrideServices, StaticServices } from 'vs/editor/standalone/browser/standaloneServices';
|
||||
import { IStandaloneThemeData, IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneThemeService';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
@@ -68,7 +68,7 @@ function withAllStandaloneServices<T extends editorCommon.IEditor>(domElement: H
|
||||
* `domElement` should be empty (not contain other dom nodes).
|
||||
* The editor will read the size of `domElement`.
|
||||
*/
|
||||
export function create(domElement: HTMLElement, options?: IEditorConstructionOptions, override?: IEditorOverrideServices): IStandaloneCodeEditor {
|
||||
export function create(domElement: HTMLElement, options?: IStandaloneEditorConstructionOptions, override?: IEditorOverrideServices): IStandaloneCodeEditor {
|
||||
return withAllStandaloneServices(domElement, override || {}, (services) => {
|
||||
return new StandaloneEditor(
|
||||
domElement,
|
||||
|
||||
@@ -29,7 +29,7 @@ import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService
|
||||
export class TestCodeEditor extends CodeEditorWidget implements editorBrowser.ICodeEditor {
|
||||
|
||||
//#region testing overrides
|
||||
protected _createConfiguration(options: editorOptions.IEditorOptions): editorCommon.IConfiguration {
|
||||
protected _createConfiguration(options: editorOptions.IEditorConstructionOptions): editorCommon.IConfiguration {
|
||||
return new TestConfiguration(options);
|
||||
}
|
||||
protected _createView(viewModel: ViewModel, cursor: Cursor): [View, boolean] {
|
||||
|
||||
Vendored
+12
-3
@@ -813,7 +813,7 @@ declare namespace monaco.editor {
|
||||
* `domElement` should be empty (not contain other dom nodes).
|
||||
* The editor will read the size of `domElement`.
|
||||
*/
|
||||
export function create(domElement: HTMLElement, options?: IEditorConstructionOptions, override?: IEditorOverrideServices): IStandaloneCodeEditor;
|
||||
export function create(domElement: HTMLElement, options?: IStandaloneEditorConstructionOptions, override?: IEditorOverrideServices): IStandaloneCodeEditor;
|
||||
|
||||
/**
|
||||
* Emitted when an editor is created.
|
||||
@@ -1051,7 +1051,7 @@ declare namespace monaco.editor {
|
||||
/**
|
||||
* The options to create an editor.
|
||||
*/
|
||||
export interface IEditorConstructionOptions extends IEditorOptions {
|
||||
export interface IStandaloneEditorConstructionOptions extends IEditorConstructionOptions {
|
||||
/**
|
||||
* The initial model associated with this code editor.
|
||||
*/
|
||||
@@ -2061,6 +2061,8 @@ declare namespace monaco.editor {
|
||||
/**
|
||||
* Instructs the editor to remeasure its container. This method should
|
||||
* be called when the container of the editor gets resized.
|
||||
*
|
||||
* If a dimension is passed in, the passed in value will be used.
|
||||
*/
|
||||
layout(dimension?: IDimension): void;
|
||||
/**
|
||||
@@ -2918,6 +2920,13 @@ declare namespace monaco.editor {
|
||||
showUnused?: boolean;
|
||||
}
|
||||
|
||||
export interface IEditorConstructionOptions extends IEditorOptions {
|
||||
/**
|
||||
* The initial editor dimension (to avoid measuring the container).
|
||||
*/
|
||||
dimension?: IDimension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration options for the diff editor.
|
||||
*/
|
||||
@@ -5131,7 +5140,7 @@ declare namespace monaco.languages {
|
||||
|
||||
/**
|
||||
* The document symbol provider interface defines the contract between extensions and
|
||||
* the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_goto-symbol)-feature.
|
||||
* the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-symbol)-feature.
|
||||
*/
|
||||
export interface DocumentSymbolProvider {
|
||||
displayName?: string;
|
||||
|
||||
@@ -8,6 +8,7 @@ import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth
|
||||
import { ICredentialsService } from 'vs/platform/credentials/common/credentials';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
|
||||
const SERVICE_NAME = 'VS Code';
|
||||
const ACCOUNT = 'MyAccount';
|
||||
@@ -23,9 +24,10 @@ export class AuthTokenService extends Disposable implements IAuthTokenService {
|
||||
constructor(
|
||||
@ICredentialsService private readonly credentialsService: ICredentialsService,
|
||||
@IProductService productService: IProductService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
) {
|
||||
super();
|
||||
if (productService.settingsSyncStoreUrl) {
|
||||
if (productService.settingsSyncStoreUrl && configurationService.getValue('configurationSync.enableAuth')) {
|
||||
this._status = AuthTokenStatus.Inactive;
|
||||
this.getToken().then(token => {
|
||||
if (token) {
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { MessageBoxOptions, SaveDialogOptions, OpenDialogOptions, dialog, FileFilter, BrowserWindow } from 'electron';
|
||||
import { Queue } from 'vs/base/common/async';
|
||||
import { IStateService } from 'vs/platform/state/node/state';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { dirname } from 'vs/base/common/path';
|
||||
import { normalizeNFC } from 'vs/base/common/normalization';
|
||||
import { exists } from 'vs/base/node/pfs';
|
||||
import { INativeOpenDialogOptions, MessageBoxReturnValue, SaveDialogReturnValue, OpenDialogReturnValue } from 'vs/platform/dialogs/node/dialogs';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { localize } from 'vs/nls';
|
||||
import { WORKSPACE_FILTER } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
|
||||
export const IDialogMainService = createDecorator<IDialogMainService>('dialogMainService');
|
||||
|
||||
export interface IDialogMainService {
|
||||
|
||||
_serviceBrand: undefined;
|
||||
|
||||
pickFileFolder(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise<string[] | undefined>;
|
||||
pickFolder(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise<string[] | undefined>;
|
||||
pickFile(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise<string[] | undefined>;
|
||||
pickWorkspace(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise<string[] | undefined>;
|
||||
|
||||
showMessageBox(options: MessageBoxOptions, window?: BrowserWindow): Promise<MessageBoxReturnValue>;
|
||||
showSaveDialog(options: SaveDialogOptions, window?: BrowserWindow): Promise<SaveDialogReturnValue>;
|
||||
showOpenDialog(options: OpenDialogOptions, window?: BrowserWindow): Promise<OpenDialogReturnValue>;
|
||||
}
|
||||
|
||||
interface IInternalNativeOpenDialogOptions extends INativeOpenDialogOptions {
|
||||
pickFolders?: boolean;
|
||||
pickFiles?: boolean;
|
||||
|
||||
title: string;
|
||||
buttonLabel?: string;
|
||||
filters?: FileFilter[];
|
||||
}
|
||||
|
||||
export class DialogMainService implements IDialogMainService {
|
||||
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private static readonly workingDirPickerStorageKey = 'pickerWorkingDir';
|
||||
|
||||
private readonly mapWindowToDialogQueue: Map<number, Queue<void>>;
|
||||
private readonly noWindowDialogQueue: Queue<void>;
|
||||
|
||||
constructor(
|
||||
@IStateService private readonly stateService: IStateService
|
||||
) {
|
||||
this.mapWindowToDialogQueue = new Map<number, Queue<void>>();
|
||||
this.noWindowDialogQueue = new Queue<void>();
|
||||
}
|
||||
|
||||
pickFileFolder(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise<string[] | undefined> {
|
||||
return this.doPick({ ...options, pickFolders: true, pickFiles: true, title: localize('open', "Open") }, window);
|
||||
}
|
||||
|
||||
pickFolder(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise<string[] | undefined> {
|
||||
return this.doPick({ ...options, pickFolders: true, title: localize('openFolder', "Open Folder") }, window);
|
||||
}
|
||||
|
||||
pickFile(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise<string[] | undefined> {
|
||||
return this.doPick({ ...options, pickFiles: true, title: localize('openFile', "Open File") }, window);
|
||||
}
|
||||
|
||||
pickWorkspace(options: INativeOpenDialogOptions, window?: BrowserWindow): Promise<string[] | undefined> {
|
||||
const title = localize('openWorkspaceTitle', "Open Workspace");
|
||||
const buttonLabel = mnemonicButtonLabel(localize({ key: 'openWorkspace', comment: ['&& denotes a mnemonic'] }, "&&Open"));
|
||||
const filters = WORKSPACE_FILTER;
|
||||
|
||||
return this.doPick({ ...options, pickFiles: true, title, filters, buttonLabel }, window);
|
||||
}
|
||||
|
||||
private async doPick(options: IInternalNativeOpenDialogOptions, window?: BrowserWindow): Promise<string[] | undefined> {
|
||||
|
||||
// Ensure dialog options
|
||||
const dialogOptions: OpenDialogOptions = {
|
||||
title: options.title,
|
||||
buttonLabel: options.buttonLabel,
|
||||
filters: options.filters
|
||||
};
|
||||
|
||||
// Ensure defaultPath
|
||||
dialogOptions.defaultPath = options.defaultPath || this.stateService.getItem<string>(DialogMainService.workingDirPickerStorageKey);
|
||||
|
||||
|
||||
// Ensure properties
|
||||
if (typeof options.pickFiles === 'boolean' || typeof options.pickFolders === 'boolean') {
|
||||
dialogOptions.properties = undefined; // let it override based on the booleans
|
||||
|
||||
if (options.pickFiles && options.pickFolders) {
|
||||
dialogOptions.properties = ['multiSelections', 'openDirectory', 'openFile', 'createDirectory'];
|
||||
}
|
||||
}
|
||||
|
||||
if (!dialogOptions.properties) {
|
||||
dialogOptions.properties = ['multiSelections', options.pickFolders ? 'openDirectory' : 'openFile', 'createDirectory'];
|
||||
}
|
||||
|
||||
if (isMacintosh) {
|
||||
dialogOptions.properties.push('treatPackageAsDirectory'); // always drill into .app files
|
||||
}
|
||||
|
||||
// Show Dialog
|
||||
const windowToUse = window || BrowserWindow.getFocusedWindow();
|
||||
|
||||
const result = await this.showOpenDialog(dialogOptions, withNullAsUndefined(windowToUse));
|
||||
if (result && result.filePaths && result.filePaths.length > 0) {
|
||||
|
||||
// Remember path in storage for next time
|
||||
this.stateService.setItem(DialogMainService.workingDirPickerStorageKey, dirname(result.filePaths[0]));
|
||||
|
||||
return result.filePaths;
|
||||
}
|
||||
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-check
|
||||
}
|
||||
|
||||
private getDialogQueue(window?: BrowserWindow): Queue<any> {
|
||||
if (!window) {
|
||||
return this.noWindowDialogQueue;
|
||||
}
|
||||
|
||||
let windowDialogQueue = this.mapWindowToDialogQueue.get(window.id);
|
||||
if (!windowDialogQueue) {
|
||||
windowDialogQueue = new Queue<any>();
|
||||
this.mapWindowToDialogQueue.set(window.id, windowDialogQueue);
|
||||
}
|
||||
|
||||
return windowDialogQueue;
|
||||
}
|
||||
|
||||
showMessageBox(options: MessageBoxOptions, window?: BrowserWindow): Promise<MessageBoxReturnValue> {
|
||||
return this.getDialogQueue(window).queue(async () => {
|
||||
return new Promise(resolve => {
|
||||
if (window) {
|
||||
return dialog.showMessageBox(window, options, (response, checkboxChecked) => resolve({ response, checkboxChecked }));
|
||||
}
|
||||
|
||||
return dialog.showMessageBox(options);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
showSaveDialog(options: SaveDialogOptions, window?: BrowserWindow): Promise<SaveDialogReturnValue> {
|
||||
|
||||
function normalizePath(path: string | undefined): string | undefined {
|
||||
if (path && isMacintosh) {
|
||||
path = normalizeNFC(path); // normalize paths returned from the OS
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
return this.getDialogQueue(window).queue(async () => {
|
||||
return new Promise<SaveDialogReturnValue>(resolve => {
|
||||
if (window) {
|
||||
dialog.showSaveDialog(window, options, filePath => resolve({ filePath }));
|
||||
} else {
|
||||
dialog.showSaveDialog(options, filePath => resolve({ filePath }));
|
||||
}
|
||||
}).then(result => {
|
||||
result.filePath = normalizePath(result.filePath);
|
||||
|
||||
return result;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
showOpenDialog(options: OpenDialogOptions, window?: BrowserWindow): Promise<OpenDialogReturnValue> {
|
||||
|
||||
function normalizePaths(paths: string[] | undefined): string[] | undefined {
|
||||
if (paths && paths.length > 0 && isMacintosh) {
|
||||
paths = paths.map(path => normalizeNFC(path)); // normalize paths returned from the OS
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
return this.getDialogQueue(window).queue(async () => {
|
||||
|
||||
// Ensure the path exists (if provided)
|
||||
if (options.defaultPath) {
|
||||
const pathExists = await exists(options.defaultPath);
|
||||
if (!pathExists) {
|
||||
options.defaultPath = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Show dialog
|
||||
return new Promise<OpenDialogReturnValue>(resolve => {
|
||||
if (window) {
|
||||
dialog.showOpenDialog(window, options, filePaths => resolve({ filePaths }));
|
||||
} else {
|
||||
dialog.showOpenDialog(options, filePaths => resolve({ filePaths }));
|
||||
}
|
||||
}).then(result => {
|
||||
result.filePaths = normalizePaths(result.filePaths);
|
||||
|
||||
return result;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -13,3 +13,16 @@ export interface INativeOpenDialogOptions {
|
||||
telemetryEventName?: string;
|
||||
telemetryExtraData?: ITelemetryData;
|
||||
}
|
||||
|
||||
export interface MessageBoxReturnValue {
|
||||
response: number;
|
||||
checkboxChecked: boolean;
|
||||
}
|
||||
|
||||
export interface SaveDialogReturnValue {
|
||||
filePath?: string;
|
||||
}
|
||||
|
||||
export interface OpenDialogReturnValue {
|
||||
filePaths?: string[];
|
||||
}
|
||||
|
||||
@@ -5,16 +5,17 @@
|
||||
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
|
||||
import { MessageBoxOptions, MessageBoxReturnValue, shell, OpenDevToolsOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue, CrashReporterStartOptions, crashReporter, Menu, BrowserWindow, app } from 'electron';
|
||||
import { INativeOpenInWindowOptions } from 'vs/platform/windows/node/window';
|
||||
import { MessageBoxOptions, shell, OpenDevToolsOptions, SaveDialogOptions, OpenDialogOptions, CrashReporterStartOptions, crashReporter, Menu, BrowserWindow, app } from 'electron';
|
||||
import { INativeOpenWindowOptions } from 'vs/platform/windows/node/window';
|
||||
import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
|
||||
import { IOpenedWindow, OpenContext, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows';
|
||||
import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs';
|
||||
import { INativeOpenDialogOptions, MessageBoxReturnValue, SaveDialogReturnValue, OpenDialogReturnValue } from 'vs/platform/dialogs/node/dialogs';
|
||||
import { isMacintosh, IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { IElectronService } from 'vs/platform/electron/node/electron';
|
||||
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
|
||||
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||
import { AddFirstParameterToFunctions } from 'vs/base/common/types';
|
||||
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs';
|
||||
|
||||
export class ElectronMainService implements AddFirstParameterToFunctions<IElectronService, Promise<any> /* only methods, not events */, number /* window ID */> {
|
||||
|
||||
@@ -22,6 +23,7 @@ export class ElectronMainService implements AddFirstParameterToFunctions<IElectr
|
||||
|
||||
constructor(
|
||||
@IWindowsMainService private readonly windowsMainService: IWindowsMainService,
|
||||
@IDialogMainService private readonly dialogMainService: IDialogMainService,
|
||||
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService
|
||||
) {
|
||||
@@ -61,7 +63,7 @@ export class ElectronMainService implements AddFirstParameterToFunctions<IElectr
|
||||
}
|
||||
|
||||
async getActiveWindowId(windowId: number): Promise<number | undefined> {
|
||||
const activeWindow = this.windowsMainService.getFocusedWindow() || this.windowsMainService.getLastActiveWindow();
|
||||
const activeWindow = BrowserWindow.getFocusedWindow() || this.windowsMainService.getLastActiveWindow();
|
||||
if (activeWindow) {
|
||||
return activeWindow.id;
|
||||
}
|
||||
@@ -69,11 +71,17 @@ export class ElectronMainService implements AddFirstParameterToFunctions<IElectr
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async openEmptyWindow(windowId: number, options?: IOpenEmptyWindowOptions): Promise<void> {
|
||||
this.windowsMainService.openEmptyWindow(OpenContext.API, options);
|
||||
openWindow(windowId: number, options?: IOpenEmptyWindowOptions): Promise<void>;
|
||||
openWindow(windowId: number, toOpen: IWindowOpenable[], options?: INativeOpenWindowOptions): Promise<void>;
|
||||
openWindow(windowId: number, arg1?: IOpenEmptyWindowOptions | IWindowOpenable[], arg2?: INativeOpenWindowOptions): Promise<void> {
|
||||
if (Array.isArray(arg1)) {
|
||||
return this.doOpenWindow(windowId, arg1, arg2);
|
||||
}
|
||||
|
||||
return this.doOpenEmptyWindow(windowId, arg1);
|
||||
}
|
||||
|
||||
async openInWindow(windowId: number, toOpen: IWindowOpenable[], options: INativeOpenInWindowOptions = Object.create(null)): Promise<void> {
|
||||
private async doOpenWindow(windowId: number, toOpen: IWindowOpenable[], options: INativeOpenWindowOptions = Object.create(null)): Promise<void> {
|
||||
if (toOpen.length > 0) {
|
||||
this.windowsMainService.open({
|
||||
context: OpenContext.API,
|
||||
@@ -91,6 +99,10 @@ export class ElectronMainService implements AddFirstParameterToFunctions<IElectr
|
||||
}
|
||||
}
|
||||
|
||||
private async doOpenEmptyWindow(windowId: number, options?: IOpenEmptyWindowOptions): Promise<void> {
|
||||
this.windowsMainService.openEmptyWindow(OpenContext.API, options);
|
||||
}
|
||||
|
||||
async toggleFullScreen(windowId: number): Promise<void> {
|
||||
const window = this.windowsMainService.getWindowById(windowId);
|
||||
if (window) {
|
||||
@@ -164,15 +176,24 @@ export class ElectronMainService implements AddFirstParameterToFunctions<IElectr
|
||||
//#region Dialog
|
||||
|
||||
async showMessageBox(windowId: number, options: MessageBoxOptions): Promise<MessageBoxReturnValue> {
|
||||
return this.windowsMainService.showMessageBox(options, this.windowsMainService.getWindowById(windowId));
|
||||
return this.dialogMainService.showMessageBox(options, this.toBrowserWindow(windowId));
|
||||
}
|
||||
|
||||
async showSaveDialog(windowId: number, options: SaveDialogOptions): Promise<SaveDialogReturnValue> {
|
||||
return this.windowsMainService.showSaveDialog(options, this.windowsMainService.getWindowById(windowId));
|
||||
return this.dialogMainService.showSaveDialog(options, this.toBrowserWindow(windowId));
|
||||
}
|
||||
|
||||
async showOpenDialog(windowId: number, options: OpenDialogOptions): Promise<OpenDialogReturnValue> {
|
||||
return this.windowsMainService.showOpenDialog(options, this.windowsMainService.getWindowById(windowId));
|
||||
return this.dialogMainService.showOpenDialog(options, this.toBrowserWindow(windowId));
|
||||
}
|
||||
|
||||
private toBrowserWindow(windowId: number): BrowserWindow | undefined {
|
||||
const window = this.windowsMainService.getWindowById(windowId);
|
||||
if (window) {
|
||||
return window.win;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async pickFileFolderAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise<void> {
|
||||
@@ -214,7 +235,9 @@ export class ElectronMainService implements AddFirstParameterToFunctions<IElectr
|
||||
}
|
||||
|
||||
async openExternal(windowId: number, url: string): Promise<boolean> {
|
||||
return this.windowsMainService.openExternal(url);
|
||||
shell.openExternal(url);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async updateTouchBar(windowId: number, items: ISerializableCommandAction[][]): Promise<void> {
|
||||
@@ -229,7 +252,7 @@ export class ElectronMainService implements AddFirstParameterToFunctions<IElectr
|
||||
//#region macOS Touchbar
|
||||
|
||||
async newWindowTab(): Promise<void> {
|
||||
this.windowsMainService.openNewTabbedWindow(OpenContext.API);
|
||||
this.windowsMainService.open({ context: OpenContext.API, cli: this.environmentService.args, forceNewTabbedWindow: true, forceEmpty: true });
|
||||
}
|
||||
|
||||
async showPreviousWindowTab(): Promise<void> {
|
||||
@@ -267,7 +290,7 @@ export class ElectronMainService implements AddFirstParameterToFunctions<IElectr
|
||||
}
|
||||
}
|
||||
|
||||
async closeWorkpsace(windowId: number): Promise<void> {
|
||||
async closeWorkspace(windowId: number): Promise<void> {
|
||||
const window = this.windowsMainService.getWindowById(windowId);
|
||||
if (window) {
|
||||
return this.windowsMainService.closeWorkspace(window);
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { MessageBoxOptions, MessageBoxReturnValue, OpenDevToolsOptions, SaveDialogOptions, OpenDialogOptions, OpenDialogReturnValue, SaveDialogReturnValue, CrashReporterStartOptions } from 'electron';
|
||||
import { MessageBoxOptions, OpenDevToolsOptions, SaveDialogOptions, OpenDialogOptions, CrashReporterStartOptions } from 'electron';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IWindowOpenable, IOpenEmptyWindowOptions, IOpenedWindow } from 'vs/platform/windows/common/windows';
|
||||
import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs';
|
||||
import { INativeOpenDialogOptions, MessageBoxReturnValue, SaveDialogReturnValue, OpenDialogReturnValue } from 'vs/platform/dialogs/node/dialogs';
|
||||
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
|
||||
import { ParsedArgs } from 'vscode-minimist';
|
||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { INativeOpenInWindowOptions } from 'vs/platform/windows/node/window';
|
||||
import { INativeOpenWindowOptions } from 'vs/platform/windows/node/window';
|
||||
|
||||
export const IElectronService = createDecorator<IElectronService>('electronService');
|
||||
|
||||
@@ -33,8 +33,8 @@ export interface IElectronService {
|
||||
getWindowCount(): Promise<number>;
|
||||
getActiveWindowId(): Promise<number | undefined>;
|
||||
|
||||
openEmptyWindow(options?: IOpenEmptyWindowOptions): Promise<void>;
|
||||
openInWindow(toOpen: IWindowOpenable[], options?: INativeOpenInWindowOptions): Promise<void>;
|
||||
openWindow(options?: IOpenEmptyWindowOptions): Promise<void>;
|
||||
openWindow(toOpen: IWindowOpenable[], options?: INativeOpenWindowOptions): Promise<void>;
|
||||
|
||||
toggleFullScreen(): Promise<void>;
|
||||
|
||||
@@ -76,7 +76,7 @@ export interface IElectronService {
|
||||
// Lifecycle
|
||||
relaunch(options?: { addArgs?: string[], removeArgs?: string[] }): Promise<void>;
|
||||
reload(): Promise<void>;
|
||||
closeWorkpsace(): Promise<void>;
|
||||
closeWorkspace(): Promise<void>;
|
||||
closeWindow(): Promise<void>;
|
||||
quit(): Promise<void>;
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ISharedProcess } from 'vs/platform/windows/electron-main/windows';
|
||||
|
||||
export const ISharedProcessMainService = createDecorator<ISharedProcessMainService>('sharedProcessMainService');
|
||||
|
||||
@@ -15,6 +14,12 @@ export interface ISharedProcessMainService {
|
||||
whenSharedProcessReady(): Promise<void>;
|
||||
toggleSharedProcessWindow(): Promise<void>;
|
||||
}
|
||||
|
||||
export interface ISharedProcess {
|
||||
whenReady(): Promise<void>;
|
||||
toggle(): void;
|
||||
}
|
||||
|
||||
export class SharedProcessMainService implements ISharedProcessMainService {
|
||||
|
||||
_serviceBrand: undefined;
|
||||
|
||||
@@ -7,15 +7,16 @@ import { localize } from 'vs/nls';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv';
|
||||
import { IIssueService, IssueReporterData, IssueReporterFeatures, ProcessExplorerData } from 'vs/platform/issue/node/issue';
|
||||
import { BrowserWindow, ipcMain, screen, dialog, IpcMainEvent, Display } from 'electron';
|
||||
import { BrowserWindow, ipcMain, screen, Event as IpcMainEvent, Display, shell } from 'electron';
|
||||
import { ILaunchMainService } from 'vs/platform/launch/electron-main/launchMainService';
|
||||
import { PerformanceInfo, isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics';
|
||||
import { IDiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsService';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { isMacintosh, IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IWindowState, IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
|
||||
import { IWindowState } from 'vs/platform/windows/electron-main/windows';
|
||||
import { listProcesses } from 'vs/base/node/ps';
|
||||
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs';
|
||||
|
||||
const DEFAULT_BACKGROUND_COLOR = '#1E1E1E';
|
||||
|
||||
@@ -33,7 +34,7 @@ export class IssueMainService implements IIssueService {
|
||||
@ILaunchMainService private readonly launchMainService: ILaunchMainService,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@IDiagnosticsService private readonly diagnosticsService: IDiagnosticsService,
|
||||
@IWindowsMainService private readonly windowsMainService: IWindowsMainService
|
||||
@IDialogMainService private readonly dialogMainService: IDialogMainService
|
||||
) {
|
||||
this.registerListeners();
|
||||
}
|
||||
@@ -89,7 +90,7 @@ export class IssueMainService implements IIssueService {
|
||||
};
|
||||
|
||||
if (this._issueWindow) {
|
||||
dialog.showMessageBox(this._issueWindow, messageOptions)
|
||||
this.dialogMainService.showMessageBox(messageOptions, this._issueWindow)
|
||||
.then(result => {
|
||||
event.sender.send('vscode:issueReporterClipboardResponse', result.response === 0);
|
||||
});
|
||||
@@ -113,7 +114,7 @@ export class IssueMainService implements IIssueService {
|
||||
};
|
||||
|
||||
if (this._issueWindow) {
|
||||
dialog.showMessageBox(this._issueWindow, messageOptions)
|
||||
this.dialogMainService.showMessageBox(messageOptions, this._issueWindow)
|
||||
.then(result => {
|
||||
if (result.response === 0) {
|
||||
if (this._issueWindow) {
|
||||
@@ -146,7 +147,7 @@ export class IssueMainService implements IIssueService {
|
||||
});
|
||||
|
||||
ipcMain.on('vscode:openExternal', (_: unknown, arg: string) => {
|
||||
this.windowsMainService.openExternal(arg);
|
||||
shell.openExternal(arg);
|
||||
});
|
||||
|
||||
ipcMain.on('vscode:closeIssueReporter', (event: IpcMainEvent) => {
|
||||
|
||||
@@ -141,6 +141,7 @@ export class LaunchMainService implements ILaunchMainService {
|
||||
}
|
||||
}
|
||||
|
||||
// Open new Window
|
||||
if (openNewWindow) {
|
||||
usedWindows = this.windowsMainService.open({
|
||||
context,
|
||||
@@ -150,8 +151,18 @@ export class LaunchMainService implements ILaunchMainService {
|
||||
forceEmpty: true,
|
||||
waitMarkerFileURI
|
||||
});
|
||||
} else {
|
||||
usedWindows = [this.windowsMainService.focusLastActive(args, context)];
|
||||
}
|
||||
|
||||
// Focus existing window or open if none opened
|
||||
else {
|
||||
const lastActive = this.windowsMainService.getLastActiveWindow();
|
||||
if (lastActive) {
|
||||
lastActive.focus();
|
||||
|
||||
usedWindows = [lastActive];
|
||||
} else {
|
||||
usedWindows = this.windowsMainService.open({ context, cli: args, forceEmpty: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +227,7 @@ export class LaunchMainService implements ILaunchMainService {
|
||||
mainPID: process.pid,
|
||||
mainArguments: process.argv.slice(1),
|
||||
windows,
|
||||
screenReader: !!app.accessibilitySupportEnabled,
|
||||
screenReader: !!app.isAccessibilitySupportEnabled(),
|
||||
gpuFeatureStatus: app.getGPUFeatureStatus()
|
||||
});
|
||||
}
|
||||
|
||||
@@ -87,4 +87,10 @@ export class BufferLogService extends AbstractLogService implements ILogService
|
||||
this._logger.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
flush(): void {
|
||||
if (this._logger) {
|
||||
this._logger.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,8 +78,7 @@ export class FileLogService extends AbstractLogService implements ILogService {
|
||||
}
|
||||
}
|
||||
|
||||
flush(): Promise<void> {
|
||||
return this.queue.queue(() => Promise.resolve());
|
||||
flush(): void {
|
||||
}
|
||||
|
||||
log(level: LogLevel, args: any[]): void {
|
||||
|
||||
@@ -41,6 +41,11 @@ export interface ILogger extends IDisposable {
|
||||
warn(message: string, ...args: any[]): void;
|
||||
error(message: string | Error, ...args: any[]): void;
|
||||
critical(message: string | Error, ...args: any[]): void;
|
||||
|
||||
/**
|
||||
* An operation to flush the contents. Can be synchronous.
|
||||
*/
|
||||
flush(): void;
|
||||
}
|
||||
|
||||
export interface ILogService extends ILogger {
|
||||
@@ -69,6 +74,7 @@ export abstract class AbstractLogService extends Disposable {
|
||||
getLevel(): LogLevel {
|
||||
return this.level;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ConsoleLogMainService extends AbstractLogService implements ILogService {
|
||||
@@ -145,6 +151,11 @@ export class ConsoleLogMainService extends AbstractLogService implements ILogSer
|
||||
dispose(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
flush(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ConsoleLogService extends AbstractLogService implements ILogService {
|
||||
@@ -192,7 +203,13 @@ export class ConsoleLogService extends AbstractLogService implements ILogService
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void { }
|
||||
dispose(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
flush(): void {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
export class ConsoleLogInMainService extends AbstractLogService implements ILogService {
|
||||
@@ -240,7 +257,13 @@ export class ConsoleLogInMainService extends AbstractLogService implements ILogS
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void { }
|
||||
dispose(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
flush(): void {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
export class MultiplexLogService extends AbstractLogService implements ILogService {
|
||||
@@ -296,6 +319,12 @@ export class MultiplexLogService extends AbstractLogService implements ILogServi
|
||||
}
|
||||
}
|
||||
|
||||
flush(): void {
|
||||
for (const logService of this.logServices) {
|
||||
logService.flush();
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
for (const logService of this.logServices) {
|
||||
logService.dispose();
|
||||
@@ -346,6 +375,10 @@ export class DelegatedLogService extends Disposable implements ILogService {
|
||||
critical(message: string | Error, ...args: any[]): void {
|
||||
this.logService.critical(message, ...args);
|
||||
}
|
||||
|
||||
flush(): void {
|
||||
this.logService.flush();
|
||||
}
|
||||
}
|
||||
|
||||
export class NullLogService implements ILogService {
|
||||
@@ -360,6 +393,7 @@ export class NullLogService implements ILogService {
|
||||
error(message: string | Error, ...args: any[]): void { }
|
||||
critical(message: string | Error, ...args: any[]): void { }
|
||||
dispose(): void { }
|
||||
flush(): void { }
|
||||
}
|
||||
|
||||
export function getLogLevel(environmentService: IEnvironmentService): LogLevel {
|
||||
|
||||
@@ -32,7 +32,7 @@ export class LoggerService extends Disposable implements ILoggerService {
|
||||
if (resource.scheme === Schemas.file) {
|
||||
const baseName = basename(resource);
|
||||
const ext = extname(resource);
|
||||
logger = new SpdLogService(baseName.substring(0, baseName.length - ext.length), dirname(resource).path, this.logService.getLevel());
|
||||
logger = new SpdLogService(baseName.substring(0, baseName.length - ext.length), dirname(resource).fsPath, this.logService.getLevel());
|
||||
} else {
|
||||
logger = this.instantiationService.createInstance(FileLogService, basename(resource), resource, this.logService.getLevel());
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ interface ILog {
|
||||
message: string;
|
||||
}
|
||||
|
||||
function log(logger: spdlog.RotatingLogger, level: LogLevel, message: string, sync: boolean): void {
|
||||
function log(logger: spdlog.RotatingLogger, level: LogLevel, message: string): void {
|
||||
switch (level) {
|
||||
case LogLevel.Trace: logger.trace(message); break;
|
||||
case LogLevel.Debug: logger.debug(message); break;
|
||||
@@ -40,9 +40,6 @@ function log(logger: spdlog.RotatingLogger, level: LogLevel, message: string, sy
|
||||
case LogLevel.Critical: logger.critical(message); break;
|
||||
default: throw new Error('Invalid log level');
|
||||
}
|
||||
if (sync) {
|
||||
logger.flush();
|
||||
}
|
||||
}
|
||||
|
||||
export class SpdLogService extends AbstractLogService implements ILogService {
|
||||
@@ -53,7 +50,7 @@ export class SpdLogService extends AbstractLogService implements ILogService {
|
||||
private _loggerCreationPromise: Promise<void> | undefined = undefined;
|
||||
private _logger: spdlog.RotatingLogger | undefined;
|
||||
|
||||
constructor(private readonly name: string, private readonly logsFolder: string, level: LogLevel, private readonly sync: boolean = false) {
|
||||
constructor(private readonly name: string, private readonly logsFolder: string, level: LogLevel) {
|
||||
super();
|
||||
this.setLevel(level);
|
||||
this._createSpdLogLogger();
|
||||
@@ -72,7 +69,7 @@ export class SpdLogService extends AbstractLogService implements ILogService {
|
||||
this._logger = logger;
|
||||
this._logger.setLevel(this.getLevel());
|
||||
for (const { level, message } of this.buffer) {
|
||||
log(this._logger, level, message, this.sync);
|
||||
log(this._logger, level, message);
|
||||
}
|
||||
this.buffer = [];
|
||||
}
|
||||
@@ -83,7 +80,7 @@ export class SpdLogService extends AbstractLogService implements ILogService {
|
||||
|
||||
private _log(level: LogLevel, message: string): void {
|
||||
if (this._logger) {
|
||||
log(this._logger, level, message, this.sync);
|
||||
log(this._logger, level, message);
|
||||
} else if (this.getLevel() <= level) {
|
||||
this.buffer.push({ level, message });
|
||||
}
|
||||
@@ -132,6 +129,14 @@ export class SpdLogService extends AbstractLogService implements ILogService {
|
||||
}
|
||||
}
|
||||
|
||||
flush(): void {
|
||||
if (this._logger) {
|
||||
this._logger.flush();
|
||||
} else if (this._loggerCreationPromise) {
|
||||
this._loggerCreationPromise.then(() => this.flush());
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
if (this._logger) {
|
||||
this.disposeLogger();
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as nls from 'vs/nls';
|
||||
import { isMacintosh, language } from 'vs/base/common/platform';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { app, shell, Menu, MenuItem, BrowserWindow, MenuItemConstructorOptions, WebContents, Event, KeyboardEvent } from 'electron';
|
||||
import { app, shell, Menu, MenuItem, BrowserWindow, MenuItemConstructorOptions, WebContents, Event, Event as KeyboardEvent } from 'electron';
|
||||
import { OpenContext, IRunActionInWindowRequest, getTitleBarStyle, IRunKeybindingInWindowRequest, IWindowOpenable } from 'vs/platform/windows/common/windows';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
@@ -368,13 +368,13 @@ export class Menubar {
|
||||
const servicesMenu = new Menu();
|
||||
const services = new MenuItem({ label: nls.localize('mServices', "Services"), role: 'services', submenu: servicesMenu });
|
||||
const hide = new MenuItem({ label: nls.localize('mHide', "Hide {0}", product.nameLong), role: 'hide', accelerator: 'Command+H' });
|
||||
const hideOthers = new MenuItem({ label: nls.localize('mHideOthers', "Hide Others"), role: 'hideOthers', accelerator: 'Command+Alt+H' });
|
||||
const hideOthers = new MenuItem({ label: nls.localize('mHideOthers', "Hide Others"), role: 'hideothers', accelerator: 'Command+Alt+H' });
|
||||
const showAll = new MenuItem({ label: nls.localize('mShowAll', "Show All"), role: 'unhide' });
|
||||
const quit = new MenuItem(this.likeAction('workbench.action.quit', {
|
||||
label: nls.localize('miQuit', "Quit {0}", product.nameLong), click: () => {
|
||||
if (
|
||||
this.windowsMainService.getWindowCount() === 0 || // allow to quit when no more windows are open
|
||||
!!this.windowsMainService.getFocusedWindow() || // allow to quit when window has focus (fix for https://github.com/Microsoft/vscode/issues/39191)
|
||||
this.windowsMainService.getWindowCount() === 0 || // allow to quit when no more windows are open
|
||||
!!BrowserWindow.getFocusedWindow() || // allow to quit when window has focus (fix for https://github.com/Microsoft/vscode/issues/39191)
|
||||
this.windowsMainService.getLastActiveWindow()!.isMinimized() // allow to quit when window has no focus but is minimized (https://github.com/Microsoft/vscode/issues/63000)
|
||||
) {
|
||||
this.windowsMainService.quit();
|
||||
@@ -557,7 +557,7 @@ export class Menubar {
|
||||
label: this.mnemonicLabel(nls.localize('miCheckForUpdates', "Check for &&Updates...")), click: () => setTimeout(() => {
|
||||
this.reportMenuActionTelemetry('CheckForUpdate');
|
||||
|
||||
const focusedWindow = this.windowsMainService.getFocusedWindow();
|
||||
const focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
const context = focusedWindow ? { windowId: focusedWindow.id } : null;
|
||||
this.updateService.checkForUpdates(context);
|
||||
}, 0)
|
||||
@@ -697,15 +697,16 @@ export class Menubar {
|
||||
|
||||
private makeContextAwareClickHandler(click: () => void, contextSpecificHandlers: IMenuItemClickHandler): () => void {
|
||||
return () => {
|
||||
|
||||
// No Active Window
|
||||
const activeWindow = this.windowsMainService.getFocusedWindow();
|
||||
const activeWindow = BrowserWindow.getFocusedWindow();
|
||||
if (!activeWindow) {
|
||||
return contextSpecificHandlers.inNoWindow();
|
||||
}
|
||||
|
||||
// DevTools focused
|
||||
if (activeWindow.win.webContents.isDevToolsFocused()) {
|
||||
return contextSpecificHandlers.inDevTools(activeWindow.win.webContents.devToolsWebContents);
|
||||
if (activeWindow.webContents.isDevToolsFocused()) {
|
||||
return contextSpecificHandlers.inDevTools(activeWindow.webContents.devToolsWebContents);
|
||||
}
|
||||
|
||||
// Finally execute command in Window
|
||||
@@ -719,14 +720,15 @@ export class Menubar {
|
||||
// https://github.com/Microsoft/vscode/issues/11928
|
||||
// Still allow to run when the last active window is minimized though for
|
||||
// https://github.com/Microsoft/vscode/issues/63000
|
||||
let activeWindow = this.windowsMainService.getFocusedWindow();
|
||||
if (!activeWindow) {
|
||||
let activeBrowserWindow = BrowserWindow.getFocusedWindow();
|
||||
if (!activeBrowserWindow) {
|
||||
const lastActiveWindow = this.windowsMainService.getLastActiveWindow();
|
||||
if (lastActiveWindow && lastActiveWindow.isMinimized()) {
|
||||
activeWindow = lastActiveWindow;
|
||||
activeBrowserWindow = lastActiveWindow.win;
|
||||
}
|
||||
}
|
||||
|
||||
const activeWindow = activeBrowserWindow ? this.windowsMainService.getWindowById(activeBrowserWindow.id) : undefined;
|
||||
if (activeWindow) {
|
||||
this.logService.trace('menubar#runActionInRenderer', invocation);
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ export function extractLocalHostUriMetaDataForPortMapping(uri: URI): { address:
|
||||
if (uri.scheme !== 'http' && uri.scheme !== 'https') {
|
||||
return undefined;
|
||||
}
|
||||
const localhostMatch = /^(localhost|127\.0\.0\.1):(\d+)$/.exec(uri.authority);
|
||||
const localhostMatch = /^(localhost|127\.0\.0\.1|0\.0\.0\.0):(\d+)$/.exec(uri.authority);
|
||||
if (!localhostMatch) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ class TestableLogService extends AbstractLogService implements ILogService {
|
||||
}
|
||||
|
||||
dispose(): void { }
|
||||
flush(): void { }
|
||||
}
|
||||
|
||||
suite('AIAdapter', () => {
|
||||
@@ -198,4 +199,4 @@ suite('AIAdapter', () => {
|
||||
}
|
||||
}]));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -63,6 +63,12 @@ export function registerConfiguration(): IDisposable {
|
||||
$ref: ignoredSettingsSchemaId,
|
||||
additionalProperties: true,
|
||||
uniqueItems: true
|
||||
},
|
||||
'configurationSync.enableAuth': {
|
||||
'type': 'boolean',
|
||||
description: localize('configurationSync.enableAuth', "Enables authentication and requires VS Code restart when changed"),
|
||||
'default': false,
|
||||
'scope': ConfigurationScope.APPLICATION
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -44,4 +44,8 @@ export class UserDataSyncLogService extends AbstractLogService implements IUserD
|
||||
this.logger.critical(message, ...args);
|
||||
}
|
||||
|
||||
flush(): void {
|
||||
this.logger.flush();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -131,27 +131,32 @@ export class UserDataAutoSync extends Disposable {
|
||||
@IAuthTokenService private readonly authTokenService: IAuthTokenService,
|
||||
) {
|
||||
super();
|
||||
this.updateEnablement();
|
||||
this.sync(true);
|
||||
this._register(Event.any<any>(authTokenService.onDidChangeStatus, userDataSyncService.onDidChangeStatus)(() => this.updateEnablement()));
|
||||
this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('configurationSync.enable'))(() => this.updateEnablement()));
|
||||
this.updateEnablement(false);
|
||||
this._register(Event.any<any>(authTokenService.onDidChangeStatus, userDataSyncService.onDidChangeStatus)(() => this.updateEnablement(true)));
|
||||
this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('configurationSync.enable'))(() => this.updateEnablement(true)));
|
||||
|
||||
// Sync immediately if there is a local change.
|
||||
this._register(Event.debounce(this.userDataSyncService.onDidChangeLocal, () => undefined, 500)(() => this.sync(false)));
|
||||
}
|
||||
|
||||
private updateEnablement(): void {
|
||||
private updateEnablement(stopIfDisabled: boolean): void {
|
||||
const enabled = this.isSyncEnabled();
|
||||
if (this.enabled !== enabled) {
|
||||
this.enabled = enabled;
|
||||
if (this.enabled) {
|
||||
this.userDataSyncLogService.info('Syncing configuration started');
|
||||
this.sync(true);
|
||||
} else {
|
||||
if (this.enabled === enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.enabled = enabled;
|
||||
if (this.enabled) {
|
||||
this.userDataSyncLogService.info('Syncing configuration started');
|
||||
this.sync(true);
|
||||
return;
|
||||
} else {
|
||||
if (stopIfDisabled) {
|
||||
this.userDataSyncService.stop();
|
||||
this.userDataSyncLogService.info('Syncing configuration stopped.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private async sync(loop: boolean): Promise<void> {
|
||||
|
||||
@@ -19,15 +19,17 @@ export interface IOpenedWindow {
|
||||
filename?: string;
|
||||
}
|
||||
|
||||
export interface IOpenInWindowOptions {
|
||||
forceNewWindow?: boolean;
|
||||
export interface IBaseOpenWindowsOptions {
|
||||
forceReuseWindow?: boolean;
|
||||
}
|
||||
|
||||
export interface IOpenWindowOptions extends IBaseOpenWindowsOptions {
|
||||
forceNewWindow?: boolean;
|
||||
|
||||
noRecentEntry?: boolean;
|
||||
}
|
||||
|
||||
export interface IOpenEmptyWindowOptions {
|
||||
reuse?: boolean;
|
||||
export interface IOpenEmptyWindowOptions extends IBaseOpenWindowsOptions {
|
||||
remoteAuthority?: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@ import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { IWorkspaceIdentifier, IEnterWorkspaceResult } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { MessageBoxReturnValue, SaveDialogReturnValue, OpenDialogReturnValue, Rectangle, BrowserWindow, MessageBoxOptions, SaveDialogOptions, OpenDialogOptions } from 'electron';
|
||||
import { Rectangle, BrowserWindow } from 'electron';
|
||||
|
||||
export interface IWindowState {
|
||||
width?: number;
|
||||
@@ -86,38 +86,34 @@ export interface IWindowsCountChangedEvent {
|
||||
}
|
||||
|
||||
export interface IWindowsMainService {
|
||||
|
||||
_serviceBrand: undefined;
|
||||
|
||||
// events
|
||||
readonly onWindowReady: Event<ICodeWindow>;
|
||||
readonly onWindowsCountChanged: Event<IWindowsCountChangedEvent>;
|
||||
readonly onWindowClose: Event<number>;
|
||||
|
||||
// methods
|
||||
reload(win: ICodeWindow, cli?: ParsedArgs): void;
|
||||
enterWorkspace(win: ICodeWindow, path: URI): Promise<IEnterWorkspaceResult | undefined>;
|
||||
closeWorkspace(win: ICodeWindow): void;
|
||||
open(openConfig: IOpenConfiguration): ICodeWindow[];
|
||||
openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): void;
|
||||
openEmptyWindow(context: OpenContext, options?: IOpenEmptyWindowOptions): ICodeWindow[];
|
||||
openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): ICodeWindow[];
|
||||
|
||||
pickFileFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void>;
|
||||
pickFolderAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void>;
|
||||
pickFileAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void>;
|
||||
pickWorkspaceAndOpen(options: INativeOpenDialogOptions, win?: ICodeWindow): Promise<void>;
|
||||
showMessageBox(options: MessageBoxOptions, win?: ICodeWindow): Promise<MessageBoxReturnValue>;
|
||||
showSaveDialog(options: SaveDialogOptions, win?: ICodeWindow): Promise<SaveDialogReturnValue>;
|
||||
showOpenDialog(options: OpenDialogOptions, win?: ICodeWindow): Promise<OpenDialogReturnValue>;
|
||||
focusLastActive(cli: ParsedArgs, context: OpenContext): ICodeWindow;
|
||||
getLastActiveWindow(): ICodeWindow | undefined;
|
||||
waitForWindowCloseOrLoad(windowId: number): Promise<void>;
|
||||
openEmptyWindow(context: OpenContext, options?: IOpenEmptyWindowOptions): ICodeWindow[];
|
||||
openNewTabbedWindow(context: OpenContext): ICodeWindow[];
|
||||
openExternal(url: string): Promise<boolean>;
|
||||
|
||||
sendToFocused(channel: string, ...args: any[]): void;
|
||||
sendToAll(channel: string, payload: any, windowIdsToIgnore?: number[]): void;
|
||||
getFocusedWindow(): ICodeWindow | undefined;
|
||||
|
||||
getLastActiveWindow(): ICodeWindow | undefined;
|
||||
|
||||
getWindowById(windowId: number): ICodeWindow | undefined;
|
||||
getWindows(): ICodeWindow[];
|
||||
getWindowCount(): number;
|
||||
|
||||
waitForWindowCloseOrLoad(windowId: number): Promise<void>;
|
||||
reload(win: ICodeWindow, cli?: ParsedArgs): void;
|
||||
closeWorkspace(win: ICodeWindow): void;
|
||||
quit(): void;
|
||||
}
|
||||
|
||||
@@ -139,8 +135,3 @@ export interface IOpenConfiguration {
|
||||
readonly initialStartup?: boolean;
|
||||
readonly noRecentEntry?: boolean;
|
||||
}
|
||||
|
||||
export interface ISharedProcess {
|
||||
whenReady(): Promise<void>;
|
||||
toggle(): void;
|
||||
}
|
||||
|
||||
@@ -3,12 +3,136 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IOpenInWindowOptions } from 'vs/platform/windows/common/windows';
|
||||
import { OpenContext, IOpenWindowOptions } from 'vs/platform/windows/common/windows';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as extpath from 'vs/base/common/extpath';
|
||||
import { IWorkspaceIdentifier, IResolvedWorkspace, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { isEqual, isEqualOrParent } from 'vs/base/common/resources';
|
||||
|
||||
export interface INativeOpenInWindowOptions extends IOpenInWindowOptions {
|
||||
export interface INativeOpenWindowOptions extends IOpenWindowOptions {
|
||||
diffMode?: boolean;
|
||||
addMode?: boolean;
|
||||
gotoLineMode?: boolean;
|
||||
waitMarkerFileURI?: URI;
|
||||
}
|
||||
|
||||
export interface IWindowContext {
|
||||
openedWorkspace?: IWorkspaceIdentifier;
|
||||
openedFolderUri?: URI;
|
||||
|
||||
extensionDevelopmentPath?: string[];
|
||||
lastFocusTime: number;
|
||||
}
|
||||
|
||||
export interface IBestWindowOrFolderOptions<W extends IWindowContext> {
|
||||
windows: W[];
|
||||
newWindow: boolean;
|
||||
context: OpenContext;
|
||||
fileUri?: URI;
|
||||
userHome?: string;
|
||||
codeSettingsFolder?: string;
|
||||
localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null;
|
||||
}
|
||||
|
||||
export function findBestWindowOrFolderForFile<W extends IWindowContext>({ windows, newWindow, context, fileUri, localWorkspaceResolver: workspaceResolver }: IBestWindowOrFolderOptions<W>): W | undefined {
|
||||
if (!newWindow && fileUri && (context === OpenContext.DESKTOP || context === OpenContext.CLI || context === OpenContext.DOCK)) {
|
||||
const windowOnFilePath = findWindowOnFilePath(windows, fileUri, workspaceResolver);
|
||||
if (windowOnFilePath) {
|
||||
return windowOnFilePath;
|
||||
}
|
||||
}
|
||||
return !newWindow ? getLastActiveWindow(windows) : undefined;
|
||||
}
|
||||
|
||||
function findWindowOnFilePath<W extends IWindowContext>(windows: W[], fileUri: URI, localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null): W | null {
|
||||
|
||||
// First check for windows with workspaces that have a parent folder of the provided path opened
|
||||
for (const window of windows) {
|
||||
const workspace = window.openedWorkspace;
|
||||
if (workspace) {
|
||||
const resolvedWorkspace = localWorkspaceResolver(workspace);
|
||||
if (resolvedWorkspace) {
|
||||
// workspace could be resolved: It's in the local file system
|
||||
if (resolvedWorkspace.folders.some(folder => isEqualOrParent(fileUri, folder.uri))) {
|
||||
return window;
|
||||
}
|
||||
} else {
|
||||
// use the config path instead
|
||||
if (isEqualOrParent(fileUri, workspace.configPath)) {
|
||||
return window;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then go with single folder windows that are parent of the provided file path
|
||||
const singleFolderWindowsOnFilePath = windows.filter(window => window.openedFolderUri && isEqualOrParent(fileUri, window.openedFolderUri));
|
||||
if (singleFolderWindowsOnFilePath.length) {
|
||||
return singleFolderWindowsOnFilePath.sort((a, b) => -(a.openedFolderUri!.path.length - b.openedFolderUri!.path.length))[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getLastActiveWindow<W extends IWindowContext>(windows: W[]): W | undefined {
|
||||
const lastFocusedDate = Math.max.apply(Math, windows.map(window => window.lastFocusTime));
|
||||
|
||||
return windows.filter(window => window.lastFocusTime === lastFocusedDate)[0];
|
||||
}
|
||||
|
||||
export function findWindowOnWorkspace<W extends IWindowContext>(windows: W[], workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier)): W | null {
|
||||
if (isSingleFolderWorkspaceIdentifier(workspace)) {
|
||||
for (const window of windows) {
|
||||
// match on folder
|
||||
if (isSingleFolderWorkspaceIdentifier(workspace)) {
|
||||
if (window.openedFolderUri && isEqual(window.openedFolderUri, workspace)) {
|
||||
return window;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isWorkspaceIdentifier(workspace)) {
|
||||
for (const window of windows) {
|
||||
// match on workspace
|
||||
if (window.openedWorkspace && window.openedWorkspace.id === workspace.id) {
|
||||
return window;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function findWindowOnExtensionDevelopmentPath<W extends IWindowContext>(windows: W[], extensionDevelopmentPaths: string[]): W | null {
|
||||
|
||||
const matches = (uriString: string): boolean => {
|
||||
return extensionDevelopmentPaths.some(p => extpath.isEqual(p, uriString, !platform.isLinux /* ignorecase */));
|
||||
};
|
||||
|
||||
for (const window of windows) {
|
||||
// match on extension development path. The path can be one or more paths or uri strings, using paths.isEqual is not 100% correct but good enough
|
||||
const currPaths = window.extensionDevelopmentPath;
|
||||
if (currPaths && currPaths.some(p => matches(p))) {
|
||||
return window;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function findWindowOnWorkspaceOrFolderUri<W extends IWindowContext>(windows: W[], uri: URI | undefined): W | null {
|
||||
if (!uri) {
|
||||
return null;
|
||||
}
|
||||
for (const window of windows) {
|
||||
// check for workspace config path
|
||||
if (window.openedWorkspace && isEqual(window.openedWorkspace.configPath, uri)) {
|
||||
return window;
|
||||
}
|
||||
|
||||
// check for folder path
|
||||
if (window.openedFolderUri && isEqual(window.openedFolderUri, uri)) {
|
||||
return window;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+10
-10
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import { findBestWindowOrFolderForFile, ISimpleWindow, IBestWindowOrFolderOptions } from 'vs/code/node/windowsFinder';
|
||||
import { IBestWindowOrFolderOptions, IWindowContext, findBestWindowOrFolderForFile } from 'vs/platform/windows/node/window';
|
||||
import { OpenContext } from 'vs/platform/windows/common/windows';
|
||||
import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
|
||||
@@ -20,7 +20,7 @@ const testWorkspace: IWorkspaceIdentifier = {
|
||||
|
||||
const testWorkspaceFolders = toWorkspaceFolders([{ path: path.join(fixturesFolder, 'vscode_workspace_1_folder') }, { path: path.join(fixturesFolder, 'vscode_workspace_2_folder') }], testWorkspace.configPath);
|
||||
|
||||
function options(custom?: Partial<IBestWindowOrFolderOptions<ISimpleWindow>>): IBestWindowOrFolderOptions<ISimpleWindow> {
|
||||
function options(custom?: Partial<IBestWindowOrFolderOptions<IWindowContext>>): IBestWindowOrFolderOptions<IWindowContext> {
|
||||
return {
|
||||
windows: [],
|
||||
newWindow: false,
|
||||
@@ -31,10 +31,10 @@ function options(custom?: Partial<IBestWindowOrFolderOptions<ISimpleWindow>>): I
|
||||
};
|
||||
}
|
||||
|
||||
const vscodeFolderWindow: ISimpleWindow = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'vscode_folder')) };
|
||||
const lastActiveWindow: ISimpleWindow = { lastFocusTime: 3, openedFolderUri: undefined };
|
||||
const noVscodeFolderWindow: ISimpleWindow = { lastFocusTime: 2, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder')) };
|
||||
const windows: ISimpleWindow[] = [
|
||||
const vscodeFolderWindow: IWindowContext = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'vscode_folder')) };
|
||||
const lastActiveWindow: IWindowContext = { lastFocusTime: 3, openedFolderUri: undefined };
|
||||
const noVscodeFolderWindow: IWindowContext = { lastFocusTime: 2, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder')) };
|
||||
const windows: IWindowContext[] = [
|
||||
vscodeFolderWindow,
|
||||
lastActiveWindow,
|
||||
noVscodeFolderWindow,
|
||||
@@ -102,7 +102,7 @@ suite('WindowsFinder', () => {
|
||||
windows,
|
||||
fileUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'file.txt'))
|
||||
})), vscodeFolderWindow);
|
||||
const window: ISimpleWindow = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'nested_folder')) };
|
||||
const window: IWindowContext = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'nested_folder')) };
|
||||
assert.equal(findBestWindowOrFolderForFile(options({
|
||||
windows: [window],
|
||||
fileUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'nested_folder', 'subfolder', 'file.txt'))
|
||||
@@ -110,8 +110,8 @@ suite('WindowsFinder', () => {
|
||||
});
|
||||
|
||||
test('More specific existing window wins', () => {
|
||||
const window: ISimpleWindow = { lastFocusTime: 2, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder')) };
|
||||
const nestedFolderWindow: ISimpleWindow = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder', 'nested_folder')) };
|
||||
const window: IWindowContext = { lastFocusTime: 2, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder')) };
|
||||
const nestedFolderWindow: IWindowContext = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder', 'nested_folder')) };
|
||||
assert.equal(findBestWindowOrFolderForFile(options({
|
||||
windows: [window, nestedFolderWindow],
|
||||
fileUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder', 'nested_folder', 'subfolder', 'file.txt'))
|
||||
@@ -119,7 +119,7 @@ suite('WindowsFinder', () => {
|
||||
});
|
||||
|
||||
test('Workspace folder wins', () => {
|
||||
const window: ISimpleWindow = { lastFocusTime: 1, openedWorkspace: testWorkspace };
|
||||
const window: IWindowContext = { lastFocusTime: 1, openedWorkspace: testWorkspace };
|
||||
assert.equal(findBestWindowOrFolderForFile(options({
|
||||
windows: [window],
|
||||
fileUri: URI.file(path.join(fixturesFolder, 'vscode_workspace_2_folder', 'nested_vscode_folder', 'subfolder', 'file.txt'))
|
||||
@@ -31,7 +31,7 @@ export interface IWorkspacesService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
// Management
|
||||
enterWorkspace(path: URI): Promise<IEnterWorkspaceResult | undefined>;
|
||||
enterWorkspace(path: URI): Promise<IEnterWorkspaceResult | null>;
|
||||
createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise<IWorkspaceIdentifier>;
|
||||
deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise<void>;
|
||||
getWorkspaceIdentifier(workspacePath: URI): Promise<IWorkspaceIdentifier>;
|
||||
|
||||
@@ -23,6 +23,7 @@ import { getSimpleWorkspaceLabel } from 'vs/platform/label/common/label';
|
||||
import { exists } from 'vs/base/node/pfs';
|
||||
import { ILifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
export const IWorkspacesHistoryMainService = createDecorator<IWorkspacesHistoryMainService>('workspacesHistoryMainService');
|
||||
|
||||
@@ -40,7 +41,7 @@ export interface IWorkspacesHistoryMainService {
|
||||
updateWindowsJumpList(): void;
|
||||
}
|
||||
|
||||
export class WorkspacesHistoryMainService implements IWorkspacesHistoryMainService {
|
||||
export class WorkspacesHistoryMainService extends Disposable implements IWorkspacesHistoryMainService {
|
||||
|
||||
private static readonly MAX_TOTAL_RECENT_ENTRIES = 100;
|
||||
|
||||
@@ -60,18 +61,27 @@ export class WorkspacesHistoryMainService implements IWorkspacesHistoryMainServi
|
||||
private readonly _onRecentlyOpenedChange = new Emitter<void>();
|
||||
readonly onRecentlyOpenedChange: CommonEvent<void> = this._onRecentlyOpenedChange.event;
|
||||
|
||||
private macOSRecentDocumentsUpdater: ThrottledDelayer<void>;
|
||||
private macOSRecentDocumentsUpdater = this._register(new ThrottledDelayer<void>(800));
|
||||
|
||||
constructor(
|
||||
@IStateService private readonly stateService: IStateService,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService,
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService,
|
||||
@ILifecycleMainService lifecycleMainService: ILifecycleMainService
|
||||
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService
|
||||
) {
|
||||
this.macOSRecentDocumentsUpdater = new ThrottledDelayer<void>(800);
|
||||
super();
|
||||
|
||||
lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.handleWindowsJumpList());
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
|
||||
// Install window jump list after opening window
|
||||
this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.handleWindowsJumpList());
|
||||
|
||||
// Add to history when entering workspace
|
||||
this._register(this.workspacesMainService.onWorkspaceEntered(event => this.addRecentlyOpened([{ workspace: event.workspace }])));
|
||||
}
|
||||
|
||||
private handleWindowsJumpList(): void {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IWorkspaceIdentifier, hasWorkspaceFileExtension, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, IUntitledWorkspaceInfo, getStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { IWorkspaceIdentifier, hasWorkspaceFileExtension, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, IUntitledWorkspaceInfo, getStoredWorkspaceFolder, IEnterWorkspaceResult } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { join, dirname } from 'vs/base/common/path';
|
||||
import { mkdirp, writeFile, rimrafSync, readdirSync, writeFileSync } from 'vs/base/node/pfs';
|
||||
@@ -17,31 +17,43 @@ import { toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { originalFSPath, isEqualOrParent, joinPath } from 'vs/base/common/resources';
|
||||
import { originalFSPath, isEqualOrParent, joinPath, isEqual, basename } from 'vs/base/common/resources';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ICodeWindow } from 'vs/platform/windows/electron-main/windows';
|
||||
import { localize } from 'vs/nls';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { MessageBoxOptions, BrowserWindow } from 'electron';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { IBackupMainService } from 'vs/platform/backup/electron-main/backup';
|
||||
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs';
|
||||
import { findWindowOnWorkspace } from 'vs/platform/windows/node/window';
|
||||
|
||||
export const IWorkspacesMainService = createDecorator<IWorkspacesMainService>('workspacesMainService');
|
||||
|
||||
export interface IWorkspaceEnteredEvent {
|
||||
window: ICodeWindow;
|
||||
workspace: IWorkspaceIdentifier;
|
||||
}
|
||||
|
||||
export interface IWorkspacesMainService {
|
||||
|
||||
_serviceBrand: undefined;
|
||||
|
||||
readonly onUntitledWorkspaceDeleted: Event<IWorkspaceIdentifier>;
|
||||
readonly onWorkspaceEntered: Event<IWorkspaceEnteredEvent>;
|
||||
|
||||
enterWorkspace(intoWindow: ICodeWindow, openedWindows: ICodeWindow[], path: URI): Promise<IEnterWorkspaceResult | null>;
|
||||
|
||||
createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise<IWorkspaceIdentifier>;
|
||||
createUntitledWorkspaceSync(folders?: IWorkspaceFolderCreationData[]): IWorkspaceIdentifier;
|
||||
|
||||
resolveLocalWorkspaceSync(path: URI): IResolvedWorkspace | null;
|
||||
|
||||
isUntitledWorkspace(workspace: IWorkspaceIdentifier): boolean;
|
||||
|
||||
deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise<void>;
|
||||
deleteUntitledWorkspaceSync(workspace: IWorkspaceIdentifier): void;
|
||||
|
||||
getUntitledWorkspacesSync(): IUntitledWorkspaceInfo[];
|
||||
isUntitledWorkspace(workspace: IWorkspaceIdentifier): boolean;
|
||||
|
||||
createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise<IWorkspaceIdentifier>;
|
||||
|
||||
deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise<void>;
|
||||
|
||||
resolveLocalWorkspaceSync(path: URI): IResolvedWorkspace | null;
|
||||
getWorkspaceIdentifier(workspacePath: URI): Promise<IWorkspaceIdentifier>;
|
||||
}
|
||||
|
||||
@@ -59,9 +71,14 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain
|
||||
private readonly _onUntitledWorkspaceDeleted = this._register(new Emitter<IWorkspaceIdentifier>());
|
||||
readonly onUntitledWorkspaceDeleted: Event<IWorkspaceIdentifier> = this._onUntitledWorkspaceDeleted.event;
|
||||
|
||||
private readonly _onWorkspaceEntered = this._register(new Emitter<IWorkspaceEnteredEvent>());
|
||||
readonly onWorkspaceEntered: Event<IWorkspaceEnteredEvent> = this._onWorkspaceEntered.event;
|
||||
|
||||
constructor(
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService,
|
||||
@ILogService private readonly logService: ILogService
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@IBackupMainService private readonly backupMainService: IBackupMainService,
|
||||
@IDialogMainService private readonly dialogMainService: IDialogMainService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -236,6 +253,74 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain
|
||||
}
|
||||
return untitledWorkspaces;
|
||||
}
|
||||
|
||||
async enterWorkspace(window: ICodeWindow, windows: ICodeWindow[], path: URI): Promise<IEnterWorkspaceResult | null> {
|
||||
if (!window || !window.win || !window.isReady) {
|
||||
return null; // return early if the window is not ready or disposed
|
||||
}
|
||||
|
||||
const isValid = await this.isValidTargetWorkspacePath(window, windows, path);
|
||||
if (!isValid) {
|
||||
return null; // return early if the workspace is not valid
|
||||
}
|
||||
|
||||
const result = this.doEnterWorkspace(window, getWorkspaceIdentifier(path));
|
||||
|
||||
// Emit as event
|
||||
this._onWorkspaceEntered.fire({ window, workspace: result.workspace });
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async isValidTargetWorkspacePath(window: ICodeWindow, windows: ICodeWindow[], path?: URI): Promise<boolean> {
|
||||
if (!path) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (window.openedWorkspace && isEqual(window.openedWorkspace.configPath, path)) {
|
||||
return false; // window is already opened on a workspace with that path
|
||||
}
|
||||
|
||||
// Prevent overwriting a workspace that is currently opened in another window
|
||||
if (findWindowOnWorkspace(windows, getWorkspaceIdentifier(path))) {
|
||||
const options: MessageBoxOptions = {
|
||||
title: product.nameLong,
|
||||
type: 'info',
|
||||
buttons: [localize('ok', "OK")],
|
||||
message: localize('workspaceOpenedMessage', "Unable to save workspace '{0}'", basename(path)),
|
||||
detail: localize('workspaceOpenedDetail', "The workspace is already opened in another window. Please close that window first and then try again."),
|
||||
noLink: true
|
||||
};
|
||||
|
||||
await this.dialogMainService.showMessageBox(options, withNullAsUndefined(BrowserWindow.getFocusedWindow()));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true; // OK
|
||||
}
|
||||
|
||||
private doEnterWorkspace(window: ICodeWindow, workspace: IWorkspaceIdentifier): IEnterWorkspaceResult {
|
||||
window.focus();
|
||||
|
||||
// Register window for backups and migrate current backups over
|
||||
let backupPath: string | undefined;
|
||||
if (!window.config.extensionDevelopmentPath) {
|
||||
backupPath = this.backupMainService.registerWorkspaceBackupSync({ workspace, remoteAuthority: window.remoteAuthority }, window.config.backupPath);
|
||||
}
|
||||
|
||||
// if the window was opened on an untitled workspace, delete it.
|
||||
if (window.openedWorkspace && this.isUntitledWorkspace(window.openedWorkspace)) {
|
||||
this.deleteUntitledWorkspaceSync(window.openedWorkspace);
|
||||
}
|
||||
|
||||
// Update window configuration properly based on transition to workspace
|
||||
window.config.folderUri = undefined;
|
||||
window.config.workspace = workspace;
|
||||
window.config.backupPath = backupPath;
|
||||
|
||||
return { workspace, backupPath };
|
||||
}
|
||||
}
|
||||
|
||||
function getWorkspaceId(configPath: URI): string {
|
||||
|
||||
@@ -23,13 +23,13 @@ export class WorkspacesService implements AddFirstParameterToFunctions<IWorkspac
|
||||
|
||||
//#region Workspace Management
|
||||
|
||||
async enterWorkspace(windowId: number, path: URI): Promise<IEnterWorkspaceResult | undefined> {
|
||||
async enterWorkspace(windowId: number, path: URI): Promise<IEnterWorkspaceResult | null> {
|
||||
const window = this.windowsMainService.getWindowById(windowId);
|
||||
if (window) {
|
||||
return this.windowsMainService.enterWorkspace(window, path);
|
||||
return this.workspacesMainService.enterWorkspace(window, this.windowsMainService.getWindows(), path);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return null;
|
||||
}
|
||||
|
||||
createUntitledWorkspace(windowId: number, folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise<IWorkspaceIdentifier> {
|
||||
|
||||
@@ -18,6 +18,7 @@ import { getRandomTestPath } from 'vs/base/test/node/testUtils';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { normalizeDriveLetter } from 'vs/base/common/labels';
|
||||
import { dirname, joinPath } from 'vs/base/common/resources';
|
||||
import { TestBackupMainService, TestDialogMainService } from 'vs/workbench/test/workbenchTestServices';
|
||||
|
||||
suite('WorkspacesMainService', () => {
|
||||
const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'workspacesservice');
|
||||
@@ -43,7 +44,7 @@ suite('WorkspacesMainService', () => {
|
||||
let service: WorkspacesMainService;
|
||||
|
||||
setup(async () => {
|
||||
service = new WorkspacesMainService(environmentService, logService);
|
||||
service = new WorkspacesMainService(environmentService, logService, new TestBackupMainService(), new TestDialogMainService());
|
||||
|
||||
// Delete any existing backups completely and then re-create it.
|
||||
await pfs.rimraf(untitledWorkspacesHomePath, pfs.RimRafMode.MOVE);
|
||||
|
||||
Vendored
+1
-39
@@ -1085,45 +1085,7 @@ declare module 'vscode' {
|
||||
|
||||
//#region Custom editors, mjbvz
|
||||
|
||||
export enum WebviewContentState {
|
||||
/**
|
||||
* The webview content cannot be modified.
|
||||
*
|
||||
* This disables save.
|
||||
*/
|
||||
Readonly = 1,
|
||||
|
||||
/**
|
||||
* The webview content has not been changed but they can be modified and saved.
|
||||
*/
|
||||
Unchanged = 2,
|
||||
|
||||
/**
|
||||
* The webview content has been changed and can be saved.
|
||||
*/
|
||||
Dirty = 3,
|
||||
}
|
||||
|
||||
export interface WebviewEditorState {
|
||||
readonly contentState: WebviewContentState;
|
||||
}
|
||||
|
||||
export interface WebviewPanel {
|
||||
editorState: WebviewEditorState;
|
||||
|
||||
/**
|
||||
* Fired when the webview is being saved.
|
||||
*
|
||||
* Both `Unchanged` and `Dirty` editors can be saved.
|
||||
*
|
||||
* Extensions should call `waitUntil` to signal when the save operation complete
|
||||
*/
|
||||
readonly onWillSave: Event<{ waitUntil: (thenable: Thenable<boolean>) => void }>;
|
||||
}
|
||||
|
||||
export interface WebviewEditor extends WebviewPanel {
|
||||
// TODO: We likely do not want `editorState` and `onWillSave` enabled for
|
||||
// resource backed webviews
|
||||
}
|
||||
|
||||
export interface WebviewEditorProvider {
|
||||
@@ -1168,7 +1130,7 @@ declare module 'vscode' {
|
||||
*
|
||||
* @return A uri that can be used on the client machine.
|
||||
*/
|
||||
export function resolveExternalUri(target: Uri): Thenable<Uri>;
|
||||
export function asExternalUri(target: Uri): Thenable<Uri>;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
@@ -11,7 +11,7 @@ import * as search from 'vs/workbench/contrib/search/common/search';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Position as EditorPosition } from 'vs/editor/common/core/position';
|
||||
import { Range as EditorRange, IRange } from 'vs/editor/common/core/range';
|
||||
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, IDefinitionLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyItemDto, ISuggestDataDto, ICodeActionDto } from '../common/extHost.protocol';
|
||||
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, IDefinitionLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyItemDto, ISuggestDataDto, ICodeActionDto, ISuggestDataDtoField } from '../common/extHost.protocol';
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
@@ -328,20 +328,20 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
|
||||
private static _inflateSuggestDto(defaultRange: IRange, data: ISuggestDataDto): modes.CompletionItem {
|
||||
return {
|
||||
label: data.a,
|
||||
kind: data.b,
|
||||
tags: data.n,
|
||||
detail: data.c,
|
||||
documentation: data.d,
|
||||
sortText: data.e,
|
||||
filterText: data.f,
|
||||
preselect: data.g,
|
||||
insertText: typeof data.h === 'undefined' ? data.a : data.h,
|
||||
insertTextRules: data.i,
|
||||
range: data.j || defaultRange,
|
||||
commitCharacters: data.k,
|
||||
additionalTextEdits: data.l,
|
||||
command: data.m,
|
||||
label: data[ISuggestDataDtoField.label],
|
||||
kind: data[ISuggestDataDtoField.kind],
|
||||
tags: data[ISuggestDataDtoField.kindModifier],
|
||||
detail: data[ISuggestDataDtoField.detail],
|
||||
documentation: data[ISuggestDataDtoField.documentation],
|
||||
sortText: data[ISuggestDataDtoField.sortText],
|
||||
filterText: data[ISuggestDataDtoField.filterText],
|
||||
preselect: data[ISuggestDataDtoField.preselect],
|
||||
insertText: typeof data.h === 'undefined' ? data[ISuggestDataDtoField.label] : data.h,
|
||||
insertTextRules: data[ISuggestDataDtoField.insertTextRules],
|
||||
range: data[ISuggestDataDtoField.range] || defaultRange,
|
||||
commitCharacters: data[ISuggestDataDtoField.commitCharacters],
|
||||
additionalTextEdits: data[ISuggestDataDtoField.additionalTextEdits],
|
||||
command: data[ISuggestDataDtoField.command],
|
||||
// not-standard
|
||||
_id: data.x,
|
||||
};
|
||||
|
||||
@@ -47,7 +47,7 @@ export class MainThreadWindow implements MainThreadWindowShape {
|
||||
return this.openerService.open(uri, { openExternal: true, allowTunneling: options.allowTunneling });
|
||||
}
|
||||
|
||||
async $resolveExternalUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise<UriComponents> {
|
||||
async $asExternalUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise<UriComponents> {
|
||||
const uri = URI.revive(uriComponents);
|
||||
const result = await this.openerService.resolveExternalUri(uri, options);
|
||||
return result.resolved;
|
||||
|
||||
@@ -11,7 +11,7 @@ import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||
import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IOpenInWindowOptions, IWindowOpenable } from 'vs/platform/windows/common/windows';
|
||||
import { IOpenWindowOptions, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows';
|
||||
import { IWorkspacesService, hasWorkspaceFileExtension, IRecent } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
@@ -49,7 +49,7 @@ export class OpenFolderAPICommand {
|
||||
if (!uri) {
|
||||
return executor.executeCommand('_files.pickFolderAndOpen', { forceNewWindow: arg.forceNewWindow });
|
||||
}
|
||||
const options: IOpenInWindowOptions = { forceNewWindow: arg.forceNewWindow, forceReuseWindow: arg.forceReuseWindow, noRecentEntry: arg.noRecentEntry };
|
||||
const options: IOpenWindowOptions = { forceNewWindow: arg.forceNewWindow, forceReuseWindow: arg.forceReuseWindow, noRecentEntry: arg.noRecentEntry };
|
||||
uri = URI.revive(uri);
|
||||
const uriToOpen: IWindowOpenable = (hasWorkspaceFileExtension(uri) || uri.scheme === Schemas.untitled) ? { workspaceUri: uri } : { folderUri: uri };
|
||||
return executor.executeCommand('_files.windowOpen', [uriToOpen], options);
|
||||
@@ -75,10 +75,12 @@ interface INewWindowAPICommandOptions {
|
||||
export class NewWindowAPICommand {
|
||||
public static ID = 'vscode.newWindow';
|
||||
public static execute(executor: ICommandsExecutor, options?: INewWindowAPICommandOptions): Promise<any> {
|
||||
return executor.executeCommand('_files.newWindow', {
|
||||
reuse: options && options.reuseWindow,
|
||||
const commandOptions: IOpenEmptyWindowOptions = {
|
||||
forceReuseWindow: options && options.reuseWindow,
|
||||
remoteAuthority: options && options.remoteAuthority
|
||||
});
|
||||
};
|
||||
|
||||
return executor.executeCommand('_files.newWindow', commandOptions);
|
||||
}
|
||||
}
|
||||
CommandsRegistry.registerCommand({
|
||||
|
||||
@@ -249,9 +249,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
openExternal(uri: URI) {
|
||||
return extHostWindow.openUri(uri, { allowTunneling: !!initData.remote.isRemote });
|
||||
},
|
||||
resolveExternalUri(uri: URI) {
|
||||
asExternalUri(uri: URI) {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostWindow.resolveExternalUri(uri, { allowTunneling: !!initData.remote.isRemote });
|
||||
return extHostWindow.asExternalUri(uri, { allowTunneling: !!initData.remote.isRemote });
|
||||
},
|
||||
get remoteName() {
|
||||
return getRemoteName(initData.remote.authority);
|
||||
|
||||
@@ -750,7 +750,7 @@ export interface IOpenUriOptions {
|
||||
export interface MainThreadWindowShape extends IDisposable {
|
||||
$getWindowVisibility(): Promise<boolean>;
|
||||
$openUri(uri: UriComponents, options: IOpenUriOptions): Promise<boolean>;
|
||||
$resolveExternalUri(uri: UriComponents, options: IOpenUriOptions): Promise<UriComponents>;
|
||||
$asExternalUri(uri: UriComponents, options: IOpenUriOptions): Promise<UriComponents>;
|
||||
}
|
||||
|
||||
// -- extension host
|
||||
@@ -944,21 +944,38 @@ export class IdObject {
|
||||
}
|
||||
}
|
||||
|
||||
export const enum ISuggestDataDtoField {
|
||||
label = 'a',
|
||||
kind = 'b',
|
||||
detail = 'c',
|
||||
documentation = 'd',
|
||||
sortText = 'e',
|
||||
filterText = 'f',
|
||||
preselect = 'g',
|
||||
insertText = 'h',
|
||||
insertTextRules = 'i',
|
||||
range = 'j',
|
||||
commitCharacters = 'k',
|
||||
additionalTextEdits = 'l',
|
||||
command = 'm',
|
||||
kindModifier = 'n',
|
||||
}
|
||||
|
||||
export interface ISuggestDataDto {
|
||||
a/* label */: string;
|
||||
b/* kind */: modes.CompletionItemKind;
|
||||
c/* detail */?: string;
|
||||
d/* documentation */?: string | IMarkdownString;
|
||||
e/* sortText */?: string;
|
||||
f/* filterText */?: string;
|
||||
g/* preselect */?: boolean;
|
||||
h/* insertText */?: string;
|
||||
i/* insertTextRules */?: modes.CompletionItemInsertTextRule;
|
||||
j/* range */?: IRange;
|
||||
k/* commitCharacters */?: string[];
|
||||
l/* additionalTextEdits */?: ISingleEditOperation[];
|
||||
m/* command */?: modes.Command;
|
||||
n/* kindModifier */?: modes.CompletionItemTag[];
|
||||
[ISuggestDataDtoField.label]: string;
|
||||
[ISuggestDataDtoField.kind]: modes.CompletionItemKind;
|
||||
[ISuggestDataDtoField.detail]?: string;
|
||||
[ISuggestDataDtoField.documentation]?: string | IMarkdownString;
|
||||
[ISuggestDataDtoField.sortText]?: string;
|
||||
[ISuggestDataDtoField.filterText]?: string;
|
||||
[ISuggestDataDtoField.preselect]?: boolean;
|
||||
[ISuggestDataDtoField.insertText]?: string;
|
||||
[ISuggestDataDtoField.insertTextRules]?: modes.CompletionItemInsertTextRule;
|
||||
[ISuggestDataDtoField.range]?: IRange;
|
||||
[ISuggestDataDtoField.commitCharacters]?: string[];
|
||||
[ISuggestDataDtoField.additionalTextEdits]?: ISingleEditOperation[];
|
||||
[ISuggestDataDtoField.command]?: modes.Command;
|
||||
[ISuggestDataDtoField.kindModifier]?: modes.CompletionItemTag[];
|
||||
// not-standard
|
||||
x?: ChainedCacheId;
|
||||
}
|
||||
|
||||
@@ -327,6 +327,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
|
||||
}
|
||||
|
||||
this._logService.info(`ExtensionService#_doActivateExtension ${extensionDescription.identifier.value} ${JSON.stringify(reason)}`);
|
||||
this._logService.flush();
|
||||
|
||||
const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup);
|
||||
return Promise.all([
|
||||
|
||||
@@ -724,18 +724,18 @@ class SuggestAdapter {
|
||||
//
|
||||
x: id,
|
||||
//
|
||||
a: item.label,
|
||||
b: typeConvert.CompletionItemKind.from(item.kind),
|
||||
n: item.tags && item.tags.map(typeConvert.CompletionItemTag.from),
|
||||
c: item.detail,
|
||||
d: typeof item.documentation === 'undefined' ? undefined : typeConvert.MarkdownString.fromStrict(item.documentation),
|
||||
e: item.sortText,
|
||||
f: item.filterText,
|
||||
g: item.preselect,
|
||||
i: item.keepWhitespace ? modes.CompletionItemInsertTextRule.KeepWhitespace : 0,
|
||||
k: item.commitCharacters,
|
||||
l: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from),
|
||||
m: this._commands.toInternal(item.command, disposables),
|
||||
[extHostProtocol.ISuggestDataDtoField.label]: item.label,
|
||||
[extHostProtocol.ISuggestDataDtoField.kind]: typeConvert.CompletionItemKind.from(item.kind),
|
||||
[extHostProtocol.ISuggestDataDtoField.kindModifier]: item.tags && item.tags.map(typeConvert.CompletionItemTag.from),
|
||||
[extHostProtocol.ISuggestDataDtoField.detail]: item.detail,
|
||||
[extHostProtocol.ISuggestDataDtoField.documentation]: typeof item.documentation === 'undefined' ? undefined : typeConvert.MarkdownString.fromStrict(item.documentation),
|
||||
[extHostProtocol.ISuggestDataDtoField.sortText]: item.sortText,
|
||||
[extHostProtocol.ISuggestDataDtoField.filterText]: item.filterText,
|
||||
[extHostProtocol.ISuggestDataDtoField.preselect]: item.preselect,
|
||||
[extHostProtocol.ISuggestDataDtoField.insertTextRules]: item.keepWhitespace ? modes.CompletionItemInsertTextRule.KeepWhitespace : 0,
|
||||
[extHostProtocol.ISuggestDataDtoField.commitCharacters]: item.commitCharacters,
|
||||
[extHostProtocol.ISuggestDataDtoField.additionalTextEdits]: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from),
|
||||
[extHostProtocol.ISuggestDataDtoField.command]: this._commands.toInternal(item.command, disposables),
|
||||
};
|
||||
|
||||
// 'insertText'-logic
|
||||
|
||||
@@ -859,7 +859,7 @@ export namespace SignatureInformation {
|
||||
return {
|
||||
label: info.label,
|
||||
documentation: info.documentation ? MarkdownString.fromStrict(info.documentation) : undefined,
|
||||
parameters: info.parameters && info.parameters.map(ParameterInformation.from)
|
||||
parameters: Array.isArray(info.parameters) ? info.parameters.map(ParameterInformation.from) : []
|
||||
};
|
||||
}
|
||||
|
||||
@@ -867,7 +867,7 @@ export namespace SignatureInformation {
|
||||
return {
|
||||
label: info.label,
|
||||
documentation: htmlContent.isMarkdownString(info.documentation) ? MarkdownString.to(info.documentation) : info.documentation,
|
||||
parameters: info.parameters && info.parameters.map(ParameterInformation.to)
|
||||
parameters: Array.isArray(info.parameters) ? info.parameters.map(ParameterInformation.to) : []
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -878,7 +878,7 @@ export namespace SignatureHelp {
|
||||
return {
|
||||
activeSignature: help.activeSignature,
|
||||
activeParameter: help.activeParameter,
|
||||
signatures: help.signatures && help.signatures.map(SignatureInformation.from)
|
||||
signatures: Array.isArray(help.signatures) ? help.signatures.map(SignatureInformation.from) : [],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -886,7 +886,7 @@ export namespace SignatureHelp {
|
||||
return {
|
||||
activeSignature: help.activeSignature,
|
||||
activeParameter: help.activeParameter,
|
||||
signatures: help.signatures && help.signatures.map(SignatureInformation.to)
|
||||
signatures: Array.isArray(help.signatures) ? help.signatures.map(SignatureInformation.to) : [],
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1163,13 +1163,3 @@ export namespace LogLevel {
|
||||
return types.LogLevel.Info;
|
||||
}
|
||||
}
|
||||
export namespace WebviewContentState {
|
||||
export function from(state: vscode.WebviewContentState): modes.WebviewContentState {
|
||||
switch (state) {
|
||||
case types.WebviewContentState.Readonly: return modes.WebviewContentState.Readonly;
|
||||
case types.WebviewContentState.Unchanged: return modes.WebviewContentState.Unchanged;
|
||||
case types.WebviewContentState.Dirty: return modes.WebviewContentState.Dirty;
|
||||
default: throw new Error('Unknown vscode.WebviewContentState');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user