Merge from vscode ec07311dab2556c9d66a4cb3eecdc21c524202e1 (#6739)

This commit is contained in:
Anthony Dresser
2019-08-13 19:14:03 -07:00
committed by GitHub
parent a645a09f42
commit 82c1c57c76
77 changed files with 1319 additions and 741 deletions

View File

@@ -1354,6 +1354,15 @@
"scope": "resource",
"default": false,
"description": "%config.supportCancellation%"
},
"git.branchSortOrder": {
"type": "string",
"enum": [
"committerdate",
"alphabetically"
],
"default": "committerdate",
"description": "%config.branchSortOrder%"
}
}
},

View File

@@ -127,6 +127,7 @@
"config.confirmForcePush": "Controls whether to ask for confirmation before force-pushing.",
"config.openDiffOnClick": "Controls whether the diff editor should be opened when clicking a change. Otherwise the regular editor will be opened.",
"config.supportCancellation": "Controls whether a notification comes up when running the Sync action, which allows the user to cancel the operation.",
"config.branchSortOrder": "Controls the sort order for branches.",
"colors.added": "Color for added resources.",
"colors.modified": "Color for modified resources.",
"colors.deleted": "Color for deleted resources.",

View File

@@ -1624,8 +1624,14 @@ export class Repository {
.map(([ref]) => ({ name: ref, type: RefType.Head } as Branch));
}
async getRefs(): Promise<Ref[]> {
const result = await this.run(['for-each-ref', '--format', '%(refname) %(objectname)', '--sort', '-committerdate']);
async getRefs(opts?: { sort?: 'alphabetically' | 'committerdate' }): Promise<Ref[]> {
const args = ['for-each-ref', '--format', '%(refname) %(objectname)'];
if (opts && opts.sort && opts.sort !== 'alphabetically') {
args.push('--sort', opts.sort);
}
const result = await this.run(args);
const fn = (line: string): Ref | null => {
let match: RegExpExecArray | null;

View File

@@ -701,6 +701,9 @@ export class Repository implements Disposable {
onConfigListener(updateIndexGroupVisibility, this, this.disposables);
updateIndexGroupVisibility();
const onConfigListenerForBranchSortOrder = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.branchSortOrder', root));
onConfigListenerForBranchSortOrder(this.updateModelState, this, this.disposables);
this.mergeGroup.hideWhenEmpty = true;
this.disposables.push(this.mergeGroup);
@@ -1405,7 +1408,6 @@ export class Repository implements Disposable {
const config = workspace.getConfiguration('git');
const shouldIgnore = config.get<boolean>('ignoreLimitWarning') === true;
const useIcons = !config.get<boolean>('decorations.enabled', true);
this.isRepositoryHuge = didHitLimit;
if (didHitLimit && !shouldIgnore && !this.didWarnAboutLimit) {
@@ -1455,7 +1457,8 @@ export class Repository implements Disposable {
// noop
}
const [refs, remotes, submodules, rebaseCommit] = await Promise.all([this.repository.getRefs(), this.repository.getRemotes(), this.repository.getSubmodules(), this.getRebaseCommit()]);
const sort = config.get<'alphabetically' | 'committerdate'>('branchSortOrder') || 'alphabetically';
const [refs, remotes, submodules, rebaseCommit] = await Promise.all([this.repository.getRefs({ sort }), this.repository.getRemotes(), this.repository.getSubmodules(), this.getRebaseCommit()]);
this._HEAD = HEAD;
this._refs = refs;

View File

@@ -77,7 +77,7 @@
"vscode-ripgrep": "^1.5.6",
"vscode-sqlite3": "4.0.8",
"vscode-textmate": "^4.2.2",
"xterm": "3.15.0-beta98",
"xterm": "3.15.0-beta99",
"xterm-addon-search": "0.2.0-beta3",
"xterm-addon-web-links": "0.1.0-beta10",
"yauzl": "^2.9.2",

View File

@@ -21,7 +21,7 @@
"vscode-proxy-agent": "0.4.0",
"vscode-ripgrep": "^1.5.6",
"vscode-textmate": "^4.2.2",
"xterm": "3.15.0-beta98",
"xterm": "3.15.0-beta99",
"xterm-addon-search": "0.2.0-beta3",
"xterm-addon-web-links": "0.1.0-beta10",
"yauzl": "^2.9.2",

View File

@@ -1,3 +0,0 @@
disturl "http://nodejs.org/dist"
target "10.11.0"
runtime "node"

View File

@@ -1227,10 +1227,10 @@ xterm-addon-web-links@0.1.0-beta10:
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23"
integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg==
xterm@3.15.0-beta98:
version "3.15.0-beta98"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta98.tgz#37f37c35577422880e7ef673cc37f9d2a45dd40c"
integrity sha512-vZbg2LcRvoiJOgr1MyeLFM9mF4uib3BWUWDHyFc+vZ58CTuK0iczOvFXgk/ySo23ZLqwmHQSigLgmWvZ8J5G0Q==
xterm@3.15.0-beta99:
version "3.15.0-beta99"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta99.tgz#0010a7ea5d56cbb08a1e3a525b353c96a158e7a0"
integrity sha512-Vm0ZWToWwO4uk/28Kqvqt9L92h5EU2z4WR9I6xcQaPIBmkJPINIARU4LWQnvaOfgFhRbpwBMveTfh8/jM97lPg==
yauzl@^2.9.2:
version "2.10.0"

View File

@@ -22,7 +22,6 @@ import { ExtHostModelView } from 'sql/workbench/api/common/extHostModelView';
import { ExtHostConnectionManagement } from 'sql/workbench/api/common/extHostConnectionManagement';
import { ExtHostDashboard } from 'sql/workbench/api/common/extHostDashboard';
import { ExtHostObjectExplorer } from 'sql/workbench/api/common/extHostObjectExplorer';
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
import { ExtHostModelViewDialog } from 'sql/workbench/api/common/extHostModelViewDialog';
import { ExtHostModelViewTreeViews } from 'sql/workbench/api/common/extHostModelViewTree';
import { ExtHostQueryEditor } from 'sql/workbench/api/common/extHostQueryEditor';
@@ -56,7 +55,7 @@ export function createApiFactory(accessor: ServicesAccessor): ISqlExtensionApiFa
const instaServer = accessor.get(IInstantiationService);
const uriTransformer = accessor.get(IURITransformerService);
const rpcProtocol = accessor.get(IExtHostRpcService);
const extHostLogService = <ExtHostLogService>accessor.get(ILogService);
const extHostLogService = accessor.get(ILogService);
let vsCodeFactory = instaServer.invokeFunction(extHostApi.createApiFactoryAndRegisterActors);
// Addressable instances

View File

@@ -14,7 +14,7 @@
},
"include": [
"typings/require.d.ts",
"./typings/require-monaco.d.ts",
"typings/require-monaco.d.ts",
"typings/thenable.d.ts",
"typings/es6-promise.d.ts",
"typings/lib.es2018.promise.d.ts",

View File

@@ -7,7 +7,7 @@ import 'vs/css!./gridview';
import { Orientation } from 'vs/base/browser/ui/sash/sash';
import { Disposable } from 'vs/base/common/lifecycle';
import { tail2 as tail, equals } from 'vs/base/common/arrays';
import { orthogonal, IView as IGridViewView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles, IViewSize, ILayoutController, LayoutController } from './gridview';
import { orthogonal, IView as IGridViewView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles, IViewSize, LayoutController, IGridViewOptions } from './gridview';
import { Event } from 'vs/base/common/event';
import { InvisibleSizing } from 'vs/base/browser/ui/splitview/splitview';
@@ -193,11 +193,8 @@ export namespace Sizing {
export interface IGridStyles extends IGridViewStyles { }
export interface IGridOptions {
readonly styles?: IGridStyles;
readonly proportionalLayout?: boolean;
export interface IGridOptions extends IGridViewOptions {
readonly firstViewVisibleCachedSize?: number;
readonly layoutController?: ILayoutController;
}
export class Grid<T extends IView = IView> extends Disposable {

View File

@@ -76,6 +76,11 @@ export class LayoutController implements ILayoutController {
constructor(public isLayoutEnabled: boolean) { }
}
export class MultiplexLayoutController implements ILayoutController {
get isLayoutEnabled(): boolean { return this.layoutControllers.every(l => l.isLayoutEnabled); }
constructor(private layoutControllers: ILayoutController[]) { }
}
export interface IGridViewOptions {
readonly styles?: IGridViewStyles;
readonly proportionalLayout?: boolean; // default true
@@ -170,6 +175,7 @@ class BranchNode implements ISplitView, IDisposable {
constructor(
readonly orientation: Orientation,
readonly layoutController: ILayoutController,
styles: IGridViewStyles,
readonly proportionalLayout: boolean,
size: number = 0,
@@ -181,7 +187,7 @@ class BranchNode implements ISplitView, IDisposable {
this.element = $('.monaco-grid-branch-node');
this.splitview = new SplitView(this.element, { orientation, styles, proportionalLayout });
this.splitview.layout(size);
this.splitview.layout(size, orthogonalSize);
const onDidSashReset = Event.map(this.splitview.onDidSashReset, i => [i]);
this.splitviewSashResetDisposable = onDidSashReset(this._onDidSashReset.fire, this._onDidSashReset);
@@ -198,12 +204,20 @@ class BranchNode implements ISplitView, IDisposable {
}
}
layout(size: number): void {
layout(size: number, orthogonalSize: number | undefined): void {
if (!this.layoutController.isLayoutEnabled) {
return;
}
if (typeof orthogonalSize !== 'number') {
throw new Error('Invalid state');
}
// branch nodes should flip the normal/orthogonal directions
this._size = orthogonalSize;
this._orthogonalSize = size;
for (const child of this.children) {
child.orthogonalLayout(size);
}
this.splitview.layout(orthogonalSize, size);
}
setVisible(visible: boolean): void {
@@ -212,11 +226,6 @@ class BranchNode implements ISplitView, IDisposable {
}
}
orthogonalLayout(size: number): void {
this._size = size;
this.splitview.layout(size);
}
addChild(node: Node, size: number | Sizing, index: number): void {
if (index < 0 || index > this.children.length) {
throw new Error('Invalid index');
@@ -347,6 +356,10 @@ class BranchNode implements ISplitView, IDisposable {
throw new Error('Invalid index');
}
if (this.splitview.isViewVisible(index) === visible) {
return;
}
this.splitview.setViewVisible(index, visible);
this._onDidChange.fire(undefined);
}
@@ -539,12 +552,18 @@ class LeafNode implements ISplitView, IDisposable {
// noop
}
layout(size: number): void {
this._size = size;
if (this.layoutController.isLayoutEnabled) {
this.view.layout(this.width, this.height, orthogonal(this.orientation));
layout(size: number, orthogonalSize: number | undefined): void {
if (!this.layoutController.isLayoutEnabled) {
return;
}
if (typeof orthogonalSize !== 'number') {
throw new Error('Invalid state');
}
this._size = size;
this._orthogonalSize = orthogonalSize;
this.view.layout(this.width, this.height, orthogonal(this.orientation));
}
setVisible(visible: boolean): void {
@@ -553,14 +572,6 @@ class LeafNode implements ISplitView, IDisposable {
}
}
orthogonalLayout(size: number): void {
this._orthogonalSize = size;
if (this.layoutController.isLayoutEnabled) {
this.view.layout(this.width, this.height, orthogonal(this.orientation));
}
}
dispose(): void { }
}
@@ -568,7 +579,7 @@ type Node = BranchNode | LeafNode;
function flipNode<T extends Node>(node: T, size: number, orthogonalSize: number): T {
if (node instanceof BranchNode) {
const result = new BranchNode(orthogonal(node.orientation), node.styles, node.proportionalLayout, size, orthogonalSize);
const result = new BranchNode(orthogonal(node.orientation), node.layoutController, node.styles, node.proportionalLayout, size, orthogonalSize);
let totalSize = 0;
@@ -589,7 +600,7 @@ function flipNode<T extends Node>(node: T, size: number, orthogonalSize: number)
return result as T;
} else {
return new LeafNode((node as LeafNode).view, orthogonal(node.orientation), (node as LeafNode).layoutController, orthogonalSize) as T;
return new LeafNode((node as LeafNode).view, orthogonal(node.orientation), node.layoutController, orthogonalSize) as T;
}
}
@@ -634,8 +645,7 @@ export class GridView implements IDisposable {
const { size, orthogonalSize } = this._root;
this.root = flipNode(this._root, orthogonalSize, size);
this.root.layout(size);
this.root.orthogonalLayout(orthogonalSize);
this.root.layout(size, orthogonalSize);
}
get width(): number { return this.root.width; }
@@ -649,14 +659,25 @@ export class GridView implements IDisposable {
private _onDidChange = new Relay<IViewSize | undefined>();
readonly onDidChange = this._onDidChange.event;
/**
* The first layout controller makes sure layout only propagates
* to the views after the very first call to gridview.layout()
*/
private firstLayoutController: LayoutController;
private layoutController: LayoutController;
constructor(options: IGridViewOptions = {}) {
this.element = $('.monaco-grid-view');
this.styles = options.styles || defaultStyles;
this.proportionalLayout = typeof options.proportionalLayout !== 'undefined' ? !!options.proportionalLayout : true;
this.root = new BranchNode(Orientation.VERTICAL, this.styles, this.proportionalLayout);
this.layoutController = options.layoutController || new LayoutController(true);
this.firstLayoutController = new LayoutController(false);
this.layoutController = new MultiplexLayoutController([
this.firstLayoutController,
...(options.layoutController ? [options.layoutController] : [])
]);
this.root = new BranchNode(Orientation.VERTICAL, this.layoutController, this.styles, this.proportionalLayout);
}
style(styles: IGridViewStyles): void {
@@ -665,9 +686,10 @@ export class GridView implements IDisposable {
}
layout(width: number, height: number): void {
this.firstLayoutController.isLayoutEnabled = true;
const [size, orthogonalSize] = this.root.orientation === Orientation.HORIZONTAL ? [height, width] : [width, height];
this.root.layout(size);
this.root.orthogonalLayout(orthogonalSize);
this.root.layout(size, orthogonalSize);
}
addView(view: IView, size: number | Sizing, location: number[]): void {
@@ -694,9 +716,8 @@ export class GridView implements IDisposable {
grandParent.removeChild(parentIndex);
const newParent = new BranchNode(parent.orientation, this.styles, this.proportionalLayout, parent.size, parent.orthogonalSize);
const newParent = new BranchNode(parent.orientation, parent.layoutController, this.styles, this.proportionalLayout, parent.size, parent.orthogonalSize);
grandParent.addChild(newParent, parent.size, parentIndex);
newParent.orthogonalLayout(parent.orthogonalSize);
const newSibling = new LeafNode(parent.view, grandParent.orientation, this.layoutController, parent.size);
newParent.addChild(newSibling, newSiblingSize, 0);
@@ -827,9 +848,6 @@ export class GridView implements IDisposable {
fromParent.addChild(toNode, fromSize, fromIndex);
toParent.addChild(fromNode, toSize, toIndex);
fromParent.layout(fromParent.orthogonalSize);
toParent.layout(toParent.orthogonalSize);
}
}

View File

@@ -24,12 +24,12 @@ const defaultStyles: ISplitViewStyles = {
};
export interface ISplitViewOptions {
orientation?: Orientation; // default Orientation.VERTICAL
styles?: ISplitViewStyles;
orthogonalStartSash?: Sash;
orthogonalEndSash?: Sash;
inverseAltBehavior?: boolean;
proportionalLayout?: boolean; // default true
readonly orientation?: Orientation; // default Orientation.VERTICAL
readonly styles?: ISplitViewStyles;
readonly orthogonalStartSash?: Sash;
readonly orthogonalEndSash?: Sash;
readonly inverseAltBehavior?: boolean;
readonly proportionalLayout?: boolean; // default true
}
/**
@@ -48,7 +48,7 @@ export interface IView {
readonly onDidChange: Event<number | undefined>;
readonly priority?: LayoutPriority;
readonly snap?: boolean;
layout(size: number, orientation: Orientation): void;
layout(size: number, orthogonalSize: number | undefined): void;
setVisible?(visible: boolean): void;
}
@@ -125,13 +125,13 @@ abstract class ViewItem {
dom.addClass(container, 'visible');
}
layout(): void {
layout(_orthogonalSize: number | undefined): void {
this.container.scrollTop = 0;
this.container.scrollLeft = 0;
}
layoutView(orientation: Orientation): void {
this.view.layout(this.size, orientation);
layoutView(orthogonalSize: number | undefined): void {
this.view.layout(this.size, orthogonalSize);
}
dispose(): IView {
@@ -142,19 +142,19 @@ abstract class ViewItem {
class VerticalViewItem extends ViewItem {
layout(): void {
super.layout();
layout(orthogonalSize: number | undefined): void {
super.layout(orthogonalSize);
this.container.style.height = `${this.size}px`;
this.layoutView(Orientation.VERTICAL);
this.layoutView(orthogonalSize);
}
}
class HorizontalViewItem extends ViewItem {
layout(): void {
super.layout();
layout(orthogonalSize: number | undefined): void {
super.layout(orthogonalSize);
this.container.style.width = `${this.size}px`;
this.layoutView(Orientation.HORIZONTAL);
this.layoutView(orthogonalSize);
}
}
@@ -205,6 +205,7 @@ export class SplitView extends Disposable {
private sashContainer: HTMLElement;
private viewContainer: HTMLElement;
private size = 0;
private orthogonalSize: number | undefined;
private contentSize = 0;
private proportions: undefined | number[] = undefined;
private viewItems: ViewItem[] = [];
@@ -475,9 +476,10 @@ export class SplitView extends Disposable {
return viewItem.cachedVisibleSize;
}
layout(size: number): void {
layout(size: number, orthogonalSize?: number): void {
const previousSize = Math.max(this.size, this.contentSize);
this.size = size;
this.orthogonalSize = orthogonalSize;
if (!this.proportions) {
const indexes = range(this.viewItems.length);
@@ -820,7 +822,7 @@ export class SplitView extends Disposable {
this.contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
// Layout views
this.viewItems.forEach(item => item.layout());
this.viewItems.forEach(item => item.layout(this.orthogonalSize));
// Layout sashes
this.sashItems.forEach(item => item.sash.layout());

View File

@@ -16,7 +16,7 @@ export interface IWorker extends IDisposable {
}
export interface IWorkerCallback {
(message: string): void;
(message: any): void;
}
export interface IWorkerFactory {

View File

@@ -5,7 +5,7 @@
import * as assert from 'assert';
import { Emitter } from 'vs/base/common/event';
import { SplitView, IView, Orientation, Sizing, LayoutPriority } from 'vs/base/browser/ui/splitview/splitview';
import { SplitView, IView, Sizing, LayoutPriority } from 'vs/base/browser/ui/splitview/splitview';
import { Sash, SashState } from 'vs/base/browser/ui/sash/sash';
class TestView implements IView {
@@ -27,7 +27,9 @@ class TestView implements IView {
private _size = 0;
get size(): number { return this._size; }
private _onDidLayout = new Emitter<{ size: number; orientation: Orientation }>();
private _orthogonalSize: number | undefined = 0;
get orthogonalSize(): number | undefined { return this._orthogonalSize; }
private _onDidLayout = new Emitter<{ size: number; orthogonalSize: number | undefined }>();
readonly onDidLayout = this._onDidLayout.event;
private _onDidFocus = new Emitter<void>();
@@ -41,9 +43,10 @@ class TestView implements IView {
assert(_minimumSize <= _maximumSize, 'splitview view minimum size must be <= maximum size');
}
layout(size: number, orientation: Orientation): void {
layout(size: number, orthogonalSize: number | undefined): void {
this._size = size;
this._onDidLayout.fire({ size, orientation });
this._orthogonalSize = orthogonalSize;
this._onDidLayout.fire({ size, orthogonalSize });
}
focus(): void {
@@ -523,4 +526,24 @@ suite('Splitview', () => {
view2.dispose();
view1.dispose();
});
});
test('orthogonal size propagates to views', () => {
const view1 = new TestView(20, Number.POSITIVE_INFINITY);
const view2 = new TestView(20, Number.POSITIVE_INFINITY);
const view3 = new TestView(20, Number.POSITIVE_INFINITY, LayoutPriority.Low);
const splitview = new SplitView(container, { proportionalLayout: false });
splitview.layout(200);
splitview.addView(view1, Sizing.Distribute);
splitview.addView(view2, Sizing.Distribute);
splitview.addView(view3, Sizing.Distribute);
splitview.layout(200, 100);
assert.deepEqual([view1.orthogonalSize, view2.orthogonalSize, view3.orthogonalSize], [100, 100, 100]);
splitview.dispose();
view3.dispose();
view2.dispose();
view1.dispose();
});
});

View File

@@ -20,8 +20,8 @@
let loadCode = function (moduleId: string) {
require([moduleId], function (ws) {
setTimeout(function () {
let messageHandler = ws.create((msg: any) => {
(<any>self).postMessage(msg);
let messageHandler = ws.create((msg: any, transfer?: Transferable[]) => {
(<any>self).postMessage(msg, transfer);
}, null);
self.onmessage = (e) => messageHandler.onmessage(e.data);

View File

@@ -27,7 +27,7 @@ bootstrapWindow.load([
perf.mark('main/startup');
// @ts-ignore
return require('vs/workbench/electron-browser/main').main(configuration);
return require('vs/workbench/electron-browser/desktop.main').main(configuration);
});
}, {
removeDeveloperKeybindingsAfterLoad: true,

View File

@@ -129,6 +129,10 @@ export interface MarkerStatistics {
export namespace IMarkerData {
const emptyString = '';
export function makeKey(markerData: IMarkerData): string {
return makeKeyOptionalMessage(markerData, true);
}
export function makeKeyOptionalMessage(markerData: IMarkerData, useMessage: boolean): string {
let result: string[] = [emptyString];
if (markerData.source) {
result.push(markerData.source.replace('¦', '\¦'));
@@ -145,7 +149,10 @@ export namespace IMarkerData {
} else {
result.push(emptyString);
}
if (markerData.message) {
// Modifed to not include the message as part of the marker key to work around
// https://github.com/microsoft/vscode/issues/77475
if (markerData.message && useMessage) {
result.push(markerData.message.replace('¦', '\¦'));
} else {
result.push(emptyString);

View File

@@ -12,6 +12,7 @@ export const lastSessionDateStorageKey = 'telemetry.lastSessionDate';
import * as Platform from 'vs/base/common/platform';
import * as uuid from 'vs/base/common/uuid';
import { cleanRemoteAuthority } from 'vs/platform/telemetry/common/telemetryUtils';
export async function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string | undefined, version: string | undefined, machineId: string, remoteAuthority?: string): Promise<{ [name: string]: string | undefined }> {
const result: { [name: string]: string | undefined; } = Object.create(null);
@@ -69,18 +70,3 @@ export async function resolveWorkbenchCommonProperties(storageService: IStorageS
return result;
}
function cleanRemoteAuthority(remoteAuthority?: string): string {
if (!remoteAuthority) {
return 'none';
}
let ret = 'other';
// Whitelisted remote authorities
['ssh-remote', 'dev-container', 'wsl'].forEach((res: string) => {
if (remoteAuthority!.indexOf(`${res}+`) === 0) {
ret = res;
}
});
return ret;
}

View File

@@ -288,6 +288,22 @@ export function validateTelemetryData(data?: any): { properties: Properties, mea
};
}
export function cleanRemoteAuthority(remoteAuthority?: string): string {
if (!remoteAuthority) {
return 'none';
}
let ret = 'other';
// Whitelisted remote authorities
['ssh-remote', 'dev-container', 'attached-container', 'wsl'].forEach((res: string) => {
if (remoteAuthority!.indexOf(`${res}+`) === 0) {
ret = res;
}
});
return ret;
}
function flatten(obj: any, result: { [key: string]: any }, order: number = 0, prefix?: string): void {
if (!obj) {
return;

View File

@@ -6,6 +6,7 @@
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties';
import { instanceStorageKey, firstSessionDateStorageKey, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry';
import { cleanRemoteAuthority } from 'vs/platform/telemetry/common/telemetryUtils';
// {{ SQL CARBON EDIT }}
import product from 'vs/platform/product/node/product';
@@ -57,19 +58,3 @@ function setUsageDates(storageService: IStorageService): void {
const monthlyLastUseDate = storageService.get('telemetry.monthlyLastUseDate', StorageScope.GLOBAL, appStartDate.toUTCString());
storageService.store('telemetry.monthlyLastUseDate', monthlyLastUseDate, StorageScope.GLOBAL);
}
function cleanRemoteAuthority(remoteAuthority?: string): string {
if (!remoteAuthority) {
return 'none';
}
let ret = 'other';
// Whitelisted remote authorities
['ssh-remote', 'dev-container', 'wsl'].forEach((res: string) => {
if (remoteAuthority!.indexOf(`${res}+`) === 0) {
ret = res;
}
});
return ret;
}

4
src/vs/vscode.d.ts vendored
View File

@@ -5208,7 +5208,7 @@ declare module 'vscode' {
*/
export enum TaskScope {
/**
* The task is a global task
* The task is a global task. Global tasks are currrently not supported.
*/
Global = 1,
@@ -5237,7 +5237,7 @@ declare module 'vscode' {
* Creates a new task.
*
* @param definition The task definition as defined in the taskDefinitions extension point.
* @param scope Specifies the task's scope. It is either a global or a workspace task or a task for a specific workspace folder.
* @param scope Specifies the task's scope. It is either a global or a workspace task or a task for a specific workspace folder. Global tasks are currently not supported.
* @param name The task's name. Is presented in the user interface.
* @param source The task's source (e.g. 'gulp', 'npm', ...). Is presented in the user interface.
* @param execution The process or shell execution.

View File

@@ -124,7 +124,7 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
this._dataProviders.forEach((dataProvider, treeViewId) => {
const treeView = this.getTreeView(treeViewId);
if (treeView) {
treeView.dataProvider = null;
treeView.dataProvider = undefined;
}
});
this._dataProviders.clear();

View File

@@ -15,7 +15,7 @@ import { OverviewRulerLane } from 'vs/editor/common/model';
import * as languageConfiguration from 'vs/editor/common/modes/languageConfiguration';
import { score } from 'vs/editor/common/modes/languageSelector';
import * as files from 'vs/platform/files/common/files';
import { ExtHostContext, MainContext } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostContext, MainContext, ExtHostLogServiceShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostApiCommands } from 'vs/workbench/api/common/extHostApiCommands';
import { ExtHostClipboard } from 'vs/workbench/api/common/extHostClipboard';
import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
@@ -33,7 +33,6 @@ import { ExtHostFileSystem } from 'vs/workbench/api/common/extHostFileSystem';
import { ExtHostFileSystemEventService } from 'vs/workbench/api/common/extHostFileSystemEventService';
import { ExtHostLanguageFeatures } from 'vs/workbench/api/common/extHostLanguageFeatures';
import { ExtHostLanguages } from 'vs/workbench/api/common/extHostLanguages';
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
import { ExtHostMessageService } from 'vs/workbench/api/common/extHostMessageService';
import { IExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
import { ExtHostProgress } from 'vs/workbench/api/common/extHostProgress';
@@ -95,10 +94,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const uriTransformer = accessor.get(IURITransformerService);
const rpcProtocol = accessor.get(IExtHostRpcService);
const extHostStorage = accessor.get(IExtHostStorage);
const extHostLogService = <ExtHostLogService>accessor.get(ILogService);
const extHostLogService = accessor.get(ILogService);
// register addressable instances
rpcProtocol.set(ExtHostContext.ExtHostLogService, extHostLogService);
rpcProtocol.set(ExtHostContext.ExtHostLogService, <ExtHostLogServiceShape><any>extHostLogService);
rpcProtocol.set(ExtHostContext.ExtHostWorkspace, extHostWorkspace);
rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration);
rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService);
@@ -147,10 +146,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostStatusBar = new ExtHostStatusBar(rpcProtocol);
const extHostLanguages = new ExtHostLanguages(rpcProtocol, extHostDocuments);
// Register an output channel for exthost log
const outputChannelName = initData.remote.isRemote ? nls.localize('remote extension host Log', "Remote Extension Host") : nls.localize('extension host Log', "Extension Host");
extHostOutputService.createOutputChannelFromLogFile(outputChannelName, extHostLogService.logFile);
// Register API-ish commands
ExtHostApiCommands.register(extHostCommands);

View File

@@ -14,7 +14,6 @@ import { ILogService } from 'vs/platform/log/common/log';
import { ExtHostExtensionServiceShape, IInitData, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape, IResolveAuthorityResult } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfiguration, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionContext, IExtensionModule, HostExtension, ExtensionActivationTimesFragment } from 'vs/workbench/api/common/extHostExtensionActivator';
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
import { ExtHostStorage, IExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions';
@@ -75,7 +74,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
protected readonly _instaService: IInstantiationService;
protected readonly _extHostWorkspace: ExtHostWorkspace;
protected readonly _extHostConfiguration: ExtHostConfiguration;
protected readonly _extHostLogService: ExtHostLogService;
protected readonly _logService: ILogService;
protected readonly _mainThreadWorkspaceProxy: MainThreadWorkspaceShape;
protected readonly _mainThreadTelemetryProxy: MainThreadTelemetryShape;
@@ -102,7 +101,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
@IExtHostRpcService extHostContext: IExtHostRpcService,
@IExtHostWorkspace extHostWorkspace: IExtHostWorkspace,
@IExtHostConfiguration extHostConfiguration: IExtHostConfiguration,
@ILogService extHostLogService: ExtHostLogService,
@ILogService logService: ILogService,
@IExtHostInitDataService initData: IExtHostInitDataService,
@IExtensionStoragePaths storagePath: IExtensionStoragePaths
) {
@@ -112,7 +111,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
this._extHostWorkspace = extHostWorkspace;
this._extHostConfiguration = extHostConfiguration;
this._extHostLogService = extHostLogService;
this._logService = logService;
this._disposables = new DisposableStore();
this._mainThreadWorkspaceProxy = this._extHostContext.getProxy(MainContext.MainThreadWorkspace);
@@ -329,14 +328,14 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
return Promise.resolve(new EmptyExtension(ExtensionActivationTimes.NONE));
}
this._extHostLogService.info(`ExtensionService#_doActivateExtension ${extensionDescription.identifier.value} ${JSON.stringify(reason)}`);
this._logService.info(`ExtensionService#_doActivateExtension ${extensionDescription.identifier.value} ${JSON.stringify(reason)}`);
const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup);
return Promise.all<any>([
this._loadCommonJSModule(extensionDescription.main, activationTimesBuilder),
this._loadExtensionContext(extensionDescription)
]).then(values => {
return AbstractExtHostExtensionService._callActivate(this._extHostLogService, extensionDescription.identifier, <IExtensionModule>values[0], <IExtensionContext>values[1], activationTimesBuilder);
return AbstractExtHostExtensionService._callActivate(this._logService, extensionDescription.identifier, <IExtensionModule>values[0], <IExtensionContext>values[1], activationTimesBuilder);
});
}
@@ -347,7 +346,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
const globalState = new ExtensionMemento(extensionDescription.identifier.value, true, this._storage);
const workspaceState = new ExtensionMemento(extensionDescription.identifier.value, false, this._storage);
this._extHostLogService.trace(`ExtensionService#loadExtensionContext ${extensionDescription.identifier.value}`);
this._logService.trace(`ExtensionService#loadExtensionContext ${extensionDescription.identifier.value}`);
return Promise.all([
globalState.whenReady,
workspaceState.whenReady,
@@ -359,10 +358,10 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
workspaceState,
subscriptions: [],
get extensionPath() { return extensionDescription.extensionLocation.fsPath; },
storagePath: this._storagePath.workspaceValue(extensionDescription),
globalStoragePath: this._storagePath.globalValue(extensionDescription),
get storagePath() { return that._storagePath.workspaceValue(extensionDescription); },
get globalStoragePath() { return that._storagePath.globalValue(extensionDescription); },
asAbsolutePath: (relativePath: string) => { return path.join(extensionDescription.extensionLocation.fsPath, relativePath); },
logPath: that._extHostLogService.getLogDirectory(extensionDescription.identifier),
get logPath() { return path.join(that._initData.logsLocation.fsPath, extensionDescription.identifier.value); },
executionContext: this._initData.remote.isRemote ? ExtensionExecutionContext.Remote : ExtensionExecutionContext.Local,
});
});
@@ -385,7 +384,8 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
try {
activationTimesBuilder.activateCallStart();
logService.trace(`ExtensionService#_callActivateOptional ${extensionId.value}`);
const activateResult: Promise<IExtensionAPI> = extensionModule.activate.apply(global, [context]);
const scope = typeof global === 'object' ? global : self; // `global` is nodejs while `self` is for workers
const activateResult: Promise<IExtensionAPI> = extensionModule.activate.apply(scope, [context]);
activationTimesBuilder.activateCallStop();
activationTimesBuilder.activateResolveStart();
@@ -478,7 +478,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
}
private async _activateIfGlobPatterns(folders: ReadonlyArray<vscode.WorkspaceFolder>, extensionId: ExtensionIdentifier, globPatterns: string[]): Promise<void> {
this._extHostLogService.trace(`extensionHostMain#activateIfGlobPatterns: fileSearch, extension: ${extensionId.value}, entryPoint: workspaceContains`);
this._logService.trace(`extensionHostMain#activateIfGlobPatterns: fileSearch, extension: ${extensionId.value}, entryPoint: workspaceContains`);
if (globPatterns.length === 0) {
return Promise.resolve(undefined);
@@ -525,7 +525,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
}
private async _doHandleExtensionTests(): Promise<void> {
const { extensionDevelopmentLocationURI: extensionDevelopmentLocationURI, extensionTestsLocationURI } = this._initData.environment;
const { extensionDevelopmentLocationURI, extensionTestsLocationURI } = this._initData.environment;
if (!(extensionDevelopmentLocationURI && extensionTestsLocationURI && extensionTestsLocationURI.scheme === Schemas.file)) {
return Promise.resolve(undefined);
}
@@ -605,7 +605,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
.then(() => this._handleEagerExtensions())
.then(() => this._handleExtensionTests())
.then(() => {
this._extHostLogService.info(`eager extensions activated`);
this._logService.info(`eager extensions activated`);
});
}

View File

@@ -1,34 +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 { join } from 'vs/base/common/path';
import { ILogService, DelegatedLogService, LogLevel } from 'vs/platform/log/common/log';
import { ExtHostLogServiceShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions';
import { URI } from 'vs/base/common/uri';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
export class ExtHostLogService extends DelegatedLogService implements ILogService, ExtHostLogServiceShape {
private _logsPath: string;
readonly logFile: URI;
constructor(
delegate: ILogService,
logsPath: string,
) {
super(delegate);
this._logsPath = logsPath;
this.logFile = URI.file(join(logsPath, `${ExtensionHostLogFileName}.log`));
}
$setLevel(level: LogLevel): void {
this.setLevel(level);
}
getLogDirectory(extensionID: ExtensionIdentifier): string {
return join(this._logsPath, extensionID.value);
}
}

View File

@@ -24,8 +24,11 @@ import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePa
import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
import { IExtHostStorage, ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
import { ILogService } from 'vs/platform/log/common/log';
import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
// register singleton services
registerSingleton(ILogService, ExtHostLogService);
registerSingleton(IExtHostOutputService, ExtHostOutputService2);
registerSingleton(IExtHostWorkspace, ExtHostWorkspace);
registerSingleton(IExtHostDecorations, ExtHostDecorations);

View File

@@ -44,14 +44,24 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService {
}
// Do this when extension service exists, but extensions are not being activated yet.
await connectProxyResolver(this._extHostWorkspace, configProvider, this, this._extHostLogService, this._mainThreadTelemetryProxy);
await connectProxyResolver(this._extHostWorkspace, configProvider, this, this._logService, this._mainThreadTelemetryProxy);
// Use IPC messages to forward console-calls, note that the console is
// already patched to use`process.send()`
const nativeProcessSend = process.send!;
const mainThreadConsole = this._extHostContext.getProxy(MainContext.MainThreadConsole);
process.send = (...args: any[]) => {
if (args.length === 0 || !args[0] || args[0].type !== '__$console') {
return nativeProcessSend.apply(process, args);
}
mainThreadConsole.$logExtensionHostMessage(args[0]);
};
}
protected _loadCommonJSModule<T>(modulePath: string, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
let r: T | null = null;
activationTimesBuilder.codeLoadingStart();
this._extHostLogService.info(`ExtensionService#loadCommonJSModule ${modulePath}`);
this._logService.info(`ExtensionService#loadCommonJSModule ${modulePath}`);
try {
r = require.__$__nodeRequire<T>(modulePath);
} catch (e) {

View File

@@ -0,0 +1,36 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { join } from 'vs/base/common/path';
import { ILogService, DelegatedLogService, LogLevel } from 'vs/platform/log/common/log';
import { ExtHostLogServiceShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions';
import { URI } from 'vs/base/common/uri';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { Schemas } from 'vs/base/common/network';
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
import { IExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
export class ExtHostLogService extends DelegatedLogService implements ILogService, ExtHostLogServiceShape {
constructor(
@IExtHostInitDataService initData: IExtHostInitDataService,
@IExtHostOutputService extHostOutputService: IExtHostOutputService
) {
if (initData.logsLocation.scheme !== Schemas.file) { throw new Error('Only file-logging supported'); }
super(new SpdLogService(ExtensionHostLogFileName, initData.logsLocation.fsPath, initData.logLevel));
// Register an output channel for exthost log
extHostOutputService.createOutputChannelFromLogFile(
initData.remote.isRemote ? localize('remote extension host Log', "Remote Extension Host") : localize('extension host Log', "Extension Host"),
URI.file(join(initData.logsLocation.fsPath, `${ExtensionHostLogFileName}.log`))
);
}
$setLevel(level: LogLevel): void {
this.setLevel(level);
}
}

View File

@@ -0,0 +1,98 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createApiFactoryAndRegisterActors, IExtensionApiFactory } from 'vs/workbench/api/common/extHost.api.impl';
import { ExtensionActivationTimesBuilder } from 'vs/workbench/api/common/extHostExtensionActivator';
import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
import { endsWith } from 'vs/base/common/strings';
import { IExtensionDescription, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
import * as vscode from 'vscode';
import { TernarySearchTree } from 'vs/base/common/map';
import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
class ApiInstances {
private readonly _apiInstances = new Map<string, typeof vscode>();
constructor(
private readonly _apiFactory: IExtensionApiFactory,
private readonly _extensionPaths: TernarySearchTree<IExtensionDescription>,
private readonly _extensionRegistry: ExtensionDescriptionRegistry,
private readonly _configProvider: ExtHostConfigProvider,
) {
//
}
get(modulePath: string): typeof vscode {
const extension = this._extensionPaths.findSubstr(modulePath) || nullExtensionDescription;
const id = ExtensionIdentifier.toKey(extension.identifier);
let apiInstance = this._apiInstances.get(id);
if (!apiInstance) {
apiInstance = this._apiFactory(extension, this._extensionRegistry, this._configProvider);
this._apiInstances.set(id, apiInstance);
}
return apiInstance;
}
}
export class ExtHostExtensionService extends AbstractExtHostExtensionService {
private _apiInstances?: ApiInstances;
protected async _beforeAlmostReadyToRunExtensions(): Promise<void> {
// initialize API and register actors
const apiFactory = this._instaService.invokeFunction(createApiFactoryAndRegisterActors);
const configProvider = await this._extHostConfiguration.getConfigProvider();
const extensionPath = await this.getExtensionPathIndex();
this._apiInstances = new ApiInstances(apiFactory, extensionPath, this._registry, configProvider);
}
protected _loadCommonJSModule<T>(modulePath: string, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
// make sure modulePath ends with `.js`
const suffix = '.js';
modulePath = endsWith(modulePath, suffix) ? modulePath : modulePath + suffix;
interface FakeCommonJSSelf {
module?: object;
exports?: object;
require?: (module: string) => any;
window?: object;
__dirname: never;
__filename: never;
}
// FAKE commonjs world that only collects exports
const patchSelf: FakeCommonJSSelf = <any>self;
const module = { exports: {} };
patchSelf.module = module;
patchSelf.exports = module.exports;
patchSelf.window = self; // <- that's improper but might help extensions that aren't authored correctly
// FAKE require function that only works for the vscode-module
patchSelf.require = (module: string) => {
if (module !== 'vscode') {
throw new Error(`Cannot load module '${module}'`);
}
return this._apiInstances!.get(modulePath);
};
try {
activationTimesBuilder.codeLoadingStart();
importScripts(modulePath);
} finally {
activationTimesBuilder.codeLoadingStop();
}
return Promise.resolve(module.exports as T);
}
async $setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void> {
throw new Error('Not supported');
}
}

View File

@@ -0,0 +1,84 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ILogService, LogLevel, AbstractLogService } from 'vs/platform/log/common/log';
import { ExtHostLogServiceShape } from 'vs/workbench/api/common/extHost.protocol';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { IExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
import * as vscode from 'vscode';
export class ExtHostLogService extends AbstractLogService implements ILogService, ExtHostLogServiceShape {
_serviceBrand: any;
private readonly _logChannel: vscode.OutputChannel;
constructor(
@IExtHostInitDataService initData: IExtHostInitDataService,
@IExtHostOutputService extHostOutputService: IExtHostOutputService
) {
super();
this.setLevel(initData.logLevel);
this._logChannel = extHostOutputService.createOutputChannel('Log (Worker Extension Host)');
}
$setLevel(level: LogLevel): void {
this.setLevel(level);
}
trace(_message: string, ..._args: any[]): void {
if (this.getLevel() <= LogLevel.Trace) {
this._logChannel.appendLine(this._format(arguments));
}
}
debug(_message: string, ..._args: any[]): void {
if (this.getLevel() <= LogLevel.Debug) {
this._logChannel.appendLine(this._format(arguments));
}
}
info(_message: string, ..._args: any[]): void {
if (this.getLevel() <= LogLevel.Info) {
this._logChannel.appendLine(this._format(arguments));
}
}
warn(_message: string, ..._args: any[]): void {
if (this.getLevel() <= LogLevel.Warning) {
this._logChannel.appendLine(this._format(arguments));
}
}
error(_message: string | Error, ..._args: any[]): void {
if (this.getLevel() <= LogLevel.Error) {
this._logChannel.appendLine(this._format(arguments));
}
}
critical(_message: string | Error, ..._args: any[]): void {
if (this.getLevel() <= LogLevel.Critical) {
this._logChannel.appendLine(String(arguments));
}
}
private _format(args: any): string {
let result = '';
for (let i = 0; i < args.length; i++) {
let a = args[i];
if (typeof a === 'object') {
try {
a = JSON.stringify(a);
} catch (e) { }
}
result += (i > 0 ? ' ' : '') + a;
}
return result;
}
}

View File

@@ -71,6 +71,7 @@ export abstract class BreadcrumbsConfig<T> {
static FilePath = BreadcrumbsConfig._stub<'on' | 'off' | 'last'>('breadcrumbs.filePath');
static SymbolPath = BreadcrumbsConfig._stub<'on' | 'off' | 'last'>('breadcrumbs.symbolPath');
static SymbolSortOrder = BreadcrumbsConfig._stub<'position' | 'name' | 'type'>('breadcrumbs.symbolSortOrder');
static Icons = BreadcrumbsConfig._stub<boolean>('breadcrumbs.icons');
static FileExcludes = BreadcrumbsConfig._stub<glob.IExpression>('files.exclude');
@@ -160,6 +161,11 @@ Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfigurat
localize('symbolSortOrder.name', "Show symbol outline in alphabetical order."),
localize('symbolSortOrder.type', "Show symbol outline in symbol type order."),
]
},
'breadcrumbs.icons': {
description: localize('icons', "Render breadcrumb items with icons."),
type: 'boolean',
default: true
}
}
});

View File

@@ -69,7 +69,9 @@ class Item extends BreadcrumbsItem {
return false;
}
if (this.element instanceof FileElement && other.element instanceof FileElement) {
return isEqual(this.element.uri, other.element.uri, false);
return (isEqual(this.element.uri, other.element.uri, false) &&
this.options.showFileIcons === other.options.showFileIcons &&
this.options.showSymbolIcons === other.options.showSymbolIcons);
}
if (this.element instanceof TreeElement && other.element instanceof TreeElement) {
return this.element.id === other.element.id;
@@ -143,6 +145,7 @@ export class BreadcrumbsControl {
private readonly _ckBreadcrumbsActive: IContextKey<boolean>;
private readonly _cfUseQuickPick: BreadcrumbsConfig<boolean>;
private readonly _cfShowIcons: BreadcrumbsConfig<boolean>;
readonly domNode: HTMLDivElement;
private readonly _widget: BreadcrumbsWidget;
@@ -185,6 +188,7 @@ export class BreadcrumbsControl {
this._ckBreadcrumbsActive = BreadcrumbsControl.CK_BreadcrumbsActive.bindTo(this._contextKeyService);
this._cfUseQuickPick = BreadcrumbsConfig.UseQuickPick.bindTo(_configurationService);
this._cfShowIcons = BreadcrumbsConfig.Icons.bindTo(_configurationService);
this._disposables.add(breadcrumbsService.register(this._editorGroup.id, this._widget));
}
@@ -196,6 +200,7 @@ export class BreadcrumbsControl {
this._ckBreadcrumbsVisible.reset();
this._ckBreadcrumbsActive.reset();
this._cfUseQuickPick.dispose();
this._cfShowIcons.dispose();
this._widget.dispose();
this.domNode.remove();
}
@@ -246,15 +251,23 @@ export class BreadcrumbsControl {
dom.toggleClass(this.domNode, 'backslash-path', this._labelService.getSeparator(uri.scheme, uri.authority) === '\\');
const updateBreadcrumbs = () => {
const items = model.getElements().map(element => new Item(element, this._options, this._instantiationService));
const showIcons = this._cfShowIcons.getValue();
const options: IBreadcrumbsControlOptions = {
...this._options,
showFileIcons: this._options.showFileIcons && showIcons,
showSymbolIcons: this._options.showSymbolIcons && showIcons
};
const items = model.getElements().map(element => new Item(element, options, this._instantiationService));
this._widget.setItems(items);
this._widget.reveal(items[items.length - 1]);
};
const listener = model.onDidUpdate(updateBreadcrumbs);
const configListener = this._cfShowIcons.onDidChange(updateBreadcrumbs);
updateBreadcrumbs();
this._breadcrumbsDisposables.clear();
this._breadcrumbsDisposables.add(model);
this._breadcrumbsDisposables.add(listener);
this._breadcrumbsDisposables.add(configListener);
// close picker on hide/update
this._breadcrumbsDisposables.add({

View File

@@ -806,7 +806,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
//#region openEditor()
openEditor(editor: EditorInput, options?: EditorOptions): Promise<IEditor | null> {
async openEditor(editor: EditorInput, options?: EditorOptions): Promise<IEditor | null> {
// Guard against invalid inputs
if (!editor) {
@@ -822,7 +822,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}
// Proceed with opening
return this.doOpenEditor(editor, options).then(withUndefinedAsNull);
return withUndefinedAsNull(await this.doOpenEditor(editor, options));
}
private doOpenEditor(editor: EditorInput, options?: EditorOptions): Promise<IEditor | undefined> {

View File

@@ -63,7 +63,7 @@ export class SidebarPart extends CompositePart<Viewlet> implements IViewletServi
return undefined; // {{SQL CARBON EDIT}} strict-null-check
}
return width;
return Math.max(width, 300);
}
//#endregion

View File

@@ -161,12 +161,12 @@ export class CustomTreeView extends Disposable implements ITreeView {
private _showCollapseAllAction = false;
private focused: boolean = false;
private domNode: HTMLElement;
private treeContainer: HTMLElement;
private domNode!: HTMLElement;
private treeContainer!: HTMLElement;
private _messageValue: string | undefined;
private messageElement: HTMLDivElement;
private tree: WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore>;
private treeLabels: ResourceLabels;
private messageElement!: HTMLDivElement;
private tree: WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore> | undefined;
private treeLabels: ResourceLabels | undefined;
private root: ITreeItem;
private elementsToRefresh: ITreeItem[] = [];
private menus: TitleMenus;
@@ -218,12 +218,12 @@ export class CustomTreeView extends Disposable implements ITreeView {
this.create();
}
private _dataProvider: ITreeViewDataProvider | null;
get dataProvider(): ITreeViewDataProvider | null {
private _dataProvider: ITreeViewDataProvider | undefined;
get dataProvider(): ITreeViewDataProvider | undefined {
return this._dataProvider;
}
set dataProvider(dataProvider: ITreeViewDataProvider | null) {
set dataProvider(dataProvider: ITreeViewDataProvider | undefined) {
if (dataProvider) {
this._dataProvider = new class implements ITreeViewDataProvider {
async getChildren(node: ITreeItem): Promise<ITreeItem[]> {
@@ -238,7 +238,7 @@ export class CustomTreeView extends Disposable implements ITreeView {
this.updateMessage();
this.refresh();
} else {
this._dataProvider = null;
this._dataProvider = undefined;
this.updateMessage();
}
}
@@ -399,7 +399,7 @@ export class CustomTreeView extends Disposable implements ITreeView {
if (!e.browserEvent) {
return;
}
const selection = this.tree.getSelection();
const selection = this.tree!.getSelection();
if ((selection.length === 1) && selection[0].command) {
this.commandService.executeCommand(selection[0].command.id, ...(selection[0].command.arguments || []));
}
@@ -416,7 +416,7 @@ export class CustomTreeView extends Disposable implements ITreeView {
event.preventDefault();
event.stopPropagation();
this.tree.setFocus([node]);
this.tree!.setFocus([node]);
const actions = treeMenus.getResourceContextActions(node);
if (!actions.length) {
return;
@@ -436,13 +436,13 @@ export class CustomTreeView extends Disposable implements ITreeView {
onHide: (wasCancelled?: boolean) => {
if (wasCancelled) {
this.tree.domFocus();
this.tree!.domFocus();
}
},
getActionsContext: () => (<TreeViewItemHandleArg>{ $treeViewId: this.id, $treeItemHandle: node.handle }),
actionRunner: new MultipleSelectionActionRunner(() => this.tree.getSelection())
actionRunner: new MultipleSelectionActionRunner(() => this.tree!.getSelection())
});
}
@@ -479,8 +479,8 @@ export class CustomTreeView extends Disposable implements ITreeView {
DOM.clearNode(this.messageElement);
}
private _height: number;
private _width: number;
private _height: number = 0;
private _width: number = 0;
layout(height: number, width: number) {
if (height && width) {
this._height = height;
@@ -532,10 +532,11 @@ export class CustomTreeView extends Disposable implements ITreeView {
}
async expand(itemOrItems: ITreeItem | ITreeItem[]): Promise<void> {
if (this.tree) {
const tree = this.tree;
if (tree) {
itemOrItems = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
await Promise.all(itemOrItems.map(element => {
return this.tree.expand(element, false);
return tree.expand(element, false);
}));
}
return Promise.resolve(undefined);
@@ -575,18 +576,19 @@ export class CustomTreeView extends Disposable implements ITreeView {
private refreshing: boolean = false;
private async doRefresh(elements: ITreeItem[]): Promise<void> {
if (this.tree) {
const tree = this.tree;
if (tree) {
this.refreshing = true;
const parents: Set<ITreeItem> = new Set<ITreeItem>();
elements.forEach(element => {
if (element !== this.root) {
const parent = this.tree.getParentElement(element);
const parent = tree.getParentElement(element);
parents.add(parent);
} else {
parents.add(element);
}
});
await Promise.all(Array.from(parents.values()).map(element => this.tree.updateChildren(element, true)));
await Promise.all(Array.from(parents.values()).map(element => tree.updateChildren(element, true)));
this.refreshing = false;
this.updateContentAreas();
if (this.focused) {
@@ -772,7 +774,7 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
}
class Aligner extends Disposable {
private _tree: WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore>;
private _tree: WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore> | undefined;
constructor(private themeService: IWorkbenchThemeService) {
super();
@@ -790,11 +792,15 @@ class Aligner extends Disposable {
return false;
}
const parent: ITreeItem = this._tree.getParentElement(treeItem) || this._tree.getInput();
if (this.hasIcon(parent)) {
if (this._tree) {
const parent: ITreeItem = this._tree.getParentElement(treeItem) || this._tree.getInput();
if (this.hasIcon(parent)) {
return false;
}
return !!parent.children && parent.children.every(c => c.collapsibleState === TreeItemCollapsibleState.None || !this.hasIcon(c));
} else {
return false;
}
return !!parent.children && parent.children.every(c => c.collapsibleState === TreeItemCollapsibleState.None || !this.hasIcon(c));
}
private hasIcon(node: ITreeItem): boolean {

View File

@@ -7,6 +7,10 @@
border-top: none !important; /* less clutter: do not show any border for first views in a panel */
}
.monaco-panel-view .panel > .panel-header > .actions.show {
display: initial;
}
.monaco-panel-view .panel > .panel-header h3.title {
white-space: nowrap;
text-overflow: ellipsis;

View File

@@ -41,6 +41,7 @@ export interface IViewletPanelOptions extends IPanelOptions {
actionRunner?: IActionRunner;
id: string;
title: string;
showActionsAlways?: boolean;
}
export abstract class ViewletPanel extends Panel implements IView {
@@ -67,6 +68,7 @@ export abstract class ViewletPanel extends Panel implements IView {
protected actionRunner?: IActionRunner;
protected toolbar: ToolBar;
private readonly showActionsAlways: boolean = false;
private headerContainer: HTMLElement;
private titleContainer: HTMLElement;
@@ -82,6 +84,7 @@ export abstract class ViewletPanel extends Panel implements IView {
this.id = options.id;
this.title = options.title;
this.actionRunner = options.actionRunner;
this.showActionsAlways = !!options.showActionsAlways;
this.focusedViewContextKey = FocusedViewContext.bindTo(contextKeyService);
}
@@ -133,6 +136,7 @@ export abstract class ViewletPanel extends Panel implements IView {
this.renderHeaderTitle(container, this.title);
const actions = append(container, $('.actions'));
toggleClass(actions, 'show', this.showActionsAlways);
this.toolbar = new ToolBar(actions, this.contextMenuService, {
orientation: ActionsOrientation.HORIZONTAL,
actionViewItemProvider: action => this.getActionViewItem(action),

View File

@@ -8,9 +8,8 @@ import * as browser from 'vs/base/browser/browser';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { Event } from 'vs/base/common/event';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IGalleryExtension, IExtensionIdentifier, IReportedExtension, IExtensionManagementService, ILocalExtension, IGalleryMetadata } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionTipsService, ExtensionRecommendationReason, IExtensionRecommendation } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { ExtensionType, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { IURLHandler, IURLService } from 'vs/platform/url/common/url';
import { ConsoleLogService, ILogService } from 'vs/platform/log/common/log';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
@@ -24,7 +23,7 @@ import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common
import { ITunnelService } from 'vs/platform/remote/common/tunnel';
// tslint:disable-next-line: import-patterns
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { addDisposableListener, EventType } from 'vs/base/browser/dom';
import { addDisposableListener, EventType, windowOpenNoOpener } from 'vs/base/browser/dom';
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
import { pathsToEditors } from 'vs/workbench/common/editor';
import { IFileService } from 'vs/platform/files/common/files';
@@ -90,63 +89,6 @@ registerSingleton(IExtensionTipsService, SimpleExtensionTipsService, true);
//#endregion
export class SimpleExtensionManagementService implements IExtensionManagementService {
_serviceBrand: any;
onInstallExtension = Event.None;
onDidInstallExtension = Event.None;
onUninstallExtension = Event.None;
onDidUninstallExtension = Event.None;
zip(extension: ILocalExtension): Promise<URI> {
// @ts-ignore
return Promise.resolve(undefined);
}
unzip(zipLocation: URI, type: ExtensionType): Promise<IExtensionIdentifier> {
// @ts-ignore
return Promise.resolve(undefined);
}
install(vsix: URI): Promise<ILocalExtension> {
// @ts-ignore
return Promise.resolve(undefined);
}
installFromGallery(extension: IGalleryExtension): Promise<ILocalExtension> {
// @ts-ignore
return Promise.resolve(undefined);
}
uninstall(extension: ILocalExtension, force?: boolean): Promise<void> {
return Promise.resolve(undefined);
}
reinstallFromGallery(extension: ILocalExtension): Promise<void> {
return Promise.resolve(undefined);
}
getInstalled(type?: ExtensionType): Promise<ILocalExtension[]> {
// @ts-ignore
return Promise.resolve([]);
}
getExtensionsReport(): Promise<IReportedExtension[]> {
// @ts-ignore
return Promise.resolve([]);
}
updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): Promise<ILocalExtension> {
// @ts-ignore
return Promise.resolve(local);
}
}
registerSingleton(IExtensionManagementService, SimpleExtensionManagementService);
//#endregion
//#region Extension URL Handler
export const IExtensionUrlHandler = createDecorator<IExtensionUrlHandler>('inactiveExtensionUrlHandler');
@@ -784,6 +726,8 @@ export class SimpleWindowsService implements IWindowsService {
// This needs to be handled from browser process to prevent
// foreground ordering issues on Windows
openExternal(_url: string): Promise<boolean> {
windowOpenNoOpener(_url);
return Promise.resolve(true);
}

View File

@@ -300,7 +300,7 @@ export interface IViewsService {
export interface ITreeView extends IDisposable {
dataProvider: ITreeViewDataProvider | null;
dataProvider: ITreeViewDataProvider | undefined;
showCollapseAllAction: boolean;

View File

@@ -607,11 +607,9 @@ class CallStackDataSource implements IAsyncDataSource<IDebugModel, CallStackItem
return threads.length === 1 ? this.getThreadChildren(<Thread>threads[0]) : Promise.resolve(threads);
} else if (isDebugSession(element)) {
const childSessions = this.debugService.getModel().getSessions().filter(s => s.parentSession === element);
if (childSessions.length) {
return Promise.resolve(childSessions);
}
const threads: CallStackItem[] = element.getAllThreads();
return Promise.resolve(element.getAllThreads());
return Promise.resolve(threads.concat(childSessions));
} else {
return this.getThreadChildren(<Thread>element);
}

View File

@@ -134,29 +134,33 @@ interface IActiveElement {
focus(): void;
}
interface IExtensionEditorTemplate {
iconContainer: HTMLElement;
icon: HTMLImageElement;
name: HTMLElement;
identifier: HTMLElement;
preview: HTMLElement;
builtin: HTMLElement;
license: HTMLElement;
publisher: HTMLElement;
installCount: HTMLElement;
rating: HTMLElement;
repository: HTMLElement;
description: HTMLElement;
extensionActionBar: ActionBar;
navbar: NavBar;
content: HTMLElement;
subtextContainer: HTMLElement;
subtext: HTMLElement;
ignoreActionbar: ActionBar;
header: HTMLElement;
}
export class ExtensionEditor extends BaseEditor {
static readonly ID: string = 'workbench.editor.extension';
private iconContainer: HTMLElement;
private icon: HTMLImageElement;
private name: HTMLElement;
private identifier: HTMLElement;
private preview: HTMLElement;
private builtin: HTMLElement;
private license: HTMLElement;
private publisher: HTMLElement;
private installCount: HTMLElement;
private rating: HTMLElement;
private repository: HTMLElement;
private description: HTMLElement;
private extensionActionBar: ActionBar;
private navbar: NavBar;
private content: HTMLElement;
private subtextContainer: HTMLElement;
private subtext: HTMLElement;
private ignoreActionbar: ActionBar;
private header: HTMLElement;
private template: IExtensionEditorTemplate | undefined;
private extensionReadme: Cache<string> | null;
private extensionChangelog: Cache<string> | null;
@@ -165,7 +169,7 @@ export class ExtensionEditor extends BaseEditor {
private layoutParticipants: ILayoutParticipant[] = [];
private readonly contentDisposables = this._register(new DisposableStore());
private readonly transientDisposables = this._register(new DisposableStore());
private activeElement: IActiveElement | null;
private activeElement: IActiveElement | null = null;
private editorLoadComplete: boolean = false;
constructor(
@@ -193,43 +197,43 @@ export class ExtensionEditor extends BaseEditor {
const root = append(parent, $('.extension-editor'));
root.tabIndex = 0; // this is required for the focus tracker on the editor
root.style.outline = 'none';
this.header = append(root, $('.header'));
const header = append(root, $('.header'));
this.iconContainer = append(this.header, $('.icon-container'));
this.icon = append(this.iconContainer, $<HTMLImageElement>('img.icon', { draggable: false }));
const iconContainer = append(header, $('.icon-container'));
const icon = append(iconContainer, $<HTMLImageElement>('img.icon', { draggable: false }));
const details = append(this.header, $('.details'));
const details = append(header, $('.details'));
const title = append(details, $('.title'));
this.name = append(title, $('span.name.clickable', { title: localize('name', "Extension name") }));
this.identifier = append(title, $('span.identifier', { title: localize('extension id', "Extension identifier") }));
const name = append(title, $('span.name.clickable', { title: localize('name', "Extension name") }));
const identifier = append(title, $('span.identifier', { title: localize('extension id', "Extension identifier") }));
this.preview = append(title, $('span.preview', { title: localize('preview', "Preview") }));
this.preview.textContent = localize('preview', "Preview");
const preview = append(title, $('span.preview', { title: localize('preview', "Preview") }));
preview.textContent = localize('preview', "Preview");
this.builtin = append(title, $('span.builtin'));
this.builtin.textContent = localize('builtin', "Built-in");
const builtin = append(title, $('span.builtin'));
builtin.textContent = localize('builtin', "Built-in");
const subtitle = append(details, $('.subtitle'));
this.publisher = append(subtitle, $('span.publisher.clickable', { title: localize('publisher', "Publisher name"), tabIndex: 0 }));
const publisher = append(subtitle, $('span.publisher.clickable', { title: localize('publisher', "Publisher name"), tabIndex: 0 }));
this.installCount = append(subtitle, $('span.install', { title: localize('install count', "Install count"), tabIndex: 0 }));
const installCount = append(subtitle, $('span.install', { title: localize('install count', "Install count"), tabIndex: 0 }));
this.rating = append(subtitle, $('span.rating.clickable', { title: localize('rating', "Rating"), tabIndex: 0 }));
const rating = append(subtitle, $('span.rating.clickable', { title: localize('rating', "Rating"), tabIndex: 0 }));
this.repository = append(subtitle, $('span.repository.clickable'));
this.repository.textContent = localize('repository', 'Repository');
this.repository.style.display = 'none';
this.repository.tabIndex = 0;
const repository = append(subtitle, $('span.repository.clickable'));
repository.textContent = localize('repository', 'Repository');
repository.style.display = 'none';
repository.tabIndex = 0;
this.license = append(subtitle, $('span.license.clickable'));
this.license.textContent = localize('license', 'License');
this.license.style.display = 'none';
this.license.tabIndex = 0;
const license = append(subtitle, $('span.license.clickable'));
license.textContent = localize('license', 'License');
license.style.display = 'none';
license.tabIndex = 0;
this.description = append(details, $('.description'));
const description = append(details, $('.description'));
const extensionActions = append(details, $('.actions'));
this.extensionActionBar = new ActionBar(extensionActions, {
const extensionActionBar = this._register(new ActionBar(extensionActions, {
animated: false,
actionViewItemProvider: (action: Action) => {
if (action instanceof ExtensionEditorDropDownAction) {
@@ -237,29 +241,48 @@ export class ExtensionEditor extends BaseEditor {
}
return undefined;
}
});
}));
this.subtextContainer = append(details, $('.subtext-container'));
this.subtext = append(this.subtextContainer, $('.subtext'));
this.ignoreActionbar = new ActionBar(this.subtextContainer, { animated: false });
const subtextContainer = append(details, $('.subtext-container'));
const subtext = append(subtextContainer, $('.subtext'));
const ignoreActionbar = this._register(new ActionBar(subtextContainer, { animated: false }));
this._register(this.extensionActionBar);
this._register(this.ignoreActionbar);
this._register(Event.chain(this.extensionActionBar.onDidRun)
this._register(Event.chain(extensionActionBar.onDidRun)
.map(({ error }) => error)
.filter(error => !!error)
.on(this.onError, this));
this._register(Event.chain(this.ignoreActionbar.onDidRun)
this._register(Event.chain(ignoreActionbar.onDidRun)
.map(({ error }) => error)
.filter(error => !!error)
.on(this.onError, this));
const body = append(root, $('.body'));
this.navbar = new NavBar(body);
const navbar = new NavBar(body);
this.content = append(body, $('.content'));
const content = append(body, $('.content'));
this.template = {
builtin,
content,
description,
extensionActionBar,
header,
icon,
iconContainer,
identifier,
ignoreActionbar,
installCount,
license,
name,
navbar,
preview,
publisher,
rating,
repository,
subtext,
subtextContainer
};
}
private onClick(element: HTMLElement, callback: () => void): IDisposable {
@@ -277,6 +300,13 @@ export class ExtensionEditor extends BaseEditor {
}
async setInput(input: ExtensionsInput, options: EditorOptions, token: CancellationToken): Promise<void> {
if (this.template) {
await this.updateTemplate(input, this.template);
}
return super.setInput(input, options, token);
}
private async updateTemplate(input: ExtensionsInput, template: IExtensionEditorTemplate): Promise<void> {
const runningExtensions = await this.extensionService.getExtensions();
const colorThemes = await this.workbenchThemeService.getColorThemes();
const fileIconThemes = await this.workbenchThemeService.getFileIconThemes();
@@ -291,18 +321,18 @@ export class ExtensionEditor extends BaseEditor {
this.extensionChangelog = new Cache(() => createCancelablePromise(token => extension.getChangelog(token)));
this.extensionManifest = new Cache(() => createCancelablePromise(token => extension.getManifest(token)));
const remoteBadge = this.instantiationService.createInstance(RemoteBadgeWidget, this.iconContainer, true);
const onError = Event.once(domEvent(this.icon, 'error'));
onError(() => this.icon.src = extension.iconUrlFallback, null, this.transientDisposables);
this.icon.src = extension.iconUrl;
const remoteBadge = this.instantiationService.createInstance(RemoteBadgeWidget, template.iconContainer, true);
const onError = Event.once(domEvent(template.icon, 'error'));
onError(() => template.icon.src = extension.iconUrlFallback, null, this.transientDisposables);
template.icon.src = extension.iconUrl;
this.name.textContent = extension.displayName;
this.identifier.textContent = extension.identifier.id;
this.preview.style.display = extension.preview ? 'inherit' : 'none';
this.builtin.style.display = extension.type === ExtensionType.System ? 'inherit' : 'none';
template.name.textContent = extension.displayName;
template.identifier.textContent = extension.identifier.id;
template.preview.style.display = extension.preview ? 'inherit' : 'none';
template.builtin.style.display = extension.type === ExtensionType.System ? 'inherit' : 'none';
this.publisher.textContent = extension.publisherDisplayName;
this.description.textContent = extension.description;
template.publisher.textContent = extension.publisherDisplayName;
template.description.textContent = extension.description;
const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason();
let recommendationsData = {};
@@ -320,51 +350,50 @@ export class ExtensionEditor extends BaseEditor {
*/
this.telemetryService.publicLog('extensionGallery:openExtension', assign(extension.telemetryData, recommendationsData));
toggleClass(this.name, 'clickable', !!extension.url);
toggleClass(this.publisher, 'clickable', !!extension.url);
toggleClass(this.rating, 'clickable', !!extension.url);
toggleClass(template.name, 'clickable', !!extension.url);
toggleClass(template.publisher, 'clickable', !!extension.url);
toggleClass(template.rating, 'clickable', !!extension.url);
if (extension.url) {
this.transientDisposables.add(this.onClick(this.name, () => window.open(extension.url)));
this.transientDisposables.add(this.onClick(this.rating, () => window.open(`${extension.url}#review-details`)));
this.transientDisposables.add(this.onClick(this.publisher, () => {
this.transientDisposables.add(this.onClick(template.name, () => window.open(extension.url)));
this.transientDisposables.add(this.onClick(template.rating, () => window.open(`${extension.url}#review-details`)));
this.transientDisposables.add(this.onClick(template.publisher, () => {
this.viewletService.openViewlet(VIEWLET_ID, true)
.then(viewlet => viewlet as IExtensionsViewlet)
.then(viewlet => viewlet.search(`publisher:"${extension.publisherDisplayName}"`));
}));
if (extension.licenseUrl) {
this.transientDisposables.add(this.onClick(this.license, () => window.open(extension.licenseUrl)));
this.license.style.display = 'initial';
this.transientDisposables.add(this.onClick(template.license, () => window.open(extension.licenseUrl)));
template.license.style.display = 'initial';
} else {
this.license.style.display = 'none';
template.license.style.display = 'none';
}
} else {
this.license.style.display = 'none';
template.license.style.display = 'none';
}
// {{SQL CARBON EDIT}} add license url
if (extension.licenseUrl) {
this.license.onclick = finalHandler(() => window.open(extension.licenseUrl));
this.license.style.display = 'initial';
template.license.onclick = finalHandler(() => window.open(extension.licenseUrl));
template.license.style.display = 'initial';
} else {
this.license.onclick = null;
this.license.style.display = 'none';
template.license.onclick = null;
template.license.style.display = 'none';
}
// {{SQL CARBON EDIT}} - End
if (extension.repository) {
this.transientDisposables.add(this.onClick(this.repository, () => window.open(extension.repository)));
this.repository.style.display = 'initial';
this.transientDisposables.add(this.onClick(template.repository, () => window.open(extension.repository)));
template.repository.style.display = 'initial';
}
else {
this.repository.style.display = 'none';
template.repository.style.display = 'none';
}
const widgets = [
remoteBadge,
// {{SQL CARBON EDIT}} Remove the widgets
// this.instantiationService.createInstance(InstallCountWidget, this.installCount, false),
// this.instantiationService.createInstance(RatingsWidget, this.rating, false)
// this.instantiationService.createInstance(InstallCountWidget, template.installCount, false), {{SQL CARBON EDIT}} Remove the widgets
// this.instantiationService.createInstance(RatingsWidget, template.rating, false) {{SQL CARBON EDIT}} Remove the widgets
];
const reloadAction = this.instantiationService.createInstance(ReloadAction);
const combinedInstallAction = this.instantiationService.createInstance(CombinedInstallAction);
@@ -387,20 +416,20 @@ export class ExtensionEditor extends BaseEditor {
const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets]);
extensionContainers.extension = extension;
this.extensionActionBar.clear();
this.extensionActionBar.push(actions, { icon: true, label: true });
template.extensionActionBar.clear();
template.extensionActionBar.push(actions, { icon: true, label: true });
for (const disposable of [...actions, ...widgets, extensionContainers]) {
this.transientDisposables.add(disposable);
}
this.setSubText(extension, reloadAction);
this.content.innerHTML = ''; // Clear content before setting navbar actions.
this.setSubText(extension, reloadAction, template);
template.content.innerHTML = ''; // Clear content before setting navbar actions.
this.navbar.clear();
this.navbar.onChange(this.onNavbarChange.bind(this, extension), this, this.transientDisposables);
template.navbar.clear();
template.navbar.onChange(e => this.onNavbarChange(extension, e, template), this, this.transientDisposables);
if (extension.hasReadme()) {
this.navbar.push(NavbarSection.Readme, localize('details', "Details"), localize('detailstooltip', "Extension details, rendered from the extension's 'README.md' file"));
template.navbar.push(NavbarSection.Readme, localize('details', "Details"), localize('detailstooltip', "Extension details, rendered from the extension's 'README.md' file"));
}
this.extensionManifest.get()
.promise
@@ -409,25 +438,23 @@ export class ExtensionEditor extends BaseEditor {
combinedInstallAction.manifest = manifest;
}
if (extension.extensionPack.length) {
this.navbar.push(NavbarSection.ExtensionPack, localize('extensionPack', "Extension Pack"), localize('extensionsPack', "Set of extensions that can be installed together"));
template.navbar.push(NavbarSection.ExtensionPack, localize('extensionPack', "Extension Pack"), localize('extensionsPack', "Set of extensions that can be installed together"));
}
if (manifest && manifest.contributes) {
this.navbar.push(NavbarSection.Contributions, localize('contributions', "Contributions"), localize('contributionstooltip', "Lists contributions to VS Code by this extension"));
template.navbar.push(NavbarSection.Contributions, localize('contributions', "Contributions"), localize('contributionstooltip', "Lists contributions to VS Code by this extension"));
}
if (extension.hasChangelog()) {
this.navbar.push(NavbarSection.Changelog, localize('changelog', "Changelog"), localize('changelogtooltip', "Extension update history, rendered from the extension's 'CHANGELOG.md' file"));
template.navbar.push(NavbarSection.Changelog, localize('changelog', "Changelog"), localize('changelogtooltip', "Extension update history, rendered from the extension's 'CHANGELOG.md' file"));
}
if (extension.dependencies.length) {
this.navbar.push(NavbarSection.Dependencies, localize('dependencies', "Dependencies"), localize('dependenciestooltip', "Lists extensions this extension depends on"));
template.navbar.push(NavbarSection.Dependencies, localize('dependencies', "Dependencies"), localize('dependenciestooltip', "Lists extensions this extension depends on"));
}
this.editorLoadComplete = true;
});
return super.setInput(input, options, token);
}
private setSubText(extension: IExtension, reloadAction: ReloadAction): void {
hide(this.subtextContainer);
private setSubText(extension: IExtension, reloadAction: ReloadAction, template: IExtensionEditorTemplate): void {
hide(template.subtextContainer);
const ignoreAction = this.instantiationService.createInstance(IgnoreExtensionRecommendationAction);
const undoIgnoreAction = this.instantiationService.createInstance(UndoIgnoreExtensionRecommendationAction);
@@ -436,23 +463,23 @@ export class ExtensionEditor extends BaseEditor {
ignoreAction.enabled = false;
undoIgnoreAction.enabled = false;
this.ignoreActionbar.clear();
this.ignoreActionbar.push([ignoreAction, undoIgnoreAction], { icon: true, label: true });
template.ignoreActionbar.clear();
template.ignoreActionbar.push([ignoreAction, undoIgnoreAction], { icon: true, label: true });
this.transientDisposables.add(ignoreAction);
this.transientDisposables.add(undoIgnoreAction);
const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason();
if (extRecommendations[extension.identifier.id.toLowerCase()]) {
ignoreAction.enabled = true;
this.subtext.textContent = extRecommendations[extension.identifier.id.toLowerCase()].reasonText;
show(this.subtextContainer);
template.subtext.textContent = extRecommendations[extension.identifier.id.toLowerCase()].reasonText;
show(template.subtextContainer);
} else if (this.extensionTipsService.getAllIgnoredRecommendations().global.indexOf(extension.identifier.id.toLowerCase()) !== -1) {
undoIgnoreAction.enabled = true;
this.subtext.textContent = localize('recommendationHasBeenIgnored', "You have chosen not to receive recommendations for this extension.");
show(this.subtextContainer);
template.subtext.textContent = localize('recommendationHasBeenIgnored', "You have chosen not to receive recommendations for this extension.");
show(template.subtextContainer);
}
else {
this.subtext.textContent = '';
template.subtext.textContent = '';
}
this.extensionTipsService.onRecommendationChange(change => {
@@ -462,28 +489,28 @@ export class ExtensionEditor extends BaseEditor {
const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason();
if (extRecommendations[extension.identifier.id.toLowerCase()]) {
ignoreAction.enabled = true;
this.subtext.textContent = extRecommendations[extension.identifier.id.toLowerCase()].reasonText;
template.subtext.textContent = extRecommendations[extension.identifier.id.toLowerCase()].reasonText;
}
} else {
undoIgnoreAction.enabled = true;
ignoreAction.enabled = false;
this.subtext.textContent = localize('recommendationHasBeenIgnored', "You have chosen not to receive recommendations for this extension.");
template.subtext.textContent = localize('recommendationHasBeenIgnored', "You have chosen not to receive recommendations for this extension.");
}
}
});
this.transientDisposables.add(reloadAction.onDidChange(e => {
if (e.tooltip) {
this.subtext.textContent = reloadAction.tooltip;
show(this.subtextContainer);
template.subtext.textContent = reloadAction.tooltip;
show(template.subtextContainer);
ignoreAction.enabled = false;
undoIgnoreAction.enabled = false;
}
if (e.enabled === true) {
show(this.subtextContainer);
show(template.subtextContainer);
}
if (e.enabled === false) {
hide(this.subtextContainer);
hide(template.subtextContainer);
}
}));
}
@@ -507,7 +534,7 @@ export class ExtensionEditor extends BaseEditor {
}
}
private onNavbarChange(extension: IExtension, { id, focus }: { id: string, focus: boolean }): void {
private onNavbarChange(extension: IExtension, { id, focus }: { id: string | null, focus: boolean }, template: IExtensionEditorTemplate): void {
if (this.editorLoadComplete) {
/* __GDPR__
"extensionEditor:navbarChange" : {
@@ -521,30 +548,32 @@ export class ExtensionEditor extends BaseEditor {
}
this.contentDisposables.clear();
this.content.innerHTML = '';
template.content.innerHTML = '';
this.activeElement = null;
this.open(id, extension)
.then(activeElement => {
this.activeElement = activeElement;
if (focus) {
this.focus();
}
});
if (id) {
this.open(id, extension, template)
.then(activeElement => {
this.activeElement = activeElement;
if (focus) {
this.focus();
}
});
}
}
private open(id: string, extension: IExtension): Promise<IActiveElement | null> {
private open(id: string, extension: IExtension, template: IExtensionEditorTemplate): Promise<IActiveElement | null> {
switch (id) {
case NavbarSection.Readme: return this.openReadme();
case NavbarSection.Contributions: return this.openContributions();
case NavbarSection.Changelog: return this.openChangelog();
case NavbarSection.Dependencies: return this.openDependencies(extension);
case NavbarSection.ExtensionPack: return this.openExtensionPack(extension);
case NavbarSection.Readme: return this.openReadme(template);
case NavbarSection.Contributions: return this.openContributions(template);
case NavbarSection.Changelog: return this.openChangelog(template);
case NavbarSection.Dependencies: return this.openDependencies(extension, template);
case NavbarSection.ExtensionPack: return this.openExtensionPack(extension, template);
}
return Promise.resolve(null);
}
private openMarkdown(cacheResult: CacheResult<string>, noContentCopy: string): Promise<IActiveElement> {
return this.loadContents(() => cacheResult)
private openMarkdown(cacheResult: CacheResult<string>, noContentCopy: string, template: IExtensionEditorTemplate): Promise<IActiveElement> {
return this.loadContents(() => cacheResult, template)
.then(marked.parse)
.then(content => this.renderBody(content))
.then(removeEmbeddedSVGs)
@@ -556,7 +585,7 @@ export class ExtensionEditor extends BaseEditor {
{
svgWhiteList: this.extensionsWorkbenchService.allowedBadgeProviders,
});
webviewElement.mountTo(this.content);
webviewElement.mountTo(template.content);
this.contentDisposables.add(webviewElement.onDidFocus(() => this.fireOnDidFocus()));
const removeLayoutParticipant = arrays.insert(this.layoutParticipants, webviewElement);
this.contentDisposables.add(toDisposable(removeLayoutParticipant));
@@ -575,7 +604,7 @@ export class ExtensionEditor extends BaseEditor {
return webviewElement;
})
.then(undefined, () => {
const p = append(this.content, $('p.nocontent'));
const p = append(template.content, $('p.nocontent'));
p.textContent = noContentCopy;
return p;
});
@@ -769,17 +798,17 @@ export class ExtensionEditor extends BaseEditor {
</html>`;
}
private openReadme(): Promise<IActiveElement> {
return this.openMarkdown(this.extensionReadme!.get(), localize('noReadme', "No README available."));
private openReadme(template: IExtensionEditorTemplate): Promise<IActiveElement> {
return this.openMarkdown(this.extensionReadme!.get(), localize('noReadme', "No README available."), template);
}
private openChangelog(): Promise<IActiveElement> {
return this.openMarkdown(this.extensionChangelog!.get(), localize('noChangelog', "No Changelog available."));
private openChangelog(template: IExtensionEditorTemplate): Promise<IActiveElement> {
return this.openMarkdown(this.extensionChangelog!.get(), localize('noChangelog', "No Changelog available."), template);
}
private openContributions(): Promise<IActiveElement> {
private openContributions(template: IExtensionEditorTemplate): Promise<IActiveElement> {
const content = $('div', { class: 'subcontent', tabindex: '0' });
return this.loadContents(() => this.extensionManifest!.get())
return this.loadContents(() => this.extensionManifest!.get(), template)
.then(manifest => {
if (!manifest) {
return content;
@@ -811,28 +840,28 @@ export class ExtensionEditor extends BaseEditor {
const isEmpty = !renders.some(x => x);
if (isEmpty) {
append(content, $('p.nocontent')).textContent = localize('noContributions', "No Contributions");
append(this.content, content);
append(template.content, content);
} else {
append(this.content, scrollableContent.getDomNode());
append(template.content, scrollableContent.getDomNode());
this.contentDisposables.add(scrollableContent);
}
return content;
}, () => {
append(content, $('p.nocontent')).textContent = localize('noContributions', "No Contributions");
append(this.content, content);
append(template.content, content);
return content;
});
}
private openDependencies(extension: IExtension): Promise<IActiveElement> {
private openDependencies(extension: IExtension, template: IExtensionEditorTemplate): Promise<IActiveElement> {
if (arrays.isFalsyOrEmpty(extension.dependencies)) {
append(this.content, $('p.nocontent')).textContent = localize('noDependencies', "No Dependencies");
return Promise.resolve(this.content);
append(template.content, $('p.nocontent')).textContent = localize('noDependencies', "No Dependencies");
return Promise.resolve(template.content);
}
const content = $('div', { class: 'subcontent' });
const scrollableContent = new DomScrollableElement(content, {});
append(this.content, scrollableContent.getDomNode());
append(template.content, scrollableContent.getDomNode());
this.contentDisposables.add(scrollableContent);
const dependenciesTree = this.instantiationService.createInstance(ExtensionsTree, new ExtensionData(extension, null, extension => extension.dependencies || [], this.extensionsWorkbenchService), content);
@@ -849,10 +878,10 @@ export class ExtensionEditor extends BaseEditor {
return Promise.resolve({ focus() { dependenciesTree.domFocus(); } });
}
private openExtensionPack(extension: IExtension): Promise<IActiveElement> {
private openExtensionPack(extension: IExtension, template: IExtensionEditorTemplate): Promise<IActiveElement> {
const content = $('div', { class: 'subcontent' });
const scrollableContent = new DomScrollableElement(content, {});
append(this.content, scrollableContent.getDomNode());
append(template.content, scrollableContent.getDomNode());
this.contentDisposables.add(scrollableContent);
const extensionsPackTree = this.instantiationService.createInstance(ExtensionsTree, new ExtensionData(extension, null, extension => extension.extensionPack || [], this.extensionsWorkbenchService), content);
@@ -1272,11 +1301,11 @@ export class ExtensionEditor extends BaseEditor {
return null;
}
private loadContents<T>(loadingTask: () => CacheResult<T>): Promise<T> {
addClass(this.content, 'loading');
private loadContents<T>(loadingTask: () => CacheResult<T>, template: IExtensionEditorTemplate): Promise<T> {
addClass(template.content, 'loading');
const result = loadingTask();
const onDone = () => removeClass(this.content, 'loading');
const onDone = () => removeClass(template.content, 'loading');
result.promise.then(onDone, onDone);
this.contentDisposables.add(toDisposable(() => result.dispose()));

View File

@@ -3097,7 +3097,10 @@ interface IExtensionPickItem extends IQuickPickItem {
export class InstallLocalExtensionsInRemoteAction extends Action {
private extensions: IExtension[] | undefined = undefined;
constructor(
private readonly selectAndInstall: boolean,
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
@@ -3109,32 +3112,56 @@ export class InstallLocalExtensionsInRemoteAction extends Action {
) {
super('workbench.extensions.actions.installLocalExtensionsInRemote');
this.update();
this._register(this.extensionsWorkbenchService.onChange(() => this.update()));
this.extensionsWorkbenchService.queryLocal().then(() => this.updateExtensions());
this._register(this.extensionsWorkbenchService.onChange(() => {
if (this.extensions) {
this.updateExtensions();
}
}));
}
get label(): string {
return this.extensionManagementServerService.remoteExtensionManagementServer ?
localize('install local extensions', "Install Local Extensions in {0}...", this.extensionManagementServerService.remoteExtensionManagementServer.label) : '';
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
return this.selectAndInstall ?
localize('select and install local extensions', "Install Local Extensions in {0}...", this.extensionManagementServerService.remoteExtensionManagementServer.label)
: localize('install local extensions', "Install Local Extensions in {0}", this.extensionManagementServerService.remoteExtensionManagementServer.label);
}
return '';
}
private updateExtensions(): void {
this.extensions = this.extensionsWorkbenchService.local;
this.update();
}
private update(): void {
this.enabled = this.getLocalExtensionsToInstall().length > 0;
this.enabled = !!this.extensions && this.getExtensionsToInstall(this.extensions).length > 0;
this.tooltip = this.label;
}
private getLocalExtensionsToInstall(): IExtension[] {
return this.extensionsWorkbenchService.local.filter(extension => {
async run(): Promise<void> {
if (this.selectAndInstall) {
return this.selectAndInstallLocalExtensions();
} else {
const extensionsToInstall = await this.queryExtensionsToInstall();
return this.installLocalExtensions(extensionsToInstall);
}
}
private async queryExtensionsToInstall(): Promise<IExtension[]> {
const local = await this.extensionsWorkbenchService.queryLocal();
return this.getExtensionsToInstall(local);
}
private getExtensionsToInstall(local: IExtension[]): IExtension[] {
return local.filter(extension => {
const action = this.instantiationService.createInstance(RemoteInstallAction);
action.extension = extension;
return action.enabled;
});
}
async run(): Promise<void> {
this.selectAndInstallLocalExtensions();
return Promise.resolve();
}
private selectAndInstallLocalExtensions(): void {
private async selectAndInstallLocalExtensions(): Promise<void> {
const quickPick = this.quickInputService.createQuickPick<IExtensionPickItem>();
quickPick.busy = true;
const disposable = quickPick.onDidAccept(() => {
@@ -3144,7 +3171,7 @@ export class InstallLocalExtensionsInRemoteAction extends Action {
this.onDidAccept(quickPick.selectedItems);
});
quickPick.show();
const localExtensionsToInstall = this.getLocalExtensionsToInstall();
const localExtensionsToInstall = await this.queryExtensionsToInstall();
quickPick.busy = false;
if (localExtensionsToInstall.length) {
quickPick.title = localize('install local extensions title', "Install Local Extensions in {0}", this.extensionManagementServerService.remoteExtensionManagementServer!.label);

View File

@@ -156,7 +156,7 @@ export class UnknownExtensionRenderer implements IListRenderer<ITreeNode<IExtens
class OpenExtensionAction extends Action {
private _extensionData: IExtensionData;
private _extensionData: IExtensionData | undefined;
constructor(@IExtensionsWorkbenchService private readonly extensionsWorkdbenchService: IExtensionsWorkbenchService) {
super('extensions.action.openExtension', '');
@@ -166,12 +166,11 @@ class OpenExtensionAction extends Action {
this._extensionData = extension;
}
public get extensionData(): IExtensionData {
return this._extensionData;
}
run(sideByside: boolean): Promise<any> {
return this.extensionsWorkdbenchService.open(this.extensionData.extension, sideByside);
if (this._extensionData) {
return this.extensionsWorkdbenchService.open(this._extensionData.extension, sideByside);
}
return Promise.resolve();
}
}
@@ -263,4 +262,4 @@ export class ExtensionData implements IExtensionData {
}
return null;
}
}
}

View File

@@ -22,7 +22,7 @@ import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, AutoUpdate
import {
ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowDisabledExtensionsAction,
ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction,
EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction, InstallLocalExtensionsInRemoteAction
EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction
} from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionEnablementService, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
@@ -323,7 +323,8 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensionsViewlet {
private onSearchChange: EventOf<string>;
private readonly _onSearchChange: Emitter<string> = this._register(new Emitter<string>());
private readonly onSearchChange: EventOf<string> = this._onSearchChange.event;
private nonEmptyWorkspaceContextKey: IContextKey<boolean>;
private defaultViewsContextKey: IContextKey<boolean>;
private searchMarketplaceExtensionsContextKey: IContextKey<boolean>;
@@ -337,12 +338,10 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
private defaultRecommendedExtensionsContextKey: IContextKey<boolean>;
private searchDelayer: Delayer<void>;
private root: HTMLElement;
private searchBox: SuggestEnabledInput;
private extensionsBox: HTMLElement;
private primaryActions: IAction[];
private secondaryActions: IAction[] | null;
private root: HTMLElement | undefined;
private searchBox: SuggestEnabledInput | undefined;
private primaryActions: IAction[] | undefined;
private secondaryActions: IAction[] | null = null;
private readonly searchViewletState: MementoObject;
constructor(
@@ -352,7 +351,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
@IInstantiationService instantiationService: IInstantiationService,
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
@INotificationService private readonly notificationService: INotificationService,
@IViewletService private readonly viewletService: IViewletService,
@IThemeService themeService: IThemeService,
@@ -422,32 +420,35 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
this._register(attachSuggestEnabledInputBoxStyler(this.searchBox, this.themeService));
const _searchChange = new Emitter<string>();
this.onSearchChange = _searchChange.event;
this._register(this.searchBox.onInputDidChange(() => {
this.triggerSearch();
_searchChange.fire(this.searchBox.getValue());
this._onSearchChange.fire(this.searchBox!.getValue());
}, this));
this._register(this.searchBox.onShouldFocusResults(() => this.focusListView(), this));
this._register(this.onDidChangeVisibility(visible => {
if (visible) {
this.searchBox.focus();
this.searchBox!.focus();
}
}));
this.extensionsBox = append(this.root, $('.extensions'));
super.create(this.extensionsBox);
super.create(append(this.root, $('.extensions')));
}
focus(): void {
this.searchBox.focus();
if (this.searchBox) {
this.searchBox.focus();
}
}
layout(dimension: Dimension): void {
toggleClass(this.root, 'narrow', dimension.width <= 300);
this.searchBox.layout({ height: 20, width: dimension.width - 34 });
if (this.root) {
toggleClass(this.root, 'narrow', dimension.width <= 300);
}
if (this.searchBox) {
this.searchBox.layout({ height: 20, width: dimension.width - 34 });
}
super.layout(new Dimension(dimension.width, dimension.height - 38));
}
@@ -458,7 +459,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
getActions(): IAction[] {
if (!this.primaryActions) {
this.primaryActions = [
this.instantiationService.createInstance(ClearExtensionsInputAction, ClearExtensionsInputAction.ID, ClearExtensionsInputAction.LABEL, this.onSearchChange, this.searchBox.getValue())
this.instantiationService.createInstance(ClearExtensionsInputAction, ClearExtensionsInputAction.ID, ClearExtensionsInputAction.LABEL, this.onSearchChange, this.searchBox ? this.searchBox.getValue() : '')
];
}
return this.primaryActions;
@@ -484,7 +485,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
this.instantiationService.createInstance(CheckForUpdatesAction, CheckForUpdatesAction.ID, CheckForUpdatesAction.LABEL),
...(this.configurationService.getValue(AutoUpdateConfigurationKey) ? [this.instantiationService.createInstance(DisableAutoUpdateAction, DisableAutoUpdateAction.ID, DisableAutoUpdateAction.LABEL)] : [this.instantiationService.createInstance(UpdateAllAction, UpdateAllAction.ID, UpdateAllAction.LABEL), this.instantiationService.createInstance(EnableAutoUpdateAction, EnableAutoUpdateAction.ID, EnableAutoUpdateAction.LABEL)]),
this.instantiationService.createInstance(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL),
...(this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer ? [this.instantiationService.createInstance(InstallLocalExtensionsInRemoteAction)] : []),
new Separator(),
this.instantiationService.createInstance(DisableAllAction, DisableAllAction.ID, DisableAllAction.LABEL),
this.instantiationService.createInstance(EnableAllAction, EnableAllAction.ID, EnableAllAction.LABEL)
@@ -495,22 +495,24 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
}
search(value: string): void {
const event = new Event('input', { bubbles: true }) as SearchInputEvent;
event.immediate = true;
if (this.searchBox) {
const event = new Event('input', { bubbles: true }) as SearchInputEvent;
event.immediate = true;
this.searchBox.setValue(value);
this.searchBox.setValue(value);
}
}
private triggerSearch(immediate = false): void {
this.searchDelayer.trigger(() => this.doSearch(), immediate || !this.searchBox.getValue() ? 0 : 500).then(undefined, err => this.onError(err));
private triggerSearch(): void {
this.searchDelayer.trigger(() => this.doSearch(), this.searchBox && this.searchBox.getValue() ? 500 : 0).then(undefined, err => this.onError(err));
}
private normalizedQuery(): string {
return this.searchBox.getValue().replace(/@category/g, 'category').replace(/@tag:/g, 'tag:').replace(/@ext:/g, 'ext:');
return this.searchBox ? this.searchBox.getValue().replace(/@category/g, 'category').replace(/@tag:/g, 'tag:').replace(/@ext:/g, 'ext:') : '';
}
protected saveState(): void {
const value = this.searchBox.getValue();
const value = this.searchBox ? this.searchBox.getValue() : '';
if (ExtensionsListView.isLocalExtensionsQuery(value)) {
this.searchViewletState['query.value'] = value;
} else {

View File

@@ -14,11 +14,11 @@ import { IExtensionManagementServer, IExtensionManagementServerService, IExtensi
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { append, $, toggleClass } from 'vs/base/browser/dom';
import { append, $, toggleClass, addClass } from 'vs/base/browser/dom';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Delegate, Renderer, IExtensionsViewState } from 'vs/workbench/contrib/extensions/browser/extensionsList';
import { IExtension, IExtensionsWorkbenchService, ExtensionState } from '../common/extensions';
import { Query } from '../common/extensionQuery';
import { IExtension, IExtensionsWorkbenchService, ExtensionState } from 'vs/workbench/contrib/extensions/common/extensions';
import { Query } from 'vs/workbench/contrib/extensions/common/extensionQuery';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { attachBadgeStyler } from 'vs/platform/theme/common/styler';
@@ -27,8 +27,8 @@ import { OpenGlobalSettingsAction } from 'vs/workbench/contrib/preferences/brows
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
import { ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { InstallWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, ManageExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { InstallWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, ManageExtensionAction, InstallLocalExtensionsInRemoteAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { WorkbenchPagedList } from 'vs/platform/list/browser/listService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
@@ -74,15 +74,16 @@ class ExtensionListViewWarning extends Error { }
export class ExtensionsListView extends ViewletPanel {
private readonly server: IExtensionManagementServer | undefined;
private messageContainer: HTMLElement;
private messageSeverityIcon: HTMLElement;
private messageBox: HTMLElement;
private extensionsList: HTMLElement;
private badge: CountBadge;
protected badgeContainer: HTMLElement;
private list: WorkbenchPagedList<IExtension> | null;
private queryRequest: { query: string, request: CancelablePromise<IPagedModel<IExtension>> } | null;
protected readonly server: IExtensionManagementServer | undefined;
private bodyTemplate: {
messageContainer: HTMLElement;
messageSeverityIcon: HTMLElement;
messageBox: HTMLElement;
extensionsList: HTMLElement;
} | undefined;
private badge: CountBadge | undefined;
private list: WorkbenchPagedList<IExtension> | null = null;
private queryRequest: { query: string, request: CancelablePromise<IPagedModel<IExtension>> } | null = null;
constructor(
options: ExtensionsListViewOptions,
@@ -104,31 +105,27 @@ export class ExtensionsListView extends ViewletPanel {
@IProductService protected readonly productService: IProductService,
@IContextKeyService contextKeyService: IContextKeyService,
) {
super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService, contextKeyService);
super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: options.title, showActionsAlways: true }, keybindingService, contextMenuService, configurationService, contextKeyService);
this.server = options.server;
}
protected renderHeader(container: HTMLElement): void {
this.renderHeaderTitle(container);
}
addClass(container, 'extension-view-header');
super.renderHeader(container);
renderHeaderTitle(container: HTMLElement): void {
super.renderHeaderTitle(container, this.title);
this.badgeContainer = append(container, $('.count-badge-wrapper'));
this.badge = new CountBadge(this.badgeContainer);
this.badge = new CountBadge(append(container, $('.count-badge-wrapper')));
this._register(attachBadgeStyler(this.badge, this.themeService));
}
renderBody(container: HTMLElement): void {
this.extensionsList = append(container, $('.extensions-list'));
this.messageContainer = append(container, $('.message-container'));
this.messageSeverityIcon = append(this.messageContainer, $(''));
this.messageBox = append(this.messageContainer, $('.message'));
const extensionsList = append(container, $('.extensions-list'));
const messageContainer = append(container, $('.message-container'));
const messageSeverityIcon = append(messageContainer, $(''));
const messageBox = append(messageContainer, $('.message'));
const delegate = new Delegate();
const extensionsViewState = new ExtensionsViewState();
const renderer = this.instantiationService.createInstance(Renderer, extensionsViewState);
this.list = this.instantiationService.createInstance(WorkbenchPagedList, this.extensionsList, delegate, [renderer], {
this.list = this.instantiationService.createInstance(WorkbenchPagedList, extensionsList, delegate, [renderer], {
ariaLabel: localize('extensions', "Extensions"),
multipleSelectionSupport: false,
setRowLineHeight: false,
@@ -148,10 +145,19 @@ export class ExtensionsListView extends ViewletPanel {
.map(e => e.elements[0])
.filter(e => !!e)
.on(this.pin, this));
this.bodyTemplate = {
extensionsList,
messageBox,
messageContainer,
messageSeverityIcon
};
}
protected layoutBody(height: number, width: number): void {
this.extensionsList.style.height = height + 'px';
if (this.bodyTemplate) {
this.bodyTemplate.extensionsList.style.height = height + 'px';
}
if (this.list) {
this.list.layout(height, width);
}
@@ -501,7 +507,7 @@ export class ExtensionsListView extends ViewletPanel {
}
private _searchExperiments: Promise<IExperiment[]>;
private _searchExperiments: Promise<IExperiment[]> | undefined;
private getSearchExperiments(): Promise<IExperiment[]> {
if (!this._searchExperiments) {
this._searchExperiments = this.experimentService.getExperimentsByType(ExperimentActionType.ExtensionSearchResults);
@@ -773,24 +779,27 @@ export class ExtensionsListView extends ViewletPanel {
this.list.scrollTop = 0;
const count = this.count();
toggleClass(this.extensionsList, 'hidden', count === 0);
toggleClass(this.messageContainer, 'hidden', count > 0);
this.badge.setCount(count);
if (this.bodyTemplate && this.badge) {
if (count === 0 && this.isBodyVisible()) {
if (error) {
if (error instanceof ExtensionListViewWarning) {
this.messageSeverityIcon.className = SeverityIcon.className(Severity.Warning);
this.messageBox.textContent = getErrorMessage(error);
toggleClass(this.bodyTemplate.extensionsList, 'hidden', count === 0);
toggleClass(this.bodyTemplate.messageContainer, 'hidden', count > 0);
this.badge.setCount(count);
if (count === 0 && this.isBodyVisible()) {
if (error) {
if (error instanceof ExtensionListViewWarning) {
this.bodyTemplate.messageSeverityIcon.className = SeverityIcon.className(Severity.Warning);
this.bodyTemplate.messageBox.textContent = getErrorMessage(error);
} else {
this.bodyTemplate.messageSeverityIcon.className = SeverityIcon.className(Severity.Error);
this.bodyTemplate.messageBox.textContent = localize('error', "Error while loading extensions. {0}", getErrorMessage(error));
}
} else {
this.messageSeverityIcon.className = SeverityIcon.className(Severity.Error);
this.messageBox.textContent = localize('error', "Error while loading extensions. {0}", getErrorMessage(error));
this.bodyTemplate.messageSeverityIcon.className = '';
this.bodyTemplate.messageBox.textContent = localize('no extensions found', "No extensions found.");
}
} else {
this.messageSeverityIcon.className = '';
this.messageBox.textContent = localize('no extensions found', "No extensions found.");
alert(this.bodyTemplate.messageBox.textContent);
}
alert(this.messageBox.textContent);
}
}
}
@@ -949,6 +958,15 @@ export class ServerExtensionsView extends ExtensionsListView {
}
return super.show(query.trim());
}
getActions(): IAction[] {
if (this.extensionManagementServerService.localExtensionManagementServer === this.server) {
const installLocalExtensionsInRemoteAction = this._register(this.instantiationService.createInstance(InstallLocalExtensionsInRemoteAction, false));
installLocalExtensionsInRemoteAction.class = 'octicon octicon-cloud-download';
return [installLocalExtensionsInRemoteAction];
}
return [];
}
}
export class EnabledExtensionsView extends ExtensionsListView {
@@ -1030,7 +1048,7 @@ export class RecommendedExtensionsView extends ExtensionsListView {
export class WorkspaceRecommendedExtensionsView extends ExtensionsListView {
private readonly recommendedExtensionsQuery = '@recommended:workspace';
private installAllAction: InstallWorkspaceRecommendedExtensionsAction;
private installAllAction: InstallWorkspaceRecommendedExtensionsAction | undefined;
renderBody(container: HTMLElement): void {
super.renderBody(container);
@@ -1040,25 +1058,15 @@ export class WorkspaceRecommendedExtensionsView extends ExtensionsListView {
this._register(this.contextService.onDidChangeWorkbenchState(() => this.update()));
}
renderHeader(container: HTMLElement): void {
super.renderHeader(container);
getActions(): IAction[] {
if (!this.installAllAction) {
this.installAllAction = this._register(this.instantiationService.createInstance(InstallWorkspaceRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsAction.ID, InstallWorkspaceRecommendedExtensionsAction.LABEL, []));
this.installAllAction.class = 'octicon octicon-cloud-download';
}
const listActionBar = $('.list-actionbar-container');
container.insertBefore(listActionBar, this.badgeContainer);
const actionbar = this._register(new ActionBar(listActionBar, {
animated: false
}));
actionbar.onDidRun(({ error }) => error && this.notificationService.error(error));
this.installAllAction = this._register(this.instantiationService.createInstance(InstallWorkspaceRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsAction.ID, InstallWorkspaceRecommendedExtensionsAction.LABEL, []));
const configureWorkspaceFolderAction = this._register(this.instantiationService.createInstance(ConfigureWorkspaceFolderRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction.ID, ConfigureWorkspaceFolderRecommendedExtensionsAction.LABEL));
this.installAllAction.class = 'octicon octicon-cloud-download';
configureWorkspaceFolderAction.class = 'octicon octicon-pencil';
actionbar.push([this.installAllAction], { icon: true, label: false });
actionbar.push([configureWorkspaceFolderAction], { icon: true, label: false });
return [this.installAllAction, configureWorkspaceFolderAction];
}
async show(query: string): Promise<IPagedModel<IExtension>> {
@@ -1073,9 +1081,11 @@ export class WorkspaceRecommendedExtensionsView extends ExtensionsListView {
this.setRecommendationsToInstall();
}
private setRecommendationsToInstall(): Promise<void> {
return this.getRecommendationsToInstall()
.then(recommendations => { this.installAllAction.recommendations = recommendations; });
private async setRecommendationsToInstall(): Promise<void> {
const recommendations = await this.getRecommendationsToInstall();
if (this.installAllAction) {
this.installAllAction.recommendations = recommendations;
}
}
private getRecommendationsToInstall(): Promise<IExtensionRecommendation[]> {

View File

@@ -18,9 +18,9 @@ import { Emitter, Event } from 'vs/base/common/event';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
export abstract class ExtensionWidget extends Disposable implements IExtensionContainer {
private _extension: IExtension;
get extension(): IExtension { return this._extension; }
set extension(extension: IExtension) { this._extension = extension; this.update(); }
private _extension: IExtension | null = null;
get extension(): IExtension | null { return this._extension; }
set extension(extension: IExtension | null) { this._extension = extension; this.update(); }
update(): void { this.render(); }
abstract render(): void;
}
@@ -183,7 +183,7 @@ export class RecommendationWidget extends ExtensionWidget {
private element?: HTMLElement;
private readonly disposables = this._register(new DisposableStore());
private _tooltip: string;
private _tooltip: string = '';
get tooltip(): string { return this._tooltip; }
set tooltip(tooltip: string) {
if (this._tooltip !== tooltip) {
@@ -314,4 +314,4 @@ class RemoteBadge extends Disposable {
updateTitle();
}
}
}
}

View File

@@ -500,7 +500,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
private readonly _onChange: Emitter<IExtension | undefined> = new Emitter<IExtension | undefined>();
get onChange(): Event<IExtension | undefined> { return this._onChange.event; }
private _extensionAllowedBadgeProviders: string[];
private _extensionAllowedBadgeProviders: string[] | undefined;
private installing: IExtension[] = [];
constructor(
@@ -1151,12 +1151,12 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
}
private _ignoredAutoUpdateExtensions: string[];
private _ignoredAutoUpdateExtensions: string[] | undefined;
private get ignoredAutoUpdateExtensions(): string[] {
if (!this._ignoredAutoUpdateExtensions) {
this._ignoredAutoUpdateExtensions = JSON.parse(this.storageService.get('extensions.ignoredAutoUpdateExtension', StorageScope.GLOBAL, '[]') || '[]');
}
return this._ignoredAutoUpdateExtensions;
return this._ignoredAutoUpdateExtensions!;
}
private set ignoredAutoUpdateExtensions(extensionIds: string[]) {

View File

@@ -6,8 +6,3 @@
.monaco-workbench .activitybar > .content .monaco-action-bar .action-label.extensions {
-webkit-mask: url('extensions-activity-bar.svg') no-repeat 50% 50%;
}
.extensions .split-view-view .panel-header .count-badge-wrapper {
position: absolute;
right: 12px;
}

View File

@@ -27,13 +27,16 @@
height: calc(100% - 38px);
}
.extensions-viewlet > .extensions .list-actionbar-container .monaco-action-bar .action-item > .octicon {
font-size: 12px;
line-height: 1;
margin-right: 10px;
.extensions-viewlet > .extensions .extension-view-header .monaco-action-bar {
margin-right: 4px;
}
.extensions-viewlet > .extensions .list-actionbar-container .monaco-action-bar .action-item.disabled {
.extensions-viewlet > .extensions .extension-view-header .monaco-action-bar .action-item > .action-label.icon.octicon {
vertical-align: middle;
line-height: 22px;
}
.extensions-viewlet > .extensions .extension-view-header .monaco-action-bar .action-item.disabled {
display: none;
}
@@ -44,7 +47,7 @@
}
.extensions-viewlet > .extensions .panel-header {
padding-right: 28px;
padding-right: 6px;
}
.extensions-viewlet > .extensions .panel-header > .title {

View File

@@ -22,7 +22,7 @@ export class RemoteExtensionsInstaller extends Disposable implements IWorkbenchC
) {
super();
if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) {
const installLocalExtensionsInRemoteAction = instantiationService.createInstance(InstallLocalExtensionsInRemoteAction);
const installLocalExtensionsInRemoteAction = instantiationService.createInstance(InstallLocalExtensionsInRemoteAction, true);
CommandsRegistry.registerCommand('workbench.extensions.installLocalExtensions', () => installLocalExtensionsInRemoteAction.run());
let disposable = Disposable.None;
const appendMenuItem = () => {

View File

@@ -44,7 +44,7 @@ import { CLOSE_EDITORS_AND_GROUP_COMMAND_ID } from 'vs/workbench/browser/parts/e
import { coalesce } from 'vs/base/common/arrays';
import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree';
import { ExplorerItem, NewExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel';
import { onUnexpectedError } from 'vs/base/common/errors';
import { onUnexpectedError, getErrorMessage } from 'vs/base/common/errors';
// {{SQL CARBON EDIT}}
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
@@ -1140,7 +1140,7 @@ export const pasteFileHandler = async (accessor: ServicesAccessor) => {
return await fileService.copy(fileToPaste, targetFile);
}
} catch (e) {
onError(notificationService, new Error(nls.localize('fileDeleted', "File to paste was deleted or moved meanwhile")));
onError(notificationService, new Error(nls.localize('fileDeleted', "File to paste was deleted or moved meanwhile. {0}", getErrorMessage(e))));
return undefined;
}
}));

View File

@@ -14,14 +14,11 @@ import { EditorOptions } from 'vs/workbench/common/editor';
import { IOutputChannelDescriptor, IOutputChannel, IOutputService, Extensions, OUTPUT_PANEL_ID, IOutputChannelRegistry, OUTPUT_SCHEME, LOG_SCHEME, CONTEXT_ACTIVE_LOG_OUTPUT, LOG_MIME, OUTPUT_MIME } from 'vs/workbench/contrib/output/common/output';
import { OutputPanel } from 'vs/workbench/contrib/output/browser/outputPanel';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { OutputLinkProvider } from 'vs/workbench/contrib/output/common/outputLinkProvider';
import { ITextModelService, ITextModelContentProvider } from 'vs/editor/common/services/resolverService';
import { ITextModel } from 'vs/editor/common/model';
import { IPanel } from 'vs/workbench/common/panel';
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { ILogService } from 'vs/platform/log/common/log';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
@@ -77,10 +74,7 @@ export class OutputService extends Disposable implements IOutputService, ITextMo
@IStorageService private readonly storageService: IStorageService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IPanelService private readonly panelService: IPanelService,
@IWorkspaceContextService contextService: IWorkspaceContextService,
@ITextModelService textModelResolverService: ITextModelService,
@IEnvironmentService environmentService: IEnvironmentService,
@IWindowService windowService: IWindowService,
@ILogService private readonly logService: ILogService,
@ILifecycleService private readonly lifecycleService: ILifecycleService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,

View File

@@ -854,7 +854,7 @@ export class SettingsEditor2 extends BaseEditor {
this._register(model.onDidChangeGroups(() => this.onConfigUpdate()));
this.defaultSettingsEditorModel = model;
return this.onConfigUpdate();
return this.onConfigUpdate(undefined, true);
});
}
return Promise.resolve(null);

View File

@@ -36,7 +36,8 @@ export class LabelContribution implements IWorkbenchContribution {
formatting: {
label: '${path}',
separator: remoteEnvironment.os === OperatingSystem.Windows ? '\\' : '/',
tildify: remoteEnvironment.os !== OperatingSystem.Windows
tildify: remoteEnvironment.os !== OperatingSystem.Windows,
normalizeDriveLetter: remoteEnvironment.os === OperatingSystem.Windows
}
});
}

View File

@@ -179,10 +179,10 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
private static nextHandle: number = 0;
private _schemaVersion: JsonSchemaVersion;
private _executionEngine: ExecutionEngine;
private _workspaceFolders: IWorkspaceFolder[];
private _ignoredWorkspaceFolders: IWorkspaceFolder[];
private _schemaVersion: JsonSchemaVersion | undefined;
private _executionEngine: ExecutionEngine | undefined;
private _workspaceFolders: IWorkspaceFolder[] | undefined;
private _ignoredWorkspaceFolders: IWorkspaceFolder[] | undefined;
private _showIgnoreMessage?: boolean;
private _providers: Map<number, ITaskProvider>;
private _providerTypes: Map<number, string>;
@@ -192,7 +192,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
protected _taskSystem?: ITaskSystem;
protected _taskSystemListener?: IDisposable;
private _recentlyUsedTasks: LinkedMap<string, string>;
private _recentlyUsedTasks: LinkedMap<string, string> | undefined;
protected _taskRunningState: IContextKey<boolean>;
@@ -375,28 +375,28 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
if (!this._workspaceFolders) {
this.updateSetup();
}
return this._workspaceFolders;
return this._workspaceFolders!;
}
private get ignoredWorkspaceFolders(): IWorkspaceFolder[] {
if (!this._ignoredWorkspaceFolders) {
this.updateSetup();
}
return this._ignoredWorkspaceFolders;
return this._ignoredWorkspaceFolders!;
}
protected get executionEngine(): ExecutionEngine {
if (this._executionEngine === undefined) {
this.updateSetup();
}
return this._executionEngine;
return this._executionEngine!;
}
private get schemaVersion(): JsonSchemaVersion {
if (this._schemaVersion === undefined) {
this.updateSetup();
}
return this._schemaVersion;
return this._schemaVersion!;
}
private get showIgnoreMessage(): boolean {

View File

@@ -155,9 +155,10 @@ export class TerminalTaskSystem implements ITaskSystem {
private idleTaskTerminals: LinkedMap<string, string>;
private sameTaskTerminals: IStringDictionary<string>;
private taskSystemInfoResolver: TaskSystemInfoResolver;
private lastTask: VerifiedTask;
private currentTask: VerifiedTask;
private isRerun: boolean;
private lastTask: VerifiedTask | undefined;
// Should always be set in run
private currentTask!: VerifiedTask;
private isRerun: boolean = false;
private readonly _onDidStateChange: Emitter<TaskEvent>;
@@ -485,28 +486,32 @@ export class TerminalTaskSystem implements ITaskSystem {
}
private reexecuteCommand(task: CustomTask | ContributedTask, trigger: string): Promise<ITaskSummary> {
const workspaceFolder = this.currentTask.workspaceFolder = this.lastTask.workspaceFolder;
const lastTask = this.lastTask;
if (!lastTask) {
return Promise.reject(new Error('No task previously run'));
}
const workspaceFolder = this.currentTask.workspaceFolder = lastTask.workspaceFolder;
let variables = new Set<string>();
this.collectTaskVariables(variables, task);
// Check that the task hasn't changed to include new variables
let hasAllVariables = true;
variables.forEach(value => {
if (value.substring(2, value.length - 1) in this.lastTask.getVerifiedTask().resolvedVariables) {
if (value.substring(2, value.length - 1) in lastTask.getVerifiedTask().resolvedVariables) {
hasAllVariables = false;
}
});
if (!hasAllVariables) {
return this.resolveVariablesFromSet(this.lastTask.getVerifiedTask().systemInfo, this.lastTask.getVerifiedTask().workspaceFolder, task, variables).then((resolvedVariables) => {
return this.resolveVariablesFromSet(lastTask.getVerifiedTask().systemInfo, lastTask.getVerifiedTask().workspaceFolder, task, variables).then((resolvedVariables) => {
this.currentTask.resolvedVariables = resolvedVariables;
return this.executeInTerminal(task, trigger, new VariableResolver(this.lastTask.getVerifiedTask().workspaceFolder, this.lastTask.getVerifiedTask().systemInfo, resolvedVariables.variables, this.configurationResolverService), workspaceFolder!);
return this.executeInTerminal(task, trigger, new VariableResolver(lastTask.getVerifiedTask().workspaceFolder, lastTask.getVerifiedTask().systemInfo, resolvedVariables.variables, this.configurationResolverService), workspaceFolder!);
}, reason => {
return Promise.reject(reason);
});
} else {
this.currentTask.resolvedVariables = this.lastTask.getVerifiedTask().resolvedVariables;
return this.executeInTerminal(task, trigger, new VariableResolver(this.lastTask.getVerifiedTask().workspaceFolder, this.lastTask.getVerifiedTask().systemInfo, this.lastTask.getVerifiedTask().resolvedVariables.variables, this.configurationResolverService), workspaceFolder!);
this.currentTask.resolvedVariables = lastTask.getVerifiedTask().resolvedVariables;
return this.executeInTerminal(task, trigger, new VariableResolver(lastTask.getVerifiedTask().workspaceFolder, lastTask.getVerifiedTask().systemInfo, lastTask.getVerifiedTask().resolvedVariables.variables, this.configurationResolverService), workspaceFolder!);
}
}
@@ -923,7 +928,7 @@ export class TerminalTaskSystem implements ITaskSystem {
args = resolvedResult.args;
commandExecutable = CommandString.value(command);
this.currentTask.shellLaunchConfig = launchConfigs = this.isRerun ? this.lastTask.getVerifiedTask().shellLaunchConfig : await this.createShellLaunchConfig(task, workspaceFolder, resolver, platform, options, command, args, waitOnExit);
this.currentTask.shellLaunchConfig = launchConfigs = (this.isRerun && this.lastTask) ? this.lastTask.getVerifiedTask().shellLaunchConfig : await this.createShellLaunchConfig(task, workspaceFolder, resolver, platform, options, command, args, waitOnExit);
if (launchConfigs === undefined) {
return [undefined, undefined, new TaskError(Severity.Error, nls.localize('TerminalTaskSystem', 'Can\'t execute a shell command on an UNC drive using cmd.exe.'), TaskErrors.UnknownError)];
}

View File

@@ -44,10 +44,10 @@ export abstract class AbstractProblemCollector implements IDisposable {
private bufferLength: number;
private openModels: IStringDictionary<boolean>;
private readonly modelListeners = new DisposableStore();
private tail: Promise<void>;
private tail: Promise<void> | undefined;
// [owner] -> ApplyToKind
private applyToByOwner: Map<string, ApplyToKind>;
protected applyToByOwner: Map<string, ApplyToKind>;
// [owner] -> [resource] -> URI
private resourcesToClean: Map<string, Map<string, URI>>;
// [owner] -> [resource] -> [markerkey] -> markerData
@@ -278,9 +278,14 @@ export abstract class AbstractProblemCollector implements IDisposable {
markersPerResource = new Map<string, IMarkerData>();
markersPerOwner.set(resourceAsString, markersPerResource);
}
let key = IMarkerData.makeKey(marker);
let key = IMarkerData.makeKeyOptionalMessage(marker, false);
let existingMarker;
if (!markersPerResource.has(key)) {
markersPerResource.set(key, marker);
} else if (((existingMarker = markersPerResource.get(key)) !== undefined) && existingMarker.message.length < marker.message.length) {
// Most likely https://github.com/microsoft/vscode/issues/77475
// Heuristic dictates that when the key is the same and message is smaller, we have hit this limitation.
markersPerResource.set(key, marker);
}
}
@@ -344,8 +349,8 @@ export const enum ProblemHandlingStrategy {
export class StartStopProblemCollector extends AbstractProblemCollector implements IProblemMatcher {
private owners: string[];
private currentOwner: string;
private currentResource: string;
private currentOwner: string | undefined;
private currentResource: string | undefined;
constructor(problemMatchers: ProblemMatcher[], markerService: IMarkerService, modelService: IModelService, _strategy: ProblemHandlingStrategy = ProblemHandlingStrategy.Clean, fileService?: IFileService) {
super(problemMatchers, markerService, modelService, fileService);
@@ -397,8 +402,8 @@ export class WatchingProblemCollector extends AbstractProblemCollector implement
private _activeBackgroundMatchers: Set<string>;
// Current State
private currentOwner: string | null;
private currentResource: string | null;
private currentOwner: string | undefined;
private currentResource: string | undefined;
constructor(problemMatchers: ProblemMatcher[], markerService: IMarkerService, modelService: IModelService, fileService?: IFileService) {
super(problemMatchers, markerService, modelService, fileService);
@@ -503,8 +508,8 @@ export class WatchingProblemCollector extends AbstractProblemCollector implement
private resetCurrentResource(): void {
this.reportMarkersForCurrentResource();
this.currentOwner = null;
this.currentResource = null;
this.currentOwner = undefined;
this.currentResource = undefined;
}
private reportMarkersForCurrentResource(): void {
@@ -512,4 +517,11 @@ export class WatchingProblemCollector extends AbstractProblemCollector implement
this.deliverMarkersPerOwnerAndResource(this.currentOwner, this.currentResource);
}
}
}
public done(): void {
[...this.applyToByOwner.keys()].forEach(owner => {
this.recordResourcesToClean(owner);
});
super.done();
}
}

View File

@@ -264,7 +264,7 @@ abstract class AbstractLineMatcher implements ILineMatcher {
public abstract get matchLength(): number;
protected fillProblemData(data: ProblemData | null, pattern: ProblemPattern, matches: RegExpExecArray): data is ProblemData {
protected fillProblemData(data: ProblemData | undefined, pattern: ProblemPattern, matches: RegExpExecArray): data is ProblemData {
if (data) {
this.fillProperty(data, 'file', pattern, matches, true);
this.appendProperty(data, 'message', pattern, matches, true);
@@ -449,7 +449,7 @@ class SingleLineMatcher extends AbstractLineMatcher {
class MultiLineMatcher extends AbstractLineMatcher {
private patterns: ProblemPattern[];
private data: ProblemData | null;
private data: ProblemData | undefined;
constructor(matcher: ProblemMatcher, fileService?: IFileService) {
super(matcher, fileService);
@@ -480,7 +480,7 @@ class MultiLineMatcher extends AbstractLineMatcher {
}
let loop = !!this.patterns[this.patterns.length - 1].loop;
if (!loop) {
this.data = null;
this.data = undefined;
}
const markerMatch = data ? this.getMarkerMatch(data) : null;
return { match: markerMatch ? markerMatch : null, continue: loop };
@@ -491,7 +491,7 @@ class MultiLineMatcher extends AbstractLineMatcher {
Assert.ok(pattern.loop === true && this.data !== null);
let matches = pattern.regexp.exec(line);
if (!matches) {
this.data = null;
this.data = undefined;
return null;
}
let data = Objects.deepClone(this.data);
@@ -794,7 +794,7 @@ export namespace Config {
fileLocation?: string | string[];
/**
* The name of a predefined problem pattern, the inline definintion
* The name of a predefined problem pattern, the inline definition
* of a problem pattern or an array of problem patterns to match
* problems spread over multiple lines.
*/

View File

@@ -681,7 +681,7 @@ export namespace RunOptions {
}
}
class ParseContext {
interface ParseContext {
workspaceFolder: IWorkspaceFolder;
problemReporter: IProblemReporter;
namedProblemMatchers: IStringDictionary<NamedProblemMatcher>;

View File

@@ -89,7 +89,7 @@ class TaskDefinitionRegistryImpl implements ITaskDefinitionRegistry {
private taskTypes: IStringDictionary<Tasks.TaskDefinition>;
private readyPromise: Promise<void>;
private _schema: IJSONSchema;
private _schema: IJSONSchema | undefined;
constructor() {
this.taskTypes = Object.create(null);

View File

@@ -518,7 +518,7 @@ export abstract class CommonTask {
/**
* The cached label.
*/
_label: string;
_label: string = '';
type?: string;
@@ -614,7 +614,7 @@ export abstract class CommonTask {
export class CustomTask extends CommonTask {
type: '$customized'; // CUSTOMIZED_TASK_TYPE
type!: '$customized'; // CUSTOMIZED_TASK_TYPE
/**
* Indicated the source of the task (e.g. tasks.json or extension)
@@ -626,7 +626,7 @@ export class CustomTask extends CommonTask {
/**
* The command configuration
*/
command: CommandConfiguration;
command: CommandConfiguration = {};
public constructor(id: string, source: WorkspaceTaskSource, label: string, type: string, command: CommandConfiguration | undefined,
hasDefinedMatchers: boolean, runOptions: RunOptions, configurationProperties: ConfigurationProperties) {
@@ -754,8 +754,9 @@ export class ContributedTask extends CommonTask {
/**
* Indicated the source of the task (e.g. tasks.json or extension)
* Set in the super constructor
*/
_source: ExtensionTaskSource;
_source!: ExtensionTaskSource;
defines: KeyedTaskIdentifier;
@@ -824,7 +825,7 @@ export class InMemoryTask extends CommonTask {
*/
_source: InMemoryTaskSource;
type: 'inMemory';
type!: 'inMemory';
public constructor(id: string, source: InMemoryTaskSource, label: string, type: string,
runOptions: RunOptions, configurationProperties: ConfigurationProperties) {

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./watermark';
import { Disposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { assign } from 'vs/base/common/objects';
import { isMacintosh, OS } from 'vs/base/common/platform';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
@@ -42,65 +42,21 @@ interface WatermarkEntry {
}
// {{SQL CARBON EDIT}}
const showServers: WatermarkEntry = {
text: nls.localize('watermark.showServers', "Show Servers"),
id: OpenDataExplorerViewletAction.ID
};
const showServers: WatermarkEntry = { text: nls.localize('watermark.showServers', "Show Servers"), id: OpenDataExplorerViewletAction.ID };
const newSqlFile: WatermarkEntry = { text: nls.localize('watermark.newSqlFile', "New SQL File"), id: GlobalNewUntitledFileAction.ID };
const newNotebook: WatermarkEntry = { text: nls.localize('watermark.newNotebook', "New Notebook"), id: NewNotebookAction.ID };
const newSqlFile: WatermarkEntry = {
text: nls.localize('watermark.newSqlFile', "New SQL File"),
id: GlobalNewUntitledFileAction.ID
};
const newNotebook: WatermarkEntry = {
text: nls.localize('watermark.newNotebook', "New Notebook"),
id: NewNotebookAction.ID
};
const showCommands: WatermarkEntry = {
text: nls.localize('watermark.showCommands', "Show All Commands"),
id: ShowAllCommandsAction.ID
};
const quickOpen: WatermarkEntry = {
text: nls.localize('watermark.quickOpen', "Go to File"),
id: QUICKOPEN_ACTION_ID
};
const openFileNonMacOnly: WatermarkEntry = {
text: nls.localize('watermark.openFile', "Open File"),
id: OpenFileAction.ID,
mac: false
};
const openFolderNonMacOnly: WatermarkEntry = {
text: nls.localize('watermark.openFolder', "Open Folder"),
id: OpenFolderAction.ID,
mac: false
};
const openFileOrFolderMacOnly: WatermarkEntry = {
text: nls.localize('watermark.openFileFolder', "Open File or Folder"),
id: OpenFileFolderAction.ID,
mac: true
};
const openRecent: WatermarkEntry = {
text: nls.localize('watermark.openRecent', "Open Recent"),
id: 'workbench.action.openRecent'
};
const newUntitledFile: WatermarkEntry = {
text: nls.localize('watermark.newUntitledFile', "New Untitled File"),
id: GlobalNewUntitledFileAction.ID
};
const showCommands: WatermarkEntry = { text: nls.localize('watermark.showCommands', "Show All Commands"), id: ShowAllCommandsAction.ID };
const quickOpen: WatermarkEntry = { text: nls.localize('watermark.quickOpen', "Go to File"), id: QUICKOPEN_ACTION_ID };
const openFileNonMacOnly: WatermarkEntry = { text: nls.localize('watermark.openFile', "Open File"), id: OpenFileAction.ID, mac: false };
const openFolderNonMacOnly: WatermarkEntry = { text: nls.localize('watermark.openFolder', "Open Folder"), id: OpenFolderAction.ID, mac: false };
const openFileOrFolderMacOnly: WatermarkEntry = { text: nls.localize('watermark.openFileFolder', "Open File or Folder"), id: OpenFileFolderAction.ID, mac: true };
const openRecent: WatermarkEntry = { text: nls.localize('watermark.openRecent', "Open Recent"), id: 'workbench.action.openRecent' };
const newUntitledFile: WatermarkEntry = { text: nls.localize('watermark.newUntitledFile', "New Untitled File"), id: GlobalNewUntitledFileAction.ID };
const newUntitledFileMacOnly: WatermarkEntry = assign({ mac: true }, newUntitledFile);
const toggleTerminal: WatermarkEntry = {
text: nls.localize({ key: 'watermark.toggleTerminal', comment: ['toggle is a verb here'] }, "Toggle Terminal"),
id: TERMINAL_COMMAND_ID.TOGGLE
};
const findInFiles: WatermarkEntry = {
text: nls.localize('watermark.findInFiles', "Find in Files"),
id: FindInFilesActionId
};
const startDebugging: WatermarkEntry = {
text: nls.localize('watermark.startDebugging', "Start Debugging"),
id: StartAction.ID
};
const toggleTerminal: WatermarkEntry = { text: nls.localize({ key: 'watermark.toggleTerminal', comment: ['toggle is a verb here'] }, "Toggle Terminal"), id: TERMINAL_COMMAND_ID.TOGGLE };
const findInFiles: WatermarkEntry = { text: nls.localize('watermark.findInFiles', "Find in Files"), id: FindInFilesActionId };
const startDebugging: WatermarkEntry = { text: nls.localize('watermark.startDebugging', "Start Debugging"), id: StartAction.ID };
// {{SQL CARBON EDIT}} - Replace noFolderEntries and folderEntries
const noFolderEntries = [
@@ -121,13 +77,13 @@ const folderEntries = [
const WORKBENCH_TIPS_ENABLED_KEY = 'workbench.tips.enabled';
export class WatermarkContribution extends Disposable implements IWorkbenchContribution {
private watermark: HTMLElement;
private watermarkDisposable = this._register(new DisposableStore());
private enabled: boolean;
private workbenchState: WorkbenchState;
constructor(
@ILifecycleService lifecycleService: ILifecycleService,
@ILifecycleService private readonly lifecycleService: ILifecycleService,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
@IKeybindingService private readonly keybindingService: IKeybindingService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@@ -135,13 +91,20 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr
@IEditorGroupsService private readonly editorGroupsService: IEditorGroupsService
) {
super();
this.workbenchState = contextService.getWorkbenchState();
lifecycleService.onShutdown(this.dispose, this);
this.workbenchState = contextService.getWorkbenchState();
this.enabled = this.configurationService.getValue<boolean>(WORKBENCH_TIPS_ENABLED_KEY);
this.registerListeners();
if (this.enabled) {
this.create();
}
}
private registerListeners(): void {
this.lifecycleService.onShutdown(this.dispose, this);
this._register(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(WORKBENCH_TIPS_ENABLED_KEY)) {
const enabled = this.configurationService.getValue<boolean>(WORKBENCH_TIPS_ENABLED_KEY);
@@ -155,6 +118,7 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr
}
}
}));
this._register(this.contextService.onDidChangeWorkbenchState(e => {
const previousWorkbenchState = this.workbenchState;
this.workbenchState = this.contextService.getWorkbenchState();
@@ -175,6 +139,7 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr
const selected = folder ? folderEntries : noFolderEntries
.filter(entry => !('mac' in entry) || entry.mac === isMacintosh)
.filter(entry => !!CommandsRegistry.getCommand(entry.id));
const update = () => {
dom.clearNode(box);
selected.map(entry => {
@@ -187,10 +152,14 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr
dd.innerHTML = keybinding.element.outerHTML;
});
};
update();
dom.prepend(container.firstElementChild as HTMLElement, this.watermark);
this._register(this.keybindingService.onDidUpdateKeybindings(update));
this._register(this.editorGroupsService.onDidLayout(dimension => this.handleEditorPartSize(container, dimension)));
this.watermarkDisposable.add(this.keybindingService.onDidUpdateKeybindings(update));
this.watermarkDisposable.add(this.editorGroupsService.onDidLayout(dimension => this.handleEditorPartSize(container, dimension)));
this.handleEditorPartSize(container, this.editorGroupsService.contentDimension);
}
@@ -205,9 +174,11 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr
private destroy(): void {
if (this.watermark) {
this.watermark.remove();
const container = this.layoutService.getContainer(Parts.EDITOR_PART);
container.classList.remove('has-watermark');
this.dispose();
this.watermarkDisposable.clear();
}
}

View File

@@ -47,16 +47,16 @@ export class WebviewPortMappingManager extends Disposable {
if (this.extensionLocation && this.extensionLocation.scheme === REMOTE_HOST_SCHEME) {
const tunnel = await this.getOrCreateTunnel(mapping.extensionHostPort);
if (tunnel) {
return uri.with({
return encodeURI(uri.with({
authority: `127.0.0.1:${tunnel.tunnelLocalPort}`,
}).toString();
}).toString(true));
}
}
if (mapping.webviewPort !== mapping.extensionHostPort) {
return uri.with({
return encodeURI(uri.with({
authority: `${requestLocalHostInfo.address}:${mapping.extensionHostPort}`
}).toString();
}).toString(true));
}
}
}
@@ -84,4 +84,4 @@ export class WebviewPortMappingManager extends Disposable {
}
return tunnel;
}
}
}

View File

@@ -18,6 +18,8 @@ import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/co
import { RemoteExtensionHostClient, IInitDataProvider } from 'vs/workbench/services/extensions/common/remoteExtensionHostClient';
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { WebWorkerExtensionHostStarter } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter';
import { URI } from 'vs/base/common/uri';
export class ExtensionService extends AbstractExtensionService implements IExtensionService {
@@ -62,6 +64,11 @@ export class ExtensionService extends AbstractExtensionService implements IExten
const result: ExtensionHostProcessManager[] = [];
const remoteAgentConnection = this._remoteAgentService.getConnection()!;
const webHostProcessWorker = this._instantiationService.createInstance(WebWorkerExtensionHostStarter, true, Promise.resolve([]), URI.parse('empty:value')); //todo@joh
const webHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, webHostProcessWorker, remoteAgentConnection.remoteAuthority, initialActivationEvents);
result.push(webHostProcessManager);
const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, this.getExtensions(), this._createProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory);
const remoteExtHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, remoteExtHostProcessWorker, remoteAgentConnection.remoteAuthority, initialActivationEvents);
result.push(remoteExtHostProcessManager);

View File

@@ -0,0 +1,150 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { DefaultWorkerFactory } from 'vs/base/worker/defaultWorkerFactory';
import { Emitter, Event } from 'vs/base/common/event';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { VSBuffer } from 'vs/base/common/buffer';
import { createMessageOfType, MessageType, isMessageOfType } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { ILabelService } from 'vs/platform/label/common/label';
import { ILogService } from 'vs/platform/log/common/log';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import * as platform from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
import { IExtensionHostStarter } from 'vs/workbench/services/extensions/common/extensions';
import { IProductService } from 'vs/platform/product/common/product';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
export class WebWorkerExtensionHostStarter implements IExtensionHostStarter {
private _toDispose = new DisposableStore();
private _isTerminating: boolean = false;
private _protocol?: IMessagePassingProtocol;
private readonly _onDidExit = new Emitter<[number, string | null]>();
readonly onExit: Event<[number, string | null]> = this._onDidExit.event;
constructor(
private readonly _autoStart: boolean,
private readonly _extensions: Promise<IExtensionDescription[]>,
private readonly _extensionHostLogsLocation: URI,
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
@ILabelService private readonly _labelService: ILabelService,
@ILogService private readonly _logService: ILogService,
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
@IProductService private readonly _productService: IProductService,
) {
}
async start(): Promise<IMessagePassingProtocol> {
if (!this._protocol) {
const emitter = new Emitter<VSBuffer>();
const worker = new DefaultWorkerFactory('WorkerExtensionHost').create(
'vs/workbench/services/extensions/worker/extensionHostWorker', data => {
if (data instanceof ArrayBuffer) {
emitter.fire(VSBuffer.wrap(new Uint8Array(data, 0, data.byteLength)));
} else {
console.warn('UNKNOWN data received', data);
this._onDidExit.fire([77, 'UNKNOWN data received']);
}
}, err => {
this._onDidExit.fire([81, err]);
console.error(err);
}
);
// keep for cleanup
this._toDispose.add(emitter);
this._toDispose.add(worker);
const protocol: IMessagePassingProtocol = {
onMessage: emitter.event,
send: vsbuf => {
const data = vsbuf.buffer.buffer.slice(vsbuf.buffer.byteOffset, vsbuf.buffer.byteOffset + vsbuf.buffer.byteLength);
worker.postMessage(data, [data]);
}
};
// extension host handshake happens below
// (1) <== wait for: Ready
// (2) ==> send: init data
// (3) <== wait for: Initialized
await Event.toPromise(Event.filter(protocol.onMessage, msg => isMessageOfType(msg, MessageType.Ready)));
protocol.send(VSBuffer.fromString(JSON.stringify(await this._createExtHostInitData())));
await Event.toPromise(Event.filter(protocol.onMessage, msg => isMessageOfType(msg, MessageType.Initialized)));
this._protocol = protocol;
}
return this._protocol;
}
dispose(): void {
if (!this._protocol) {
this._toDispose.dispose();
return;
}
if (this._isTerminating) {
return;
}
this._isTerminating = true;
this._protocol.send(createMessageOfType(MessageType.Terminate));
setTimeout(() => this._toDispose.dispose(), 10 * 1000);
}
getInspectPort(): number | undefined {
return undefined;
}
private async _createExtHostInitData(): Promise<IInitData> {
const [telemetryInfo, extensionDescriptions] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._extensions]);
const workspace = this._contextService.getWorkspace();
return {
commit: this._productService.commit,
version: this._productService.version,
vscodeVersion: this._productService.vscodeVersion,
parentPid: -1,
environment: {
isExtensionDevelopmentDebug: false,
appRoot: this._environmentService.appRoot ? URI.file(this._environmentService.appRoot) : undefined,
appSettingsHome: this._environmentService.appSettingsHome ? this._environmentService.appSettingsHome : undefined,
appName: this._productService.nameLong,
appUriScheme: this._productService.urlProtocol,
appLanguage: platform.language,
extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI,
extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI,
globalStorageHome: URI.parse('fake:globalStorageHome'), //todo@joh URI.file(this._environmentService.globalStorageHome),
userHome: URI.parse('fake:userHome'), //todo@joh URI.file(this._environmentService.userHome),
webviewResourceRoot: this._environmentService.webviewResourceRoot,
webviewCspSource: this._environmentService.webviewCspSource,
},
workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? undefined : {
configuration: workspace.configuration || undefined,
id: workspace.id,
name: this._labelService.getWorkspaceLabel(workspace)
},
resolvedExtensions: [],
hostExtensions: [],
extensions: extensionDescriptions,
telemetryInfo,
logLevel: this._logService.getLevel(),
logsLocation: this._extensionHostLogsLocation,
autoStart: this._autoStart,
remote: {
authority: this._environmentService.configuration.remoteAuthority,
isRemote: false
},
};
}
}

View File

@@ -10,7 +10,6 @@ import { URI, setUriThrowOnMissingScheme } from 'vs/base/common/uri';
import { IURITransformer } from 'vs/base/common/uriIpc';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { IInitData, MainContext, MainThreadConsoleShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
import { RPCProtocol } from 'vs/workbench/services/extensions/common/rpcProtocol';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ILogService } from 'vs/platform/log/common/log';
@@ -35,10 +34,6 @@ export interface IConsolePatchFn {
(mainThreadConsole: MainThreadConsoleShape): any;
}
export interface ILogServiceFn {
(initData: IInitData): ILogService;
}
export class ExtensionHostMain {
private _isTerminating: boolean;
@@ -50,8 +45,6 @@ export class ExtensionHostMain {
protocol: IMessagePassingProtocol,
initData: IInitData,
hostUtils: IHostUtils,
consolePatchFn: IConsolePatchFn,
logServiceFn: ILogServiceFn,
uriTransformer: IURITransformer | null
) {
this._isTerminating = false;
@@ -61,27 +54,27 @@ export class ExtensionHostMain {
// ensure URIs are transformed and revived
initData = ExtensionHostMain._transform(initData, rpcProtocol);
// allow to patch console
consolePatchFn(rpcProtocol.getProxy(MainContext.MainThreadConsole));
// services
const extHostLogService = new ExtHostLogService(logServiceFn(initData), initData.logsLocation.fsPath);
this._disposables.add(extHostLogService);
// bootstrap services
const services = new ServiceCollection(...getSingletonServiceDescriptors());
services.set(IExtHostInitDataService, { _serviceBrand: undefined, ...initData });
services.set(IExtHostRpcService, new ExtHostRpcService(rpcProtocol));
services.set(ILogService, extHostLogService);
services.set(IURITransformerService, new URITransformerService(uriTransformer));
services.set(IHostUtils, hostUtils);
const instaService: IInstantiationService = new InstantiationService(services, true);
extHostLogService.info('extension host started');
extHostLogService.trace('initData', initData);
// todo@joh
// ugly self - inject
const logService = instaService.invokeFunction(accessor => accessor.get(ILogService));
this._disposables.add(logService);
// todo@joh -> not soo nice...
logService.info('extension host started');
logService.trace('initData', initData);
// todo@joh
// ugly self - inject
// must call initialize *after* creating the extension service
// because `initialize` itself creates instances that depend on it
this._extensionService = instaService.invokeFunction(accessor => accessor.get(IExtHostExtensionService));
this._extensionService.initialize();

View File

@@ -354,6 +354,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
}
const result: ExtensionHostProcessManager[] = [];
const extHostProcessWorker = this._instantiationService.createInstance(ExtensionHostProcessWorker, autoStart, extensions, this._extensionHostLogsLocation);
const extHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, true, extHostProcessWorker, null, initialActivationEvents);
result.push(extHostProcessManager);

View File

@@ -12,16 +12,14 @@ import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { PersistentProtocol, ProtocolConstants, createBufferedEvent } from 'vs/base/parts/ipc/common/ipc.net';
import { NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
import product from 'vs/platform/product/node/product';
import { IInitData, MainThreadConsoleShape } from 'vs/workbench/api/common/extHost.protocol';
import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
import { MessageType, createMessageOfType, isMessageOfType, IExtHostSocketMessage, IExtHostReadyMessage } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
import { ExtensionHostMain, IExitFn, ILogServiceFn } from 'vs/workbench/services/extensions/common/extensionHostMain';
import { ExtensionHostMain, IExitFn } from 'vs/workbench/services/extensions/common/extensionHostMain';
import { VSBuffer } from 'vs/base/common/buffer';
import { ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions';
import { IURITransformer, URITransformer, IRawURITransformer } from 'vs/base/common/uriIpc';
import { exists } from 'vs/base/node/pfs';
import { realpath } from 'vs/base/node/extpath';
import { IHostUtils } from 'vs/workbench/api/common/extHostExtensionService';
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
import 'vs/workbench/api/node/extHost.services';
interface ParsedExtHostArgs {
@@ -70,21 +68,6 @@ function patchProcess(allowExit: boolean) {
};
}
// use IPC messages to forward console-calls
function patchPatchedConsole(mainThreadConsole: MainThreadConsoleShape): void {
// The console is already patched to use `process.send()`
const nativeProcessSend = process.send!;
process.send = (...args: any[]) => {
if (args.length === 0 || !args[0] || args[0].type !== '__$console') {
return nativeProcessSend.apply(process, args);
}
mainThreadConsole.$logExtensionHostMessage(args[0]);
};
}
const createLogService: ILogServiceFn = initData => new SpdLogService(ExtensionHostLogFileName, initData.logsLocation.fsPath, initData.logLevel);
interface IRendererConnection {
protocol: IMessagePassingProtocol;
initData: IInitData;
@@ -206,7 +189,7 @@ async function createExtHostProtocol(): Promise<IMessagePassingProtocol> {
}
function connectToRenderer(protocol: IMessagePassingProtocol): Promise<IRendererConnection> {
return new Promise<IRendererConnection>((c, e) => {
return new Promise<IRendererConnection>((c) => {
// Listen init data message
const first = protocol.onMessage(raw => {
@@ -335,8 +318,6 @@ export async function startExtensionHostProcess(): Promise<void> {
renderer.protocol,
initData,
hostUtils,
patchPatchedConsole,
createLogService,
uriTransformer
);

View File

@@ -17,11 +17,11 @@ import { IExtHostWorkspaceProvider } from 'vs/workbench/api/common/extHostWorksp
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
import { ProxyAgent } from 'vscode-proxy-agent';
import { MainThreadTelemetryShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
import { URI } from 'vs/base/common/uri';
import { promisify } from 'util';
import { ILogService } from 'vs/platform/log/common/log';
interface ConnectionResult {
proxy: string;
@@ -34,7 +34,7 @@ export function connectProxyResolver(
extHostWorkspace: IExtHostWorkspaceProvider,
configProvider: ExtHostConfigProvider,
extensionService: ExtHostExtensionService,
extHostLogService: ExtHostLogService,
extHostLogService: ILogService,
mainThreadTelemetry: MainThreadTelemetryShape
) {
const resolveProxy = setupProxyResolution(extHostWorkspace, configProvider, extHostLogService, mainThreadTelemetry);
@@ -47,7 +47,7 @@ const maxCacheEntries = 5000; // Cache can grow twice that much due to 'oldCache
function setupProxyResolution(
extHostWorkspace: IExtHostWorkspaceProvider,
configProvider: ExtHostConfigProvider,
extHostLogService: ExtHostLogService,
extHostLogService: ILogService,
mainThreadTelemetry: MainThreadTelemetryShape
) {
const env = process.env;
@@ -421,7 +421,7 @@ function configureModuleLoading(extensionService: ExtHostExtensionService, looku
});
}
function useSystemCertificates(extHostLogService: ExtHostLogService, useSystemCertificates: boolean, opts: http.RequestOptions, callback: () => void) {
function useSystemCertificates(extHostLogService: ILogService, useSystemCertificates: boolean, opts: http.RequestOptions, callback: () => void) {
if (useSystemCertificates) {
getCaCertificates(extHostLogService)
.then(caCertificates => {
@@ -443,7 +443,7 @@ function useSystemCertificates(extHostLogService: ExtHostLogService, useSystemCe
}
let _caCertificates: ReturnType<typeof readCaCertificates> | Promise<undefined>;
async function getCaCertificates(extHostLogService: ExtHostLogService) {
async function getCaCertificates(extHostLogService: ILogService) {
if (!_caCertificates) {
_caCertificates = readCaCertificates()
.then(res => res && res.certs.length ? res : undefined)
@@ -469,24 +469,26 @@ async function readCaCertificates() {
}
async function readWindowsCaCertificates() {
const winCA = await import('vscode-windows-ca-certs');
// Not using await to work around minifier bug (https://github.com/microsoft/vscode/issues/79044).
return import('vscode-windows-ca-certs')
.then(winCA => {
let ders: any[] = [];
const store = winCA();
try {
let der: any;
while (der = store.next()) {
ders.push(der);
}
} finally {
store.done();
}
let ders: any[] = [];
const store = winCA();
try {
let der: any;
while (der = store.next()) {
ders.push(der);
}
} finally {
store.done();
}
const certs = new Set(ders.map(derToPem));
return {
certs: Array.from(certs),
append: true
};
const certs = new Set(ders.map(derToPem));
return {
certs: Array.from(certs),
append: true
};
});
}
async function readMacCaCertificates() {

View File

@@ -0,0 +1,57 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IExtHostOutputService, ExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
import { IExtHostWorkspace, ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { IExtHostDecorations, ExtHostDecorations } from 'vs/workbench/api/common/extHostDecorations';
import { IExtHostConfiguration, ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
import { IExtHostCommands, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
import { IExtHostTask } from 'vs/workbench/api/common/extHostTask';
import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService';
import { IExtHostSearch } from 'vs/workbench/api/common/extHostSearch';
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
import { IExtHostStorage, ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
import { ExtHostExtensionService } from 'vs/workbench/api/worker/extHostExtensionService';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { ILogService } from 'vs/platform/log/common/log';
import { ExtHostLogService } from 'vs/workbench/api/worker/extHostLogService';
// register singleton services
registerSingleton(ILogService, ExtHostLogService);
registerSingleton(IExtHostOutputService, ExtHostOutputService);
registerSingleton(IExtHostWorkspace, ExtHostWorkspace);
registerSingleton(IExtHostDecorations, ExtHostDecorations);
registerSingleton(IExtHostConfiguration, ExtHostConfiguration);
registerSingleton(IExtHostCommands, ExtHostCommands);
registerSingleton(IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors);
registerSingleton(IExtHostStorage, ExtHostStorage);
registerSingleton(IExtHostExtensionService, ExtHostExtensionService);
// register services that only throw errors
function NotImplementedProxy<T>(name: ServiceIdentifier<T>): { new(): T } {
return <any>class {
constructor() {
return new Proxy({}, {
get(target: any, prop: string | number) {
if (target[prop]) {
return target[prop];
}
throw new Error(`Not Implemented: ${name}->${String(prop)}`);
}
});
}
};
}
registerSingleton(IExtHostTerminalService, class extends NotImplementedProxy(IExtHostTerminalService) { });
registerSingleton(IExtHostTask, class extends NotImplementedProxy(IExtHostTask) { });
registerSingleton(IExtHostDebugService, class extends NotImplementedProxy(IExtHostDebugService) { });
registerSingleton(IExtHostSearch, class extends NotImplementedProxy(IExtHostSearch) { });
registerSingleton(IExtensionStoragePaths, class extends NotImplementedProxy(IExtensionStoragePaths) {
whenReady = Promise.resolve();
});

View File

@@ -0,0 +1,117 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IRequestHandler } from 'vs/base/common/worker/simpleWorker';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { VSBuffer } from 'vs/base/common/buffer';
import { Emitter } from 'vs/base/common/event';
import { isMessageOfType, MessageType, createMessageOfType } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
import { ExtensionHostMain } from 'vs/workbench/services/extensions/common/extensionHostMain';
import { IHostUtils } from 'vs/workbench/api/common/extHostExtensionService';
import 'vs/workbench/services/extensions/worker/extHost.services';
// worker-self
declare namespace self {
function close(): void;
}
// do not allow extensions to call terminate
const nativeClose = self.close.bind(self);
self.close = () => console.trace('An extension called terminate and this was prevented');
let onTerminate = nativeClose;
const hostUtil = new class implements IHostUtils {
_serviceBrand: any;
exit(_code?: number | undefined): void {
nativeClose();
}
async exists(_path: string): Promise<boolean> {
return true;
}
async realpath(path: string): Promise<string> {
return path;
}
};
//todo@joh do not allow extensions to call postMessage and other globals...
class ExtensionWorker implements IRequestHandler {
// worker-contract
readonly _requestHandlerBrand: any;
readonly onmessage: (data: any) => any;
// protocol
readonly protocol: IMessagePassingProtocol;
constructor(postMessage: (message: any, transfer?: Transferable[]) => any) {
let emitter = new Emitter<VSBuffer>();
let terminating = false;
this.onmessage = data => {
if (!(data instanceof ArrayBuffer)) {
console.warn('UNKNOWN data received', data);
return;
}
const msg = VSBuffer.wrap(new Uint8Array(data, 0, data.byteLength));
if (isMessageOfType(msg, MessageType.Terminate)) {
// handle terminate-message right here
terminating = true;
onTerminate();
return;
}
// emit non-terminate messages to the outside
emitter.fire(msg);
};
this.protocol = {
onMessage: emitter.event,
send: vsbuf => {
if (!terminating) {
const data = vsbuf.buffer.buffer.slice(vsbuf.buffer.byteOffset, vsbuf.buffer.byteOffset + vsbuf.buffer.byteLength);
postMessage(data, [data]);
}
}
};
}
}
interface IRendererConnection {
protocol: IMessagePassingProtocol;
initData: IInitData;
}
function connectToRenderer(protocol: IMessagePassingProtocol): Promise<IRendererConnection> {
return new Promise<IRendererConnection>(resolve => {
const once = protocol.onMessage(raw => {
once.dispose();
const initData = <IInitData>JSON.parse(raw.toString());
protocol.send(createMessageOfType(MessageType.Initialized));
resolve({ protocol, initData });
});
protocol.send(createMessageOfType(MessageType.Ready));
});
}
export function create(postMessage: (message: any, transfer?: Transferable[]) => any): IRequestHandler {
const res = new ExtensionWorker(postMessage);
connectToRenderer(res.protocol).then(data => {
const extHostMain = new ExtensionHostMain(
data.protocol,
data.initData,
hostUtil,
null,
);
onTerminate = () => extHostMain.terminate();
});
return res;
}

View File

@@ -21,8 +21,8 @@ import 'vs/workbench/workbench.common.main';
//#region --- workbench (desktop main)
import 'sql/setup'; // {{SQL CARBON EDIT}}
import 'vs/workbench/electron-browser/main.contribution';
import 'vs/workbench/electron-browser/main';
import 'vs/workbench/electron-browser/desktop.contribution';
import 'vs/workbench/electron-browser/desktop.main';
//#endregion
@@ -33,7 +33,6 @@ import 'vs/workbench/services/textMate/electron-browser/textMateService';
import 'vs/workbench/services/workspace/electron-browser/workspaceEditingService';
import 'vs/workbench/services/extensions/common/inactiveExtensionUrlHandler';
import 'vs/workbench/services/search/node/searchService';
import 'vs/workbench/contrib/debug/electron-browser/extensionHostDebugService';
import 'vs/workbench/services/output/node/outputChannelModelService';
import 'vs/workbench/services/textfile/node/textFileService';
import 'vs/workbench/services/dialogs/electron-browser/dialogService';
@@ -49,7 +48,6 @@ import 'vs/workbench/services/configurationResolver/electron-browser/configurati
import 'vs/workbench/services/extensionManagement/node/extensionManagementService';
import 'vs/workbench/services/accessibility/node/accessibilityService';
import 'vs/workbench/services/remote/node/tunnelService';
import 'vs/workbench/contrib/stats/electron-browser/workspaceStatsService';
import 'vs/workbench/services/backup/node/backupFileService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
@@ -214,6 +212,7 @@ import 'vs/workbench/contrib/localizations/browser/localizations.contribution';
import 'vs/workbench/contrib/logs/electron-browser/logs.contribution';
// Stats
import 'vs/workbench/contrib/stats/electron-browser/workspaceStatsService';
import 'vs/workbench/contrib/stats/electron-browser/stats.contribution';
// Rapid Render Splash
@@ -221,6 +220,7 @@ import 'vs/workbench/contrib/splash/electron-browser/partsSplash.contribution';
// Debug
// import 'vs/workbench/contrib/debug/node/debugHelperService'; {{SQL CARBON EDIT}}
import 'vs/workbench/contrib/debug/electron-browser/extensionHostDebugService';
// Webview
import 'vs/workbench/contrib/webview/electron-browser/webview.contribution';

View File

@@ -48,6 +48,11 @@ export interface IWorkbenchConstructionOptions {
* A factory for web sockets.
*/
webSocketFactory?: IWebSocketFactory;
/**
* Experimental: Whether to enable the smoke test driver.
*/
driver?: boolean;
}
/**

View File

@@ -10297,10 +10297,10 @@ xterm-addon-web-links@0.1.0-beta10:
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23"
integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg==
xterm@3.15.0-beta98:
version "3.15.0-beta98"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta98.tgz#37f37c35577422880e7ef673cc37f9d2a45dd40c"
integrity sha512-vZbg2LcRvoiJOgr1MyeLFM9mF4uib3BWUWDHyFc+vZ58CTuK0iczOvFXgk/ySo23ZLqwmHQSigLgmWvZ8J5G0Q==
xterm@3.15.0-beta99:
version "3.15.0-beta99"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta99.tgz#0010a7ea5d56cbb08a1e3a525b353c96a158e7a0"
integrity sha512-Vm0ZWToWwO4uk/28Kqvqt9L92h5EU2z4WR9I6xcQaPIBmkJPINIARU4LWQnvaOfgFhRbpwBMveTfh8/jM97lPg==
y18n@^3.2.1:
version "3.2.1"