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
+9
View File
@@ -1354,6 +1354,15 @@
"scope": "resource", "scope": "resource",
"default": false, "default": false,
"description": "%config.supportCancellation%" "description": "%config.supportCancellation%"
},
"git.branchSortOrder": {
"type": "string",
"enum": [
"committerdate",
"alphabetically"
],
"default": "committerdate",
"description": "%config.branchSortOrder%"
} }
} }
}, },
+1
View File
@@ -127,6 +127,7 @@
"config.confirmForcePush": "Controls whether to ask for confirmation before force-pushing.", "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.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.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.added": "Color for added resources.",
"colors.modified": "Color for modified resources.", "colors.modified": "Color for modified resources.",
"colors.deleted": "Color for deleted resources.", "colors.deleted": "Color for deleted resources.",
+8 -2
View File
@@ -1624,8 +1624,14 @@ export class Repository {
.map(([ref]) => ({ name: ref, type: RefType.Head } as Branch)); .map(([ref]) => ({ name: ref, type: RefType.Head } as Branch));
} }
async getRefs(): Promise<Ref[]> { async getRefs(opts?: { sort?: 'alphabetically' | 'committerdate' }): Promise<Ref[]> {
const result = await this.run(['for-each-ref', '--format', '%(refname) %(objectname)', '--sort', '-committerdate']); 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 => { const fn = (line: string): Ref | null => {
let match: RegExpExecArray | null; let match: RegExpExecArray | null;
+5 -2
View File
@@ -701,6 +701,9 @@ export class Repository implements Disposable {
onConfigListener(updateIndexGroupVisibility, this, this.disposables); onConfigListener(updateIndexGroupVisibility, this, this.disposables);
updateIndexGroupVisibility(); updateIndexGroupVisibility();
const onConfigListenerForBranchSortOrder = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.branchSortOrder', root));
onConfigListenerForBranchSortOrder(this.updateModelState, this, this.disposables);
this.mergeGroup.hideWhenEmpty = true; this.mergeGroup.hideWhenEmpty = true;
this.disposables.push(this.mergeGroup); this.disposables.push(this.mergeGroup);
@@ -1405,7 +1408,6 @@ export class Repository implements Disposable {
const config = workspace.getConfiguration('git'); const config = workspace.getConfiguration('git');
const shouldIgnore = config.get<boolean>('ignoreLimitWarning') === true; const shouldIgnore = config.get<boolean>('ignoreLimitWarning') === true;
const useIcons = !config.get<boolean>('decorations.enabled', true); const useIcons = !config.get<boolean>('decorations.enabled', true);
this.isRepositoryHuge = didHitLimit; this.isRepositoryHuge = didHitLimit;
if (didHitLimit && !shouldIgnore && !this.didWarnAboutLimit) { if (didHitLimit && !shouldIgnore && !this.didWarnAboutLimit) {
@@ -1455,7 +1457,8 @@ export class Repository implements Disposable {
// noop // 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._HEAD = HEAD;
this._refs = refs; this._refs = refs;
+1 -1
View File
@@ -77,7 +77,7 @@
"vscode-ripgrep": "^1.5.6", "vscode-ripgrep": "^1.5.6",
"vscode-sqlite3": "4.0.8", "vscode-sqlite3": "4.0.8",
"vscode-textmate": "^4.2.2", "vscode-textmate": "^4.2.2",
"xterm": "3.15.0-beta98", "xterm": "3.15.0-beta99",
"xterm-addon-search": "0.2.0-beta3", "xterm-addon-search": "0.2.0-beta3",
"xterm-addon-web-links": "0.1.0-beta10", "xterm-addon-web-links": "0.1.0-beta10",
"yauzl": "^2.9.2", "yauzl": "^2.9.2",
+1 -1
View File
@@ -21,7 +21,7 @@
"vscode-proxy-agent": "0.4.0", "vscode-proxy-agent": "0.4.0",
"vscode-ripgrep": "^1.5.6", "vscode-ripgrep": "^1.5.6",
"vscode-textmate": "^4.2.2", "vscode-textmate": "^4.2.2",
"xterm": "3.15.0-beta98", "xterm": "3.15.0-beta99",
"xterm-addon-search": "0.2.0-beta3", "xterm-addon-search": "0.2.0-beta3",
"xterm-addon-web-links": "0.1.0-beta10", "xterm-addon-web-links": "0.1.0-beta10",
"yauzl": "^2.9.2", "yauzl": "^2.9.2",
-3
View File
@@ -1,3 +0,0 @@
disturl "http://nodejs.org/dist"
target "10.11.0"
runtime "node"
+4 -4
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" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23"
integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg==
xterm@3.15.0-beta98: xterm@3.15.0-beta99:
version "3.15.0-beta98" version "3.15.0-beta99"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta98.tgz#37f37c35577422880e7ef673cc37f9d2a45dd40c" resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta99.tgz#0010a7ea5d56cbb08a1e3a525b353c96a158e7a0"
integrity sha512-vZbg2LcRvoiJOgr1MyeLFM9mF4uib3BWUWDHyFc+vZ58CTuK0iczOvFXgk/ySo23ZLqwmHQSigLgmWvZ8J5G0Q== integrity sha512-Vm0ZWToWwO4uk/28Kqvqt9L92h5EU2z4WR9I6xcQaPIBmkJPINIARU4LWQnvaOfgFhRbpwBMveTfh8/jM97lPg==
yauzl@^2.9.2: yauzl@^2.9.2:
version "2.10.0" version "2.10.0"
@@ -22,7 +22,6 @@ import { ExtHostModelView } from 'sql/workbench/api/common/extHostModelView';
import { ExtHostConnectionManagement } from 'sql/workbench/api/common/extHostConnectionManagement'; import { ExtHostConnectionManagement } from 'sql/workbench/api/common/extHostConnectionManagement';
import { ExtHostDashboard } from 'sql/workbench/api/common/extHostDashboard'; import { ExtHostDashboard } from 'sql/workbench/api/common/extHostDashboard';
import { ExtHostObjectExplorer } from 'sql/workbench/api/common/extHostObjectExplorer'; 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 { ExtHostModelViewDialog } from 'sql/workbench/api/common/extHostModelViewDialog';
import { ExtHostModelViewTreeViews } from 'sql/workbench/api/common/extHostModelViewTree'; import { ExtHostModelViewTreeViews } from 'sql/workbench/api/common/extHostModelViewTree';
import { ExtHostQueryEditor } from 'sql/workbench/api/common/extHostQueryEditor'; import { ExtHostQueryEditor } from 'sql/workbench/api/common/extHostQueryEditor';
@@ -56,7 +55,7 @@ export function createApiFactory(accessor: ServicesAccessor): ISqlExtensionApiFa
const instaServer = accessor.get(IInstantiationService); const instaServer = accessor.get(IInstantiationService);
const uriTransformer = accessor.get(IURITransformerService); const uriTransformer = accessor.get(IURITransformerService);
const rpcProtocol = accessor.get(IExtHostRpcService); const rpcProtocol = accessor.get(IExtHostRpcService);
const extHostLogService = <ExtHostLogService>accessor.get(ILogService); const extHostLogService = accessor.get(ILogService);
let vsCodeFactory = instaServer.invokeFunction(extHostApi.createApiFactoryAndRegisterActors); let vsCodeFactory = instaServer.invokeFunction(extHostApi.createApiFactoryAndRegisterActors);
// Addressable instances // Addressable instances
+1 -1
View File
@@ -14,7 +14,7 @@
}, },
"include": [ "include": [
"typings/require.d.ts", "typings/require.d.ts",
"./typings/require-monaco.d.ts", "typings/require-monaco.d.ts",
"typings/thenable.d.ts", "typings/thenable.d.ts",
"typings/es6-promise.d.ts", "typings/es6-promise.d.ts",
"typings/lib.es2018.promise.d.ts", "typings/lib.es2018.promise.d.ts",
+2 -5
View File
@@ -7,7 +7,7 @@ import 'vs/css!./gridview';
import { Orientation } from 'vs/base/browser/ui/sash/sash'; import { Orientation } from 'vs/base/browser/ui/sash/sash';
import { Disposable } from 'vs/base/common/lifecycle'; import { Disposable } from 'vs/base/common/lifecycle';
import { tail2 as tail, equals } from 'vs/base/common/arrays'; 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 { Event } from 'vs/base/common/event';
import { InvisibleSizing } from 'vs/base/browser/ui/splitview/splitview'; import { InvisibleSizing } from 'vs/base/browser/ui/splitview/splitview';
@@ -193,11 +193,8 @@ export namespace Sizing {
export interface IGridStyles extends IGridViewStyles { } export interface IGridStyles extends IGridViewStyles { }
export interface IGridOptions { export interface IGridOptions extends IGridViewOptions {
readonly styles?: IGridStyles;
readonly proportionalLayout?: boolean;
readonly firstViewVisibleCachedSize?: number; readonly firstViewVisibleCachedSize?: number;
readonly layoutController?: ILayoutController;
} }
export class Grid<T extends IView = IView> extends Disposable { export class Grid<T extends IView = IView> extends Disposable {
+54 -36
View File
@@ -76,6 +76,11 @@ export class LayoutController implements ILayoutController {
constructor(public isLayoutEnabled: boolean) { } 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 { export interface IGridViewOptions {
readonly styles?: IGridViewStyles; readonly styles?: IGridViewStyles;
readonly proportionalLayout?: boolean; // default true readonly proportionalLayout?: boolean; // default true
@@ -170,6 +175,7 @@ class BranchNode implements ISplitView, IDisposable {
constructor( constructor(
readonly orientation: Orientation, readonly orientation: Orientation,
readonly layoutController: ILayoutController,
styles: IGridViewStyles, styles: IGridViewStyles,
readonly proportionalLayout: boolean, readonly proportionalLayout: boolean,
size: number = 0, size: number = 0,
@@ -181,7 +187,7 @@ class BranchNode implements ISplitView, IDisposable {
this.element = $('.monaco-grid-branch-node'); this.element = $('.monaco-grid-branch-node');
this.splitview = new SplitView(this.element, { orientation, styles, proportionalLayout }); 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]); const onDidSashReset = Event.map(this.splitview.onDidSashReset, i => [i]);
this.splitviewSashResetDisposable = onDidSashReset(this._onDidSashReset.fire, this._onDidSashReset); 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; this._orthogonalSize = size;
for (const child of this.children) { this.splitview.layout(orthogonalSize, size);
child.orthogonalLayout(size);
}
} }
setVisible(visible: boolean): void { 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 { addChild(node: Node, size: number | Sizing, index: number): void {
if (index < 0 || index > this.children.length) { if (index < 0 || index > this.children.length) {
throw new Error('Invalid index'); throw new Error('Invalid index');
@@ -347,6 +356,10 @@ class BranchNode implements ISplitView, IDisposable {
throw new Error('Invalid index'); throw new Error('Invalid index');
} }
if (this.splitview.isViewVisible(index) === visible) {
return;
}
this.splitview.setViewVisible(index, visible); this.splitview.setViewVisible(index, visible);
this._onDidChange.fire(undefined); this._onDidChange.fire(undefined);
} }
@@ -539,12 +552,18 @@ class LeafNode implements ISplitView, IDisposable {
// noop // noop
} }
layout(size: number): void { layout(size: number, orthogonalSize: number | undefined): void {
this._size = size; if (!this.layoutController.isLayoutEnabled) {
return;
if (this.layoutController.isLayoutEnabled) {
this.view.layout(this.width, this.height, orthogonal(this.orientation));
} }
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 { 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 { } dispose(): void { }
} }
@@ -568,7 +579,7 @@ type Node = BranchNode | LeafNode;
function flipNode<T extends Node>(node: T, size: number, orthogonalSize: number): T { function flipNode<T extends Node>(node: T, size: number, orthogonalSize: number): T {
if (node instanceof BranchNode) { 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; let totalSize = 0;
@@ -589,7 +600,7 @@ function flipNode<T extends Node>(node: T, size: number, orthogonalSize: number)
return result as T; return result as T;
} else { } 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; const { size, orthogonalSize } = this._root;
this.root = flipNode(this._root, orthogonalSize, size); this.root = flipNode(this._root, orthogonalSize, size);
this.root.layout(size); this.root.layout(size, orthogonalSize);
this.root.orthogonalLayout(orthogonalSize);
} }
get width(): number { return this.root.width; } get width(): number { return this.root.width; }
@@ -649,14 +659,25 @@ export class GridView implements IDisposable {
private _onDidChange = new Relay<IViewSize | undefined>(); private _onDidChange = new Relay<IViewSize | undefined>();
readonly onDidChange = this._onDidChange.event; 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; private layoutController: LayoutController;
constructor(options: IGridViewOptions = {}) { constructor(options: IGridViewOptions = {}) {
this.element = $('.monaco-grid-view'); this.element = $('.monaco-grid-view');
this.styles = options.styles || defaultStyles; this.styles = options.styles || defaultStyles;
this.proportionalLayout = typeof options.proportionalLayout !== 'undefined' ? !!options.proportionalLayout : true; 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 { style(styles: IGridViewStyles): void {
@@ -665,9 +686,10 @@ export class GridView implements IDisposable {
} }
layout(width: number, height: number): void { layout(width: number, height: number): void {
this.firstLayoutController.isLayoutEnabled = true;
const [size, orthogonalSize] = this.root.orientation === Orientation.HORIZONTAL ? [height, width] : [width, height]; const [size, orthogonalSize] = this.root.orientation === Orientation.HORIZONTAL ? [height, width] : [width, height];
this.root.layout(size); this.root.layout(size, orthogonalSize);
this.root.orthogonalLayout(orthogonalSize);
} }
addView(view: IView, size: number | Sizing, location: number[]): void { addView(view: IView, size: number | Sizing, location: number[]): void {
@@ -694,9 +716,8 @@ export class GridView implements IDisposable {
grandParent.removeChild(parentIndex); 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); grandParent.addChild(newParent, parent.size, parentIndex);
newParent.orthogonalLayout(parent.orthogonalSize);
const newSibling = new LeafNode(parent.view, grandParent.orientation, this.layoutController, parent.size); const newSibling = new LeafNode(parent.view, grandParent.orientation, this.layoutController, parent.size);
newParent.addChild(newSibling, newSiblingSize, 0); newParent.addChild(newSibling, newSiblingSize, 0);
@@ -827,9 +848,6 @@ export class GridView implements IDisposable {
fromParent.addChild(toNode, fromSize, fromIndex); fromParent.addChild(toNode, fromSize, fromIndex);
toParent.addChild(fromNode, toSize, toIndex); toParent.addChild(fromNode, toSize, toIndex);
fromParent.layout(fromParent.orthogonalSize);
toParent.layout(toParent.orthogonalSize);
} }
} }
+20 -18
View File
@@ -24,12 +24,12 @@ const defaultStyles: ISplitViewStyles = {
}; };
export interface ISplitViewOptions { export interface ISplitViewOptions {
orientation?: Orientation; // default Orientation.VERTICAL readonly orientation?: Orientation; // default Orientation.VERTICAL
styles?: ISplitViewStyles; readonly styles?: ISplitViewStyles;
orthogonalStartSash?: Sash; readonly orthogonalStartSash?: Sash;
orthogonalEndSash?: Sash; readonly orthogonalEndSash?: Sash;
inverseAltBehavior?: boolean; readonly inverseAltBehavior?: boolean;
proportionalLayout?: boolean; // default true readonly proportionalLayout?: boolean; // default true
} }
/** /**
@@ -48,7 +48,7 @@ export interface IView {
readonly onDidChange: Event<number | undefined>; readonly onDidChange: Event<number | undefined>;
readonly priority?: LayoutPriority; readonly priority?: LayoutPriority;
readonly snap?: boolean; readonly snap?: boolean;
layout(size: number, orientation: Orientation): void; layout(size: number, orthogonalSize: number | undefined): void;
setVisible?(visible: boolean): void; setVisible?(visible: boolean): void;
} }
@@ -125,13 +125,13 @@ abstract class ViewItem {
dom.addClass(container, 'visible'); dom.addClass(container, 'visible');
} }
layout(): void { layout(_orthogonalSize: number | undefined): void {
this.container.scrollTop = 0; this.container.scrollTop = 0;
this.container.scrollLeft = 0; this.container.scrollLeft = 0;
} }
layoutView(orientation: Orientation): void { layoutView(orthogonalSize: number | undefined): void {
this.view.layout(this.size, orientation); this.view.layout(this.size, orthogonalSize);
} }
dispose(): IView { dispose(): IView {
@@ -142,19 +142,19 @@ abstract class ViewItem {
class VerticalViewItem extends ViewItem { class VerticalViewItem extends ViewItem {
layout(): void { layout(orthogonalSize: number | undefined): void {
super.layout(); super.layout(orthogonalSize);
this.container.style.height = `${this.size}px`; this.container.style.height = `${this.size}px`;
this.layoutView(Orientation.VERTICAL); this.layoutView(orthogonalSize);
} }
} }
class HorizontalViewItem extends ViewItem { class HorizontalViewItem extends ViewItem {
layout(): void { layout(orthogonalSize: number | undefined): void {
super.layout(); super.layout(orthogonalSize);
this.container.style.width = `${this.size}px`; 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 sashContainer: HTMLElement;
private viewContainer: HTMLElement; private viewContainer: HTMLElement;
private size = 0; private size = 0;
private orthogonalSize: number | undefined;
private contentSize = 0; private contentSize = 0;
private proportions: undefined | number[] = undefined; private proportions: undefined | number[] = undefined;
private viewItems: ViewItem[] = []; private viewItems: ViewItem[] = [];
@@ -475,9 +476,10 @@ export class SplitView extends Disposable {
return viewItem.cachedVisibleSize; return viewItem.cachedVisibleSize;
} }
layout(size: number): void { layout(size: number, orthogonalSize?: number): void {
const previousSize = Math.max(this.size, this.contentSize); const previousSize = Math.max(this.size, this.contentSize);
this.size = size; this.size = size;
this.orthogonalSize = orthogonalSize;
if (!this.proportions) { if (!this.proportions) {
const indexes = range(this.viewItems.length); 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); this.contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
// Layout views // Layout views
this.viewItems.forEach(item => item.layout()); this.viewItems.forEach(item => item.layout(this.orthogonalSize));
// Layout sashes // Layout sashes
this.sashItems.forEach(item => item.sash.layout()); this.sashItems.forEach(item => item.sash.layout());
+1 -1
View File
@@ -16,7 +16,7 @@ export interface IWorker extends IDisposable {
} }
export interface IWorkerCallback { export interface IWorkerCallback {
(message: string): void; (message: any): void;
} }
export interface IWorkerFactory { export interface IWorkerFactory {
@@ -5,7 +5,7 @@
import * as assert from 'assert'; import * as assert from 'assert';
import { Emitter } from 'vs/base/common/event'; 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'; import { Sash, SashState } from 'vs/base/browser/ui/sash/sash';
class TestView implements IView { class TestView implements IView {
@@ -27,7 +27,9 @@ class TestView implements IView {
private _size = 0; private _size = 0;
get size(): number { return this._size; } 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; readonly onDidLayout = this._onDidLayout.event;
private _onDidFocus = new Emitter<void>(); private _onDidFocus = new Emitter<void>();
@@ -41,9 +43,10 @@ class TestView implements IView {
assert(_minimumSize <= _maximumSize, 'splitview view minimum size must be <= maximum size'); 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._size = size;
this._onDidLayout.fire({ size, orientation }); this._orthogonalSize = orthogonalSize;
this._onDidLayout.fire({ size, orthogonalSize });
} }
focus(): void { focus(): void {
@@ -523,4 +526,24 @@ suite('Splitview', () => {
view2.dispose(); view2.dispose();
view1.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();
});
}); });
+2 -2
View File
@@ -20,8 +20,8 @@
let loadCode = function (moduleId: string) { let loadCode = function (moduleId: string) {
require([moduleId], function (ws) { require([moduleId], function (ws) {
setTimeout(function () { setTimeout(function () {
let messageHandler = ws.create((msg: any) => { let messageHandler = ws.create((msg: any, transfer?: Transferable[]) => {
(<any>self).postMessage(msg); (<any>self).postMessage(msg, transfer);
}, null); }, null);
self.onmessage = (e) => messageHandler.onmessage(e.data); self.onmessage = (e) => messageHandler.onmessage(e.data);
@@ -27,7 +27,7 @@ bootstrapWindow.load([
perf.mark('main/startup'); perf.mark('main/startup');
// @ts-ignore // @ts-ignore
return require('vs/workbench/electron-browser/main').main(configuration); return require('vs/workbench/electron-browser/desktop.main').main(configuration);
}); });
}, { }, {
removeDeveloperKeybindingsAfterLoad: true, removeDeveloperKeybindingsAfterLoad: true,
+8 -1
View File
@@ -129,6 +129,10 @@ export interface MarkerStatistics {
export namespace IMarkerData { export namespace IMarkerData {
const emptyString = ''; const emptyString = '';
export function makeKey(markerData: IMarkerData): string { export function makeKey(markerData: IMarkerData): string {
return makeKeyOptionalMessage(markerData, true);
}
export function makeKeyOptionalMessage(markerData: IMarkerData, useMessage: boolean): string {
let result: string[] = [emptyString]; let result: string[] = [emptyString];
if (markerData.source) { if (markerData.source) {
result.push(markerData.source.replace('¦', '\¦')); result.push(markerData.source.replace('¦', '\¦'));
@@ -145,7 +149,10 @@ export namespace IMarkerData {
} else { } else {
result.push(emptyString); 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('¦', '\¦')); result.push(markerData.message.replace('¦', '\¦'));
} else { } else {
result.push(emptyString); result.push(emptyString);
@@ -12,6 +12,7 @@ export const lastSessionDateStorageKey = 'telemetry.lastSessionDate';
import * as Platform from 'vs/base/common/platform'; import * as Platform from 'vs/base/common/platform';
import * as uuid from 'vs/base/common/uuid'; 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 }> { 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); const result: { [name: string]: string | undefined; } = Object.create(null);
@@ -69,18 +70,3 @@ export async function resolveWorkbenchCommonProperties(storageService: IStorageS
return result; 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;
}
@@ -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 { function flatten(obj: any, result: { [key: string]: any }, order: number = 0, prefix?: string): void {
if (!obj) { if (!obj) {
return; return;
@@ -6,6 +6,7 @@
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties'; import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties';
import { instanceStorageKey, firstSessionDateStorageKey, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry'; import { instanceStorageKey, firstSessionDateStorageKey, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry';
import { cleanRemoteAuthority } from 'vs/platform/telemetry/common/telemetryUtils';
// {{ SQL CARBON EDIT }} // {{ SQL CARBON EDIT }}
import product from 'vs/platform/product/node/product'; 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()); const monthlyLastUseDate = storageService.get('telemetry.monthlyLastUseDate', StorageScope.GLOBAL, appStartDate.toUTCString());
storageService.store('telemetry.monthlyLastUseDate', monthlyLastUseDate, StorageScope.GLOBAL); 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;
}
+2 -2
View File
@@ -5208,7 +5208,7 @@ declare module 'vscode' {
*/ */
export enum TaskScope { export enum TaskScope {
/** /**
* The task is a global task * The task is a global task. Global tasks are currrently not supported.
*/ */
Global = 1, Global = 1,
@@ -5237,7 +5237,7 @@ declare module 'vscode' {
* Creates a new task. * Creates a new task.
* *
* @param definition The task definition as defined in the taskDefinitions extension point. * @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 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 source The task's source (e.g. 'gulp', 'npm', ...). Is presented in the user interface.
* @param execution The process or shell execution. * @param execution The process or shell execution.
@@ -124,7 +124,7 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
this._dataProviders.forEach((dataProvider, treeViewId) => { this._dataProviders.forEach((dataProvider, treeViewId) => {
const treeView = this.getTreeView(treeViewId); const treeView = this.getTreeView(treeViewId);
if (treeView) { if (treeView) {
treeView.dataProvider = null; treeView.dataProvider = undefined;
} }
}); });
this._dataProviders.clear(); this._dataProviders.clear();
@@ -15,7 +15,7 @@ import { OverviewRulerLane } from 'vs/editor/common/model';
import * as languageConfiguration from 'vs/editor/common/modes/languageConfiguration'; import * as languageConfiguration from 'vs/editor/common/modes/languageConfiguration';
import { score } from 'vs/editor/common/modes/languageSelector'; import { score } from 'vs/editor/common/modes/languageSelector';
import * as files from 'vs/platform/files/common/files'; 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 { ExtHostApiCommands } from 'vs/workbench/api/common/extHostApiCommands';
import { ExtHostClipboard } from 'vs/workbench/api/common/extHostClipboard'; import { ExtHostClipboard } from 'vs/workbench/api/common/extHostClipboard';
import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; 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 { ExtHostFileSystemEventService } from 'vs/workbench/api/common/extHostFileSystemEventService';
import { ExtHostLanguageFeatures } from 'vs/workbench/api/common/extHostLanguageFeatures'; import { ExtHostLanguageFeatures } from 'vs/workbench/api/common/extHostLanguageFeatures';
import { ExtHostLanguages } from 'vs/workbench/api/common/extHostLanguages'; 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 { ExtHostMessageService } from 'vs/workbench/api/common/extHostMessageService';
import { IExtHostOutputService } from 'vs/workbench/api/common/extHostOutput'; import { IExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
import { ExtHostProgress } from 'vs/workbench/api/common/extHostProgress'; import { ExtHostProgress } from 'vs/workbench/api/common/extHostProgress';
@@ -95,10 +94,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const uriTransformer = accessor.get(IURITransformerService); const uriTransformer = accessor.get(IURITransformerService);
const rpcProtocol = accessor.get(IExtHostRpcService); const rpcProtocol = accessor.get(IExtHostRpcService);
const extHostStorage = accessor.get(IExtHostStorage); const extHostStorage = accessor.get(IExtHostStorage);
const extHostLogService = <ExtHostLogService>accessor.get(ILogService); const extHostLogService = accessor.get(ILogService);
// register addressable instances // register addressable instances
rpcProtocol.set(ExtHostContext.ExtHostLogService, extHostLogService); rpcProtocol.set(ExtHostContext.ExtHostLogService, <ExtHostLogServiceShape><any>extHostLogService);
rpcProtocol.set(ExtHostContext.ExtHostWorkspace, extHostWorkspace); rpcProtocol.set(ExtHostContext.ExtHostWorkspace, extHostWorkspace);
rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration); rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration);
rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService); rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService);
@@ -147,10 +146,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostStatusBar = new ExtHostStatusBar(rpcProtocol); const extHostStatusBar = new ExtHostStatusBar(rpcProtocol);
const extHostLanguages = new ExtHostLanguages(rpcProtocol, extHostDocuments); 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 // Register API-ish commands
ExtHostApiCommands.register(extHostCommands); ExtHostApiCommands.register(extHostCommands);
@@ -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 { ExtHostExtensionServiceShape, IInitData, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape, IResolveAuthorityResult } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfiguration, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration'; 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 { 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 { ExtHostStorage, IExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions'; 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 _instaService: IInstantiationService;
protected readonly _extHostWorkspace: ExtHostWorkspace; protected readonly _extHostWorkspace: ExtHostWorkspace;
protected readonly _extHostConfiguration: ExtHostConfiguration; protected readonly _extHostConfiguration: ExtHostConfiguration;
protected readonly _extHostLogService: ExtHostLogService; protected readonly _logService: ILogService;
protected readonly _mainThreadWorkspaceProxy: MainThreadWorkspaceShape; protected readonly _mainThreadWorkspaceProxy: MainThreadWorkspaceShape;
protected readonly _mainThreadTelemetryProxy: MainThreadTelemetryShape; protected readonly _mainThreadTelemetryProxy: MainThreadTelemetryShape;
@@ -102,7 +101,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
@IExtHostRpcService extHostContext: IExtHostRpcService, @IExtHostRpcService extHostContext: IExtHostRpcService,
@IExtHostWorkspace extHostWorkspace: IExtHostWorkspace, @IExtHostWorkspace extHostWorkspace: IExtHostWorkspace,
@IExtHostConfiguration extHostConfiguration: IExtHostConfiguration, @IExtHostConfiguration extHostConfiguration: IExtHostConfiguration,
@ILogService extHostLogService: ExtHostLogService, @ILogService logService: ILogService,
@IExtHostInitDataService initData: IExtHostInitDataService, @IExtHostInitDataService initData: IExtHostInitDataService,
@IExtensionStoragePaths storagePath: IExtensionStoragePaths @IExtensionStoragePaths storagePath: IExtensionStoragePaths
) { ) {
@@ -112,7 +111,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
this._extHostWorkspace = extHostWorkspace; this._extHostWorkspace = extHostWorkspace;
this._extHostConfiguration = extHostConfiguration; this._extHostConfiguration = extHostConfiguration;
this._extHostLogService = extHostLogService; this._logService = logService;
this._disposables = new DisposableStore(); this._disposables = new DisposableStore();
this._mainThreadWorkspaceProxy = this._extHostContext.getProxy(MainContext.MainThreadWorkspace); this._mainThreadWorkspaceProxy = this._extHostContext.getProxy(MainContext.MainThreadWorkspace);
@@ -329,14 +328,14 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
return Promise.resolve(new EmptyExtension(ExtensionActivationTimes.NONE)); 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); const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup);
return Promise.all<any>([ return Promise.all<any>([
this._loadCommonJSModule(extensionDescription.main, activationTimesBuilder), this._loadCommonJSModule(extensionDescription.main, activationTimesBuilder),
this._loadExtensionContext(extensionDescription) this._loadExtensionContext(extensionDescription)
]).then(values => { ]).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 globalState = new ExtensionMemento(extensionDescription.identifier.value, true, this._storage);
const workspaceState = new ExtensionMemento(extensionDescription.identifier.value, false, 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([ return Promise.all([
globalState.whenReady, globalState.whenReady,
workspaceState.whenReady, workspaceState.whenReady,
@@ -359,10 +358,10 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
workspaceState, workspaceState,
subscriptions: [], subscriptions: [],
get extensionPath() { return extensionDescription.extensionLocation.fsPath; }, get extensionPath() { return extensionDescription.extensionLocation.fsPath; },
storagePath: this._storagePath.workspaceValue(extensionDescription), get storagePath() { return that._storagePath.workspaceValue(extensionDescription); },
globalStoragePath: this._storagePath.globalValue(extensionDescription), get globalStoragePath() { return that._storagePath.globalValue(extensionDescription); },
asAbsolutePath: (relativePath: string) => { return path.join(extensionDescription.extensionLocation.fsPath, relativePath); }, 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, executionContext: this._initData.remote.isRemote ? ExtensionExecutionContext.Remote : ExtensionExecutionContext.Local,
}); });
}); });
@@ -385,7 +384,8 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
try { try {
activationTimesBuilder.activateCallStart(); activationTimesBuilder.activateCallStart();
logService.trace(`ExtensionService#_callActivateOptional ${extensionId.value}`); 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.activateCallStop();
activationTimesBuilder.activateResolveStart(); 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> { 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) { if (globPatterns.length === 0) {
return Promise.resolve(undefined); return Promise.resolve(undefined);
@@ -525,7 +525,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
} }
private async _doHandleExtensionTests(): Promise<void> { 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)) { if (!(extensionDevelopmentLocationURI && extensionTestsLocationURI && extensionTestsLocationURI.scheme === Schemas.file)) {
return Promise.resolve(undefined); return Promise.resolve(undefined);
} }
@@ -605,7 +605,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
.then(() => this._handleEagerExtensions()) .then(() => this._handleEagerExtensions())
.then(() => this._handleExtensionTests()) .then(() => this._handleExtensionTests())
.then(() => { .then(() => {
this._extHostLogService.info(`eager extensions activated`); this._logService.info(`eager extensions activated`);
}); });
} }
@@ -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);
}
}
@@ -24,8 +24,11 @@ import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePa
import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
import { IExtHostStorage, ExtHostStorage } from 'vs/workbench/api/common/extHostStorage'; 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 // register singleton services
registerSingleton(ILogService, ExtHostLogService);
registerSingleton(IExtHostOutputService, ExtHostOutputService2); registerSingleton(IExtHostOutputService, ExtHostOutputService2);
registerSingleton(IExtHostWorkspace, ExtHostWorkspace); registerSingleton(IExtHostWorkspace, ExtHostWorkspace);
registerSingleton(IExtHostDecorations, ExtHostDecorations); registerSingleton(IExtHostDecorations, ExtHostDecorations);
@@ -44,14 +44,24 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService {
} }
// Do this when extension service exists, but extensions are not being activated yet. // 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> { protected _loadCommonJSModule<T>(modulePath: string, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
let r: T | null = null; let r: T | null = null;
activationTimesBuilder.codeLoadingStart(); activationTimesBuilder.codeLoadingStart();
this._extHostLogService.info(`ExtensionService#loadCommonJSModule ${modulePath}`); this._logService.info(`ExtensionService#loadCommonJSModule ${modulePath}`);
try { try {
r = require.__$__nodeRequire<T>(modulePath); r = require.__$__nodeRequire<T>(modulePath);
} catch (e) { } catch (e) {
@@ -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);
}
}
@@ -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');
}
}
@@ -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;
}
}
@@ -71,6 +71,7 @@ export abstract class BreadcrumbsConfig<T> {
static FilePath = BreadcrumbsConfig._stub<'on' | 'off' | 'last'>('breadcrumbs.filePath'); static FilePath = BreadcrumbsConfig._stub<'on' | 'off' | 'last'>('breadcrumbs.filePath');
static SymbolPath = BreadcrumbsConfig._stub<'on' | 'off' | 'last'>('breadcrumbs.symbolPath'); static SymbolPath = BreadcrumbsConfig._stub<'on' | 'off' | 'last'>('breadcrumbs.symbolPath');
static SymbolSortOrder = BreadcrumbsConfig._stub<'position' | 'name' | 'type'>('breadcrumbs.symbolSortOrder'); static SymbolSortOrder = BreadcrumbsConfig._stub<'position' | 'name' | 'type'>('breadcrumbs.symbolSortOrder');
static Icons = BreadcrumbsConfig._stub<boolean>('breadcrumbs.icons');
static FileExcludes = BreadcrumbsConfig._stub<glob.IExpression>('files.exclude'); 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.name', "Show symbol outline in alphabetical order."),
localize('symbolSortOrder.type', "Show symbol outline in symbol type 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
} }
} }
}); });
@@ -69,7 +69,9 @@ class Item extends BreadcrumbsItem {
return false; return false;
} }
if (this.element instanceof FileElement && other.element instanceof FileElement) { 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) { if (this.element instanceof TreeElement && other.element instanceof TreeElement) {
return this.element.id === other.element.id; return this.element.id === other.element.id;
@@ -143,6 +145,7 @@ export class BreadcrumbsControl {
private readonly _ckBreadcrumbsActive: IContextKey<boolean>; private readonly _ckBreadcrumbsActive: IContextKey<boolean>;
private readonly _cfUseQuickPick: BreadcrumbsConfig<boolean>; private readonly _cfUseQuickPick: BreadcrumbsConfig<boolean>;
private readonly _cfShowIcons: BreadcrumbsConfig<boolean>;
readonly domNode: HTMLDivElement; readonly domNode: HTMLDivElement;
private readonly _widget: BreadcrumbsWidget; private readonly _widget: BreadcrumbsWidget;
@@ -185,6 +188,7 @@ export class BreadcrumbsControl {
this._ckBreadcrumbsActive = BreadcrumbsControl.CK_BreadcrumbsActive.bindTo(this._contextKeyService); this._ckBreadcrumbsActive = BreadcrumbsControl.CK_BreadcrumbsActive.bindTo(this._contextKeyService);
this._cfUseQuickPick = BreadcrumbsConfig.UseQuickPick.bindTo(_configurationService); this._cfUseQuickPick = BreadcrumbsConfig.UseQuickPick.bindTo(_configurationService);
this._cfShowIcons = BreadcrumbsConfig.Icons.bindTo(_configurationService);
this._disposables.add(breadcrumbsService.register(this._editorGroup.id, this._widget)); this._disposables.add(breadcrumbsService.register(this._editorGroup.id, this._widget));
} }
@@ -196,6 +200,7 @@ export class BreadcrumbsControl {
this._ckBreadcrumbsVisible.reset(); this._ckBreadcrumbsVisible.reset();
this._ckBreadcrumbsActive.reset(); this._ckBreadcrumbsActive.reset();
this._cfUseQuickPick.dispose(); this._cfUseQuickPick.dispose();
this._cfShowIcons.dispose();
this._widget.dispose(); this._widget.dispose();
this.domNode.remove(); this.domNode.remove();
} }
@@ -246,15 +251,23 @@ export class BreadcrumbsControl {
dom.toggleClass(this.domNode, 'backslash-path', this._labelService.getSeparator(uri.scheme, uri.authority) === '\\'); dom.toggleClass(this.domNode, 'backslash-path', this._labelService.getSeparator(uri.scheme, uri.authority) === '\\');
const updateBreadcrumbs = () => { 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.setItems(items);
this._widget.reveal(items[items.length - 1]); this._widget.reveal(items[items.length - 1]);
}; };
const listener = model.onDidUpdate(updateBreadcrumbs); const listener = model.onDidUpdate(updateBreadcrumbs);
const configListener = this._cfShowIcons.onDidChange(updateBreadcrumbs);
updateBreadcrumbs(); updateBreadcrumbs();
this._breadcrumbsDisposables.clear(); this._breadcrumbsDisposables.clear();
this._breadcrumbsDisposables.add(model); this._breadcrumbsDisposables.add(model);
this._breadcrumbsDisposables.add(listener); this._breadcrumbsDisposables.add(listener);
this._breadcrumbsDisposables.add(configListener);
// close picker on hide/update // close picker on hide/update
this._breadcrumbsDisposables.add({ this._breadcrumbsDisposables.add({
@@ -806,7 +806,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
//#region openEditor() //#region openEditor()
openEditor(editor: EditorInput, options?: EditorOptions): Promise<IEditor | null> { async openEditor(editor: EditorInput, options?: EditorOptions): Promise<IEditor | null> {
// Guard against invalid inputs // Guard against invalid inputs
if (!editor) { if (!editor) {
@@ -822,7 +822,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
} }
// Proceed with opening // 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> { private doOpenEditor(editor: EditorInput, options?: EditorOptions): Promise<IEditor | undefined> {
@@ -63,7 +63,7 @@ export class SidebarPart extends CompositePart<Viewlet> implements IViewletServi
return undefined; // {{SQL CARBON EDIT}} strict-null-check return undefined; // {{SQL CARBON EDIT}} strict-null-check
} }
return width; return Math.max(width, 300);
} }
//#endregion //#endregion
@@ -161,12 +161,12 @@ export class CustomTreeView extends Disposable implements ITreeView {
private _showCollapseAllAction = false; private _showCollapseAllAction = false;
private focused: boolean = false; private focused: boolean = false;
private domNode: HTMLElement; private domNode!: HTMLElement;
private treeContainer: HTMLElement; private treeContainer!: HTMLElement;
private _messageValue: string | undefined; private _messageValue: string | undefined;
private messageElement: HTMLDivElement; private messageElement!: HTMLDivElement;
private tree: WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore>; private tree: WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore> | undefined;
private treeLabels: ResourceLabels; private treeLabels: ResourceLabels | undefined;
private root: ITreeItem; private root: ITreeItem;
private elementsToRefresh: ITreeItem[] = []; private elementsToRefresh: ITreeItem[] = [];
private menus: TitleMenus; private menus: TitleMenus;
@@ -218,12 +218,12 @@ export class CustomTreeView extends Disposable implements ITreeView {
this.create(); this.create();
} }
private _dataProvider: ITreeViewDataProvider | null; private _dataProvider: ITreeViewDataProvider | undefined;
get dataProvider(): ITreeViewDataProvider | null { get dataProvider(): ITreeViewDataProvider | undefined {
return this._dataProvider; return this._dataProvider;
} }
set dataProvider(dataProvider: ITreeViewDataProvider | null) { set dataProvider(dataProvider: ITreeViewDataProvider | undefined) {
if (dataProvider) { if (dataProvider) {
this._dataProvider = new class implements ITreeViewDataProvider { this._dataProvider = new class implements ITreeViewDataProvider {
async getChildren(node: ITreeItem): Promise<ITreeItem[]> { async getChildren(node: ITreeItem): Promise<ITreeItem[]> {
@@ -238,7 +238,7 @@ export class CustomTreeView extends Disposable implements ITreeView {
this.updateMessage(); this.updateMessage();
this.refresh(); this.refresh();
} else { } else {
this._dataProvider = null; this._dataProvider = undefined;
this.updateMessage(); this.updateMessage();
} }
} }
@@ -399,7 +399,7 @@ export class CustomTreeView extends Disposable implements ITreeView {
if (!e.browserEvent) { if (!e.browserEvent) {
return; return;
} }
const selection = this.tree.getSelection(); const selection = this.tree!.getSelection();
if ((selection.length === 1) && selection[0].command) { if ((selection.length === 1) && selection[0].command) {
this.commandService.executeCommand(selection[0].command.id, ...(selection[0].command.arguments || [])); 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.preventDefault();
event.stopPropagation(); event.stopPropagation();
this.tree.setFocus([node]); this.tree!.setFocus([node]);
const actions = treeMenus.getResourceContextActions(node); const actions = treeMenus.getResourceContextActions(node);
if (!actions.length) { if (!actions.length) {
return; return;
@@ -436,13 +436,13 @@ export class CustomTreeView extends Disposable implements ITreeView {
onHide: (wasCancelled?: boolean) => { onHide: (wasCancelled?: boolean) => {
if (wasCancelled) { if (wasCancelled) {
this.tree.domFocus(); this.tree!.domFocus();
} }
}, },
getActionsContext: () => (<TreeViewItemHandleArg>{ $treeViewId: this.id, $treeItemHandle: node.handle }), 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); DOM.clearNode(this.messageElement);
} }
private _height: number; private _height: number = 0;
private _width: number; private _width: number = 0;
layout(height: number, width: number) { layout(height: number, width: number) {
if (height && width) { if (height && width) {
this._height = height; this._height = height;
@@ -532,10 +532,11 @@ export class CustomTreeView extends Disposable implements ITreeView {
} }
async expand(itemOrItems: ITreeItem | ITreeItem[]): Promise<void> { async expand(itemOrItems: ITreeItem | ITreeItem[]): Promise<void> {
if (this.tree) { const tree = this.tree;
if (tree) {
itemOrItems = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems]; itemOrItems = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
await Promise.all(itemOrItems.map(element => { await Promise.all(itemOrItems.map(element => {
return this.tree.expand(element, false); return tree.expand(element, false);
})); }));
} }
return Promise.resolve(undefined); return Promise.resolve(undefined);
@@ -575,18 +576,19 @@ export class CustomTreeView extends Disposable implements ITreeView {
private refreshing: boolean = false; private refreshing: boolean = false;
private async doRefresh(elements: ITreeItem[]): Promise<void> { private async doRefresh(elements: ITreeItem[]): Promise<void> {
if (this.tree) { const tree = this.tree;
if (tree) {
this.refreshing = true; this.refreshing = true;
const parents: Set<ITreeItem> = new Set<ITreeItem>(); const parents: Set<ITreeItem> = new Set<ITreeItem>();
elements.forEach(element => { elements.forEach(element => {
if (element !== this.root) { if (element !== this.root) {
const parent = this.tree.getParentElement(element); const parent = tree.getParentElement(element);
parents.add(parent); parents.add(parent);
} else { } else {
parents.add(element); 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.refreshing = false;
this.updateContentAreas(); this.updateContentAreas();
if (this.focused) { if (this.focused) {
@@ -772,7 +774,7 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
} }
class Aligner extends Disposable { class Aligner extends Disposable {
private _tree: WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore>; private _tree: WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore> | undefined;
constructor(private themeService: IWorkbenchThemeService) { constructor(private themeService: IWorkbenchThemeService) {
super(); super();
@@ -790,11 +792,15 @@ class Aligner extends Disposable {
return false; return false;
} }
if (this._tree) {
const parent: ITreeItem = this._tree.getParentElement(treeItem) || this._tree.getInput(); const parent: ITreeItem = this._tree.getParentElement(treeItem) || this._tree.getInput();
if (this.hasIcon(parent)) { if (this.hasIcon(parent)) {
return false; return false;
} }
return !!parent.children && parent.children.every(c => c.collapsibleState === TreeItemCollapsibleState.None || !this.hasIcon(c)); return !!parent.children && parent.children.every(c => c.collapsibleState === TreeItemCollapsibleState.None || !this.hasIcon(c));
} else {
return false;
}
} }
private hasIcon(node: ITreeItem): boolean { private hasIcon(node: ITreeItem): boolean {
@@ -7,6 +7,10 @@
border-top: none !important; /* less clutter: do not show any border for first views in a panel */ 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 { .monaco-panel-view .panel > .panel-header h3.title {
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
@@ -41,6 +41,7 @@ export interface IViewletPanelOptions extends IPanelOptions {
actionRunner?: IActionRunner; actionRunner?: IActionRunner;
id: string; id: string;
title: string; title: string;
showActionsAlways?: boolean;
} }
export abstract class ViewletPanel extends Panel implements IView { export abstract class ViewletPanel extends Panel implements IView {
@@ -67,6 +68,7 @@ export abstract class ViewletPanel extends Panel implements IView {
protected actionRunner?: IActionRunner; protected actionRunner?: IActionRunner;
protected toolbar: ToolBar; protected toolbar: ToolBar;
private readonly showActionsAlways: boolean = false;
private headerContainer: HTMLElement; private headerContainer: HTMLElement;
private titleContainer: HTMLElement; private titleContainer: HTMLElement;
@@ -82,6 +84,7 @@ export abstract class ViewletPanel extends Panel implements IView {
this.id = options.id; this.id = options.id;
this.title = options.title; this.title = options.title;
this.actionRunner = options.actionRunner; this.actionRunner = options.actionRunner;
this.showActionsAlways = !!options.showActionsAlways;
this.focusedViewContextKey = FocusedViewContext.bindTo(contextKeyService); this.focusedViewContextKey = FocusedViewContext.bindTo(contextKeyService);
} }
@@ -133,6 +136,7 @@ export abstract class ViewletPanel extends Panel implements IView {
this.renderHeaderTitle(container, this.title); this.renderHeaderTitle(container, this.title);
const actions = append(container, $('.actions')); const actions = append(container, $('.actions'));
toggleClass(actions, 'show', this.showActionsAlways);
this.toolbar = new ToolBar(actions, this.contextMenuService, { this.toolbar = new ToolBar(actions, this.contextMenuService, {
orientation: ActionsOrientation.HORIZONTAL, orientation: ActionsOrientation.HORIZONTAL,
actionViewItemProvider: action => this.getActionViewItem(action), actionViewItemProvider: action => this.getActionViewItem(action),
+4 -60
View File
@@ -8,9 +8,8 @@ import * as browser from 'vs/base/browser/browser';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { Event } from 'vs/base/common/event'; import { Event } from 'vs/base/common/event';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; 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 { 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 { IURLHandler, IURLService } from 'vs/platform/url/common/url';
import { ConsoleLogService, ILogService } from 'vs/platform/log/common/log'; import { ConsoleLogService, ILogService } from 'vs/platform/log/common/log';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; 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'; import { ITunnelService } from 'vs/platform/remote/common/tunnel';
// tslint:disable-next-line: import-patterns // tslint:disable-next-line: import-patterns
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; 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 { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
import { pathsToEditors } from 'vs/workbench/common/editor'; import { pathsToEditors } from 'vs/workbench/common/editor';
import { IFileService } from 'vs/platform/files/common/files'; import { IFileService } from 'vs/platform/files/common/files';
@@ -90,63 +89,6 @@ registerSingleton(IExtensionTipsService, SimpleExtensionTipsService, true);
//#endregion //#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 //#region Extension URL Handler
export const IExtensionUrlHandler = createDecorator<IExtensionUrlHandler>('inactiveExtensionUrlHandler'); 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 // This needs to be handled from browser process to prevent
// foreground ordering issues on Windows // foreground ordering issues on Windows
openExternal(_url: string): Promise<boolean> { openExternal(_url: string): Promise<boolean> {
windowOpenNoOpener(_url);
return Promise.resolve(true); return Promise.resolve(true);
} }
+1 -1
View File
@@ -300,7 +300,7 @@ export interface IViewsService {
export interface ITreeView extends IDisposable { export interface ITreeView extends IDisposable {
dataProvider: ITreeViewDataProvider | null; dataProvider: ITreeViewDataProvider | undefined;
showCollapseAllAction: boolean; showCollapseAllAction: boolean;
@@ -607,11 +607,9 @@ class CallStackDataSource implements IAsyncDataSource<IDebugModel, CallStackItem
return threads.length === 1 ? this.getThreadChildren(<Thread>threads[0]) : Promise.resolve(threads); return threads.length === 1 ? this.getThreadChildren(<Thread>threads[0]) : Promise.resolve(threads);
} else if (isDebugSession(element)) { } else if (isDebugSession(element)) {
const childSessions = this.debugService.getModel().getSessions().filter(s => s.parentSession === element); const childSessions = this.debugService.getModel().getSessions().filter(s => s.parentSession === element);
if (childSessions.length) { const threads: CallStackItem[] = element.getAllThreads();
return Promise.resolve(childSessions);
}
return Promise.resolve(element.getAllThreads()); return Promise.resolve(threads.concat(childSessions));
} else { } else {
return this.getThreadChildren(<Thread>element); return this.getThreadChildren(<Thread>element);
} }
@@ -134,29 +134,33 @@ interface IActiveElement {
focus(): void; 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 { export class ExtensionEditor extends BaseEditor {
static readonly ID: string = 'workbench.editor.extension'; static readonly ID: string = 'workbench.editor.extension';
private iconContainer: HTMLElement; private template: IExtensionEditorTemplate | undefined;
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 extensionReadme: Cache<string> | null; private extensionReadme: Cache<string> | null;
private extensionChangelog: Cache<string> | null; private extensionChangelog: Cache<string> | null;
@@ -165,7 +169,7 @@ export class ExtensionEditor extends BaseEditor {
private layoutParticipants: ILayoutParticipant[] = []; private layoutParticipants: ILayoutParticipant[] = [];
private readonly contentDisposables = this._register(new DisposableStore()); private readonly contentDisposables = this._register(new DisposableStore());
private readonly transientDisposables = this._register(new DisposableStore()); private readonly transientDisposables = this._register(new DisposableStore());
private activeElement: IActiveElement | null; private activeElement: IActiveElement | null = null;
private editorLoadComplete: boolean = false; private editorLoadComplete: boolean = false;
constructor( constructor(
@@ -193,43 +197,43 @@ export class ExtensionEditor extends BaseEditor {
const root = append(parent, $('.extension-editor')); const root = append(parent, $('.extension-editor'));
root.tabIndex = 0; // this is required for the focus tracker on the editor root.tabIndex = 0; // this is required for the focus tracker on the editor
root.style.outline = 'none'; root.style.outline = 'none';
this.header = append(root, $('.header')); const header = append(root, $('.header'));
this.iconContainer = append(this.header, $('.icon-container')); const iconContainer = append(header, $('.icon-container'));
this.icon = append(this.iconContainer, $<HTMLImageElement>('img.icon', { draggable: false })); 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')); const title = append(details, $('.title'));
this.name = append(title, $('span.name.clickable', { title: localize('name', "Extension name") })); const name = append(title, $('span.name.clickable', { title: localize('name', "Extension name") }));
this.identifier = append(title, $('span.identifier', { title: localize('extension id', "Extension identifier") })); const identifier = append(title, $('span.identifier', { title: localize('extension id', "Extension identifier") }));
this.preview = append(title, $('span.preview', { title: localize('preview', "Preview") })); const preview = append(title, $('span.preview', { title: localize('preview', "Preview") }));
this.preview.textContent = localize('preview', "Preview"); preview.textContent = localize('preview', "Preview");
this.builtin = append(title, $('span.builtin')); const builtin = append(title, $('span.builtin'));
this.builtin.textContent = localize('builtin', "Built-in"); builtin.textContent = localize('builtin', "Built-in");
const subtitle = append(details, $('.subtitle')); 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')); const repository = append(subtitle, $('span.repository.clickable'));
this.repository.textContent = localize('repository', 'Repository'); repository.textContent = localize('repository', 'Repository');
this.repository.style.display = 'none'; repository.style.display = 'none';
this.repository.tabIndex = 0; repository.tabIndex = 0;
this.license = append(subtitle, $('span.license.clickable')); const license = append(subtitle, $('span.license.clickable'));
this.license.textContent = localize('license', 'License'); license.textContent = localize('license', 'License');
this.license.style.display = 'none'; license.style.display = 'none';
this.license.tabIndex = 0; license.tabIndex = 0;
this.description = append(details, $('.description')); const description = append(details, $('.description'));
const extensionActions = append(details, $('.actions')); const extensionActions = append(details, $('.actions'));
this.extensionActionBar = new ActionBar(extensionActions, { const extensionActionBar = this._register(new ActionBar(extensionActions, {
animated: false, animated: false,
actionViewItemProvider: (action: Action) => { actionViewItemProvider: (action: Action) => {
if (action instanceof ExtensionEditorDropDownAction) { if (action instanceof ExtensionEditorDropDownAction) {
@@ -237,29 +241,48 @@ export class ExtensionEditor extends BaseEditor {
} }
return undefined; return undefined;
} }
}); }));
this.subtextContainer = append(details, $('.subtext-container')); const subtextContainer = append(details, $('.subtext-container'));
this.subtext = append(this.subtextContainer, $('.subtext')); const subtext = append(subtextContainer, $('.subtext'));
this.ignoreActionbar = new ActionBar(this.subtextContainer, { animated: false }); const ignoreActionbar = this._register(new ActionBar(subtextContainer, { animated: false }));
this._register(this.extensionActionBar); this._register(Event.chain(extensionActionBar.onDidRun)
this._register(this.ignoreActionbar);
this._register(Event.chain(this.extensionActionBar.onDidRun)
.map(({ error }) => error) .map(({ error }) => error)
.filter(error => !!error) .filter(error => !!error)
.on(this.onError, this)); .on(this.onError, this));
this._register(Event.chain(this.ignoreActionbar.onDidRun) this._register(Event.chain(ignoreActionbar.onDidRun)
.map(({ error }) => error) .map(({ error }) => error)
.filter(error => !!error) .filter(error => !!error)
.on(this.onError, this)); .on(this.onError, this));
const body = append(root, $('.body')); 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 { 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> { 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 runningExtensions = await this.extensionService.getExtensions();
const colorThemes = await this.workbenchThemeService.getColorThemes(); const colorThemes = await this.workbenchThemeService.getColorThemes();
const fileIconThemes = await this.workbenchThemeService.getFileIconThemes(); 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.extensionChangelog = new Cache(() => createCancelablePromise(token => extension.getChangelog(token)));
this.extensionManifest = new Cache(() => createCancelablePromise(token => extension.getManifest(token))); this.extensionManifest = new Cache(() => createCancelablePromise(token => extension.getManifest(token)));
const remoteBadge = this.instantiationService.createInstance(RemoteBadgeWidget, this.iconContainer, true); const remoteBadge = this.instantiationService.createInstance(RemoteBadgeWidget, template.iconContainer, true);
const onError = Event.once(domEvent(this.icon, 'error')); const onError = Event.once(domEvent(template.icon, 'error'));
onError(() => this.icon.src = extension.iconUrlFallback, null, this.transientDisposables); onError(() => template.icon.src = extension.iconUrlFallback, null, this.transientDisposables);
this.icon.src = extension.iconUrl; template.icon.src = extension.iconUrl;
this.name.textContent = extension.displayName; template.name.textContent = extension.displayName;
this.identifier.textContent = extension.identifier.id; template.identifier.textContent = extension.identifier.id;
this.preview.style.display = extension.preview ? 'inherit' : 'none'; template.preview.style.display = extension.preview ? 'inherit' : 'none';
this.builtin.style.display = extension.type === ExtensionType.System ? 'inherit' : 'none'; template.builtin.style.display = extension.type === ExtensionType.System ? 'inherit' : 'none';
this.publisher.textContent = extension.publisherDisplayName; template.publisher.textContent = extension.publisherDisplayName;
this.description.textContent = extension.description; template.description.textContent = extension.description;
const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason(); const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason();
let recommendationsData = {}; let recommendationsData = {};
@@ -320,51 +350,50 @@ export class ExtensionEditor extends BaseEditor {
*/ */
this.telemetryService.publicLog('extensionGallery:openExtension', assign(extension.telemetryData, recommendationsData)); this.telemetryService.publicLog('extensionGallery:openExtension', assign(extension.telemetryData, recommendationsData));
toggleClass(this.name, 'clickable', !!extension.url); toggleClass(template.name, 'clickable', !!extension.url);
toggleClass(this.publisher, 'clickable', !!extension.url); toggleClass(template.publisher, 'clickable', !!extension.url);
toggleClass(this.rating, 'clickable', !!extension.url); toggleClass(template.rating, 'clickable', !!extension.url);
if (extension.url) { if (extension.url) {
this.transientDisposables.add(this.onClick(this.name, () => window.open(extension.url))); this.transientDisposables.add(this.onClick(template.name, () => window.open(extension.url)));
this.transientDisposables.add(this.onClick(this.rating, () => window.open(`${extension.url}#review-details`))); this.transientDisposables.add(this.onClick(template.rating, () => window.open(`${extension.url}#review-details`)));
this.transientDisposables.add(this.onClick(this.publisher, () => { this.transientDisposables.add(this.onClick(template.publisher, () => {
this.viewletService.openViewlet(VIEWLET_ID, true) this.viewletService.openViewlet(VIEWLET_ID, true)
.then(viewlet => viewlet as IExtensionsViewlet) .then(viewlet => viewlet as IExtensionsViewlet)
.then(viewlet => viewlet.search(`publisher:"${extension.publisherDisplayName}"`)); .then(viewlet => viewlet.search(`publisher:"${extension.publisherDisplayName}"`));
})); }));
if (extension.licenseUrl) { if (extension.licenseUrl) {
this.transientDisposables.add(this.onClick(this.license, () => window.open(extension.licenseUrl))); this.transientDisposables.add(this.onClick(template.license, () => window.open(extension.licenseUrl)));
this.license.style.display = 'initial'; template.license.style.display = 'initial';
} else { } else {
this.license.style.display = 'none'; template.license.style.display = 'none';
} }
} else { } else {
this.license.style.display = 'none'; template.license.style.display = 'none';
} }
// {{SQL CARBON EDIT}} add license url // {{SQL CARBON EDIT}} add license url
if (extension.licenseUrl) { if (extension.licenseUrl) {
this.license.onclick = finalHandler(() => window.open(extension.licenseUrl)); template.license.onclick = finalHandler(() => window.open(extension.licenseUrl));
this.license.style.display = 'initial'; template.license.style.display = 'initial';
} else { } else {
this.license.onclick = null; template.license.onclick = null;
this.license.style.display = 'none'; template.license.style.display = 'none';
} }
// {{SQL CARBON EDIT}} - End // {{SQL CARBON EDIT}} - End
if (extension.repository) { if (extension.repository) {
this.transientDisposables.add(this.onClick(this.repository, () => window.open(extension.repository))); this.transientDisposables.add(this.onClick(template.repository, () => window.open(extension.repository)));
this.repository.style.display = 'initial'; template.repository.style.display = 'initial';
} }
else { else {
this.repository.style.display = 'none'; template.repository.style.display = 'none';
} }
const widgets = [ const widgets = [
remoteBadge, remoteBadge,
// {{SQL CARBON EDIT}} Remove the widgets // this.instantiationService.createInstance(InstallCountWidget, template.installCount, false), {{SQL CARBON EDIT}} Remove the widgets
// this.instantiationService.createInstance(InstallCountWidget, this.installCount, false), // this.instantiationService.createInstance(RatingsWidget, template.rating, false) {{SQL CARBON EDIT}} Remove the widgets
// this.instantiationService.createInstance(RatingsWidget, this.rating, false)
]; ];
const reloadAction = this.instantiationService.createInstance(ReloadAction); const reloadAction = this.instantiationService.createInstance(ReloadAction);
const combinedInstallAction = this.instantiationService.createInstance(CombinedInstallAction); const combinedInstallAction = this.instantiationService.createInstance(CombinedInstallAction);
@@ -387,20 +416,20 @@ export class ExtensionEditor extends BaseEditor {
const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets]); const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets]);
extensionContainers.extension = extension; extensionContainers.extension = extension;
this.extensionActionBar.clear(); template.extensionActionBar.clear();
this.extensionActionBar.push(actions, { icon: true, label: true }); template.extensionActionBar.push(actions, { icon: true, label: true });
for (const disposable of [...actions, ...widgets, extensionContainers]) { for (const disposable of [...actions, ...widgets, extensionContainers]) {
this.transientDisposables.add(disposable); this.transientDisposables.add(disposable);
} }
this.setSubText(extension, reloadAction); this.setSubText(extension, reloadAction, template);
this.content.innerHTML = ''; // Clear content before setting navbar actions. template.content.innerHTML = ''; // Clear content before setting navbar actions.
this.navbar.clear(); template.navbar.clear();
this.navbar.onChange(this.onNavbarChange.bind(this, extension), this, this.transientDisposables); template.navbar.onChange(e => this.onNavbarChange(extension, e, template), this, this.transientDisposables);
if (extension.hasReadme()) { 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() this.extensionManifest.get()
.promise .promise
@@ -409,25 +438,23 @@ export class ExtensionEditor extends BaseEditor {
combinedInstallAction.manifest = manifest; combinedInstallAction.manifest = manifest;
} }
if (extension.extensionPack.length) { 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) { 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()) { 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) { 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; this.editorLoadComplete = true;
}); });
return super.setInput(input, options, token);
} }
private setSubText(extension: IExtension, reloadAction: ReloadAction): void { private setSubText(extension: IExtension, reloadAction: ReloadAction, template: IExtensionEditorTemplate): void {
hide(this.subtextContainer); hide(template.subtextContainer);
const ignoreAction = this.instantiationService.createInstance(IgnoreExtensionRecommendationAction); const ignoreAction = this.instantiationService.createInstance(IgnoreExtensionRecommendationAction);
const undoIgnoreAction = this.instantiationService.createInstance(UndoIgnoreExtensionRecommendationAction); const undoIgnoreAction = this.instantiationService.createInstance(UndoIgnoreExtensionRecommendationAction);
@@ -436,23 +463,23 @@ export class ExtensionEditor extends BaseEditor {
ignoreAction.enabled = false; ignoreAction.enabled = false;
undoIgnoreAction.enabled = false; undoIgnoreAction.enabled = false;
this.ignoreActionbar.clear(); template.ignoreActionbar.clear();
this.ignoreActionbar.push([ignoreAction, undoIgnoreAction], { icon: true, label: true }); template.ignoreActionbar.push([ignoreAction, undoIgnoreAction], { icon: true, label: true });
this.transientDisposables.add(ignoreAction); this.transientDisposables.add(ignoreAction);
this.transientDisposables.add(undoIgnoreAction); this.transientDisposables.add(undoIgnoreAction);
const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason(); const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason();
if (extRecommendations[extension.identifier.id.toLowerCase()]) { if (extRecommendations[extension.identifier.id.toLowerCase()]) {
ignoreAction.enabled = true; ignoreAction.enabled = true;
this.subtext.textContent = extRecommendations[extension.identifier.id.toLowerCase()].reasonText; template.subtext.textContent = extRecommendations[extension.identifier.id.toLowerCase()].reasonText;
show(this.subtextContainer); show(template.subtextContainer);
} else if (this.extensionTipsService.getAllIgnoredRecommendations().global.indexOf(extension.identifier.id.toLowerCase()) !== -1) { } else if (this.extensionTipsService.getAllIgnoredRecommendations().global.indexOf(extension.identifier.id.toLowerCase()) !== -1) {
undoIgnoreAction.enabled = true; undoIgnoreAction.enabled = true;
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.");
show(this.subtextContainer); show(template.subtextContainer);
} }
else { else {
this.subtext.textContent = ''; template.subtext.textContent = '';
} }
this.extensionTipsService.onRecommendationChange(change => { this.extensionTipsService.onRecommendationChange(change => {
@@ -462,28 +489,28 @@ export class ExtensionEditor extends BaseEditor {
const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason(); const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason();
if (extRecommendations[extension.identifier.id.toLowerCase()]) { if (extRecommendations[extension.identifier.id.toLowerCase()]) {
ignoreAction.enabled = true; ignoreAction.enabled = true;
this.subtext.textContent = extRecommendations[extension.identifier.id.toLowerCase()].reasonText; template.subtext.textContent = extRecommendations[extension.identifier.id.toLowerCase()].reasonText;
} }
} else { } else {
undoIgnoreAction.enabled = true; undoIgnoreAction.enabled = true;
ignoreAction.enabled = false; 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 => { this.transientDisposables.add(reloadAction.onDidChange(e => {
if (e.tooltip) { if (e.tooltip) {
this.subtext.textContent = reloadAction.tooltip; template.subtext.textContent = reloadAction.tooltip;
show(this.subtextContainer); show(template.subtextContainer);
ignoreAction.enabled = false; ignoreAction.enabled = false;
undoIgnoreAction.enabled = false; undoIgnoreAction.enabled = false;
} }
if (e.enabled === true) { if (e.enabled === true) {
show(this.subtextContainer); show(template.subtextContainer);
} }
if (e.enabled === false) { 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) { if (this.editorLoadComplete) {
/* __GDPR__ /* __GDPR__
"extensionEditor:navbarChange" : { "extensionEditor:navbarChange" : {
@@ -521,9 +548,10 @@ export class ExtensionEditor extends BaseEditor {
} }
this.contentDisposables.clear(); this.contentDisposables.clear();
this.content.innerHTML = ''; template.content.innerHTML = '';
this.activeElement = null; this.activeElement = null;
this.open(id, extension) if (id) {
this.open(id, extension, template)
.then(activeElement => { .then(activeElement => {
this.activeElement = activeElement; this.activeElement = activeElement;
if (focus) { if (focus) {
@@ -531,20 +559,21 @@ export class ExtensionEditor extends BaseEditor {
} }
}); });
} }
}
private open(id: string, extension: IExtension): Promise<IActiveElement | null> { private open(id: string, extension: IExtension, template: IExtensionEditorTemplate): Promise<IActiveElement | null> {
switch (id) { switch (id) {
case NavbarSection.Readme: return this.openReadme(); case NavbarSection.Readme: return this.openReadme(template);
case NavbarSection.Contributions: return this.openContributions(); case NavbarSection.Contributions: return this.openContributions(template);
case NavbarSection.Changelog: return this.openChangelog(); case NavbarSection.Changelog: return this.openChangelog(template);
case NavbarSection.Dependencies: return this.openDependencies(extension); case NavbarSection.Dependencies: return this.openDependencies(extension, template);
case NavbarSection.ExtensionPack: return this.openExtensionPack(extension); case NavbarSection.ExtensionPack: return this.openExtensionPack(extension, template);
} }
return Promise.resolve(null); return Promise.resolve(null);
} }
private openMarkdown(cacheResult: CacheResult<string>, noContentCopy: string): Promise<IActiveElement> { private openMarkdown(cacheResult: CacheResult<string>, noContentCopy: string, template: IExtensionEditorTemplate): Promise<IActiveElement> {
return this.loadContents(() => cacheResult) return this.loadContents(() => cacheResult, template)
.then(marked.parse) .then(marked.parse)
.then(content => this.renderBody(content)) .then(content => this.renderBody(content))
.then(removeEmbeddedSVGs) .then(removeEmbeddedSVGs)
@@ -556,7 +585,7 @@ export class ExtensionEditor extends BaseEditor {
{ {
svgWhiteList: this.extensionsWorkbenchService.allowedBadgeProviders, svgWhiteList: this.extensionsWorkbenchService.allowedBadgeProviders,
}); });
webviewElement.mountTo(this.content); webviewElement.mountTo(template.content);
this.contentDisposables.add(webviewElement.onDidFocus(() => this.fireOnDidFocus())); this.contentDisposables.add(webviewElement.onDidFocus(() => this.fireOnDidFocus()));
const removeLayoutParticipant = arrays.insert(this.layoutParticipants, webviewElement); const removeLayoutParticipant = arrays.insert(this.layoutParticipants, webviewElement);
this.contentDisposables.add(toDisposable(removeLayoutParticipant)); this.contentDisposables.add(toDisposable(removeLayoutParticipant));
@@ -575,7 +604,7 @@ export class ExtensionEditor extends BaseEditor {
return webviewElement; return webviewElement;
}) })
.then(undefined, () => { .then(undefined, () => {
const p = append(this.content, $('p.nocontent')); const p = append(template.content, $('p.nocontent'));
p.textContent = noContentCopy; p.textContent = noContentCopy;
return p; return p;
}); });
@@ -769,17 +798,17 @@ export class ExtensionEditor extends BaseEditor {
</html>`; </html>`;
} }
private openReadme(): Promise<IActiveElement> { private openReadme(template: IExtensionEditorTemplate): Promise<IActiveElement> {
return this.openMarkdown(this.extensionReadme!.get(), localize('noReadme', "No README available.")); return this.openMarkdown(this.extensionReadme!.get(), localize('noReadme', "No README available."), template);
} }
private openChangelog(): Promise<IActiveElement> { private openChangelog(template: IExtensionEditorTemplate): Promise<IActiveElement> {
return this.openMarkdown(this.extensionChangelog!.get(), localize('noChangelog', "No Changelog available.")); 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' }); const content = $('div', { class: 'subcontent', tabindex: '0' });
return this.loadContents(() => this.extensionManifest!.get()) return this.loadContents(() => this.extensionManifest!.get(), template)
.then(manifest => { .then(manifest => {
if (!manifest) { if (!manifest) {
return content; return content;
@@ -811,28 +840,28 @@ export class ExtensionEditor extends BaseEditor {
const isEmpty = !renders.some(x => x); const isEmpty = !renders.some(x => x);
if (isEmpty) { if (isEmpty) {
append(content, $('p.nocontent')).textContent = localize('noContributions', "No Contributions"); append(content, $('p.nocontent')).textContent = localize('noContributions', "No Contributions");
append(this.content, content); append(template.content, content);
} else { } else {
append(this.content, scrollableContent.getDomNode()); append(template.content, scrollableContent.getDomNode());
this.contentDisposables.add(scrollableContent); this.contentDisposables.add(scrollableContent);
} }
return content; return content;
}, () => { }, () => {
append(content, $('p.nocontent')).textContent = localize('noContributions', "No Contributions"); append(content, $('p.nocontent')).textContent = localize('noContributions', "No Contributions");
append(this.content, content); append(template.content, content);
return content; return content;
}); });
} }
private openDependencies(extension: IExtension): Promise<IActiveElement> { private openDependencies(extension: IExtension, template: IExtensionEditorTemplate): Promise<IActiveElement> {
if (arrays.isFalsyOrEmpty(extension.dependencies)) { if (arrays.isFalsyOrEmpty(extension.dependencies)) {
append(this.content, $('p.nocontent')).textContent = localize('noDependencies', "No Dependencies"); append(template.content, $('p.nocontent')).textContent = localize('noDependencies', "No Dependencies");
return Promise.resolve(this.content); return Promise.resolve(template.content);
} }
const content = $('div', { class: 'subcontent' }); const content = $('div', { class: 'subcontent' });
const scrollableContent = new DomScrollableElement(content, {}); const scrollableContent = new DomScrollableElement(content, {});
append(this.content, scrollableContent.getDomNode()); append(template.content, scrollableContent.getDomNode());
this.contentDisposables.add(scrollableContent); this.contentDisposables.add(scrollableContent);
const dependenciesTree = this.instantiationService.createInstance(ExtensionsTree, new ExtensionData(extension, null, extension => extension.dependencies || [], this.extensionsWorkbenchService), content); 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(); } }); 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 content = $('div', { class: 'subcontent' });
const scrollableContent = new DomScrollableElement(content, {}); const scrollableContent = new DomScrollableElement(content, {});
append(this.content, scrollableContent.getDomNode()); append(template.content, scrollableContent.getDomNode());
this.contentDisposables.add(scrollableContent); this.contentDisposables.add(scrollableContent);
const extensionsPackTree = this.instantiationService.createInstance(ExtensionsTree, new ExtensionData(extension, null, extension => extension.extensionPack || [], this.extensionsWorkbenchService), content); 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; return null;
} }
private loadContents<T>(loadingTask: () => CacheResult<T>): Promise<T> { private loadContents<T>(loadingTask: () => CacheResult<T>, template: IExtensionEditorTemplate): Promise<T> {
addClass(this.content, 'loading'); addClass(template.content, 'loading');
const result = loadingTask(); const result = loadingTask();
const onDone = () => removeClass(this.content, 'loading'); const onDone = () => removeClass(template.content, 'loading');
result.promise.then(onDone, onDone); result.promise.then(onDone, onDone);
this.contentDisposables.add(toDisposable(() => result.dispose())); this.contentDisposables.add(toDisposable(() => result.dispose()));
@@ -3097,7 +3097,10 @@ interface IExtensionPickItem extends IQuickPickItem {
export class InstallLocalExtensionsInRemoteAction extends Action { export class InstallLocalExtensionsInRemoteAction extends Action {
private extensions: IExtension[] | undefined = undefined;
constructor( constructor(
private readonly selectAndInstall: boolean,
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
@@ -3109,32 +3112,56 @@ export class InstallLocalExtensionsInRemoteAction extends Action {
) { ) {
super('workbench.extensions.actions.installLocalExtensionsInRemote'); super('workbench.extensions.actions.installLocalExtensionsInRemote');
this.update(); 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 { get label(): string {
return this.extensionManagementServerService.remoteExtensionManagementServer ? if (this.extensionManagementServerService.remoteExtensionManagementServer) {
localize('install local extensions', "Install Local Extensions in {0}...", this.extensionManagementServerService.remoteExtensionManagementServer.label) : ''; 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 { 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[] { async run(): Promise<void> {
return this.extensionsWorkbenchService.local.filter(extension => { 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); const action = this.instantiationService.createInstance(RemoteInstallAction);
action.extension = extension; action.extension = extension;
return action.enabled; return action.enabled;
}); });
} }
async run(): Promise<void> { private async selectAndInstallLocalExtensions(): Promise<void> {
this.selectAndInstallLocalExtensions();
return Promise.resolve();
}
private selectAndInstallLocalExtensions(): void {
const quickPick = this.quickInputService.createQuickPick<IExtensionPickItem>(); const quickPick = this.quickInputService.createQuickPick<IExtensionPickItem>();
quickPick.busy = true; quickPick.busy = true;
const disposable = quickPick.onDidAccept(() => { const disposable = quickPick.onDidAccept(() => {
@@ -3144,7 +3171,7 @@ export class InstallLocalExtensionsInRemoteAction extends Action {
this.onDidAccept(quickPick.selectedItems); this.onDidAccept(quickPick.selectedItems);
}); });
quickPick.show(); quickPick.show();
const localExtensionsToInstall = this.getLocalExtensionsToInstall(); const localExtensionsToInstall = await this.queryExtensionsToInstall();
quickPick.busy = false; quickPick.busy = false;
if (localExtensionsToInstall.length) { if (localExtensionsToInstall.length) {
quickPick.title = localize('install local extensions title', "Install Local Extensions in {0}", this.extensionManagementServerService.remoteExtensionManagementServer!.label); quickPick.title = localize('install local extensions title', "Install Local Extensions in {0}", this.extensionManagementServerService.remoteExtensionManagementServer!.label);
@@ -156,7 +156,7 @@ export class UnknownExtensionRenderer implements IListRenderer<ITreeNode<IExtens
class OpenExtensionAction extends Action { class OpenExtensionAction extends Action {
private _extensionData: IExtensionData; private _extensionData: IExtensionData | undefined;
constructor(@IExtensionsWorkbenchService private readonly extensionsWorkdbenchService: IExtensionsWorkbenchService) { constructor(@IExtensionsWorkbenchService private readonly extensionsWorkdbenchService: IExtensionsWorkbenchService) {
super('extensions.action.openExtension', ''); super('extensions.action.openExtension', '');
@@ -166,12 +166,11 @@ class OpenExtensionAction extends Action {
this._extensionData = extension; this._extensionData = extension;
} }
public get extensionData(): IExtensionData {
return this._extensionData;
}
run(sideByside: boolean): Promise<any> { 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();
} }
} }
@@ -22,7 +22,7 @@ import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, AutoUpdate
import { import {
ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowDisabledExtensionsAction, ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowDisabledExtensionsAction,
ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction, ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction,
EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction, InstallLocalExtensionsInRemoteAction EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction
} from 'vs/workbench/contrib/extensions/browser/extensionsActions'; } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionEnablementService, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/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 { 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 nonEmptyWorkspaceContextKey: IContextKey<boolean>;
private defaultViewsContextKey: IContextKey<boolean>; private defaultViewsContextKey: IContextKey<boolean>;
private searchMarketplaceExtensionsContextKey: IContextKey<boolean>; private searchMarketplaceExtensionsContextKey: IContextKey<boolean>;
@@ -337,12 +338,10 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
private defaultRecommendedExtensionsContextKey: IContextKey<boolean>; private defaultRecommendedExtensionsContextKey: IContextKey<boolean>;
private searchDelayer: Delayer<void>; private searchDelayer: Delayer<void>;
private root: HTMLElement; private root: HTMLElement | undefined;
private searchBox: SuggestEnabledInput | undefined;
private searchBox: SuggestEnabledInput; private primaryActions: IAction[] | undefined;
private extensionsBox: HTMLElement; private secondaryActions: IAction[] | null = null;
private primaryActions: IAction[];
private secondaryActions: IAction[] | null;
private readonly searchViewletState: MementoObject; private readonly searchViewletState: MementoObject;
constructor( constructor(
@@ -352,7 +351,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
@IInstantiationService instantiationService: IInstantiationService, @IInstantiationService instantiationService: IInstantiationService,
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
@INotificationService private readonly notificationService: INotificationService, @INotificationService private readonly notificationService: INotificationService,
@IViewletService private readonly viewletService: IViewletService, @IViewletService private readonly viewletService: IViewletService,
@IThemeService themeService: IThemeService, @IThemeService themeService: IThemeService,
@@ -422,32 +420,35 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
this._register(attachSuggestEnabledInputBoxStyler(this.searchBox, this.themeService)); this._register(attachSuggestEnabledInputBoxStyler(this.searchBox, this.themeService));
const _searchChange = new Emitter<string>();
this.onSearchChange = _searchChange.event;
this._register(this.searchBox.onInputDidChange(() => { this._register(this.searchBox.onInputDidChange(() => {
this.triggerSearch(); this.triggerSearch();
_searchChange.fire(this.searchBox.getValue()); this._onSearchChange.fire(this.searchBox!.getValue());
}, this)); }, this));
this._register(this.searchBox.onShouldFocusResults(() => this.focusListView(), this)); this._register(this.searchBox.onShouldFocusResults(() => this.focusListView(), this));
this._register(this.onDidChangeVisibility(visible => { this._register(this.onDidChangeVisibility(visible => {
if (visible) { if (visible) {
this.searchBox.focus(); this.searchBox!.focus();
} }
})); }));
this.extensionsBox = append(this.root, $('.extensions')); super.create(append(this.root, $('.extensions')));
super.create(this.extensionsBox);
} }
focus(): void { focus(): void {
if (this.searchBox) {
this.searchBox.focus(); this.searchBox.focus();
} }
}
layout(dimension: Dimension): void { layout(dimension: Dimension): void {
if (this.root) {
toggleClass(this.root, 'narrow', dimension.width <= 300); toggleClass(this.root, 'narrow', dimension.width <= 300);
}
if (this.searchBox) {
this.searchBox.layout({ height: 20, width: dimension.width - 34 }); this.searchBox.layout({ height: 20, width: dimension.width - 34 });
}
super.layout(new Dimension(dimension.width, dimension.height - 38)); super.layout(new Dimension(dimension.width, dimension.height - 38));
} }
@@ -458,7 +459,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
getActions(): IAction[] { getActions(): IAction[] {
if (!this.primaryActions) { if (!this.primaryActions) {
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; return this.primaryActions;
@@ -484,7 +485,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
this.instantiationService.createInstance(CheckForUpdatesAction, CheckForUpdatesAction.ID, CheckForUpdatesAction.LABEL), 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.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.instantiationService.createInstance(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL),
...(this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer ? [this.instantiationService.createInstance(InstallLocalExtensionsInRemoteAction)] : []),
new Separator(), new Separator(),
this.instantiationService.createInstance(DisableAllAction, DisableAllAction.ID, DisableAllAction.LABEL), this.instantiationService.createInstance(DisableAllAction, DisableAllAction.ID, DisableAllAction.LABEL),
this.instantiationService.createInstance(EnableAllAction, EnableAllAction.ID, EnableAllAction.LABEL) this.instantiationService.createInstance(EnableAllAction, EnableAllAction.ID, EnableAllAction.LABEL)
@@ -495,22 +495,24 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
} }
search(value: string): void { search(value: string): void {
if (this.searchBox) {
const event = new Event('input', { bubbles: true }) as SearchInputEvent; const event = new Event('input', { bubbles: true }) as SearchInputEvent;
event.immediate = true; event.immediate = true;
this.searchBox.setValue(value); this.searchBox.setValue(value);
} }
}
private triggerSearch(immediate = false): void { private triggerSearch(): void {
this.searchDelayer.trigger(() => this.doSearch(), immediate || !this.searchBox.getValue() ? 0 : 500).then(undefined, err => this.onError(err)); this.searchDelayer.trigger(() => this.doSearch(), this.searchBox && this.searchBox.getValue() ? 500 : 0).then(undefined, err => this.onError(err));
} }
private normalizedQuery(): string { 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 { protected saveState(): void {
const value = this.searchBox.getValue(); const value = this.searchBox ? this.searchBox.getValue() : '';
if (ExtensionsListView.isLocalExtensionsQuery(value)) { if (ExtensionsListView.isLocalExtensionsQuery(value)) {
this.searchViewletState['query.value'] = value; this.searchViewletState['query.value'] = value;
} else { } else {
@@ -14,11 +14,11 @@ import { IExtensionManagementServer, IExtensionManagementServerService, IExtensi
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; 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 { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Delegate, Renderer, IExtensionsViewState } from 'vs/workbench/contrib/extensions/browser/extensionsList'; import { Delegate, Renderer, IExtensionsViewState } from 'vs/workbench/contrib/extensions/browser/extensionsList';
import { IExtension, IExtensionsWorkbenchService, ExtensionState } from '../common/extensions'; import { IExtension, IExtensionsWorkbenchService, ExtensionState } from 'vs/workbench/contrib/extensions/common/extensions';
import { Query } from '../common/extensionQuery'; import { Query } from 'vs/workbench/contrib/extensions/common/extensionQuery';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IThemeService } from 'vs/platform/theme/common/themeService';
import { attachBadgeStyler } from 'vs/platform/theme/common/styler'; 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 { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
import { ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { InstallWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, ManageExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { InstallWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, ManageExtensionAction, InstallLocalExtensionsInRemoteAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { WorkbenchPagedList } from 'vs/platform/list/browser/listService'; import { WorkbenchPagedList } from 'vs/platform/list/browser/listService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
@@ -74,15 +74,16 @@ class ExtensionListViewWarning extends Error { }
export class ExtensionsListView extends ViewletPanel { export class ExtensionsListView extends ViewletPanel {
private readonly server: IExtensionManagementServer | undefined; protected readonly server: IExtensionManagementServer | undefined;
private messageContainer: HTMLElement; private bodyTemplate: {
private messageSeverityIcon: HTMLElement; messageContainer: HTMLElement;
private messageBox: HTMLElement; messageSeverityIcon: HTMLElement;
private extensionsList: HTMLElement; messageBox: HTMLElement;
private badge: CountBadge; extensionsList: HTMLElement;
protected badgeContainer: HTMLElement; } | undefined;
private list: WorkbenchPagedList<IExtension> | null; private badge: CountBadge | undefined;
private queryRequest: { query: string, request: CancelablePromise<IPagedModel<IExtension>> } | null; private list: WorkbenchPagedList<IExtension> | null = null;
private queryRequest: { query: string, request: CancelablePromise<IPagedModel<IExtension>> } | null = null;
constructor( constructor(
options: ExtensionsListViewOptions, options: ExtensionsListViewOptions,
@@ -104,31 +105,27 @@ export class ExtensionsListView extends ViewletPanel {
@IProductService protected readonly productService: IProductService, @IProductService protected readonly productService: IProductService,
@IContextKeyService contextKeyService: IContextKeyService, @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; this.server = options.server;
} }
protected renderHeader(container: HTMLElement): void { protected renderHeader(container: HTMLElement): void {
this.renderHeaderTitle(container); addClass(container, 'extension-view-header');
} super.renderHeader(container);
renderHeaderTitle(container: HTMLElement): void { this.badge = new CountBadge(append(container, $('.count-badge-wrapper')));
super.renderHeaderTitle(container, this.title);
this.badgeContainer = append(container, $('.count-badge-wrapper'));
this.badge = new CountBadge(this.badgeContainer);
this._register(attachBadgeStyler(this.badge, this.themeService)); this._register(attachBadgeStyler(this.badge, this.themeService));
} }
renderBody(container: HTMLElement): void { renderBody(container: HTMLElement): void {
this.extensionsList = append(container, $('.extensions-list')); const extensionsList = append(container, $('.extensions-list'));
this.messageContainer = append(container, $('.message-container')); const messageContainer = append(container, $('.message-container'));
this.messageSeverityIcon = append(this.messageContainer, $('')); const messageSeverityIcon = append(messageContainer, $(''));
this.messageBox = append(this.messageContainer, $('.message')); const messageBox = append(messageContainer, $('.message'));
const delegate = new Delegate(); const delegate = new Delegate();
const extensionsViewState = new ExtensionsViewState(); const extensionsViewState = new ExtensionsViewState();
const renderer = this.instantiationService.createInstance(Renderer, 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"), ariaLabel: localize('extensions', "Extensions"),
multipleSelectionSupport: false, multipleSelectionSupport: false,
setRowLineHeight: false, setRowLineHeight: false,
@@ -148,10 +145,19 @@ export class ExtensionsListView extends ViewletPanel {
.map(e => e.elements[0]) .map(e => e.elements[0])
.filter(e => !!e) .filter(e => !!e)
.on(this.pin, this)); .on(this.pin, this));
this.bodyTemplate = {
extensionsList,
messageBox,
messageContainer,
messageSeverityIcon
};
} }
protected layoutBody(height: number, width: number): void { 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) { if (this.list) {
this.list.layout(height, width); 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[]> { private getSearchExperiments(): Promise<IExperiment[]> {
if (!this._searchExperiments) { if (!this._searchExperiments) {
this._searchExperiments = this.experimentService.getExperimentsByType(ExperimentActionType.ExtensionSearchResults); this._searchExperiments = this.experimentService.getExperimentsByType(ExperimentActionType.ExtensionSearchResults);
@@ -773,24 +779,27 @@ export class ExtensionsListView extends ViewletPanel {
this.list.scrollTop = 0; this.list.scrollTop = 0;
const count = this.count(); const count = this.count();
toggleClass(this.extensionsList, 'hidden', count === 0); if (this.bodyTemplate && this.badge) {
toggleClass(this.messageContainer, 'hidden', count > 0);
toggleClass(this.bodyTemplate.extensionsList, 'hidden', count === 0);
toggleClass(this.bodyTemplate.messageContainer, 'hidden', count > 0);
this.badge.setCount(count); this.badge.setCount(count);
if (count === 0 && this.isBodyVisible()) { if (count === 0 && this.isBodyVisible()) {
if (error) { if (error) {
if (error instanceof ExtensionListViewWarning) { if (error instanceof ExtensionListViewWarning) {
this.messageSeverityIcon.className = SeverityIcon.className(Severity.Warning); this.bodyTemplate.messageSeverityIcon.className = SeverityIcon.className(Severity.Warning);
this.messageBox.textContent = getErrorMessage(error); this.bodyTemplate.messageBox.textContent = getErrorMessage(error);
} else { } else {
this.messageSeverityIcon.className = SeverityIcon.className(Severity.Error); this.bodyTemplate.messageSeverityIcon.className = SeverityIcon.className(Severity.Error);
this.messageBox.textContent = localize('error', "Error while loading extensions. {0}", getErrorMessage(error)); this.bodyTemplate.messageBox.textContent = localize('error', "Error while loading extensions. {0}", getErrorMessage(error));
} }
} else { } else {
this.messageSeverityIcon.className = ''; this.bodyTemplate.messageSeverityIcon.className = '';
this.messageBox.textContent = localize('no extensions found', "No extensions found."); this.bodyTemplate.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()); 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 { export class EnabledExtensionsView extends ExtensionsListView {
@@ -1030,7 +1048,7 @@ export class RecommendedExtensionsView extends ExtensionsListView {
export class WorkspaceRecommendedExtensionsView extends ExtensionsListView { export class WorkspaceRecommendedExtensionsView extends ExtensionsListView {
private readonly recommendedExtensionsQuery = '@recommended:workspace'; private readonly recommendedExtensionsQuery = '@recommended:workspace';
private installAllAction: InstallWorkspaceRecommendedExtensionsAction; private installAllAction: InstallWorkspaceRecommendedExtensionsAction | undefined;
renderBody(container: HTMLElement): void { renderBody(container: HTMLElement): void {
super.renderBody(container); super.renderBody(container);
@@ -1040,25 +1058,15 @@ export class WorkspaceRecommendedExtensionsView extends ExtensionsListView {
this._register(this.contextService.onDidChangeWorkbenchState(() => this.update())); this._register(this.contextService.onDidChangeWorkbenchState(() => this.update()));
} }
renderHeader(container: HTMLElement): void { getActions(): IAction[] {
super.renderHeader(container); if (!this.installAllAction) {
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, [])); 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'; this.installAllAction.class = 'octicon octicon-cloud-download';
configureWorkspaceFolderAction.class = 'octicon octicon-pencil'; }
actionbar.push([this.installAllAction], { icon: true, label: false }); const configureWorkspaceFolderAction = this._register(this.instantiationService.createInstance(ConfigureWorkspaceFolderRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction.ID, ConfigureWorkspaceFolderRecommendedExtensionsAction.LABEL));
actionbar.push([configureWorkspaceFolderAction], { icon: true, label: false }); configureWorkspaceFolderAction.class = 'octicon octicon-pencil';
return [this.installAllAction, configureWorkspaceFolderAction];
} }
async show(query: string): Promise<IPagedModel<IExtension>> { async show(query: string): Promise<IPagedModel<IExtension>> {
@@ -1073,9 +1081,11 @@ export class WorkspaceRecommendedExtensionsView extends ExtensionsListView {
this.setRecommendationsToInstall(); this.setRecommendationsToInstall();
} }
private setRecommendationsToInstall(): Promise<void> { private async setRecommendationsToInstall(): Promise<void> {
return this.getRecommendationsToInstall() const recommendations = await this.getRecommendationsToInstall();
.then(recommendations => { this.installAllAction.recommendations = recommendations; }); if (this.installAllAction) {
this.installAllAction.recommendations = recommendations;
}
} }
private getRecommendationsToInstall(): Promise<IExtensionRecommendation[]> { private getRecommendationsToInstall(): Promise<IExtensionRecommendation[]> {
@@ -18,9 +18,9 @@ import { Emitter, Event } from 'vs/base/common/event';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
export abstract class ExtensionWidget extends Disposable implements IExtensionContainer { export abstract class ExtensionWidget extends Disposable implements IExtensionContainer {
private _extension: IExtension; private _extension: IExtension | null = null;
get extension(): IExtension { return this._extension; } get extension(): IExtension | null { return this._extension; }
set extension(extension: IExtension) { this._extension = extension; this.update(); } set extension(extension: IExtension | null) { this._extension = extension; this.update(); }
update(): void { this.render(); } update(): void { this.render(); }
abstract render(): void; abstract render(): void;
} }
@@ -183,7 +183,7 @@ export class RecommendationWidget extends ExtensionWidget {
private element?: HTMLElement; private element?: HTMLElement;
private readonly disposables = this._register(new DisposableStore()); private readonly disposables = this._register(new DisposableStore());
private _tooltip: string; private _tooltip: string = '';
get tooltip(): string { return this._tooltip; } get tooltip(): string { return this._tooltip; }
set tooltip(tooltip: string) { set tooltip(tooltip: string) {
if (this._tooltip !== tooltip) { if (this._tooltip !== tooltip) {
@@ -500,7 +500,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
private readonly _onChange: Emitter<IExtension | undefined> = new Emitter<IExtension | undefined>(); private readonly _onChange: Emitter<IExtension | undefined> = new Emitter<IExtension | undefined>();
get onChange(): Event<IExtension | undefined> { return this._onChange.event; } get onChange(): Event<IExtension | undefined> { return this._onChange.event; }
private _extensionAllowedBadgeProviders: string[]; private _extensionAllowedBadgeProviders: string[] | undefined;
private installing: IExtension[] = []; private installing: IExtension[] = [];
constructor( constructor(
@@ -1151,12 +1151,12 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
} }
private _ignoredAutoUpdateExtensions: string[]; private _ignoredAutoUpdateExtensions: string[] | undefined;
private get ignoredAutoUpdateExtensions(): string[] { private get ignoredAutoUpdateExtensions(): string[] {
if (!this._ignoredAutoUpdateExtensions) { if (!this._ignoredAutoUpdateExtensions) {
this._ignoredAutoUpdateExtensions = JSON.parse(this.storageService.get('extensions.ignoredAutoUpdateExtension', StorageScope.GLOBAL, '[]') || '[]'); this._ignoredAutoUpdateExtensions = JSON.parse(this.storageService.get('extensions.ignoredAutoUpdateExtension', StorageScope.GLOBAL, '[]') || '[]');
} }
return this._ignoredAutoUpdateExtensions; return this._ignoredAutoUpdateExtensions!;
} }
private set ignoredAutoUpdateExtensions(extensionIds: string[]) { private set ignoredAutoUpdateExtensions(extensionIds: string[]) {
@@ -6,8 +6,3 @@
.monaco-workbench .activitybar > .content .monaco-action-bar .action-label.extensions { .monaco-workbench .activitybar > .content .monaco-action-bar .action-label.extensions {
-webkit-mask: url('extensions-activity-bar.svg') no-repeat 50% 50%; -webkit-mask: url('extensions-activity-bar.svg') no-repeat 50% 50%;
} }
.extensions .split-view-view .panel-header .count-badge-wrapper {
position: absolute;
right: 12px;
}
@@ -27,13 +27,16 @@
height: calc(100% - 38px); height: calc(100% - 38px);
} }
.extensions-viewlet > .extensions .list-actionbar-container .monaco-action-bar .action-item > .octicon { .extensions-viewlet > .extensions .extension-view-header .monaco-action-bar {
font-size: 12px; margin-right: 4px;
line-height: 1;
margin-right: 10px;
} }
.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; display: none;
} }
@@ -44,7 +47,7 @@
} }
.extensions-viewlet > .extensions .panel-header { .extensions-viewlet > .extensions .panel-header {
padding-right: 28px; padding-right: 6px;
} }
.extensions-viewlet > .extensions .panel-header > .title { .extensions-viewlet > .extensions .panel-header > .title {
@@ -22,7 +22,7 @@ export class RemoteExtensionsInstaller extends Disposable implements IWorkbenchC
) { ) {
super(); super();
if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { 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()); CommandsRegistry.registerCommand('workbench.extensions.installLocalExtensions', () => installLocalExtensionsInRemoteAction.run());
let disposable = Disposable.None; let disposable = Disposable.None;
const appendMenuItem = () => { const appendMenuItem = () => {
@@ -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 { coalesce } from 'vs/base/common/arrays';
import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree';
import { ExplorerItem, NewExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel'; 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}} // {{SQL CARBON EDIT}}
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement'; import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
@@ -1140,7 +1140,7 @@ export const pasteFileHandler = async (accessor: ServicesAccessor) => {
return await fileService.copy(fileToPaste, targetFile); return await fileService.copy(fileToPaste, targetFile);
} }
} catch (e) { } 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; return undefined;
} }
})); }));
@@ -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 { 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 { OutputPanel } from 'vs/workbench/contrib/output/browser/outputPanel';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; 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 { OutputLinkProvider } from 'vs/workbench/contrib/output/common/outputLinkProvider';
import { ITextModelService, ITextModelContentProvider } from 'vs/editor/common/services/resolverService'; import { ITextModelService, ITextModelContentProvider } from 'vs/editor/common/services/resolverService';
import { ITextModel } from 'vs/editor/common/model'; import { ITextModel } from 'vs/editor/common/model';
import { IPanel } from 'vs/workbench/common/panel'; import { IPanel } from 'vs/workbench/common/panel';
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; 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 { ILogService } from 'vs/platform/log/common/log';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; 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, @IStorageService private readonly storageService: IStorageService,
@IInstantiationService private readonly instantiationService: IInstantiationService, @IInstantiationService private readonly instantiationService: IInstantiationService,
@IPanelService private readonly panelService: IPanelService, @IPanelService private readonly panelService: IPanelService,
@IWorkspaceContextService contextService: IWorkspaceContextService,
@ITextModelService textModelResolverService: ITextModelService, @ITextModelService textModelResolverService: ITextModelService,
@IEnvironmentService environmentService: IEnvironmentService,
@IWindowService windowService: IWindowService,
@ILogService private readonly logService: ILogService, @ILogService private readonly logService: ILogService,
@ILifecycleService private readonly lifecycleService: ILifecycleService, @ILifecycleService private readonly lifecycleService: ILifecycleService,
@IContextKeyService private readonly contextKeyService: IContextKeyService, @IContextKeyService private readonly contextKeyService: IContextKeyService,
@@ -854,7 +854,7 @@ export class SettingsEditor2 extends BaseEditor {
this._register(model.onDidChangeGroups(() => this.onConfigUpdate())); this._register(model.onDidChangeGroups(() => this.onConfigUpdate()));
this.defaultSettingsEditorModel = model; this.defaultSettingsEditorModel = model;
return this.onConfigUpdate(); return this.onConfigUpdate(undefined, true);
}); });
} }
return Promise.resolve(null); return Promise.resolve(null);
@@ -36,7 +36,8 @@ export class LabelContribution implements IWorkbenchContribution {
formatting: { formatting: {
label: '${path}', label: '${path}',
separator: remoteEnvironment.os === OperatingSystem.Windows ? '\\' : '/', separator: remoteEnvironment.os === OperatingSystem.Windows ? '\\' : '/',
tildify: remoteEnvironment.os !== OperatingSystem.Windows tildify: remoteEnvironment.os !== OperatingSystem.Windows,
normalizeDriveLetter: remoteEnvironment.os === OperatingSystem.Windows
} }
}); });
} }
@@ -179,10 +179,10 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
private static nextHandle: number = 0; private static nextHandle: number = 0;
private _schemaVersion: JsonSchemaVersion; private _schemaVersion: JsonSchemaVersion | undefined;
private _executionEngine: ExecutionEngine; private _executionEngine: ExecutionEngine | undefined;
private _workspaceFolders: IWorkspaceFolder[]; private _workspaceFolders: IWorkspaceFolder[] | undefined;
private _ignoredWorkspaceFolders: IWorkspaceFolder[]; private _ignoredWorkspaceFolders: IWorkspaceFolder[] | undefined;
private _showIgnoreMessage?: boolean; private _showIgnoreMessage?: boolean;
private _providers: Map<number, ITaskProvider>; private _providers: Map<number, ITaskProvider>;
private _providerTypes: Map<number, string>; private _providerTypes: Map<number, string>;
@@ -192,7 +192,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
protected _taskSystem?: ITaskSystem; protected _taskSystem?: ITaskSystem;
protected _taskSystemListener?: IDisposable; protected _taskSystemListener?: IDisposable;
private _recentlyUsedTasks: LinkedMap<string, string>; private _recentlyUsedTasks: LinkedMap<string, string> | undefined;
protected _taskRunningState: IContextKey<boolean>; protected _taskRunningState: IContextKey<boolean>;
@@ -375,28 +375,28 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
if (!this._workspaceFolders) { if (!this._workspaceFolders) {
this.updateSetup(); this.updateSetup();
} }
return this._workspaceFolders; return this._workspaceFolders!;
} }
private get ignoredWorkspaceFolders(): IWorkspaceFolder[] { private get ignoredWorkspaceFolders(): IWorkspaceFolder[] {
if (!this._ignoredWorkspaceFolders) { if (!this._ignoredWorkspaceFolders) {
this.updateSetup(); this.updateSetup();
} }
return this._ignoredWorkspaceFolders; return this._ignoredWorkspaceFolders!;
} }
protected get executionEngine(): ExecutionEngine { protected get executionEngine(): ExecutionEngine {
if (this._executionEngine === undefined) { if (this._executionEngine === undefined) {
this.updateSetup(); this.updateSetup();
} }
return this._executionEngine; return this._executionEngine!;
} }
private get schemaVersion(): JsonSchemaVersion { private get schemaVersion(): JsonSchemaVersion {
if (this._schemaVersion === undefined) { if (this._schemaVersion === undefined) {
this.updateSetup(); this.updateSetup();
} }
return this._schemaVersion; return this._schemaVersion!;
} }
private get showIgnoreMessage(): boolean { private get showIgnoreMessage(): boolean {
@@ -155,9 +155,10 @@ export class TerminalTaskSystem implements ITaskSystem {
private idleTaskTerminals: LinkedMap<string, string>; private idleTaskTerminals: LinkedMap<string, string>;
private sameTaskTerminals: IStringDictionary<string>; private sameTaskTerminals: IStringDictionary<string>;
private taskSystemInfoResolver: TaskSystemInfoResolver; private taskSystemInfoResolver: TaskSystemInfoResolver;
private lastTask: VerifiedTask; private lastTask: VerifiedTask | undefined;
private currentTask: VerifiedTask; // Should always be set in run
private isRerun: boolean; private currentTask!: VerifiedTask;
private isRerun: boolean = false;
private readonly _onDidStateChange: Emitter<TaskEvent>; private readonly _onDidStateChange: Emitter<TaskEvent>;
@@ -485,28 +486,32 @@ export class TerminalTaskSystem implements ITaskSystem {
} }
private reexecuteCommand(task: CustomTask | ContributedTask, trigger: string): Promise<ITaskSummary> { 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>(); let variables = new Set<string>();
this.collectTaskVariables(variables, task); this.collectTaskVariables(variables, task);
// Check that the task hasn't changed to include new variables // Check that the task hasn't changed to include new variables
let hasAllVariables = true; let hasAllVariables = true;
variables.forEach(value => { 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; hasAllVariables = false;
} }
}); });
if (!hasAllVariables) { 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; 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 => { }, reason => {
return Promise.reject(reason); return Promise.reject(reason);
}); });
} else { } else {
this.currentTask.resolvedVariables = this.lastTask.getVerifiedTask().resolvedVariables; this.currentTask.resolvedVariables = 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!); 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; args = resolvedResult.args;
commandExecutable = CommandString.value(command); 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) { 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)]; 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)];
} }
@@ -44,10 +44,10 @@ export abstract class AbstractProblemCollector implements IDisposable {
private bufferLength: number; private bufferLength: number;
private openModels: IStringDictionary<boolean>; private openModels: IStringDictionary<boolean>;
private readonly modelListeners = new DisposableStore(); private readonly modelListeners = new DisposableStore();
private tail: Promise<void>; private tail: Promise<void> | undefined;
// [owner] -> ApplyToKind // [owner] -> ApplyToKind
private applyToByOwner: Map<string, ApplyToKind>; protected applyToByOwner: Map<string, ApplyToKind>;
// [owner] -> [resource] -> URI // [owner] -> [resource] -> URI
private resourcesToClean: Map<string, Map<string, URI>>; private resourcesToClean: Map<string, Map<string, URI>>;
// [owner] -> [resource] -> [markerkey] -> markerData // [owner] -> [resource] -> [markerkey] -> markerData
@@ -278,9 +278,14 @@ export abstract class AbstractProblemCollector implements IDisposable {
markersPerResource = new Map<string, IMarkerData>(); markersPerResource = new Map<string, IMarkerData>();
markersPerOwner.set(resourceAsString, markersPerResource); markersPerOwner.set(resourceAsString, markersPerResource);
} }
let key = IMarkerData.makeKey(marker); let key = IMarkerData.makeKeyOptionalMessage(marker, false);
let existingMarker;
if (!markersPerResource.has(key)) { if (!markersPerResource.has(key)) {
markersPerResource.set(key, marker); 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 { export class StartStopProblemCollector extends AbstractProblemCollector implements IProblemMatcher {
private owners: string[]; private owners: string[];
private currentOwner: string; private currentOwner: string | undefined;
private currentResource: string; private currentResource: string | undefined;
constructor(problemMatchers: ProblemMatcher[], markerService: IMarkerService, modelService: IModelService, _strategy: ProblemHandlingStrategy = ProblemHandlingStrategy.Clean, fileService?: IFileService) { constructor(problemMatchers: ProblemMatcher[], markerService: IMarkerService, modelService: IModelService, _strategy: ProblemHandlingStrategy = ProblemHandlingStrategy.Clean, fileService?: IFileService) {
super(problemMatchers, markerService, modelService, fileService); super(problemMatchers, markerService, modelService, fileService);
@@ -397,8 +402,8 @@ export class WatchingProblemCollector extends AbstractProblemCollector implement
private _activeBackgroundMatchers: Set<string>; private _activeBackgroundMatchers: Set<string>;
// Current State // Current State
private currentOwner: string | null; private currentOwner: string | undefined;
private currentResource: string | null; private currentResource: string | undefined;
constructor(problemMatchers: ProblemMatcher[], markerService: IMarkerService, modelService: IModelService, fileService?: IFileService) { constructor(problemMatchers: ProblemMatcher[], markerService: IMarkerService, modelService: IModelService, fileService?: IFileService) {
super(problemMatchers, markerService, modelService, fileService); super(problemMatchers, markerService, modelService, fileService);
@@ -503,8 +508,8 @@ export class WatchingProblemCollector extends AbstractProblemCollector implement
private resetCurrentResource(): void { private resetCurrentResource(): void {
this.reportMarkersForCurrentResource(); this.reportMarkersForCurrentResource();
this.currentOwner = null; this.currentOwner = undefined;
this.currentResource = null; this.currentResource = undefined;
} }
private reportMarkersForCurrentResource(): void { private reportMarkersForCurrentResource(): void {
@@ -512,4 +517,11 @@ export class WatchingProblemCollector extends AbstractProblemCollector implement
this.deliverMarkersPerOwnerAndResource(this.currentOwner, this.currentResource); this.deliverMarkersPerOwnerAndResource(this.currentOwner, this.currentResource);
} }
} }
public done(): void {
[...this.applyToByOwner.keys()].forEach(owner => {
this.recordResourcesToClean(owner);
});
super.done();
}
} }
@@ -264,7 +264,7 @@ abstract class AbstractLineMatcher implements ILineMatcher {
public abstract get matchLength(): number; 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) { if (data) {
this.fillProperty(data, 'file', pattern, matches, true); this.fillProperty(data, 'file', pattern, matches, true);
this.appendProperty(data, 'message', pattern, matches, true); this.appendProperty(data, 'message', pattern, matches, true);
@@ -449,7 +449,7 @@ class SingleLineMatcher extends AbstractLineMatcher {
class MultiLineMatcher extends AbstractLineMatcher { class MultiLineMatcher extends AbstractLineMatcher {
private patterns: ProblemPattern[]; private patterns: ProblemPattern[];
private data: ProblemData | null; private data: ProblemData | undefined;
constructor(matcher: ProblemMatcher, fileService?: IFileService) { constructor(matcher: ProblemMatcher, fileService?: IFileService) {
super(matcher, fileService); super(matcher, fileService);
@@ -480,7 +480,7 @@ class MultiLineMatcher extends AbstractLineMatcher {
} }
let loop = !!this.patterns[this.patterns.length - 1].loop; let loop = !!this.patterns[this.patterns.length - 1].loop;
if (!loop) { if (!loop) {
this.data = null; this.data = undefined;
} }
const markerMatch = data ? this.getMarkerMatch(data) : null; const markerMatch = data ? this.getMarkerMatch(data) : null;
return { match: markerMatch ? markerMatch : null, continue: loop }; return { match: markerMatch ? markerMatch : null, continue: loop };
@@ -491,7 +491,7 @@ class MultiLineMatcher extends AbstractLineMatcher {
Assert.ok(pattern.loop === true && this.data !== null); Assert.ok(pattern.loop === true && this.data !== null);
let matches = pattern.regexp.exec(line); let matches = pattern.regexp.exec(line);
if (!matches) { if (!matches) {
this.data = null; this.data = undefined;
return null; return null;
} }
let data = Objects.deepClone(this.data); let data = Objects.deepClone(this.data);
@@ -794,7 +794,7 @@ export namespace Config {
fileLocation?: string | string[]; 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 * of a problem pattern or an array of problem patterns to match
* problems spread over multiple lines. * problems spread over multiple lines.
*/ */
@@ -681,7 +681,7 @@ export namespace RunOptions {
} }
} }
class ParseContext { interface ParseContext {
workspaceFolder: IWorkspaceFolder; workspaceFolder: IWorkspaceFolder;
problemReporter: IProblemReporter; problemReporter: IProblemReporter;
namedProblemMatchers: IStringDictionary<NamedProblemMatcher>; namedProblemMatchers: IStringDictionary<NamedProblemMatcher>;
@@ -89,7 +89,7 @@ class TaskDefinitionRegistryImpl implements ITaskDefinitionRegistry {
private taskTypes: IStringDictionary<Tasks.TaskDefinition>; private taskTypes: IStringDictionary<Tasks.TaskDefinition>;
private readyPromise: Promise<void>; private readyPromise: Promise<void>;
private _schema: IJSONSchema; private _schema: IJSONSchema | undefined;
constructor() { constructor() {
this.taskTypes = Object.create(null); this.taskTypes = Object.create(null);
@@ -518,7 +518,7 @@ export abstract class CommonTask {
/** /**
* The cached label. * The cached label.
*/ */
_label: string; _label: string = '';
type?: string; type?: string;
@@ -614,7 +614,7 @@ export abstract class CommonTask {
export class CustomTask extends 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) * Indicated the source of the task (e.g. tasks.json or extension)
@@ -626,7 +626,7 @@ export class CustomTask extends CommonTask {
/** /**
* The command configuration * The command configuration
*/ */
command: CommandConfiguration; command: CommandConfiguration = {};
public constructor(id: string, source: WorkspaceTaskSource, label: string, type: string, command: CommandConfiguration | undefined, public constructor(id: string, source: WorkspaceTaskSource, label: string, type: string, command: CommandConfiguration | undefined,
hasDefinedMatchers: boolean, runOptions: RunOptions, configurationProperties: ConfigurationProperties) { 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) * Indicated the source of the task (e.g. tasks.json or extension)
* Set in the super constructor
*/ */
_source: ExtensionTaskSource; _source!: ExtensionTaskSource;
defines: KeyedTaskIdentifier; defines: KeyedTaskIdentifier;
@@ -824,7 +825,7 @@ export class InMemoryTask extends CommonTask {
*/ */
_source: InMemoryTaskSource; _source: InMemoryTaskSource;
type: 'inMemory'; type!: 'inMemory';
public constructor(id: string, source: InMemoryTaskSource, label: string, type: string, public constructor(id: string, source: InMemoryTaskSource, label: string, type: string,
runOptions: RunOptions, configurationProperties: ConfigurationProperties) { runOptions: RunOptions, configurationProperties: ConfigurationProperties) {
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import 'vs/css!./watermark'; 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 { assign } from 'vs/base/common/objects';
import { isMacintosh, OS } from 'vs/base/common/platform'; import { isMacintosh, OS } from 'vs/base/common/platform';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
@@ -42,65 +42,21 @@ interface WatermarkEntry {
} }
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
const showServers: WatermarkEntry = { const showServers: WatermarkEntry = { text: nls.localize('watermark.showServers', "Show Servers"), id: OpenDataExplorerViewletAction.ID };
text: nls.localize('watermark.showServers', "Show Servers"), const newSqlFile: WatermarkEntry = { text: nls.localize('watermark.newSqlFile', "New SQL File"), id: GlobalNewUntitledFileAction.ID };
id: OpenDataExplorerViewletAction.ID const newNotebook: WatermarkEntry = { text: nls.localize('watermark.newNotebook', "New Notebook"), id: NewNotebookAction.ID };
};
const newSqlFile: WatermarkEntry = { const showCommands: WatermarkEntry = { text: nls.localize('watermark.showCommands', "Show All Commands"), id: ShowAllCommandsAction.ID };
text: nls.localize('watermark.newSqlFile', "New SQL File"), const quickOpen: WatermarkEntry = { text: nls.localize('watermark.quickOpen', "Go to File"), id: QUICKOPEN_ACTION_ID };
id: GlobalNewUntitledFileAction.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 newNotebook: WatermarkEntry = { const openFileOrFolderMacOnly: WatermarkEntry = { text: nls.localize('watermark.openFileFolder', "Open File or Folder"), id: OpenFileFolderAction.ID, mac: true };
text: nls.localize('watermark.newNotebook', "New Notebook"), const openRecent: WatermarkEntry = { text: nls.localize('watermark.openRecent', "Open Recent"), id: 'workbench.action.openRecent' };
id: NewNotebookAction.ID 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 newUntitledFileMacOnly: WatermarkEntry = assign({ mac: true }, newUntitledFile);
const toggleTerminal: WatermarkEntry = { const toggleTerminal: WatermarkEntry = { text: nls.localize({ key: 'watermark.toggleTerminal', comment: ['toggle is a verb here'] }, "Toggle Terminal"), id: TERMINAL_COMMAND_ID.TOGGLE };
text: nls.localize({ key: 'watermark.toggleTerminal', comment: ['toggle is a verb here'] }, "Toggle Terminal"), const findInFiles: WatermarkEntry = { text: nls.localize('watermark.findInFiles', "Find in Files"), id: FindInFilesActionId };
id: TERMINAL_COMMAND_ID.TOGGLE const startDebugging: WatermarkEntry = { text: nls.localize('watermark.startDebugging', "Start Debugging"), id: StartAction.ID };
};
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 // {{SQL CARBON EDIT}} - Replace noFolderEntries and folderEntries
const noFolderEntries = [ const noFolderEntries = [
@@ -121,13 +77,13 @@ const folderEntries = [
const WORKBENCH_TIPS_ENABLED_KEY = 'workbench.tips.enabled'; const WORKBENCH_TIPS_ENABLED_KEY = 'workbench.tips.enabled';
export class WatermarkContribution extends Disposable implements IWorkbenchContribution { export class WatermarkContribution extends Disposable implements IWorkbenchContribution {
private watermark: HTMLElement; private watermark: HTMLElement;
private watermarkDisposable = this._register(new DisposableStore());
private enabled: boolean; private enabled: boolean;
private workbenchState: WorkbenchState; private workbenchState: WorkbenchState;
constructor( constructor(
@ILifecycleService lifecycleService: ILifecycleService, @ILifecycleService private readonly lifecycleService: ILifecycleService,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
@IKeybindingService private readonly keybindingService: IKeybindingService, @IKeybindingService private readonly keybindingService: IKeybindingService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@@ -135,13 +91,20 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr
@IEditorGroupsService private readonly editorGroupsService: IEditorGroupsService @IEditorGroupsService private readonly editorGroupsService: IEditorGroupsService
) { ) {
super(); 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.enabled = this.configurationService.getValue<boolean>(WORKBENCH_TIPS_ENABLED_KEY);
this.registerListeners();
if (this.enabled) { if (this.enabled) {
this.create(); this.create();
} }
}
private registerListeners(): void {
this.lifecycleService.onShutdown(this.dispose, this);
this._register(this.configurationService.onDidChangeConfiguration(e => { this._register(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(WORKBENCH_TIPS_ENABLED_KEY)) { if (e.affectsConfiguration(WORKBENCH_TIPS_ENABLED_KEY)) {
const enabled = this.configurationService.getValue<boolean>(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 => { this._register(this.contextService.onDidChangeWorkbenchState(e => {
const previousWorkbenchState = this.workbenchState; const previousWorkbenchState = this.workbenchState;
this.workbenchState = this.contextService.getWorkbenchState(); this.workbenchState = this.contextService.getWorkbenchState();
@@ -175,6 +139,7 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr
const selected = folder ? folderEntries : noFolderEntries const selected = folder ? folderEntries : noFolderEntries
.filter(entry => !('mac' in entry) || entry.mac === isMacintosh) .filter(entry => !('mac' in entry) || entry.mac === isMacintosh)
.filter(entry => !!CommandsRegistry.getCommand(entry.id)); .filter(entry => !!CommandsRegistry.getCommand(entry.id));
const update = () => { const update = () => {
dom.clearNode(box); dom.clearNode(box);
selected.map(entry => { selected.map(entry => {
@@ -187,10 +152,14 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr
dd.innerHTML = keybinding.element.outerHTML; dd.innerHTML = keybinding.element.outerHTML;
}); });
}; };
update(); update();
dom.prepend(container.firstElementChild as HTMLElement, this.watermark); 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); this.handleEditorPartSize(container, this.editorGroupsService.contentDimension);
} }
@@ -205,9 +174,11 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr
private destroy(): void { private destroy(): void {
if (this.watermark) { if (this.watermark) {
this.watermark.remove(); this.watermark.remove();
const container = this.layoutService.getContainer(Parts.EDITOR_PART); const container = this.layoutService.getContainer(Parts.EDITOR_PART);
container.classList.remove('has-watermark'); container.classList.remove('has-watermark');
this.dispose();
this.watermarkDisposable.clear();
} }
} }
@@ -47,16 +47,16 @@ export class WebviewPortMappingManager extends Disposable {
if (this.extensionLocation && this.extensionLocation.scheme === REMOTE_HOST_SCHEME) { if (this.extensionLocation && this.extensionLocation.scheme === REMOTE_HOST_SCHEME) {
const tunnel = await this.getOrCreateTunnel(mapping.extensionHostPort); const tunnel = await this.getOrCreateTunnel(mapping.extensionHostPort);
if (tunnel) { if (tunnel) {
return uri.with({ return encodeURI(uri.with({
authority: `127.0.0.1:${tunnel.tunnelLocalPort}`, authority: `127.0.0.1:${tunnel.tunnelLocalPort}`,
}).toString(); }).toString(true));
} }
} }
if (mapping.webviewPort !== mapping.extensionHostPort) { if (mapping.webviewPort !== mapping.extensionHostPort) {
return uri.with({ return encodeURI(uri.with({
authority: `${requestLocalHostInfo.address}:${mapping.extensionHostPort}` authority: `${requestLocalHostInfo.address}:${mapping.extensionHostPort}`
}).toString(); }).toString(true));
} }
} }
} }
@@ -18,6 +18,8 @@ import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/co
import { RemoteExtensionHostClient, IInitDataProvider } from 'vs/workbench/services/extensions/common/remoteExtensionHostClient'; import { RemoteExtensionHostClient, IInitDataProvider } from 'vs/workbench/services/extensions/common/remoteExtensionHostClient';
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; 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 { export class ExtensionService extends AbstractExtensionService implements IExtensionService {
@@ -62,6 +64,11 @@ export class ExtensionService extends AbstractExtensionService implements IExten
const result: ExtensionHostProcessManager[] = []; const result: ExtensionHostProcessManager[] = [];
const remoteAgentConnection = this._remoteAgentService.getConnection()!; 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 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); const remoteExtHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, remoteExtHostProcessWorker, remoteAgentConnection.remoteAuthority, initialActivationEvents);
result.push(remoteExtHostProcessManager); result.push(remoteExtHostProcessManager);
@@ -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
},
};
}
}
@@ -10,7 +10,6 @@ import { URI, setUriThrowOnMissingScheme } from 'vs/base/common/uri';
import { IURITransformer } from 'vs/base/common/uriIpc'; import { IURITransformer } from 'vs/base/common/uriIpc';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { IInitData, MainContext, MainThreadConsoleShape } from 'vs/workbench/api/common/extHost.protocol'; 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 { RPCProtocol } from 'vs/workbench/services/extensions/common/rpcProtocol';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ILogService } from 'vs/platform/log/common/log'; import { ILogService } from 'vs/platform/log/common/log';
@@ -35,10 +34,6 @@ export interface IConsolePatchFn {
(mainThreadConsole: MainThreadConsoleShape): any; (mainThreadConsole: MainThreadConsoleShape): any;
} }
export interface ILogServiceFn {
(initData: IInitData): ILogService;
}
export class ExtensionHostMain { export class ExtensionHostMain {
private _isTerminating: boolean; private _isTerminating: boolean;
@@ -50,8 +45,6 @@ export class ExtensionHostMain {
protocol: IMessagePassingProtocol, protocol: IMessagePassingProtocol,
initData: IInitData, initData: IInitData,
hostUtils: IHostUtils, hostUtils: IHostUtils,
consolePatchFn: IConsolePatchFn,
logServiceFn: ILogServiceFn,
uriTransformer: IURITransformer | null uriTransformer: IURITransformer | null
) { ) {
this._isTerminating = false; this._isTerminating = false;
@@ -61,27 +54,27 @@ export class ExtensionHostMain {
// ensure URIs are transformed and revived // ensure URIs are transformed and revived
initData = ExtensionHostMain._transform(initData, rpcProtocol); 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 // bootstrap services
const services = new ServiceCollection(...getSingletonServiceDescriptors()); const services = new ServiceCollection(...getSingletonServiceDescriptors());
services.set(IExtHostInitDataService, { _serviceBrand: undefined, ...initData }); services.set(IExtHostInitDataService, { _serviceBrand: undefined, ...initData });
services.set(IExtHostRpcService, new ExtHostRpcService(rpcProtocol)); services.set(IExtHostRpcService, new ExtHostRpcService(rpcProtocol));
services.set(ILogService, extHostLogService);
services.set(IURITransformerService, new URITransformerService(uriTransformer)); services.set(IURITransformerService, new URITransformerService(uriTransformer));
services.set(IHostUtils, hostUtils); services.set(IHostUtils, hostUtils);
const instaService: IInstantiationService = new InstantiationService(services, true); const instaService: IInstantiationService = new InstantiationService(services, true);
extHostLogService.info('extension host started'); // todo@joh
extHostLogService.trace('initData', initData); // 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 = instaService.invokeFunction(accessor => accessor.get(IExtHostExtensionService));
this._extensionService.initialize(); this._extensionService.initialize();
@@ -354,6 +354,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
} }
const result: ExtensionHostProcessManager[] = []; const result: ExtensionHostProcessManager[] = [];
const extHostProcessWorker = this._instantiationService.createInstance(ExtensionHostProcessWorker, autoStart, extensions, this._extensionHostLogsLocation); const extHostProcessWorker = this._instantiationService.createInstance(ExtensionHostProcessWorker, autoStart, extensions, this._extensionHostLogsLocation);
const extHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, true, extHostProcessWorker, null, initialActivationEvents); const extHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, true, extHostProcessWorker, null, initialActivationEvents);
result.push(extHostProcessManager); result.push(extHostProcessManager);
@@ -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 { PersistentProtocol, ProtocolConstants, createBufferedEvent } from 'vs/base/parts/ipc/common/ipc.net';
import { NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; import { NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
import product from 'vs/platform/product/node/product'; 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 { 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 { 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 { IURITransformer, URITransformer, IRawURITransformer } from 'vs/base/common/uriIpc';
import { exists } from 'vs/base/node/pfs'; import { exists } from 'vs/base/node/pfs';
import { realpath } from 'vs/base/node/extpath'; import { realpath } from 'vs/base/node/extpath';
import { IHostUtils } from 'vs/workbench/api/common/extHostExtensionService'; import { IHostUtils } from 'vs/workbench/api/common/extHostExtensionService';
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
import 'vs/workbench/api/node/extHost.services'; import 'vs/workbench/api/node/extHost.services';
interface ParsedExtHostArgs { 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 { interface IRendererConnection {
protocol: IMessagePassingProtocol; protocol: IMessagePassingProtocol;
initData: IInitData; initData: IInitData;
@@ -206,7 +189,7 @@ async function createExtHostProtocol(): Promise<IMessagePassingProtocol> {
} }
function connectToRenderer(protocol: IMessagePassingProtocol): Promise<IRendererConnection> { function connectToRenderer(protocol: IMessagePassingProtocol): Promise<IRendererConnection> {
return new Promise<IRendererConnection>((c, e) => { return new Promise<IRendererConnection>((c) => {
// Listen init data message // Listen init data message
const first = protocol.onMessage(raw => { const first = protocol.onMessage(raw => {
@@ -335,8 +318,6 @@ export async function startExtensionHostProcess(): Promise<void> {
renderer.protocol, renderer.protocol,
initData, initData,
hostUtils, hostUtils,
patchPatchedConsole,
createLogService,
uriTransformer uriTransformer
); );
@@ -17,11 +17,11 @@ import { IExtHostWorkspaceProvider } from 'vs/workbench/api/common/extHostWorksp
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration'; import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
import { ProxyAgent } from 'vscode-proxy-agent'; import { ProxyAgent } from 'vscode-proxy-agent';
import { MainThreadTelemetryShape } from 'vs/workbench/api/common/extHost.protocol'; 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 { toErrorMessage } from 'vs/base/common/errorMessage';
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { promisify } from 'util'; import { promisify } from 'util';
import { ILogService } from 'vs/platform/log/common/log';
interface ConnectionResult { interface ConnectionResult {
proxy: string; proxy: string;
@@ -34,7 +34,7 @@ export function connectProxyResolver(
extHostWorkspace: IExtHostWorkspaceProvider, extHostWorkspace: IExtHostWorkspaceProvider,
configProvider: ExtHostConfigProvider, configProvider: ExtHostConfigProvider,
extensionService: ExtHostExtensionService, extensionService: ExtHostExtensionService,
extHostLogService: ExtHostLogService, extHostLogService: ILogService,
mainThreadTelemetry: MainThreadTelemetryShape mainThreadTelemetry: MainThreadTelemetryShape
) { ) {
const resolveProxy = setupProxyResolution(extHostWorkspace, configProvider, extHostLogService, mainThreadTelemetry); 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( function setupProxyResolution(
extHostWorkspace: IExtHostWorkspaceProvider, extHostWorkspace: IExtHostWorkspaceProvider,
configProvider: ExtHostConfigProvider, configProvider: ExtHostConfigProvider,
extHostLogService: ExtHostLogService, extHostLogService: ILogService,
mainThreadTelemetry: MainThreadTelemetryShape mainThreadTelemetry: MainThreadTelemetryShape
) { ) {
const env = process.env; 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) { if (useSystemCertificates) {
getCaCertificates(extHostLogService) getCaCertificates(extHostLogService)
.then(caCertificates => { .then(caCertificates => {
@@ -443,7 +443,7 @@ function useSystemCertificates(extHostLogService: ExtHostLogService, useSystemCe
} }
let _caCertificates: ReturnType<typeof readCaCertificates> | Promise<undefined>; let _caCertificates: ReturnType<typeof readCaCertificates> | Promise<undefined>;
async function getCaCertificates(extHostLogService: ExtHostLogService) { async function getCaCertificates(extHostLogService: ILogService) {
if (!_caCertificates) { if (!_caCertificates) {
_caCertificates = readCaCertificates() _caCertificates = readCaCertificates()
.then(res => res && res.certs.length ? res : undefined) .then(res => res && res.certs.length ? res : undefined)
@@ -469,8 +469,9 @@ async function readCaCertificates() {
} }
async function readWindowsCaCertificates() { 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[] = []; let ders: any[] = [];
const store = winCA(); const store = winCA();
try { try {
@@ -487,6 +488,7 @@ async function readWindowsCaCertificates() {
certs: Array.from(certs), certs: Array.from(certs),
append: true append: true
}; };
});
} }
async function readMacCaCertificates() { async function readMacCaCertificates() {
@@ -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();
});
@@ -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;
}
+4 -4
View File
@@ -21,8 +21,8 @@ import 'vs/workbench/workbench.common.main';
//#region --- workbench (desktop main) //#region --- workbench (desktop main)
import 'sql/setup'; // {{SQL CARBON EDIT}} import 'sql/setup'; // {{SQL CARBON EDIT}}
import 'vs/workbench/electron-browser/main.contribution'; import 'vs/workbench/electron-browser/desktop.contribution';
import 'vs/workbench/electron-browser/main'; import 'vs/workbench/electron-browser/desktop.main';
//#endregion //#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/workspace/electron-browser/workspaceEditingService';
import 'vs/workbench/services/extensions/common/inactiveExtensionUrlHandler'; import 'vs/workbench/services/extensions/common/inactiveExtensionUrlHandler';
import 'vs/workbench/services/search/node/searchService'; 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/output/node/outputChannelModelService';
import 'vs/workbench/services/textfile/node/textFileService'; import 'vs/workbench/services/textfile/node/textFileService';
import 'vs/workbench/services/dialogs/electron-browser/dialogService'; 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/extensionManagement/node/extensionManagementService';
import 'vs/workbench/services/accessibility/node/accessibilityService'; import 'vs/workbench/services/accessibility/node/accessibilityService';
import 'vs/workbench/services/remote/node/tunnelService'; import 'vs/workbench/services/remote/node/tunnelService';
import 'vs/workbench/contrib/stats/electron-browser/workspaceStatsService';
import 'vs/workbench/services/backup/node/backupFileService'; import 'vs/workbench/services/backup/node/backupFileService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; 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'; import 'vs/workbench/contrib/logs/electron-browser/logs.contribution';
// Stats // Stats
import 'vs/workbench/contrib/stats/electron-browser/workspaceStatsService';
import 'vs/workbench/contrib/stats/electron-browser/stats.contribution'; import 'vs/workbench/contrib/stats/electron-browser/stats.contribution';
// Rapid Render Splash // Rapid Render Splash
@@ -221,6 +220,7 @@ import 'vs/workbench/contrib/splash/electron-browser/partsSplash.contribution';
// Debug // Debug
// import 'vs/workbench/contrib/debug/node/debugHelperService'; {{SQL CARBON EDIT}} // import 'vs/workbench/contrib/debug/node/debugHelperService'; {{SQL CARBON EDIT}}
import 'vs/workbench/contrib/debug/electron-browser/extensionHostDebugService';
// Webview // Webview
import 'vs/workbench/contrib/webview/electron-browser/webview.contribution'; import 'vs/workbench/contrib/webview/electron-browser/webview.contribution';
+5
View File
@@ -48,6 +48,11 @@ export interface IWorkbenchConstructionOptions {
* A factory for web sockets. * A factory for web sockets.
*/ */
webSocketFactory?: IWebSocketFactory; webSocketFactory?: IWebSocketFactory;
/**
* Experimental: Whether to enable the smoke test driver.
*/
driver?: boolean;
} }
/** /**
+4 -4
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" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23"
integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg==
xterm@3.15.0-beta98: xterm@3.15.0-beta99:
version "3.15.0-beta98" version "3.15.0-beta99"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta98.tgz#37f37c35577422880e7ef673cc37f9d2a45dd40c" resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta99.tgz#0010a7ea5d56cbb08a1e3a525b353c96a158e7a0"
integrity sha512-vZbg2LcRvoiJOgr1MyeLFM9mF4uib3BWUWDHyFc+vZ58CTuK0iczOvFXgk/ySo23ZLqwmHQSigLgmWvZ8J5G0Q== integrity sha512-Vm0ZWToWwO4uk/28Kqvqt9L92h5EU2z4WR9I6xcQaPIBmkJPINIARU4LWQnvaOfgFhRbpwBMveTfh8/jM97lPg==
y18n@^3.2.1: y18n@^3.2.1:
version "3.2.1" version "3.2.1"