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