Archived
Merge from vscode e1d3dd53d17fb1529a002e4d6fb066db0a0bd385 (#6460)
* Merge from vscode e1d3dd53d17fb1529a002e4d6fb066db0a0bd385 * fix servers icon * fix tests
This commit is contained in:
@@ -5,3 +5,6 @@ src/
|
|||||||
test/
|
test/
|
||||||
tsconfig.json
|
tsconfig.json
|
||||||
.gitignore
|
.gitignore
|
||||||
|
yarn.lock
|
||||||
|
extension.webpack.config.js
|
||||||
|
vscode-json-languageserver-*.tgz
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "vscode-json-languageserver",
|
"name": "vscode-json-languageserver",
|
||||||
"description": "JSON language server",
|
"description": "JSON language server",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"author": "Microsoft Corporation",
|
"author": "Microsoft Corporation",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -24,10 +24,9 @@
|
|||||||
"@types/node": "^10.14.8"
|
"@types/node": "^10.14.8"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepublishOnly": "npm run clean && npm run test",
|
"prepublishOnly": "npm run clean && npm run compile",
|
||||||
"preversion": "npm test",
|
"compile": "npx gulp compile-extension:json-language-features-server",
|
||||||
"compile": "gulp compile-extension:json-language-features-server",
|
"watch": "npx gulp watch-extension:json-language-features-server",
|
||||||
"watch": "gulp watch-extension:json-language-features-server",
|
|
||||||
"clean": "../../../node_modules/.bin/rimraf out",
|
"clean": "../../../node_modules/.bin/rimraf out",
|
||||||
"install-service-next": "yarn add vscode-json-languageservice@next",
|
"install-service-next": "yarn add vscode-json-languageservice@next",
|
||||||
"install-service-local": "yarn link vscode-json-languageservice",
|
"install-service-local": "yarn link vscode-json-languageservice",
|
||||||
|
|||||||
@@ -186,6 +186,7 @@ pre.hljs code > div {
|
|||||||
|
|
||||||
pre code {
|
pre code {
|
||||||
color: var(--vscode-editor-foreground);
|
color: var(--vscode-editor-foreground);
|
||||||
|
tab-size: 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ export class PreviewDocumentVersion {
|
|||||||
|
|
||||||
export class MarkdownPreview extends Disposable {
|
export class MarkdownPreview extends Disposable {
|
||||||
|
|
||||||
public static viewType = 'markdown.preview';
|
public static readonly viewType = 'markdown.preview';
|
||||||
|
|
||||||
private _resource: vscode.Uri;
|
private _resource: vscode.Uri;
|
||||||
private _locked: boolean;
|
private _locked: boolean;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import 'vs/css!sql/media/actionBarLabel';
|
import 'vs/css!sql/media/actionBarLabel';
|
||||||
|
import 'vs/css!./media/dataExplorer.contribution';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ShowViewletAction } from 'vs/workbench/browser/viewlet';
|
import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ShowViewletAction } from 'vs/workbench/browser/viewlet';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Activity Bar */
|
||||||
|
.monaco-workbench .activitybar .monaco-action-bar .action-label.dataExplorer {
|
||||||
|
-webkit-mask: url('server_page_inverse.svg') no-repeat 50% 50%;
|
||||||
|
-webkit-mask-size: 25px 25px;
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>server_inverse_16x16</title><path class="cls-1" d="M2.73,0V16H13.26V0Zm1,1h8.53v9H3.73ZM12.26,15H3.73V11h8.53Z"/><path class="cls-1" d="M7.21,4.23H4.75V1.77H7.21Zm-2-.5H6.71V2.27H5.25Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 339 B |
@@ -34,7 +34,7 @@ export function isInDOM(node: Node | null): boolean {
|
|||||||
if (node === document.body) {
|
if (node === document.body) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
node = node.parentNode;
|
node = node.parentNode || (node as ShadowRoot).host;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -806,7 +806,8 @@ export function createCSSRule(selector: string, cssText: string, style: HTMLStyl
|
|||||||
if (!style || !cssText) {
|
if (!style || !cssText) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
style.textContent = `${selector}{${cssText}}\n${style.textContent}`;
|
|
||||||
|
(<CSSStyleSheet>style.sheet).insertRule(selector + '{' + cssText + '}', 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeCSSRulesContainingSelector(ruleName: string, style: HTMLStyleElement = getSharedStyleSheet()): void {
|
export function removeCSSRulesContainingSelector(ruleName: string, style: HTMLStyleElement = getSharedStyleSheet()): void {
|
||||||
|
|||||||
@@ -102,6 +102,22 @@ class BranchNode implements ISplitView, IDisposable {
|
|||||||
return Math.min(...this.children.map(c => c.maximumOrthogonalSize));
|
return Math.min(...this.children.map(c => c.maximumOrthogonalSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get priority(): LayoutPriority {
|
||||||
|
if (this.children.length === 0) {
|
||||||
|
return LayoutPriority.Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
const priorities = this.children.map(c => typeof c.priority === 'undefined' ? LayoutPriority.Normal : c.priority);
|
||||||
|
|
||||||
|
if (priorities.some(p => p === LayoutPriority.High)) {
|
||||||
|
return LayoutPriority.High;
|
||||||
|
} else if (priorities.some(p => p === LayoutPriority.Low)) {
|
||||||
|
return LayoutPriority.Low;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LayoutPriority.Normal;
|
||||||
|
}
|
||||||
|
|
||||||
get minimumOrthogonalSize(): number {
|
get minimumOrthogonalSize(): number {
|
||||||
return this.splitview.minimumSize;
|
return this.splitview.minimumSize;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -325,13 +325,13 @@ export class SplitView extends Disposable {
|
|||||||
|
|
||||||
container.appendChild(view.element);
|
container.appendChild(view.element);
|
||||||
|
|
||||||
let highPriorityIndex: number | undefined;
|
let highPriorityIndexes: number[] | undefined;
|
||||||
|
|
||||||
if (typeof size !== 'number' && size.type === 'split') {
|
if (typeof size !== 'number' && size.type === 'split') {
|
||||||
highPriorityIndex = size.index;
|
highPriorityIndexes = [size.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.relayout(index, highPriorityIndex);
|
this.relayout([index], highPriorityIndexes);
|
||||||
this.state = State.Idle;
|
this.state = State.Idle;
|
||||||
|
|
||||||
if (typeof size !== 'number' && size.type === 'distribute') {
|
if (typeof size !== 'number' && size.type === 'distribute') {
|
||||||
@@ -420,17 +420,6 @@ export class SplitView extends Disposable {
|
|||||||
this.layoutViews();
|
this.layoutViews();
|
||||||
}
|
}
|
||||||
|
|
||||||
private relayout(lowPriorityIndex?: number, highPriorityIndex?: number): void {
|
|
||||||
const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
|
|
||||||
const lowPriorityIndexes = typeof lowPriorityIndex === 'number' ? [lowPriorityIndex] : undefined;
|
|
||||||
const highPriorityIndexes = typeof highPriorityIndex === 'number' ? [highPriorityIndex] : undefined;
|
|
||||||
|
|
||||||
this.resize(this.viewItems.length - 1, this.size - contentSize, undefined, lowPriorityIndexes, highPriorityIndexes);
|
|
||||||
this.distributeEmptySpace();
|
|
||||||
this.layoutViews();
|
|
||||||
this.saveProportions();
|
|
||||||
}
|
|
||||||
|
|
||||||
layout(size: number): void {
|
layout(size: number): void {
|
||||||
const previousSize = Math.max(this.size, this.contentSize);
|
const previousSize = Math.max(this.size, this.contentSize);
|
||||||
this.size = size;
|
this.size = size;
|
||||||
@@ -582,7 +571,7 @@ export class SplitView extends Disposable {
|
|||||||
this.layoutViews();
|
this.layoutViews();
|
||||||
} else {
|
} else {
|
||||||
item.size = size;
|
item.size = size;
|
||||||
this.relayout(index, undefined);
|
this.relayout([index], undefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -597,42 +586,32 @@ export class SplitView extends Disposable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const indexes = range(this.viewItems.length).filter(i => i !== index);
|
||||||
|
const lowPriorityIndexes = [...indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low), index];
|
||||||
|
const highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High);
|
||||||
|
|
||||||
const item = this.viewItems[index];
|
const item = this.viewItems[index];
|
||||||
size = Math.round(size);
|
size = Math.round(size);
|
||||||
size = clamp(size, item.minimumSize, item.maximumSize);
|
size = clamp(size, item.minimumSize, Math.min(item.maximumSize, this.size));
|
||||||
let delta = size - item.size;
|
|
||||||
|
|
||||||
if (delta !== 0 && index < this.viewItems.length - 1) {
|
item.size = size;
|
||||||
const downIndexes = range(index + 1, this.viewItems.length);
|
this.relayout(lowPriorityIndexes, highPriorityIndexes);
|
||||||
const collapseDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].minimumSize), 0);
|
|
||||||
const expandDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].maximumSize - this.viewItems[i].size), 0);
|
|
||||||
const deltaDown = clamp(delta, -expandDown, collapseDown);
|
|
||||||
|
|
||||||
this.resize(index, deltaDown);
|
|
||||||
delta -= deltaDown;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (delta !== 0 && index > 0) {
|
|
||||||
const upIndexes = range(index - 1, -1);
|
|
||||||
const collapseUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].minimumSize), 0);
|
|
||||||
const expandUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].maximumSize - this.viewItems[i].size), 0);
|
|
||||||
const deltaUp = clamp(-delta, -collapseUp, expandUp);
|
|
||||||
|
|
||||||
this.resize(index - 1, deltaUp);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.distributeEmptySpace();
|
|
||||||
this.layoutViews();
|
|
||||||
this.saveProportions();
|
|
||||||
this.state = State.Idle;
|
this.state = State.Idle;
|
||||||
}
|
}
|
||||||
|
|
||||||
distributeViewSizes(): void {
|
distributeViewSizes(): void {
|
||||||
const size = Math.floor(this.size / this.viewItems.length);
|
const size = Math.floor(this.size / this.viewItems.length);
|
||||||
|
|
||||||
for (let i = 0; i < this.viewItems.length - 1; i++) {
|
for (let i = 0; i < this.viewItems.length; i++) {
|
||||||
this.resizeView(i, size);
|
const item = this.viewItems[i];
|
||||||
|
item.size = clamp(size, item.minimumSize, item.maximumSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const indexes = range(this.viewItems.length);
|
||||||
|
const lowPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low);
|
||||||
|
const highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High);
|
||||||
|
|
||||||
|
this.relayout(lowPriorityIndexes, highPriorityIndexes);
|
||||||
}
|
}
|
||||||
|
|
||||||
getViewSize(index: number): number {
|
getViewSize(index: number): number {
|
||||||
@@ -643,6 +622,15 @@ export class SplitView extends Disposable {
|
|||||||
return this.viewItems[index].size;
|
return this.viewItems[index].size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private relayout(lowPriorityIndexes?: number[], highPriorityIndexes?: number[]): void {
|
||||||
|
const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
|
||||||
|
|
||||||
|
this.resize(this.viewItems.length - 1, this.size - contentSize, undefined, lowPriorityIndexes, highPriorityIndexes);
|
||||||
|
this.distributeEmptySpace();
|
||||||
|
this.layoutViews();
|
||||||
|
this.saveProportions();
|
||||||
|
}
|
||||||
|
|
||||||
private resize(
|
private resize(
|
||||||
index: number,
|
index: number,
|
||||||
delta: number,
|
delta: number,
|
||||||
@@ -830,18 +818,26 @@ export class SplitView extends Disposable {
|
|||||||
private findFirstSnapIndex(indexes: number[]): number | undefined {
|
private findFirstSnapIndex(indexes: number[]): number | undefined {
|
||||||
// visible views first
|
// visible views first
|
||||||
for (const index of indexes) {
|
for (const index of indexes) {
|
||||||
if (!this.viewItems[index].visible) {
|
const viewItem = this.viewItems[index];
|
||||||
|
|
||||||
|
if (!viewItem.visible) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.viewItems[index].snap) {
|
if (viewItem.snap) {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// then, hidden views
|
// then, hidden views
|
||||||
for (const index of indexes) {
|
for (const index of indexes) {
|
||||||
if (!this.viewItems[index].visible && this.viewItems[index].snap) {
|
const viewItem = this.viewItems[index];
|
||||||
|
|
||||||
|
if (viewItem.visible && viewItem.maximumSize - viewItem.minimumSize > 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!viewItem.visible && viewItem.snap) {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,404 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { ISpliceable } from 'vs/base/common/sequence';
|
||||||
|
import { Iterator, ISequence } from 'vs/base/common/iterator';
|
||||||
|
import { Event } from 'vs/base/common/event';
|
||||||
|
import { ITreeModel, ITreeNode, ITreeElement, ICollapseStateChangeEvent, ITreeModelSpliceEvent } from 'vs/base/browser/ui/tree/tree';
|
||||||
|
import { IObjectTreeModelOptions, ObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel';
|
||||||
|
|
||||||
|
export interface ICompressedTreeElement<T> extends ITreeElement<T> {
|
||||||
|
readonly children?: Iterator<ICompressedTreeElement<T>> | ICompressedTreeElement<T>[];
|
||||||
|
readonly incompressible?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICompressedTreeNode<T> {
|
||||||
|
readonly elements: T[];
|
||||||
|
readonly incompressible: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function compress<T>(element: ICompressedTreeElement<T>): ITreeElement<ICompressedTreeNode<T>> {
|
||||||
|
const elements = [element.element];
|
||||||
|
const incompressible = element.incompressible || false;
|
||||||
|
|
||||||
|
let childrenIterator: Iterator<ITreeElement<T>>;
|
||||||
|
let children: ITreeElement<T>[];
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
childrenIterator = Iterator.from(element.children);
|
||||||
|
children = Iterator.collect(childrenIterator, 2);
|
||||||
|
|
||||||
|
if (children.length !== 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
element = children[0];
|
||||||
|
|
||||||
|
if (element.incompressible) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.push(element.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
element: { elements, incompressible },
|
||||||
|
children: Iterator.map(Iterator.concat(Iterator.fromArray(children), childrenIterator), compress)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function _decompress<T>(element: ITreeElement<ICompressedTreeNode<T>>, index = 0): ICompressedTreeElement<T> {
|
||||||
|
let children: Iterator<ICompressedTreeElement<T>>;
|
||||||
|
|
||||||
|
if (index < element.element.elements.length - 1) {
|
||||||
|
children = Iterator.single(_decompress(element, index + 1));
|
||||||
|
} else {
|
||||||
|
children = Iterator.map(Iterator.from(element.children), el => _decompress(el, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index === 0 && element.element.incompressible) {
|
||||||
|
return { element: element.element.elements[index], children, incompressible: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { element: element.element.elements[index], children };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function decompress<T>(element: ITreeElement<ICompressedTreeNode<T>>): ICompressedTreeElement<T> {
|
||||||
|
return _decompress(element, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function splice<T>(treeElement: ICompressedTreeElement<T>, element: T, children: Iterator<ICompressedTreeElement<T>>): ICompressedTreeElement<T> {
|
||||||
|
if (treeElement.element === element) {
|
||||||
|
return { element, children };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...treeElement,
|
||||||
|
children: Iterator.map(Iterator.from(treeElement.children), e => splice(e, element, children))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICompressedObjectTreeModelOptions<T, TFilterData> extends IObjectTreeModelOptions<ICompressedTreeNode<T>, TFilterData> { }
|
||||||
|
|
||||||
|
export class CompressedObjectTreeModel<T extends NonNullable<any>, TFilterData extends NonNullable<any> = void> implements ITreeModel<ICompressedTreeNode<T> | null, TFilterData, T | null> {
|
||||||
|
|
||||||
|
readonly rootRef = null;
|
||||||
|
|
||||||
|
get onDidSplice(): Event<ITreeModelSpliceEvent<ICompressedTreeNode<T> | null, TFilterData>> { return this.model.onDidSplice; }
|
||||||
|
get onDidChangeCollapseState(): Event<ICollapseStateChangeEvent<ICompressedTreeNode<T>, TFilterData>> { return this.model.onDidChangeCollapseState; }
|
||||||
|
get onDidChangeRenderNodeCount(): Event<ITreeNode<ICompressedTreeNode<T>, TFilterData>> { return this.model.onDidChangeRenderNodeCount; }
|
||||||
|
|
||||||
|
private model: ObjectTreeModel<ICompressedTreeNode<T>, TFilterData>;
|
||||||
|
private nodes = new Map<T | null, ICompressedTreeNode<T>>();
|
||||||
|
|
||||||
|
get size(): number { return this.nodes.size; }
|
||||||
|
|
||||||
|
constructor(list: ISpliceable<ITreeNode<ICompressedTreeNode<T>, TFilterData>>, options: ICompressedObjectTreeModelOptions<T, TFilterData> = {}) {
|
||||||
|
this.model = new ObjectTreeModel(list, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
setChildren(
|
||||||
|
element: T | null,
|
||||||
|
children: ISequence<ICompressedTreeElement<T>> | undefined,
|
||||||
|
onDidCreateNode?: (node: ITreeNode<ICompressedTreeNode<T>, TFilterData>) => void,
|
||||||
|
onDidDeleteNode?: (node: ITreeNode<ICompressedTreeNode<T>, TFilterData>) => void
|
||||||
|
): Iterator<ITreeElement<T | null>> {
|
||||||
|
const insertedElements = new Set<T | null>();
|
||||||
|
const _onDidCreateNode = (node: ITreeNode<ICompressedTreeNode<T>, TFilterData>) => {
|
||||||
|
for (const element of node.element.elements) {
|
||||||
|
insertedElements.add(element);
|
||||||
|
this.nodes.set(element, node.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (this.identityProvider) {
|
||||||
|
// const id = this.identityProvider.getId(node.element).toString();
|
||||||
|
// insertedElementIds.add(id);
|
||||||
|
// this.nodesByIdentity.set(id, node);
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (onDidCreateNode) {
|
||||||
|
onDidCreateNode(node);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const _onDidDeleteNode = (node: ITreeNode<ICompressedTreeNode<T>, TFilterData>) => {
|
||||||
|
for (const element of node.element.elements) {
|
||||||
|
if (!insertedElements.has(element)) {
|
||||||
|
this.nodes.delete(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (this.identityProvider) {
|
||||||
|
// const id = this.identityProvider.getId(node.element).toString();
|
||||||
|
// if (!insertedElementIds.has(id)) {
|
||||||
|
// this.nodesByIdentity.delete(id);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (onDidDeleteNode) {
|
||||||
|
onDidDeleteNode(node);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (element === null) {
|
||||||
|
const compressedChildren = Iterator.map(Iterator.from(children), compress);
|
||||||
|
const result = this.model.setChildren(null, compressedChildren, _onDidCreateNode, _onDidDeleteNode);
|
||||||
|
return Iterator.map(result, decompress);
|
||||||
|
}
|
||||||
|
|
||||||
|
const compressedNode = this.nodes.get(element);
|
||||||
|
const node = this.model.getNode(compressedNode) as ITreeNode<ICompressedTreeNode<T>, TFilterData>;
|
||||||
|
const parent = node.parent!;
|
||||||
|
|
||||||
|
const decompressedElement = decompress(node);
|
||||||
|
const splicedElement = splice(decompressedElement, element, Iterator.from(children));
|
||||||
|
const recompressedElement = compress(splicedElement);
|
||||||
|
|
||||||
|
const parentChildren = parent.children
|
||||||
|
.map(child => child === node ? recompressedElement : child);
|
||||||
|
|
||||||
|
this.model.setChildren(parent.element, parentChildren, _onDidCreateNode, _onDidDeleteNode);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
return Iterator.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
getListIndex(location: T | null): number {
|
||||||
|
const node = this.getCompressedNode(location);
|
||||||
|
return this.model.getListIndex(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
getListRenderCount(location: T | null): number {
|
||||||
|
const node = this.getCompressedNode(location);
|
||||||
|
return this.model.getListRenderCount(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
getNode(location?: T | null | undefined): ITreeNode<ICompressedTreeNode<T> | null, TFilterData> {
|
||||||
|
if (typeof location === 'undefined') {
|
||||||
|
return this.model.getNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
const node = this.getCompressedNode(location);
|
||||||
|
return this.model.getNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: review this
|
||||||
|
getNodeLocation(node: ITreeNode<ICompressedTreeNode<T>, TFilterData>): T | null {
|
||||||
|
const compressedNode = this.model.getNodeLocation(node);
|
||||||
|
|
||||||
|
if (compressedNode === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return compressedNode.elements[compressedNode.elements.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: review this
|
||||||
|
getParentNodeLocation(location: T | null): T | null {
|
||||||
|
const compressedNode = this.getCompressedNode(location);
|
||||||
|
const parentNode = this.model.getParentNodeLocation(compressedNode);
|
||||||
|
|
||||||
|
if (parentNode === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parentNode.elements[parentNode.elements.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
getParentElement(location: T | null): ICompressedTreeNode<T> | null {
|
||||||
|
const compressedNode = this.getCompressedNode(location);
|
||||||
|
return this.model.getParentElement(compressedNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
getFirstElementChild(location: T | null): ICompressedTreeNode<T> | null | undefined {
|
||||||
|
const compressedNode = this.getCompressedNode(location);
|
||||||
|
return this.model.getFirstElementChild(compressedNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
getLastElementAncestor(location?: T | null | undefined): ICompressedTreeNode<T> | null | undefined {
|
||||||
|
const compressedNode = typeof location === 'undefined' ? undefined : this.getCompressedNode(location);
|
||||||
|
return this.model.getLastElementAncestor(compressedNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
isCollapsible(location: T | null): boolean {
|
||||||
|
const compressedNode = this.getCompressedNode(location);
|
||||||
|
return this.model.isCollapsible(compressedNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
isCollapsed(location: T | null): boolean {
|
||||||
|
const compressedNode = this.getCompressedNode(location);
|
||||||
|
return this.model.isCollapsed(compressedNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
setCollapsed(location: T | null, collapsed?: boolean | undefined, recursive?: boolean | undefined): boolean {
|
||||||
|
const compressedNode = this.getCompressedNode(location);
|
||||||
|
return this.model.setCollapsed(compressedNode, collapsed, recursive);
|
||||||
|
}
|
||||||
|
|
||||||
|
expandTo(location: T | null): void {
|
||||||
|
const compressedNode = this.getCompressedNode(location);
|
||||||
|
this.model.expandTo(compressedNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
rerender(location: T | null): void {
|
||||||
|
const compressedNode = this.getCompressedNode(location);
|
||||||
|
this.model.rerender(compressedNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
refilter(): void {
|
||||||
|
this.model.refilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
resort(location: T | null = null, recursive = true): void {
|
||||||
|
const compressedNode = this.getCompressedNode(location);
|
||||||
|
this.model.resort(compressedNode, recursive);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getCompressedNode(element: T | null): ICompressedTreeNode<T> | null {
|
||||||
|
if (element === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const node = this.nodes.get(element);
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
|
throw new Error(`Tree element not found: ${element}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ElementMapper<T> = (elements: T[]) => T;
|
||||||
|
export const DefaultElementMapper: ElementMapper<any> = elements => elements[elements.length - 1];
|
||||||
|
|
||||||
|
export type NodeMapper<T, TFilterData> = (node: ITreeNode<ICompressedTreeNode<T> | null, TFilterData>) => ITreeNode<T | null, TFilterData>;
|
||||||
|
|
||||||
|
function mapNode<T, TFilterData>(elementMapper: ElementMapper<T>, node: ITreeNode<ICompressedTreeNode<T> | null, TFilterData>): ITreeNode<T | null, TFilterData> {
|
||||||
|
return {
|
||||||
|
...node,
|
||||||
|
element: node.element === null ? null : elementMapper(node.element.elements),
|
||||||
|
children: node.children.map(child => mapNode(elementMapper, child)),
|
||||||
|
parent: typeof node.parent === 'undefined' ? node.parent : mapNode(elementMapper, node.parent)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createNodeMapper<T, TFilterData>(elementMapper: ElementMapper<T>): NodeMapper<T, TFilterData> {
|
||||||
|
return node => mapNode(elementMapper, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ILinearCompressedObjectTreeModelOptions<T, TFilterData> extends ICompressedObjectTreeModelOptions<T, TFilterData> {
|
||||||
|
readonly elementMapper?: ElementMapper<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LinearCompressedObjectTreeModel<T extends NonNullable<any>, TFilterData extends NonNullable<any> = void> implements ITreeModel<T | null, TFilterData, T | null> {
|
||||||
|
|
||||||
|
readonly rootRef = null;
|
||||||
|
|
||||||
|
get onDidSplice(): Event<ITreeModelSpliceEvent<T | null, TFilterData>> {
|
||||||
|
return Event.map(this.model.onDidSplice, ({ insertedNodes, deletedNodes }) => ({
|
||||||
|
insertedNodes: insertedNodes.map(this.mapNode),
|
||||||
|
deletedNodes: deletedNodes.map(this.mapNode),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
get onDidChangeCollapseState(): Event<ICollapseStateChangeEvent<T | null, TFilterData>> {
|
||||||
|
return Event.map(this.model.onDidChangeCollapseState, ({ node, deep }) => ({
|
||||||
|
node: this.mapNode(node),
|
||||||
|
deep
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
get onDidChangeRenderNodeCount(): Event<ITreeNode<T | null, TFilterData>> {
|
||||||
|
return Event.map(this.model.onDidChangeRenderNodeCount, this.mapNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapElement: ElementMapper<T | null>;
|
||||||
|
private mapNode: NodeMapper<T | null, TFilterData>;
|
||||||
|
private model: CompressedObjectTreeModel<T, TFilterData>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
list: ISpliceable<ITreeNode<ICompressedTreeNode<T>, TFilterData>>,
|
||||||
|
options: ILinearCompressedObjectTreeModelOptions<T, TFilterData> = {}
|
||||||
|
) {
|
||||||
|
this.mapElement = options.elementMapper || DefaultElementMapper;
|
||||||
|
this.mapNode = createNodeMapper(this.mapElement);
|
||||||
|
this.model = new CompressedObjectTreeModel(list, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
getListIndex(location: T | null): number {
|
||||||
|
return this.model.getListIndex(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
getListRenderCount(location: T | null): number {
|
||||||
|
return this.model.getListRenderCount(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
getNode(location?: T | null | undefined): ITreeNode<T | null, any> {
|
||||||
|
return this.mapNode(this.model.getNode(location));
|
||||||
|
}
|
||||||
|
|
||||||
|
getNodeLocation(node: ITreeNode<T | null, any>): T | null {
|
||||||
|
return node.element;
|
||||||
|
}
|
||||||
|
|
||||||
|
getParentNodeLocation(location: T | null): T | null {
|
||||||
|
return this.model.getParentNodeLocation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
getParentElement(location: T | null): T | null {
|
||||||
|
const result = this.model.getParentElement(location);
|
||||||
|
|
||||||
|
if (result === null) {
|
||||||
|
return null; // {{SQL CARBON EDIT}} strict-null-check
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.mapElement(result.elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
getFirstElementChild(location: T | null): T | null | undefined {
|
||||||
|
const result = this.model.getFirstElementChild(location);
|
||||||
|
|
||||||
|
if (result === null || typeof result === 'undefined') {
|
||||||
|
return null; // {{SQL CARBON EDIT}} strict-null-check
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.mapElement(result.elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
getLastElementAncestor(location?: T | null | undefined): T | null | undefined {
|
||||||
|
const result = this.model.getLastElementAncestor(location);
|
||||||
|
|
||||||
|
if (result === null || typeof result === 'undefined') {
|
||||||
|
return null; // {{SQL CARBON EDIT}} strict-null-check
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.mapElement(result.elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
isCollapsible(location: T | null): boolean {
|
||||||
|
return this.model.isCollapsible(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
isCollapsed(location: T | null): boolean {
|
||||||
|
return this.model.isCollapsed(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
setCollapsed(location: T | null, collapsed?: boolean | undefined, recursive?: boolean | undefined): boolean {
|
||||||
|
return this.model.setCollapsed(location, collapsed, recursive);
|
||||||
|
}
|
||||||
|
|
||||||
|
expandTo(location: T | null): void {
|
||||||
|
return this.model.expandTo(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
rerender(location: T | null): void {
|
||||||
|
return this.model.rerender(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
refilter(): void {
|
||||||
|
return this.model.refilter();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,7 +53,7 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
|||||||
children: ISequence<ITreeElement<T>> | undefined,
|
children: ISequence<ITreeElement<T>> | undefined,
|
||||||
onDidCreateNode?: (node: ITreeNode<T, TFilterData>) => void,
|
onDidCreateNode?: (node: ITreeNode<T, TFilterData>) => void,
|
||||||
onDidDeleteNode?: (node: ITreeNode<T, TFilterData>) => void
|
onDidDeleteNode?: (node: ITreeNode<T, TFilterData>) => void
|
||||||
): Iterator<ITreeElement<T | null>> {
|
): Iterator<ITreeElement<T>> {
|
||||||
const location = this.getElementLocation(element);
|
const location = this.getElementLocation(element);
|
||||||
return this._setChildren(location, this.preserveCollapseState(children), onDidCreateNode, onDidDeleteNode);
|
return this._setChildren(location, this.preserveCollapseState(children), onDidCreateNode, onDidDeleteNode);
|
||||||
}
|
}
|
||||||
@@ -63,7 +63,7 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
|||||||
children: ISequence<ITreeElement<T>> | undefined,
|
children: ISequence<ITreeElement<T>> | undefined,
|
||||||
onDidCreateNode?: (node: ITreeNode<T, TFilterData>) => void,
|
onDidCreateNode?: (node: ITreeNode<T, TFilterData>) => void,
|
||||||
onDidDeleteNode?: (node: ITreeNode<T, TFilterData>) => void
|
onDidDeleteNode?: (node: ITreeNode<T, TFilterData>) => void
|
||||||
): Iterator<ITreeElement<T | null>> {
|
): Iterator<ITreeElement<T>> {
|
||||||
const insertedElements = new Set<T | null>();
|
const insertedElements = new Set<T | null>();
|
||||||
const insertedElementIds = new Set<string>();
|
const insertedElementIds = new Set<string>();
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
|||||||
_onDidDeleteNode
|
_onDidDeleteNode
|
||||||
);
|
);
|
||||||
|
|
||||||
return result;
|
return result as Iterator<ITreeElement<T>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
private preserveCollapseState(elements: ISequence<ITreeElement<T>> | undefined): ISequence<ITreeElement<T>> {
|
private preserveCollapseState(elements: ISequence<ITreeElement<T>> | undefined): ISequence<ITreeElement<T>> {
|
||||||
@@ -144,7 +144,7 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
rerender(element: T): void {
|
rerender(element: T | null): void {
|
||||||
const location = this.getElementLocation(element);
|
const location = this.getElementLocation(element);
|
||||||
this.model.rerender(location);
|
this.model.rerender(location);
|
||||||
}
|
}
|
||||||
@@ -190,32 +190,32 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
|||||||
return this.model.getLastElementAncestor(location);
|
return this.model.getLastElementAncestor(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
getListIndex(element: T): number {
|
getListIndex(element: T | null): number {
|
||||||
const location = this.getElementLocation(element);
|
const location = this.getElementLocation(element);
|
||||||
return this.model.getListIndex(location);
|
return this.model.getListIndex(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
getListRenderCount(element: T): number {
|
getListRenderCount(element: T | null): number {
|
||||||
const location = this.getElementLocation(element);
|
const location = this.getElementLocation(element);
|
||||||
return this.model.getListRenderCount(location);
|
return this.model.getListRenderCount(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
isCollapsible(element: T): boolean {
|
isCollapsible(element: T | null): boolean {
|
||||||
const location = this.getElementLocation(element);
|
const location = this.getElementLocation(element);
|
||||||
return this.model.isCollapsible(location);
|
return this.model.isCollapsible(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
isCollapsed(element: T): boolean {
|
isCollapsed(element: T | null): boolean {
|
||||||
const location = this.getElementLocation(element);
|
const location = this.getElementLocation(element);
|
||||||
return this.model.isCollapsed(location);
|
return this.model.isCollapsed(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
setCollapsed(element: T, collapsed?: boolean, recursive?: boolean): boolean {
|
setCollapsed(element: T | null, collapsed?: boolean, recursive?: boolean): boolean {
|
||||||
const location = this.getElementLocation(element);
|
const location = this.getElementLocation(element);
|
||||||
return this.model.setCollapsed(location, collapsed, recursive);
|
return this.model.setCollapsed(location, collapsed, recursive);
|
||||||
}
|
}
|
||||||
|
|
||||||
expandTo(element: T): void {
|
expandTo(element: T | null): void {
|
||||||
const location = this.getElementLocation(element);
|
const location = this.getElementLocation(element);
|
||||||
this.model.expandTo(location);
|
this.model.expandTo(location);
|
||||||
}
|
}
|
||||||
@@ -238,11 +238,15 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
getNodeLocation(node: ITreeNode<T, TFilterData>): T {
|
getNodeLocation(node: ITreeNode<T, TFilterData>): T | null {
|
||||||
return node.element;
|
return node.element;
|
||||||
}
|
}
|
||||||
|
|
||||||
getParentNodeLocation(element: T): T | null {
|
getParentNodeLocation(element: T | null): T | null {
|
||||||
|
if (element === null) {
|
||||||
|
throw new Error(`Invalid getParentNodeLocation call`);
|
||||||
|
}
|
||||||
|
|
||||||
const node = this.nodes.get(element);
|
const node = this.nodes.get(element);
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ export interface ITreeModel<T, TFilterData, TRef> {
|
|||||||
setCollapsed(location: TRef, collapsed?: boolean, recursive?: boolean): boolean;
|
setCollapsed(location: TRef, collapsed?: boolean, recursive?: boolean): boolean;
|
||||||
expandTo(location: TRef): void;
|
expandTo(location: TRef): void;
|
||||||
|
|
||||||
|
rerender(location: TRef): void;
|
||||||
refilter(): void;
|
refilter(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,21 @@ export module Iterator {
|
|||||||
return _empty;
|
return _empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function single<T>(value: T): Iterator<T> {
|
||||||
|
let done = false;
|
||||||
|
|
||||||
|
return {
|
||||||
|
next(): IteratorResult<T> {
|
||||||
|
if (done) {
|
||||||
|
return FIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
done = true;
|
||||||
|
return { done: false, value };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function fromArray<T>(array: T[], index = 0, length = array.length): Iterator<T> {
|
export function fromArray<T>(array: T[], index = 0, length = array.length): Iterator<T> {
|
||||||
return {
|
return {
|
||||||
next(): IteratorResult<T> {
|
next(): IteratorResult<T> {
|
||||||
@@ -86,11 +101,47 @@ export module Iterator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function collect<T>(iterator: Iterator<T>): T[] {
|
export function collect<T>(iterator: Iterator<T>, atMost: number = Number.POSITIVE_INFINITY): T[] {
|
||||||
const result: T[] = [];
|
const result: T[] = [];
|
||||||
forEach(iterator, value => result.push(value));
|
|
||||||
|
if (atMost === 0) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
for (let next = iterator.next(); !next.done; next = iterator.next()) {
|
||||||
|
result.push(next.value);
|
||||||
|
|
||||||
|
if (++i >= atMost) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function concat<T>(...iterators: Iterator<T>[]): Iterator<T> {
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
next() {
|
||||||
|
if (i >= iterators.length) {
|
||||||
|
return FIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
const iterator = iterators[i];
|
||||||
|
const result = iterator.next();
|
||||||
|
|
||||||
|
if (result.done) {
|
||||||
|
i++;
|
||||||
|
return this.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ISequence<T> = Iterator<T> | T[];
|
export type ISequence<T> = Iterator<T> | T[];
|
||||||
|
|||||||
@@ -107,19 +107,19 @@ suite('Gridview', function () {
|
|||||||
test('simple layout', function () {
|
test('simple layout', function () {
|
||||||
gridview.layout(800, 600);
|
gridview.layout(800, 600);
|
||||||
|
|
||||||
const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
|
const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||||
gridview.addView(view1, 200, [0]);
|
gridview.addView(view1, 200, [0]);
|
||||||
assert.deepEqual(view1.size, [800, 600]);
|
assert.deepEqual(view1.size, [800, 600]);
|
||||||
assert.deepEqual(gridview.getViewSize([0]), { width: 800, height: 600 });
|
assert.deepEqual(gridview.getViewSize([0]), { width: 800, height: 600 });
|
||||||
|
|
||||||
const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
|
const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||||
gridview.addView(view2, 200, [0]);
|
gridview.addView(view2, 200, [0]);
|
||||||
assert.deepEqual(view1.size, [800, 400]);
|
assert.deepEqual(view1.size, [800, 400]);
|
||||||
assert.deepEqual(gridview.getViewSize([1]), { width: 800, height: 400 });
|
assert.deepEqual(gridview.getViewSize([1]), { width: 800, height: 400 });
|
||||||
assert.deepEqual(view2.size, [800, 200]);
|
assert.deepEqual(view2.size, [800, 200]);
|
||||||
assert.deepEqual(gridview.getViewSize([0]), { width: 800, height: 200 });
|
assert.deepEqual(gridview.getViewSize([0]), { width: 800, height: 200 });
|
||||||
|
|
||||||
const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
|
const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||||
gridview.addView(view3, 200, [1, 1]);
|
gridview.addView(view3, 200, [1, 1]);
|
||||||
assert.deepEqual(view1.size, [600, 400]);
|
assert.deepEqual(view1.size, [600, 400]);
|
||||||
assert.deepEqual(gridview.getViewSize([1, 0]), { width: 600, height: 400 });
|
assert.deepEqual(gridview.getViewSize([1, 0]), { width: 600, height: 400 });
|
||||||
@@ -128,7 +128,7 @@ suite('Gridview', function () {
|
|||||||
assert.deepEqual(view3.size, [200, 400]);
|
assert.deepEqual(view3.size, [200, 400]);
|
||||||
assert.deepEqual(gridview.getViewSize([1, 1]), { width: 200, height: 400 });
|
assert.deepEqual(gridview.getViewSize([1, 1]), { width: 200, height: 400 });
|
||||||
|
|
||||||
const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
|
const view4 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||||
gridview.addView(view4, 200, [0, 0]);
|
gridview.addView(view4, 200, [0, 0]);
|
||||||
assert.deepEqual(view1.size, [600, 400]);
|
assert.deepEqual(view1.size, [600, 400]);
|
||||||
assert.deepEqual(gridview.getViewSize([1, 0]), { width: 600, height: 400 });
|
assert.deepEqual(gridview.getViewSize([1, 0]), { width: 600, height: 400 });
|
||||||
@@ -139,7 +139,7 @@ suite('Gridview', function () {
|
|||||||
assert.deepEqual(view4.size, [200, 200]);
|
assert.deepEqual(view4.size, [200, 200]);
|
||||||
assert.deepEqual(gridview.getViewSize([0, 0]), { width: 200, height: 200 });
|
assert.deepEqual(gridview.getViewSize([0, 0]), { width: 200, height: 200 });
|
||||||
|
|
||||||
const view5 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
|
const view5 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||||
gridview.addView(view5, 100, [1, 0, 1]);
|
gridview.addView(view5, 100, [1, 0, 1]);
|
||||||
assert.deepEqual(view1.size, [600, 300]);
|
assert.deepEqual(view1.size, [600, 300]);
|
||||||
assert.deepEqual(gridview.getViewSize([1, 0, 0]), { width: 600, height: 300 });
|
assert.deepEqual(gridview.getViewSize([1, 0, 0]), { width: 600, height: 300 });
|
||||||
@@ -156,30 +156,30 @@ suite('Gridview', function () {
|
|||||||
test('simple layout with automatic size distribution', function () {
|
test('simple layout with automatic size distribution', function () {
|
||||||
gridview.layout(800, 600);
|
gridview.layout(800, 600);
|
||||||
|
|
||||||
const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
|
const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||||
gridview.addView(view1, Sizing.Distribute, [0]);
|
gridview.addView(view1, Sizing.Distribute, [0]);
|
||||||
assert.deepEqual(view1.size, [800, 600]);
|
assert.deepEqual(view1.size, [800, 600]);
|
||||||
assert.deepEqual(gridview.getViewSize([0]), { width: 800, height: 600 });
|
assert.deepEqual(gridview.getViewSize([0]), { width: 800, height: 600 });
|
||||||
|
|
||||||
const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
|
const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||||
gridview.addView(view2, Sizing.Distribute, [0]);
|
gridview.addView(view2, Sizing.Distribute, [0]);
|
||||||
assert.deepEqual(view1.size, [800, 300]);
|
assert.deepEqual(view1.size, [800, 300]);
|
||||||
assert.deepEqual(view2.size, [800, 300]);
|
assert.deepEqual(view2.size, [800, 300]);
|
||||||
|
|
||||||
const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
|
const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||||
gridview.addView(view3, Sizing.Distribute, [1, 1]);
|
gridview.addView(view3, Sizing.Distribute, [1, 1]);
|
||||||
assert.deepEqual(view1.size, [400, 300]);
|
assert.deepEqual(view1.size, [400, 300]);
|
||||||
assert.deepEqual(view2.size, [800, 300]);
|
assert.deepEqual(view2.size, [800, 300]);
|
||||||
assert.deepEqual(view3.size, [400, 300]);
|
assert.deepEqual(view3.size, [400, 300]);
|
||||||
|
|
||||||
const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
|
const view4 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||||
gridview.addView(view4, Sizing.Distribute, [0, 0]);
|
gridview.addView(view4, Sizing.Distribute, [0, 0]);
|
||||||
assert.deepEqual(view1.size, [400, 300]);
|
assert.deepEqual(view1.size, [400, 300]);
|
||||||
assert.deepEqual(view2.size, [400, 300]);
|
assert.deepEqual(view2.size, [400, 300]);
|
||||||
assert.deepEqual(view3.size, [400, 300]);
|
assert.deepEqual(view3.size, [400, 300]);
|
||||||
assert.deepEqual(view4.size, [400, 300]);
|
assert.deepEqual(view4.size, [400, 300]);
|
||||||
|
|
||||||
const view5 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
|
const view5 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||||
gridview.addView(view5, Sizing.Distribute, [1, 0, 1]);
|
gridview.addView(view5, Sizing.Distribute, [1, 0, 1]);
|
||||||
assert.deepEqual(view1.size, [400, 150]);
|
assert.deepEqual(view1.size, [400, 150]);
|
||||||
assert.deepEqual(view2.size, [400, 300]);
|
assert.deepEqual(view2.size, [400, 300]);
|
||||||
@@ -190,13 +190,13 @@ suite('Gridview', function () {
|
|||||||
|
|
||||||
test('addviews before layout call 1', function () {
|
test('addviews before layout call 1', function () {
|
||||||
|
|
||||||
const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
|
const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||||
gridview.addView(view1, 200, [0]);
|
gridview.addView(view1, 200, [0]);
|
||||||
|
|
||||||
const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
|
const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||||
gridview.addView(view2, 200, [0]);
|
gridview.addView(view2, 200, [0]);
|
||||||
|
|
||||||
const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
|
const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||||
gridview.addView(view3, 200, [1, 1]);
|
gridview.addView(view3, 200, [1, 1]);
|
||||||
|
|
||||||
gridview.layout(800, 600);
|
gridview.layout(800, 600);
|
||||||
@@ -207,14 +207,13 @@ suite('Gridview', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('addviews before layout call 2', function () {
|
test('addviews before layout call 2', function () {
|
||||||
|
const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||||
const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
|
|
||||||
gridview.addView(view1, 200, [0]);
|
gridview.addView(view1, 200, [0]);
|
||||||
|
|
||||||
const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
|
const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||||
gridview.addView(view2, 200, [0]);
|
gridview.addView(view2, 200, [0]);
|
||||||
|
|
||||||
const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE);
|
const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||||
gridview.addView(view3, 200, [0, 0]);
|
gridview.addView(view3, 200, [0, 0]);
|
||||||
|
|
||||||
gridview.layout(800, 600);
|
gridview.layout(800, 600);
|
||||||
|
|||||||
@@ -196,8 +196,8 @@ suite('Splitview', () => {
|
|||||||
splitview.resizeView(0, 70);
|
splitview.resizeView(0, 70);
|
||||||
|
|
||||||
assert.equal(view1.size, 70, 'view1 is collapsed');
|
assert.equal(view1.size, 70, 'view1 is collapsed');
|
||||||
assert.equal(view2.size, 110, 'view2 is expanded');
|
assert.equal(view2.size, 40, 'view2 stays the same');
|
||||||
assert.equal(view3.size, 20, 'view3 stays the same');
|
assert.equal(view3.size, 90, 'view3 is stretched');
|
||||||
|
|
||||||
splitview.resizeView(2, 40);
|
splitview.resizeView(2, 40);
|
||||||
|
|
||||||
@@ -474,10 +474,10 @@ suite('Splitview', () => {
|
|||||||
splitview.addView(view1, Sizing.Distribute);
|
splitview.addView(view1, Sizing.Distribute);
|
||||||
splitview.addView(view2, Sizing.Distribute);
|
splitview.addView(view2, Sizing.Distribute);
|
||||||
splitview.addView(view3, Sizing.Distribute);
|
splitview.addView(view3, Sizing.Distribute);
|
||||||
assert.deepEqual([view1.size, view2.size, view3.size], [66, 66, 68]);
|
assert.deepEqual([view1.size, view2.size, view3.size], [66, 68, 66]);
|
||||||
|
|
||||||
splitview.layout(180);
|
splitview.layout(180);
|
||||||
assert.deepEqual([view1.size, view2.size, view3.size], [66, 46, 68]);
|
assert.deepEqual([view1.size, view2.size, view3.size], [66, 48, 66]);
|
||||||
|
|
||||||
splitview.layout(124);
|
splitview.layout(124);
|
||||||
assert.deepEqual([view1.size, view2.size, view3.size], [66, 20, 38]);
|
assert.deepEqual([view1.size, view2.size, view3.size], [66, 20, 38]);
|
||||||
@@ -504,13 +504,13 @@ suite('Splitview', () => {
|
|||||||
splitview.addView(view1, Sizing.Distribute);
|
splitview.addView(view1, Sizing.Distribute);
|
||||||
splitview.addView(view2, Sizing.Distribute);
|
splitview.addView(view2, Sizing.Distribute);
|
||||||
splitview.addView(view3, Sizing.Distribute);
|
splitview.addView(view3, Sizing.Distribute);
|
||||||
assert.deepEqual([view1.size, view2.size, view3.size], [66, 66, 68]);
|
assert.deepEqual([view1.size, view2.size, view3.size], [66, 68, 66]);
|
||||||
|
|
||||||
splitview.layout(180);
|
splitview.layout(180);
|
||||||
assert.deepEqual([view1.size, view2.size, view3.size], [66, 46, 68]);
|
assert.deepEqual([view1.size, view2.size, view3.size], [66, 48, 66]);
|
||||||
|
|
||||||
splitview.layout(132);
|
splitview.layout(132);
|
||||||
assert.deepEqual([view1.size, view2.size, view3.size], [44, 20, 68]);
|
assert.deepEqual([view1.size, view2.size, view3.size], [46, 20, 66]);
|
||||||
|
|
||||||
splitview.layout(60);
|
splitview.layout(60);
|
||||||
assert.deepEqual([view1.size, view2.size, view3.size], [20, 20, 20]);
|
assert.deepEqual([view1.size, view2.size, view3.size], [20, 20, 20]);
|
||||||
|
|||||||
@@ -0,0 +1,430 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as assert from 'assert';
|
||||||
|
import { compress, ICompressedTreeElement, ICompressedTreeNode, decompress, CompressedObjectTreeModel } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';
|
||||||
|
import { Iterator } from 'vs/base/common/iterator';
|
||||||
|
import { ITreeNode } from 'vs/base/browser/ui/tree/tree';
|
||||||
|
import { ISpliceable } from 'vs/base/common/sequence';
|
||||||
|
|
||||||
|
interface IResolvedCompressedTreeElement<T> extends ICompressedTreeElement<T> {
|
||||||
|
readonly element: T;
|
||||||
|
readonly children?: ICompressedTreeElement<T>[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolve<T>(treeElement: ICompressedTreeElement<T>): IResolvedCompressedTreeElement<T> {
|
||||||
|
const result: any = { element: treeElement.element };
|
||||||
|
const children = Iterator.collect(Iterator.map(Iterator.from(treeElement.children), resolve));
|
||||||
|
|
||||||
|
if (treeElement.incompressible) {
|
||||||
|
result.incompressible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (children.length > 0) {
|
||||||
|
result.children = children;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
suite('CompressedObjectTree', function () {
|
||||||
|
|
||||||
|
suite('compress & decompress', function () {
|
||||||
|
|
||||||
|
test('small', function () {
|
||||||
|
const decompressed: ICompressedTreeElement<number> = { element: 1 };
|
||||||
|
const compressed: IResolvedCompressedTreeElement<ICompressedTreeNode<number>> =
|
||||||
|
{ element: { elements: [1], incompressible: false } };
|
||||||
|
|
||||||
|
assert.deepEqual(resolve(compress(decompressed)), compressed);
|
||||||
|
assert.deepEqual(resolve(decompress(compressed)), decompressed);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('no compression', function () {
|
||||||
|
const decompressed: ICompressedTreeElement<number> = {
|
||||||
|
element: 1, children: [
|
||||||
|
{ element: 11 },
|
||||||
|
{ element: 12 },
|
||||||
|
{ element: 13 }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const compressed: IResolvedCompressedTreeElement<ICompressedTreeNode<number>> = {
|
||||||
|
element: { elements: [1], incompressible: false },
|
||||||
|
children: [
|
||||||
|
{ element: { elements: [11], incompressible: false } },
|
||||||
|
{ element: { elements: [12], incompressible: false } },
|
||||||
|
{ element: { elements: [13], incompressible: false } }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.deepEqual(resolve(compress(decompressed)), compressed);
|
||||||
|
assert.deepEqual(resolve(decompress(compressed)), decompressed);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('single hierarchy', function () {
|
||||||
|
const decompressed: ICompressedTreeElement<number> = {
|
||||||
|
element: 1, children: [
|
||||||
|
{
|
||||||
|
element: 11, children: [
|
||||||
|
{
|
||||||
|
element: 111, children: [
|
||||||
|
{ element: 1111 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const compressed: IResolvedCompressedTreeElement<ICompressedTreeNode<number>> = {
|
||||||
|
element: { elements: [1, 11, 111, 1111], incompressible: false }
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.deepEqual(resolve(compress(decompressed)), compressed);
|
||||||
|
assert.deepEqual(resolve(decompress(compressed)), decompressed);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('deep compression', function () {
|
||||||
|
const decompressed: ICompressedTreeElement<number> = {
|
||||||
|
element: 1, children: [
|
||||||
|
{
|
||||||
|
element: 11, children: [
|
||||||
|
{
|
||||||
|
element: 111, children: [
|
||||||
|
{ element: 1111 },
|
||||||
|
{ element: 1112 },
|
||||||
|
{ element: 1113 },
|
||||||
|
{ element: 1114 },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const compressed: IResolvedCompressedTreeElement<ICompressedTreeNode<number>> = {
|
||||||
|
element: { elements: [1, 11, 111], incompressible: false },
|
||||||
|
children: [
|
||||||
|
{ element: { elements: [1111], incompressible: false } },
|
||||||
|
{ element: { elements: [1112], incompressible: false } },
|
||||||
|
{ element: { elements: [1113], incompressible: false } },
|
||||||
|
{ element: { elements: [1114], incompressible: false } },
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.deepEqual(resolve(compress(decompressed)), compressed);
|
||||||
|
assert.deepEqual(resolve(decompress(compressed)), decompressed);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('double deep compression', function () {
|
||||||
|
const decompressed: ICompressedTreeElement<number> = {
|
||||||
|
element: 1, children: [
|
||||||
|
{
|
||||||
|
element: 11, children: [
|
||||||
|
{
|
||||||
|
element: 111, children: [
|
||||||
|
{ element: 1112 },
|
||||||
|
{ element: 1113 },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
element: 12, children: [
|
||||||
|
{
|
||||||
|
element: 121, children: [
|
||||||
|
{ element: 1212 },
|
||||||
|
{ element: 1213 },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const compressed: IResolvedCompressedTreeElement<ICompressedTreeNode<number>> = {
|
||||||
|
element: { elements: [1], incompressible: false },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
element: { elements: [11, 111], incompressible: false },
|
||||||
|
children: [
|
||||||
|
{ element: { elements: [1112], incompressible: false } },
|
||||||
|
{ element: { elements: [1113], incompressible: false } },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
element: { elements: [12, 121], incompressible: false },
|
||||||
|
children: [
|
||||||
|
{ element: { elements: [1212], incompressible: false } },
|
||||||
|
{ element: { elements: [1213], incompressible: false } },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.deepEqual(resolve(compress(decompressed)), compressed);
|
||||||
|
assert.deepEqual(resolve(decompress(compressed)), decompressed);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('incompressible leaf', function () {
|
||||||
|
const decompressed: ICompressedTreeElement<number> = {
|
||||||
|
element: 1, children: [
|
||||||
|
{
|
||||||
|
element: 11, children: [
|
||||||
|
{
|
||||||
|
element: 111, children: [
|
||||||
|
{ element: 1111, incompressible: true }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const compressed: IResolvedCompressedTreeElement<ICompressedTreeNode<number>> = {
|
||||||
|
element: { elements: [1, 11, 111], incompressible: false },
|
||||||
|
children: [
|
||||||
|
{ element: { elements: [1111], incompressible: true } }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.deepEqual(resolve(compress(decompressed)), compressed);
|
||||||
|
assert.deepEqual(resolve(decompress(compressed)), decompressed);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('incompressible branch', function () {
|
||||||
|
const decompressed: ICompressedTreeElement<number> = {
|
||||||
|
element: 1, children: [
|
||||||
|
{
|
||||||
|
element: 11, children: [
|
||||||
|
{
|
||||||
|
element: 111, incompressible: true, children: [
|
||||||
|
{ element: 1111 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const compressed: IResolvedCompressedTreeElement<ICompressedTreeNode<number>> = {
|
||||||
|
element: { elements: [1, 11], incompressible: false },
|
||||||
|
children: [
|
||||||
|
{ element: { elements: [111, 1111], incompressible: true } }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.deepEqual(resolve(compress(decompressed)), compressed);
|
||||||
|
assert.deepEqual(resolve(decompress(compressed)), decompressed);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('incompressible chain', function () {
|
||||||
|
const decompressed: ICompressedTreeElement<number> = {
|
||||||
|
element: 1, children: [
|
||||||
|
{
|
||||||
|
element: 11, children: [
|
||||||
|
{
|
||||||
|
element: 111, incompressible: true, children: [
|
||||||
|
{ element: 1111, incompressible: true }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const compressed: IResolvedCompressedTreeElement<ICompressedTreeNode<number>> = {
|
||||||
|
element: { elements: [1, 11], incompressible: false },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
element: { elements: [111], incompressible: true },
|
||||||
|
children: [
|
||||||
|
{ element: { elements: [1111], incompressible: true } }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.deepEqual(resolve(compress(decompressed)), compressed);
|
||||||
|
assert.deepEqual(resolve(decompress(compressed)), decompressed);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('incompressible tree', function () {
|
||||||
|
const decompressed: ICompressedTreeElement<number> = {
|
||||||
|
element: 1, children: [
|
||||||
|
{
|
||||||
|
element: 11, incompressible: true, children: [
|
||||||
|
{
|
||||||
|
element: 111, incompressible: true, children: [
|
||||||
|
{ element: 1111, incompressible: true }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const compressed: IResolvedCompressedTreeElement<ICompressedTreeNode<number>> = {
|
||||||
|
element: { elements: [1], incompressible: false },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
element: { elements: [11], incompressible: true },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
element: { elements: [111], incompressible: true },
|
||||||
|
children: [
|
||||||
|
{ element: { elements: [1111], incompressible: true } }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.deepEqual(resolve(compress(decompressed)), compressed);
|
||||||
|
assert.deepEqual(resolve(decompress(compressed)), decompressed);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function toSpliceable<T>(arr: T[]): ISpliceable<T> {
|
||||||
|
return {
|
||||||
|
splice(start: number, deleteCount: number, elements: T[]): void {
|
||||||
|
arr.splice(start, deleteCount, ...elements);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function toArray<T>(list: ITreeNode<ICompressedTreeNode<T>>[]): T[][] {
|
||||||
|
return list.map(i => i.element.elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
suite('CompressedObjectTreeModel', function () {
|
||||||
|
|
||||||
|
test('ctor', () => {
|
||||||
|
const list: ITreeNode<ICompressedTreeNode<number>>[] = [];
|
||||||
|
const model = new CompressedObjectTreeModel<number>(toSpliceable(list));
|
||||||
|
assert(model);
|
||||||
|
assert.equal(list.length, 0);
|
||||||
|
assert.equal(model.size, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('flat', () => {
|
||||||
|
const list: ITreeNode<ICompressedTreeNode<number>>[] = [];
|
||||||
|
const model = new CompressedObjectTreeModel<number>(toSpliceable(list));
|
||||||
|
|
||||||
|
model.setChildren(null, Iterator.fromArray([
|
||||||
|
{ element: 0 },
|
||||||
|
{ element: 1 },
|
||||||
|
{ element: 2 }
|
||||||
|
]));
|
||||||
|
|
||||||
|
assert.deepEqual(toArray(list), [[0], [1], [2]]);
|
||||||
|
assert.equal(model.size, 3);
|
||||||
|
|
||||||
|
model.setChildren(null, Iterator.fromArray([
|
||||||
|
{ element: 3 },
|
||||||
|
{ element: 4 },
|
||||||
|
{ element: 5 },
|
||||||
|
]));
|
||||||
|
|
||||||
|
assert.deepEqual(toArray(list), [[3], [4], [5]]);
|
||||||
|
assert.equal(model.size, 3);
|
||||||
|
|
||||||
|
model.setChildren(null, Iterator.empty());
|
||||||
|
assert.deepEqual(toArray(list), []);
|
||||||
|
assert.equal(model.size, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('nested', () => {
|
||||||
|
const list: ITreeNode<ICompressedTreeNode<number>>[] = [];
|
||||||
|
const model = new CompressedObjectTreeModel<number>(toSpliceable(list));
|
||||||
|
|
||||||
|
model.setChildren(null, Iterator.fromArray([
|
||||||
|
{
|
||||||
|
element: 0, children: Iterator.fromArray([
|
||||||
|
{ element: 10 },
|
||||||
|
{ element: 11 },
|
||||||
|
{ element: 12 },
|
||||||
|
])
|
||||||
|
},
|
||||||
|
{ element: 1 },
|
||||||
|
{ element: 2 }
|
||||||
|
]));
|
||||||
|
|
||||||
|
assert.deepEqual(toArray(list), [[0], [10], [11], [12], [1], [2]]);
|
||||||
|
assert.equal(model.size, 6);
|
||||||
|
|
||||||
|
model.setChildren(12, Iterator.fromArray([
|
||||||
|
{ element: 120 },
|
||||||
|
{ element: 121 }
|
||||||
|
]));
|
||||||
|
|
||||||
|
assert.deepEqual(toArray(list), [[0], [10], [11], [12], [120], [121], [1], [2]]);
|
||||||
|
assert.equal(model.size, 8);
|
||||||
|
|
||||||
|
model.setChildren(0, Iterator.empty());
|
||||||
|
assert.deepEqual(toArray(list), [[0], [1], [2]]);
|
||||||
|
assert.equal(model.size, 3);
|
||||||
|
|
||||||
|
model.setChildren(null, Iterator.empty());
|
||||||
|
assert.deepEqual(toArray(list), []);
|
||||||
|
assert.equal(model.size, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('compressed', () => {
|
||||||
|
const list: ITreeNode<ICompressedTreeNode<number>>[] = [];
|
||||||
|
const model = new CompressedObjectTreeModel<number>(toSpliceable(list));
|
||||||
|
|
||||||
|
model.setChildren(null, Iterator.fromArray([
|
||||||
|
{
|
||||||
|
element: 1, children: Iterator.fromArray([{
|
||||||
|
element: 11, children: Iterator.fromArray([{
|
||||||
|
element: 111, children: Iterator.fromArray([
|
||||||
|
{ element: 1111 },
|
||||||
|
{ element: 1112 },
|
||||||
|
{ element: 1113 },
|
||||||
|
])
|
||||||
|
}])
|
||||||
|
}])
|
||||||
|
}
|
||||||
|
]));
|
||||||
|
|
||||||
|
assert.deepEqual(toArray(list), [[1, 11, 111], [1111], [1112], [1113]]);
|
||||||
|
assert.equal(model.size, 6);
|
||||||
|
|
||||||
|
model.setChildren(11, Iterator.fromArray([
|
||||||
|
{ element: 111 },
|
||||||
|
{ element: 112 },
|
||||||
|
{ element: 113 },
|
||||||
|
]));
|
||||||
|
|
||||||
|
assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113]]);
|
||||||
|
assert.equal(model.size, 5);
|
||||||
|
|
||||||
|
model.setChildren(113, Iterator.fromArray([
|
||||||
|
{ element: 1131 }
|
||||||
|
]));
|
||||||
|
|
||||||
|
assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113, 1131]]);
|
||||||
|
assert.equal(model.size, 6);
|
||||||
|
|
||||||
|
model.setChildren(1131, Iterator.fromArray([
|
||||||
|
{ element: 1132 }
|
||||||
|
]));
|
||||||
|
|
||||||
|
assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113, 1131, 1132]]);
|
||||||
|
assert.equal(model.size, 7);
|
||||||
|
|
||||||
|
model.setChildren(1131, Iterator.fromArray([
|
||||||
|
{ element: 1132 },
|
||||||
|
{ element: 1133 },
|
||||||
|
]));
|
||||||
|
|
||||||
|
assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113, 1131], [1132], [1133]]);
|
||||||
|
assert.equal(model.size, 8);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as assert from 'assert';
|
||||||
|
import { Iterator } from 'vs/base/common/iterator';
|
||||||
|
|
||||||
|
suite('Iterator', () => {
|
||||||
|
test('concat', () => {
|
||||||
|
const first = Iterator.fromArray([1, 2, 3]);
|
||||||
|
const second = Iterator.fromArray([4, 5, 6]);
|
||||||
|
const third = Iterator.fromArray([7, 8, 9]);
|
||||||
|
const actualIterator = Iterator.concat(first, second, third);
|
||||||
|
const actual = Iterator.collect(actualIterator);
|
||||||
|
|
||||||
|
assert.deepEqual(actual, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
|
||||||
|
|
||||||
<meta http-equiv="Content-Security-Policy"
|
<meta http-equiv="Content-Security-Policy"
|
||||||
content="default-src 'none'; img-src 'self' https: data: blob: vscode-remote:; media-src 'none'; child-src 'self' {{WEBVIEW_ENDPOINT}}; script-src 'self' https://az416426.vo.msecnd.net 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' ws: wss: https:; font-src 'self' blob: vscode-remote:;">
|
content="default-src 'none'; img-src 'self' https: data: blob: vscode-remote:; media-src 'none'; frame-src 'self' {{WEBVIEW_ENDPOINT}} https://*.vscode-webview-test.com; script-src 'self' https://az416426.vo.msecnd.net 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' ws: wss: https:; font-src 'self' blob: vscode-remote:;">
|
||||||
|
|
||||||
<meta id="vscode-workbench-web-configuration" data-settings="{{WORKBENCH_WEB_CONGIGURATION}}">
|
<meta id="vscode-workbench-web-configuration" data-settings="{{WORKBENCH_WEB_CONGIGURATION}}">
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ import { LocalizationsChannel } from 'vs/platform/localizations/node/localizatio
|
|||||||
import { DialogChannelClient } from 'vs/platform/dialogs/node/dialogIpc';
|
import { DialogChannelClient } from 'vs/platform/dialogs/node/dialogIpc';
|
||||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||||
import { combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
import { combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||||
import { DownloadService } from 'vs/platform/download/node/downloadService';
|
import { DownloadService } from 'vs/platform/download/common/downloadService';
|
||||||
import { IDownloadService } from 'vs/platform/download/common/download';
|
import { IDownloadService } from 'vs/platform/download/common/download';
|
||||||
import { IChannel, IServerChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc';
|
import { IChannel, IServerChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc';
|
||||||
import { NodeCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner';
|
import { NodeCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner';
|
||||||
@@ -115,7 +115,6 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
|
|||||||
services.set(ILogService, logService);
|
services.set(ILogService, logService);
|
||||||
services.set(IConfigurationService, configurationService);
|
services.set(IConfigurationService, configurationService);
|
||||||
services.set(IRequestService, new SyncDescriptor(RequestService));
|
services.set(IRequestService, new SyncDescriptor(RequestService));
|
||||||
services.set(IDownloadService, new SyncDescriptor(DownloadService));
|
|
||||||
services.set(IProductService, new SyncDescriptor(ProductService));
|
services.set(IProductService, new SyncDescriptor(ProductService));
|
||||||
|
|
||||||
const mainProcessService = new MainProcessService(server, mainRouter);
|
const mainProcessService = new MainProcessService(server, mainRouter);
|
||||||
@@ -138,6 +137,8 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
|
|||||||
disposables.add(diskFileSystemProvider);
|
disposables.add(diskFileSystemProvider);
|
||||||
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
|
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
|
||||||
|
|
||||||
|
services.set(IDownloadService, new SyncDescriptor(DownloadService));
|
||||||
|
|
||||||
const instantiationService = new InstantiationService(services);
|
const instantiationService = new InstantiationService(services);
|
||||||
|
|
||||||
let telemetryService: ITelemetryService;
|
let telemetryService: ITelemetryService;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<!-- {{SQL CARBON EDIT}} @anthonydresser add 'unsafe-eval' under script src; since its required by angular -->
|
<!-- {{SQL CARBON EDIT}} @anthonydresser add 'unsafe-eval' under script src; since its required by angular -->
|
||||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' https: data: blob: vscode-remote:; media-src 'none'; child-src 'self'; object-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; font-src 'self' https: vscode-remote:;">
|
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' https: data: blob: vscode-remote:; media-src 'none'; frame-src 'self' https://*.vscode-webview-test.com; object-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; font-src 'self' https: vscode-remote:;">
|
||||||
</head>
|
</head>
|
||||||
<body class="vs-dark" aria-label="">
|
<body class="vs-dark" aria-label="">
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -316,6 +316,9 @@ export namespace CoreNavigationCommands {
|
|||||||
const result = this._getColumnSelectResult(cursors.context, cursors.getPrimaryCursor(), cursors.getColumnSelectData(), args);
|
const result = this._getColumnSelectResult(cursors.context, cursors.getPrimaryCursor(), cursors.getColumnSelectData(), args);
|
||||||
cursors.setStates(args.source, CursorChangeReason.Explicit, result.viewStates.map((viewState) => CursorState.fromViewState(viewState)));
|
cursors.setStates(args.source, CursorChangeReason.Explicit, result.viewStates.map((viewState) => CursorState.fromViewState(viewState)));
|
||||||
cursors.setColumnSelectData({
|
cursors.setColumnSelectData({
|
||||||
|
isReal: true,
|
||||||
|
fromViewLineNumber: result.fromLineNumber,
|
||||||
|
fromViewVisualColumn: result.fromVisualColumn,
|
||||||
toViewLineNumber: result.toLineNumber,
|
toViewLineNumber: result.toLineNumber,
|
||||||
toViewVisualColumn: result.toVisualColumn
|
toViewVisualColumn: result.toVisualColumn
|
||||||
});
|
});
|
||||||
@@ -338,15 +341,15 @@ export namespace CoreNavigationCommands {
|
|||||||
|
|
||||||
// validate `args`
|
// validate `args`
|
||||||
const validatedPosition = context.model.validatePosition(args.position);
|
const validatedPosition = context.model.validatePosition(args.position);
|
||||||
|
const validatedViewPosition = context.validateViewPosition(new Position(args.viewPosition.lineNumber, args.viewPosition.column), validatedPosition);
|
||||||
|
|
||||||
let validatedViewPosition: Position;
|
let fromViewLineNumber = prevColumnSelectData.fromViewLineNumber;
|
||||||
if (args.viewPosition) {
|
let fromViewVisualColumn = prevColumnSelectData.fromViewVisualColumn;
|
||||||
validatedViewPosition = context.validateViewPosition(new Position(args.viewPosition.lineNumber, args.viewPosition.column), validatedPosition);
|
if (!prevColumnSelectData.isReal && args.setAnchorIfNotSet) {
|
||||||
} else {
|
fromViewLineNumber = validatedViewPosition.lineNumber;
|
||||||
validatedViewPosition = context.convertModelPositionToViewPosition(validatedPosition);
|
fromViewVisualColumn = args.mouseColumn - 1;
|
||||||
}
|
}
|
||||||
|
return ColumnSelection.columnSelect(context.config, context.viewModel, fromViewLineNumber, fromViewVisualColumn, validatedViewPosition.lineNumber, args.mouseColumn - 1);
|
||||||
return ColumnSelection.columnSelect(context.config, context.viewModel, primary.viewState.selection, validatedViewPosition.lineNumber, args.mouseColumn - 1);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -365,7 +368,7 @@ export namespace CoreNavigationCommands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected _getColumnSelectResult(context: CursorContext, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult {
|
protected _getColumnSelectResult(context: CursorContext, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult {
|
||||||
return ColumnSelection.columnSelectLeft(context.config, context.viewModel, primary.viewState, prevColumnSelectData.toViewLineNumber, prevColumnSelectData.toViewVisualColumn);
|
return ColumnSelection.columnSelectLeft(context.config, context.viewModel, prevColumnSelectData);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -384,7 +387,7 @@ export namespace CoreNavigationCommands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected _getColumnSelectResult(context: CursorContext, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult {
|
protected _getColumnSelectResult(context: CursorContext, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult {
|
||||||
return ColumnSelection.columnSelectRight(context.config, context.viewModel, primary.viewState, prevColumnSelectData.toViewLineNumber, prevColumnSelectData.toViewVisualColumn);
|
return ColumnSelection.columnSelectRight(context.config, context.viewModel, prevColumnSelectData);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -398,7 +401,7 @@ export namespace CoreNavigationCommands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected _getColumnSelectResult(context: CursorContext, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult {
|
protected _getColumnSelectResult(context: CursorContext, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult {
|
||||||
return ColumnSelection.columnSelectUp(context.config, context.viewModel, primary.viewState, this._isPaged, prevColumnSelectData.toViewLineNumber, prevColumnSelectData.toViewVisualColumn);
|
return ColumnSelection.columnSelectUp(context.config, context.viewModel, prevColumnSelectData, this._isPaged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,7 +439,7 @@ export namespace CoreNavigationCommands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected _getColumnSelectResult(context: CursorContext, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult {
|
protected _getColumnSelectResult(context: CursorContext, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult {
|
||||||
return ColumnSelection.columnSelectDown(context.config, context.viewModel, primary.viewState, this._isPaged, prevColumnSelectData.toViewLineNumber, prevColumnSelectData.toViewVisualColumn);
|
return ColumnSelection.columnSelectDown(context.config, context.viewModel, prevColumnSelectData, this._isPaged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ export class ViewController {
|
|||||||
public dispatchMouse(data: IMouseDispatchData): void {
|
public dispatchMouse(data: IMouseDispatchData): void {
|
||||||
if (data.middleButton) {
|
if (data.middleButton) {
|
||||||
if (data.inSelectionMode) {
|
if (data.inSelectionMode) {
|
||||||
this._columnSelect(data.position, data.mouseColumn);
|
this._columnSelect(data.position, data.mouseColumn, true);
|
||||||
} else {
|
} else {
|
||||||
this.moveTo(data.position);
|
this.moveTo(data.position);
|
||||||
}
|
}
|
||||||
@@ -182,7 +182,7 @@ export class ViewController {
|
|||||||
if (this._hasMulticursorModifier(data)) {
|
if (this._hasMulticursorModifier(data)) {
|
||||||
if (!this._hasNonMulticursorModifier(data)) {
|
if (!this._hasNonMulticursorModifier(data)) {
|
||||||
if (data.shiftKey) {
|
if (data.shiftKey) {
|
||||||
this._columnSelect(data.position, data.mouseColumn);
|
this._columnSelect(data.position, data.mouseColumn, false);
|
||||||
} else {
|
} else {
|
||||||
// Do multi-cursor operations only when purely alt is pressed
|
// Do multi-cursor operations only when purely alt is pressed
|
||||||
if (data.inSelectionMode) {
|
if (data.inSelectionMode) {
|
||||||
@@ -195,7 +195,7 @@ export class ViewController {
|
|||||||
} else {
|
} else {
|
||||||
if (data.inSelectionMode) {
|
if (data.inSelectionMode) {
|
||||||
if (data.altKey) {
|
if (data.altKey) {
|
||||||
this._columnSelect(data.position, data.mouseColumn);
|
this._columnSelect(data.position, data.mouseColumn, true);
|
||||||
} else {
|
} else {
|
||||||
this._moveToSelect(data.position);
|
this._moveToSelect(data.position);
|
||||||
}
|
}
|
||||||
@@ -222,12 +222,13 @@ export class ViewController {
|
|||||||
this._execMouseCommand(CoreNavigationCommands.MoveToSelect, this._usualArgs(viewPosition));
|
this._execMouseCommand(CoreNavigationCommands.MoveToSelect, this._usualArgs(viewPosition));
|
||||||
}
|
}
|
||||||
|
|
||||||
private _columnSelect(viewPosition: Position, mouseColumn: number): void {
|
private _columnSelect(viewPosition: Position, mouseColumn: number, setAnchorIfNotSet: boolean): void {
|
||||||
viewPosition = this._validateViewColumn(viewPosition);
|
viewPosition = this._validateViewColumn(viewPosition);
|
||||||
this._execMouseCommand(CoreNavigationCommands.ColumnSelect, {
|
this._execMouseCommand(CoreNavigationCommands.ColumnSelect, {
|
||||||
position: this._convertViewToModelPosition(viewPosition),
|
position: this._convertViewToModelPosition(viewPosition),
|
||||||
viewPosition: viewPosition,
|
viewPosition: viewPosition,
|
||||||
mouseColumn: mouseColumn
|
mouseColumn: mouseColumn,
|
||||||
|
setAnchorIfNotSet: setAnchorIfNotSet
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -324,11 +324,6 @@ class Widget {
|
|||||||
const aboveLeft0 = topLeft.left - ctx.scrollLeft;
|
const aboveLeft0 = topLeft.left - ctx.scrollLeft;
|
||||||
const belowLeft0 = bottomLeft.left - ctx.scrollLeft;
|
const belowLeft0 = bottomLeft.left - ctx.scrollLeft;
|
||||||
|
|
||||||
if (aboveLeft0 < 0 || aboveLeft0 > this._contentWidth) {
|
|
||||||
// Don't render if position is scrolled outside viewport
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let aboveTop = topLeft.top - height;
|
let aboveTop = topLeft.top - height;
|
||||||
let belowTop = bottomLeft.top + this._lineHeight;
|
let belowTop = bottomLeft.top + this._lineHeight;
|
||||||
let aboveLeft = aboveLeft0 + this._contentLeft;
|
let aboveLeft = aboveLeft0 + this._contentLeft;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { IStringBuilder } from 'vs/editor/common/core/stringBuilder';
|
|||||||
import { IConfiguration } from 'vs/editor/common/editorCommon';
|
import { IConfiguration } from 'vs/editor/common/editorCommon';
|
||||||
import { HorizontalRange } from 'vs/editor/common/view/renderingContext';
|
import { HorizontalRange } from 'vs/editor/common/view/renderingContext';
|
||||||
import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';
|
import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';
|
||||||
import { CharacterMapping, ForeignElementType, RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer';
|
import { CharacterMapping, ForeignElementType, RenderLineInput, renderViewLine, LineRange } from 'vs/editor/common/viewLayout/viewLineRenderer';
|
||||||
import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';
|
import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';
|
||||||
import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel';
|
import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel';
|
||||||
import { HIGH_CONTRAST, ThemeType } from 'vs/platform/theme/common/themeService';
|
import { HIGH_CONTRAST, ThemeType } from 'vs/platform/theme/common/themeService';
|
||||||
@@ -69,7 +69,7 @@ export class DomReadingContext {
|
|||||||
|
|
||||||
export class ViewLineOptions {
|
export class ViewLineOptions {
|
||||||
public readonly themeType: ThemeType;
|
public readonly themeType: ThemeType;
|
||||||
public readonly renderWhitespace: 'none' | 'boundary' | 'all';
|
public readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'all';
|
||||||
public readonly renderControlCharacters: boolean;
|
public readonly renderControlCharacters: boolean;
|
||||||
public readonly spaceWidth: number;
|
public readonly spaceWidth: number;
|
||||||
public readonly useMonospaceOptimizations: boolean;
|
public readonly useMonospaceOptimizations: boolean;
|
||||||
@@ -152,7 +152,7 @@ export class ViewLine implements IVisibleLine {
|
|||||||
this._options = newOptions;
|
this._options = newOptions;
|
||||||
}
|
}
|
||||||
public onSelectionChanged(): boolean {
|
public onSelectionChanged(): boolean {
|
||||||
if (alwaysRenderInlineSelection || this._options.themeType === HIGH_CONTRAST) {
|
if (alwaysRenderInlineSelection || this._options.themeType === HIGH_CONTRAST || this._options.renderWhitespace === 'selection') {
|
||||||
this._isMaybeInvalid = true;
|
this._isMaybeInvalid = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -171,7 +171,9 @@ export class ViewLine implements IVisibleLine {
|
|||||||
const options = this._options;
|
const options = this._options;
|
||||||
const actualInlineDecorations = LineDecoration.filter(lineData.inlineDecorations, lineNumber, lineData.minColumn, lineData.maxColumn);
|
const actualInlineDecorations = LineDecoration.filter(lineData.inlineDecorations, lineNumber, lineData.minColumn, lineData.maxColumn);
|
||||||
|
|
||||||
if (alwaysRenderInlineSelection || options.themeType === HIGH_CONTRAST) {
|
// Only send selection information when needed for rendering whitespace
|
||||||
|
let selectionsOnLine: LineRange[] | null = null;
|
||||||
|
if (alwaysRenderInlineSelection || options.themeType === HIGH_CONTRAST || this._options.renderWhitespace === 'selection') {
|
||||||
const selections = viewportData.selections;
|
const selections = viewportData.selections;
|
||||||
for (const selection of selections) {
|
for (const selection of selections) {
|
||||||
|
|
||||||
@@ -184,7 +186,15 @@ export class ViewLine implements IVisibleLine {
|
|||||||
const endColumn = (selection.endLineNumber === lineNumber ? selection.endColumn : lineData.maxColumn);
|
const endColumn = (selection.endLineNumber === lineNumber ? selection.endColumn : lineData.maxColumn);
|
||||||
|
|
||||||
if (startColumn < endColumn) {
|
if (startColumn < endColumn) {
|
||||||
|
if (this._options.renderWhitespace !== 'selection') {
|
||||||
actualInlineDecorations.push(new LineDecoration(startColumn, endColumn, 'inline-selected-text', InlineDecorationType.Regular));
|
actualInlineDecorations.push(new LineDecoration(startColumn, endColumn, 'inline-selected-text', InlineDecorationType.Regular));
|
||||||
|
} else {
|
||||||
|
if (!selectionsOnLine) {
|
||||||
|
selectionsOnLine = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
selectionsOnLine.push(new LineRange(startColumn - 1, endColumn - 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -204,7 +214,8 @@ export class ViewLine implements IVisibleLine {
|
|||||||
options.stopRenderingLineAfter,
|
options.stopRenderingLineAfter,
|
||||||
options.renderWhitespace,
|
options.renderWhitespace,
|
||||||
options.renderControlCharacters,
|
options.renderControlCharacters,
|
||||||
options.fontLigatures
|
options.fontLigatures,
|
||||||
|
selectionsOnLine
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this._renderedViewLine && this._renderedViewLine.input.equals(renderLineInput)) {
|
if (this._renderedViewLine && this._renderedViewLine.input.equals(renderLineInput)) {
|
||||||
|
|||||||
@@ -2047,7 +2047,8 @@ class InlineViewZonesComputer extends ViewZonesComputer {
|
|||||||
config.viewInfo.stopRenderingLineAfter,
|
config.viewInfo.stopRenderingLineAfter,
|
||||||
config.viewInfo.renderWhitespace,
|
config.viewInfo.renderWhitespace,
|
||||||
config.viewInfo.renderControlCharacters,
|
config.viewInfo.renderControlCharacters,
|
||||||
config.viewInfo.fontLigatures
|
config.viewInfo.fontLigatures,
|
||||||
|
null // Send no selections, original line cannot be selected
|
||||||
), sb);
|
), sb);
|
||||||
|
|
||||||
sb.appendASCIIString('</div>');
|
sb.appendASCIIString('</div>');
|
||||||
|
|||||||
@@ -780,7 +780,8 @@ export class DiffReview extends Disposable {
|
|||||||
config.viewInfo.stopRenderingLineAfter,
|
config.viewInfo.stopRenderingLineAfter,
|
||||||
config.viewInfo.renderWhitespace,
|
config.viewInfo.renderWhitespace,
|
||||||
config.viewInfo.renderControlCharacters,
|
config.viewInfo.renderControlCharacters,
|
||||||
config.viewInfo.fontLigatures
|
config.viewInfo.fontLigatures,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
return r.html;
|
return r.html;
|
||||||
|
|||||||
@@ -901,10 +901,11 @@ const editorConfiguration: IConfigurationNode = {
|
|||||||
},
|
},
|
||||||
'editor.renderWhitespace': {
|
'editor.renderWhitespace': {
|
||||||
'type': 'string',
|
'type': 'string',
|
||||||
'enum': ['none', 'boundary', 'all'],
|
'enum': ['none', 'boundary', 'selection', 'all'],
|
||||||
'enumDescriptions': [
|
'enumDescriptions': [
|
||||||
'',
|
'',
|
||||||
nls.localize('renderWhiteSpace.boundary', "Render whitespace characters except for single spaces between words."),
|
nls.localize('renderWhiteSpace.boundary', "Render whitespace characters except for single spaces between words."),
|
||||||
|
nls.localize('renderWhitespace.selection', "Render whitespace characters only on selected text."),
|
||||||
''
|
''
|
||||||
],
|
],
|
||||||
default: EDITOR_DEFAULTS.viewInfo.renderWhitespace,
|
default: EDITOR_DEFAULTS.viewInfo.renderWhitespace,
|
||||||
|
|||||||
@@ -664,7 +664,7 @@ export interface IEditorOptions {
|
|||||||
* Enable rendering of whitespace.
|
* Enable rendering of whitespace.
|
||||||
* Defaults to none.
|
* Defaults to none.
|
||||||
*/
|
*/
|
||||||
renderWhitespace?: 'none' | 'boundary' | 'all';
|
renderWhitespace?: 'none' | 'boundary' | 'selection' | 'all';
|
||||||
/**
|
/**
|
||||||
* Enable rendering of control characters.
|
* Enable rendering of control characters.
|
||||||
* Defaults to false.
|
* Defaults to false.
|
||||||
@@ -1005,7 +1005,7 @@ export interface InternalEditorViewOptions {
|
|||||||
readonly scrollBeyondLastColumn: number;
|
readonly scrollBeyondLastColumn: number;
|
||||||
readonly smoothScrolling: boolean;
|
readonly smoothScrolling: boolean;
|
||||||
readonly stopRenderingLineAfter: number;
|
readonly stopRenderingLineAfter: number;
|
||||||
readonly renderWhitespace: 'none' | 'boundary' | 'all';
|
readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'all';
|
||||||
readonly renderControlCharacters: boolean;
|
readonly renderControlCharacters: boolean;
|
||||||
readonly fontLigatures: boolean;
|
readonly fontLigatures: boolean;
|
||||||
readonly renderIndentGuides: boolean;
|
readonly renderIndentGuides: boolean;
|
||||||
@@ -2023,7 +2023,7 @@ export class EditorOptionsValidator {
|
|||||||
} else if (<any>renderWhitespace === false) {
|
} else if (<any>renderWhitespace === false) {
|
||||||
renderWhitespace = 'none';
|
renderWhitespace = 'none';
|
||||||
}
|
}
|
||||||
renderWhitespace = _stringSet<'none' | 'boundary' | 'all'>(renderWhitespace, defaults.renderWhitespace, ['none', 'boundary', 'all']);
|
renderWhitespace = _stringSet<'none' | 'boundary' | 'selection' | 'all'>(renderWhitespace, defaults.renderWhitespace, ['none', 'boundary', 'selection', 'all']);
|
||||||
}
|
}
|
||||||
|
|
||||||
let renderLineHighlight = opts.renderLineHighlight;
|
let renderLineHighlight = opts.renderLineHighlight;
|
||||||
|
|||||||
@@ -314,9 +314,14 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
|||||||
}
|
}
|
||||||
const primaryCursor = this._cursors.getPrimaryCursor();
|
const primaryCursor = this._cursors.getPrimaryCursor();
|
||||||
const primaryPos = primaryCursor.viewState.position;
|
const primaryPos = primaryCursor.viewState.position;
|
||||||
|
const viewLineNumber = primaryPos.lineNumber;
|
||||||
|
const viewVisualColumn = CursorColumns.visibleColumnFromColumn2(this.context.config, this.context.viewModel, primaryPos);
|
||||||
return {
|
return {
|
||||||
toViewLineNumber: primaryPos.lineNumber,
|
isReal: false,
|
||||||
toViewVisualColumn: CursorColumns.visibleColumnFromColumn2(this.context.config, this.context.viewModel, primaryPos)
|
fromViewLineNumber: viewLineNumber,
|
||||||
|
fromViewVisualColumn: viewVisualColumn,
|
||||||
|
toViewLineNumber: viewLineNumber,
|
||||||
|
toViewVisualColumn: viewVisualColumn,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,21 +3,22 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { CursorColumns, CursorConfiguration, ICursorSimpleModel, SingleCursorState } from 'vs/editor/common/controller/cursorCommon';
|
import { CursorColumns, CursorConfiguration, ICursorSimpleModel, SingleCursorState, IColumnSelectData } from 'vs/editor/common/controller/cursorCommon';
|
||||||
import { Position } from 'vs/editor/common/core/position';
|
import { Position } from 'vs/editor/common/core/position';
|
||||||
import { Range } from 'vs/editor/common/core/range';
|
import { Range } from 'vs/editor/common/core/range';
|
||||||
import { Selection } from 'vs/editor/common/core/selection';
|
|
||||||
|
|
||||||
export interface IColumnSelectResult {
|
export interface IColumnSelectResult {
|
||||||
viewStates: SingleCursorState[];
|
viewStates: SingleCursorState[];
|
||||||
reversed: boolean;
|
reversed: boolean;
|
||||||
|
fromLineNumber: number;
|
||||||
|
fromVisualColumn: number;
|
||||||
toLineNumber: number;
|
toLineNumber: number;
|
||||||
toVisualColumn: number;
|
toVisualColumn: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ColumnSelection {
|
export class ColumnSelection {
|
||||||
|
|
||||||
private static _columnSelect(config: CursorConfiguration, model: ICursorSimpleModel, fromLineNumber: number, fromVisibleColumn: number, toLineNumber: number, toVisibleColumn: number): IColumnSelectResult {
|
public static columnSelect(config: CursorConfiguration, model: ICursorSimpleModel, fromLineNumber: number, fromVisibleColumn: number, toLineNumber: number, toVisibleColumn: number): IColumnSelectResult {
|
||||||
let lineCount = Math.abs(toLineNumber - fromLineNumber) + 1;
|
let lineCount = Math.abs(toLineNumber - fromLineNumber) + 1;
|
||||||
let reversed = (fromLineNumber > toLineNumber);
|
let reversed = (fromLineNumber > toLineNumber);
|
||||||
let isRTL = (fromVisibleColumn > toVisibleColumn);
|
let isRTL = (fromVisibleColumn > toVisibleColumn);
|
||||||
@@ -61,64 +62,65 @@ export class ColumnSelection {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result.length === 0) {
|
||||||
|
// We are after all the lines, so add cursor at the end of each line
|
||||||
|
for (let i = 0; i < lineCount; i++) {
|
||||||
|
const lineNumber = fromLineNumber + (reversed ? -i : i);
|
||||||
|
const maxColumn = model.getLineMaxColumn(lineNumber);
|
||||||
|
|
||||||
|
result.push(new SingleCursorState(
|
||||||
|
new Range(lineNumber, maxColumn, lineNumber, maxColumn), 0,
|
||||||
|
new Position(lineNumber, maxColumn), 0
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
viewStates: result,
|
viewStates: result,
|
||||||
reversed: reversed,
|
reversed: reversed,
|
||||||
|
fromLineNumber: fromLineNumber,
|
||||||
|
fromVisualColumn: fromVisibleColumn,
|
||||||
toLineNumber: toLineNumber,
|
toLineNumber: toLineNumber,
|
||||||
toVisualColumn: toVisibleColumn
|
toVisualColumn: toVisibleColumn
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static columnSelect(config: CursorConfiguration, model: ICursorSimpleModel, fromViewSelection: Selection, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult {
|
public static columnSelectLeft(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData): IColumnSelectResult {
|
||||||
const fromViewPosition = new Position(fromViewSelection.selectionStartLineNumber, fromViewSelection.selectionStartColumn);
|
let toViewVisualColumn = prevColumnSelectData.toViewVisualColumn;
|
||||||
const fromViewVisibleColumn = CursorColumns.visibleColumnFromColumn2(config, model, fromViewPosition);
|
|
||||||
return ColumnSelection._columnSelect(config, model, fromViewPosition.lineNumber, fromViewVisibleColumn, toViewLineNumber, toViewVisualColumn);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static columnSelectLeft(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult {
|
|
||||||
if (toViewVisualColumn > 1) {
|
if (toViewVisualColumn > 1) {
|
||||||
toViewVisualColumn--;
|
toViewVisualColumn--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.columnSelect(config, model, cursor.selection, toViewLineNumber, toViewVisualColumn);
|
return ColumnSelection.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, prevColumnSelectData.toViewLineNumber, toViewVisualColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static columnSelectRight(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult {
|
public static columnSelectRight(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData): IColumnSelectResult {
|
||||||
let maxVisualViewColumn = 0;
|
let maxVisualViewColumn = 0;
|
||||||
let minViewLineNumber = Math.min(cursor.position.lineNumber, toViewLineNumber);
|
const minViewLineNumber = Math.min(prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.toViewLineNumber);
|
||||||
let maxViewLineNumber = Math.max(cursor.position.lineNumber, toViewLineNumber);
|
const maxViewLineNumber = Math.max(prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.toViewLineNumber);
|
||||||
for (let lineNumber = minViewLineNumber; lineNumber <= maxViewLineNumber; lineNumber++) {
|
for (let lineNumber = minViewLineNumber; lineNumber <= maxViewLineNumber; lineNumber++) {
|
||||||
let lineMaxViewColumn = model.getLineMaxColumn(lineNumber);
|
const lineMaxViewColumn = model.getLineMaxColumn(lineNumber);
|
||||||
let lineMaxVisualViewColumn = CursorColumns.visibleColumnFromColumn2(config, model, new Position(lineNumber, lineMaxViewColumn));
|
const lineMaxVisualViewColumn = CursorColumns.visibleColumnFromColumn2(config, model, new Position(lineNumber, lineMaxViewColumn));
|
||||||
maxVisualViewColumn = Math.max(maxVisualViewColumn, lineMaxVisualViewColumn);
|
maxVisualViewColumn = Math.max(maxVisualViewColumn, lineMaxVisualViewColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let toViewVisualColumn = prevColumnSelectData.toViewVisualColumn;
|
||||||
if (toViewVisualColumn < maxVisualViewColumn) {
|
if (toViewVisualColumn < maxVisualViewColumn) {
|
||||||
toViewVisualColumn++;
|
toViewVisualColumn++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.columnSelect(config, model, cursor.selection, toViewLineNumber, toViewVisualColumn);
|
return this.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, prevColumnSelectData.toViewLineNumber, toViewVisualColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static columnSelectUp(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, isPaged: boolean, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult {
|
public static columnSelectUp(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData, isPaged: boolean): IColumnSelectResult {
|
||||||
let linesCount = isPaged ? config.pageSize : 1;
|
const linesCount = isPaged ? config.pageSize : 1;
|
||||||
|
const toViewLineNumber = Math.max(1, prevColumnSelectData.toViewLineNumber - linesCount);
|
||||||
toViewLineNumber -= linesCount;
|
return this.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, toViewLineNumber, prevColumnSelectData.toViewVisualColumn);
|
||||||
if (toViewLineNumber < 1) {
|
|
||||||
toViewLineNumber = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.columnSelect(config, model, cursor.selection, toViewLineNumber, toViewVisualColumn);
|
public static columnSelectDown(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData, isPaged: boolean): IColumnSelectResult {
|
||||||
}
|
const linesCount = isPaged ? config.pageSize : 1;
|
||||||
|
const toViewLineNumber = Math.min(model.getLineCount(), prevColumnSelectData.toViewLineNumber + linesCount);
|
||||||
public static columnSelectDown(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, isPaged: boolean, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult {
|
return this.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, toViewLineNumber, prevColumnSelectData.toViewVisualColumn);
|
||||||
let linesCount = isPaged ? config.pageSize : 1;
|
|
||||||
|
|
||||||
toViewLineNumber += linesCount;
|
|
||||||
if (toViewLineNumber > model.getLineCount()) {
|
|
||||||
toViewLineNumber = model.getLineCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.columnSelect(config, model, cursor.selection, toViewLineNumber, toViewVisualColumn);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ import { VerticalRevealType } from 'vs/editor/common/view/viewEvents';
|
|||||||
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
|
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
|
||||||
|
|
||||||
export interface IColumnSelectData {
|
export interface IColumnSelectData {
|
||||||
|
isReal: boolean;
|
||||||
|
fromViewLineNumber: number;
|
||||||
|
fromViewVisualColumn: number;
|
||||||
toViewLineNumber: number;
|
toViewLineNumber: number;
|
||||||
toViewVisualColumn: number;
|
toViewVisualColumn: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel';
|
|||||||
export const enum RenderWhitespace {
|
export const enum RenderWhitespace {
|
||||||
None = 0,
|
None = 0,
|
||||||
Boundary = 1,
|
Boundary = 1,
|
||||||
All = 2
|
Selection = 2,
|
||||||
|
All = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
class LinePart {
|
class LinePart {
|
||||||
@@ -31,6 +32,28 @@ class LinePart {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class LineRange {
|
||||||
|
/**
|
||||||
|
* Zero-based offset on which the range starts, inclusive.
|
||||||
|
*/
|
||||||
|
public readonly startOffset: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zero-based offset on which the range ends, inclusive.
|
||||||
|
*/
|
||||||
|
public readonly endOffset: number;
|
||||||
|
|
||||||
|
constructor(startIndex: number, endIndex: number) {
|
||||||
|
this.startOffset = startIndex;
|
||||||
|
this.endOffset = endIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public equals(otherLineRange: LineRange) {
|
||||||
|
return this.startOffset === otherLineRange.startOffset
|
||||||
|
&& this.endOffset === otherLineRange.endOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class RenderLineInput {
|
export class RenderLineInput {
|
||||||
|
|
||||||
public readonly useMonospaceOptimizations: boolean;
|
public readonly useMonospaceOptimizations: boolean;
|
||||||
@@ -49,6 +72,12 @@ export class RenderLineInput {
|
|||||||
public readonly renderControlCharacters: boolean;
|
public readonly renderControlCharacters: boolean;
|
||||||
public readonly fontLigatures: boolean;
|
public readonly fontLigatures: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defined only when renderWhitespace is 'selection'. Selections are non-overlapping,
|
||||||
|
* and ordered by position within the line.
|
||||||
|
*/
|
||||||
|
public readonly selectionsOnLine: LineRange[] | null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
useMonospaceOptimizations: boolean,
|
useMonospaceOptimizations: boolean,
|
||||||
canUseHalfwidthRightwardsArrow: boolean,
|
canUseHalfwidthRightwardsArrow: boolean,
|
||||||
@@ -62,9 +91,10 @@ export class RenderLineInput {
|
|||||||
tabSize: number,
|
tabSize: number,
|
||||||
spaceWidth: number,
|
spaceWidth: number,
|
||||||
stopRenderingLineAfter: number,
|
stopRenderingLineAfter: number,
|
||||||
renderWhitespace: 'none' | 'boundary' | 'all',
|
renderWhitespace: 'none' | 'boundary' | 'selection' | 'all',
|
||||||
renderControlCharacters: boolean,
|
renderControlCharacters: boolean,
|
||||||
fontLigatures: boolean
|
fontLigatures: boolean,
|
||||||
|
selectionsOnLine: LineRange[] | null
|
||||||
) {
|
) {
|
||||||
this.useMonospaceOptimizations = useMonospaceOptimizations;
|
this.useMonospaceOptimizations = useMonospaceOptimizations;
|
||||||
this.canUseHalfwidthRightwardsArrow = canUseHalfwidthRightwardsArrow;
|
this.canUseHalfwidthRightwardsArrow = canUseHalfwidthRightwardsArrow;
|
||||||
@@ -83,10 +113,35 @@ export class RenderLineInput {
|
|||||||
? RenderWhitespace.All
|
? RenderWhitespace.All
|
||||||
: renderWhitespace === 'boundary'
|
: renderWhitespace === 'boundary'
|
||||||
? RenderWhitespace.Boundary
|
? RenderWhitespace.Boundary
|
||||||
|
: renderWhitespace === 'selection'
|
||||||
|
? RenderWhitespace.Selection
|
||||||
: RenderWhitespace.None
|
: RenderWhitespace.None
|
||||||
);
|
);
|
||||||
this.renderControlCharacters = renderControlCharacters;
|
this.renderControlCharacters = renderControlCharacters;
|
||||||
this.fontLigatures = fontLigatures;
|
this.fontLigatures = fontLigatures;
|
||||||
|
this.selectionsOnLine = selectionsOnLine && selectionsOnLine.sort((a, b) => a.startOffset < b.startOffset ? -1 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sameSelection(otherSelections: LineRange[] | null): boolean {
|
||||||
|
if (this.selectionsOnLine === null) {
|
||||||
|
return otherSelections === null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otherSelections === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otherSelections.length !== this.selectionsOnLine.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < this.selectionsOnLine.length; i++) {
|
||||||
|
if (!this.selectionsOnLine[i].equals(otherSelections[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public equals(other: RenderLineInput): boolean {
|
public equals(other: RenderLineInput): boolean {
|
||||||
@@ -106,6 +161,7 @@ export class RenderLineInput {
|
|||||||
&& this.fontLigatures === other.fontLigatures
|
&& this.fontLigatures === other.fontLigatures
|
||||||
&& LineDecoration.equalsArr(this.lineDecorations, other.lineDecorations)
|
&& LineDecoration.equalsArr(this.lineDecorations, other.lineDecorations)
|
||||||
&& this.lineTokens.equals(other.lineTokens)
|
&& this.lineTokens.equals(other.lineTokens)
|
||||||
|
&& this.sameSelection(other.selectionsOnLine)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -338,8 +394,8 @@ function resolveRenderLineInput(input: RenderLineInput): ResolvedRenderLineInput
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tokens = transformAndRemoveOverflowing(input.lineTokens, input.fauxIndentLength, len);
|
let tokens = transformAndRemoveOverflowing(input.lineTokens, input.fauxIndentLength, len);
|
||||||
if (input.renderWhitespace === RenderWhitespace.All || input.renderWhitespace === RenderWhitespace.Boundary) {
|
if (input.renderWhitespace === RenderWhitespace.All || input.renderWhitespace === RenderWhitespace.Boundary || (input.renderWhitespace === RenderWhitespace.Selection && !!input.selectionsOnLine)) {
|
||||||
tokens = _applyRenderWhitespace(lineContent, len, input.continuesWithWrappedLine, tokens, input.fauxIndentLength, input.tabSize, useMonospaceOptimizations, input.renderWhitespace === RenderWhitespace.Boundary);
|
tokens = _applyRenderWhitespace(lineContent, len, input.continuesWithWrappedLine, tokens, input.fauxIndentLength, input.tabSize, useMonospaceOptimizations, input.selectionsOnLine, input.renderWhitespace === RenderWhitespace.Boundary);
|
||||||
}
|
}
|
||||||
let containsForeignElements = ForeignElementType.None;
|
let containsForeignElements = ForeignElementType.None;
|
||||||
if (input.lineDecorations.length > 0) {
|
if (input.lineDecorations.length > 0) {
|
||||||
@@ -481,7 +537,7 @@ function splitLargeTokens(lineContent: string, tokens: LinePart[], onlyAtSpaces:
|
|||||||
* Moreover, a token is created for every visual indent because on some fonts the glyphs used for rendering whitespace (→ or ·) do not have the same width as .
|
* Moreover, a token is created for every visual indent because on some fonts the glyphs used for rendering whitespace (→ or ·) do not have the same width as .
|
||||||
* The rendering phase will generate `style="width:..."` for these tokens.
|
* The rendering phase will generate `style="width:..."` for these tokens.
|
||||||
*/
|
*/
|
||||||
function _applyRenderWhitespace(lineContent: string, len: number, continuesWithWrappedLine: boolean, tokens: LinePart[], fauxIndentLength: number, tabSize: number, useMonospaceOptimizations: boolean, onlyBoundary: boolean): LinePart[] {
|
function _applyRenderWhitespace(lineContent: string, len: number, continuesWithWrappedLine: boolean, tokens: LinePart[], fauxIndentLength: number, tabSize: number, useMonospaceOptimizations: boolean, selections: LineRange[] | null, onlyBoundary: boolean): LinePart[] {
|
||||||
|
|
||||||
let result: LinePart[] = [], resultLen = 0;
|
let result: LinePart[] = [], resultLen = 0;
|
||||||
let tokenIndex = 0;
|
let tokenIndex = 0;
|
||||||
@@ -511,11 +567,17 @@ function _applyRenderWhitespace(lineContent: string, len: number, continuesWithW
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
tmpIndent = tmpIndent % tabSize;
|
tmpIndent = tmpIndent % tabSize;
|
||||||
|
|
||||||
let wasInWhitespace = false;
|
let wasInWhitespace = false;
|
||||||
|
let currentSelectionIndex = 0;
|
||||||
|
let currentSelection = selections && selections[currentSelectionIndex];
|
||||||
for (let charIndex = fauxIndentLength; charIndex < len; charIndex++) {
|
for (let charIndex = fauxIndentLength; charIndex < len; charIndex++) {
|
||||||
const chCode = lineContent.charCodeAt(charIndex);
|
const chCode = lineContent.charCodeAt(charIndex);
|
||||||
|
|
||||||
|
if (currentSelection && charIndex >= currentSelection.endOffset) {
|
||||||
|
currentSelectionIndex++;
|
||||||
|
currentSelection = selections && selections[currentSelectionIndex];
|
||||||
|
}
|
||||||
|
|
||||||
let isInWhitespace: boolean;
|
let isInWhitespace: boolean;
|
||||||
if (charIndex < firstNonWhitespaceIndex || charIndex > lastNonWhitespaceIndex) {
|
if (charIndex < firstNonWhitespaceIndex || charIndex > lastNonWhitespaceIndex) {
|
||||||
// in leading or trailing whitespace
|
// in leading or trailing whitespace
|
||||||
@@ -540,6 +602,11 @@ function _applyRenderWhitespace(lineContent: string, len: number, continuesWithW
|
|||||||
isInWhitespace = false;
|
isInWhitespace = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If rendering whitespace on selection, check that the charIndex falls within a selection
|
||||||
|
if (isInWhitespace && selections) {
|
||||||
|
isInWhitespace = !!currentSelection && currentSelection.startOffset <= charIndex && currentSelection.endOffset > charIndex;
|
||||||
|
}
|
||||||
|
|
||||||
if (wasInWhitespace) {
|
if (wasInWhitespace) {
|
||||||
// was in whitespace token
|
// was in whitespace token
|
||||||
if (!isInWhitespace || (!useMonospaceOptimizations && tmpIndent >= tabSize)) {
|
if (!isInWhitespace || (!useMonospaceOptimizations && tmpIndent >= tabSize)) {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import { contrastBorder, editorFindMatch, editorFindMatchBorder, editorFindMatch
|
|||||||
import { ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
import { ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||||
import { ContextScopedFindInput, ContextScopedHistoryInputBox } from 'vs/platform/browser/contextScopedHistoryWidget';
|
import { ContextScopedFindInput, ContextScopedHistoryInputBox } from 'vs/platform/browser/contextScopedHistoryWidget';
|
||||||
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
||||||
|
import { alert as alertFn } from 'vs/base/browser/ui/aria/aria';
|
||||||
|
|
||||||
export interface IFindController {
|
export interface IFindController {
|
||||||
replace(): void;
|
replace(): void;
|
||||||
@@ -372,13 +373,26 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
} else {
|
} else {
|
||||||
label = NLS_NO_RESULTS;
|
label = NLS_NO_RESULTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._matchesCount.appendChild(document.createTextNode(label));
|
this._matchesCount.appendChild(document.createTextNode(label));
|
||||||
|
|
||||||
|
alertFn(this._getAriaLabel(label, this._state.currentMatch, this._state.searchString), true);
|
||||||
MAX_MATCHES_COUNT_WIDTH = Math.max(MAX_MATCHES_COUNT_WIDTH, this._matchesCount.clientWidth);
|
MAX_MATCHES_COUNT_WIDTH = Math.max(MAX_MATCHES_COUNT_WIDTH, this._matchesCount.clientWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----- actions
|
// ----- actions
|
||||||
|
|
||||||
|
private _getAriaLabel(label: string, currentMatch: Range | null, searchString: string): string {
|
||||||
|
if (label === NLS_NO_RESULTS) {
|
||||||
|
return searchString === ''
|
||||||
|
? nls.localize('ariaSearchNoResultEmpty', "{0} found", label)
|
||||||
|
: nls.localize('ariaSearchNoResult', "{0} found for {1}", label, searchString);
|
||||||
|
}
|
||||||
|
return currentMatch
|
||||||
|
? nls.localize('ariaSearchNoResultWithLineNum', "{0} found for {1} at {2}", label, searchString, currentMatch.startLineNumber + ':' + currentMatch.startColumn)
|
||||||
|
: nls.localize('ariaSearchNoResultWithLineNumNoCurrentMatch', "{0} found for {1}", label, searchString);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If 'selection find' is ON we should not disable the button (its function is to cancel 'selection find').
|
* If 'selection find' is ON we should not disable the button (its function is to cancel 'selection find').
|
||||||
* If 'selection find' is OFF we enable the button only if there is a selection.
|
* If 'selection find' is OFF we enable the button only if there is a selection.
|
||||||
|
|||||||
@@ -581,7 +581,7 @@ export class DeleteAllLeftAction extends AbstractDeleteAllToBoundaryAction {
|
|||||||
return new Range(selection.startLineNumber, 1, selection.startLineNumber, selection.startColumn);
|
return new Range(selection.startLineNumber, 1, selection.startLineNumber, selection.startColumn);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return selection;
|
return new Range(selection.startLineNumber, 1, selection.endLineNumber, selection.endColumn);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ suite('Editor Contrib - Line Operations', () => {
|
|||||||
|
|
||||||
editor.setSelections([new Selection(2, 2, 2, 2), new Selection(2, 4, 2, 5)]);
|
editor.setSelections([new Selection(2, 2, 2, 2), new Selection(2, 4, 2, 5)]);
|
||||||
deleteAllLeftAction.run(null!, editor);
|
deleteAllLeftAction.run(null!, editor);
|
||||||
assert.equal(model.getLineContent(2), 'ord', '002');
|
assert.equal(model.getLineContent(2), 'd', '002');
|
||||||
|
|
||||||
editor.setSelections([new Selection(3, 2, 3, 5), new Selection(3, 7, 3, 7)]);
|
editor.setSelections([new Selection(3, 2, 3, 5), new Selection(3, 7, 3, 7)]);
|
||||||
deleteAllLeftAction.run(null!, editor);
|
deleteAllLeftAction.run(null!, editor);
|
||||||
@@ -276,11 +276,11 @@ suite('Editor Contrib - Line Operations', () => {
|
|||||||
|
|
||||||
editor.setSelections([new Selection(4, 3, 4, 3), new Selection(4, 5, 5, 4)]);
|
editor.setSelections([new Selection(4, 3, 4, 3), new Selection(4, 5, 5, 4)]);
|
||||||
deleteAllLeftAction.run(null!, editor);
|
deleteAllLeftAction.run(null!, editor);
|
||||||
assert.equal(model.getLineContent(4), 'lljour', '004');
|
assert.equal(model.getLineContent(4), 'jour', '004');
|
||||||
|
|
||||||
editor.setSelections([new Selection(5, 3, 6, 3), new Selection(6, 5, 7, 5), new Selection(7, 7, 7, 7)]);
|
editor.setSelections([new Selection(5, 3, 6, 3), new Selection(6, 5, 7, 5), new Selection(7, 7, 7, 7)]);
|
||||||
deleteAllLeftAction.run(null!, editor);
|
deleteAllLeftAction.run(null!, editor);
|
||||||
assert.equal(model.getLineContent(5), 'horlworld', '005');
|
assert.equal(model.getLineContent(5), 'world', '005');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -25,79 +25,43 @@ import { IOpenerService } from 'vs/platform/opener/common/opener';
|
|||||||
import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry';
|
import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||||
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||||
|
|
||||||
const HOVER_MESSAGE_GENERAL_META = new MarkdownString().appendText(
|
function getHoverMessage(link: Link, useMetaKey: boolean): MarkdownString {
|
||||||
platform.isMacintosh
|
const executeCmd = link.url && /^command:/i.test(link.url.toString());
|
||||||
? nls.localize('links.navigate.mac', "Follow link (cmd + click)")
|
|
||||||
: nls.localize('links.navigate', "Follow link (ctrl + click)")
|
|
||||||
);
|
|
||||||
|
|
||||||
const HOVER_MESSAGE_COMMAND_META = new MarkdownString().appendText(
|
const label = link.tooltip
|
||||||
platform.isMacintosh
|
? link.tooltip
|
||||||
? nls.localize('links.command.mac', "Execute command (cmd + click)")
|
: executeCmd
|
||||||
: nls.localize('links.command', "Execute command (ctrl + click)")
|
? nls.localize('links.navigate.executeCmd', 'Execute command')
|
||||||
);
|
: nls.localize('links.navigate.follow', 'Follow link');
|
||||||
|
|
||||||
const HOVER_MESSAGE_GENERAL_ALT = new MarkdownString().appendText(
|
const kb = useMetaKey
|
||||||
platform.isMacintosh
|
? platform.isMacintosh
|
||||||
? nls.localize('links.navigate.al.mac', "Follow link (option + click)")
|
? nls.localize('links.navigate.kb.meta.mac', "cmd + click")
|
||||||
: nls.localize('links.navigate.al', "Follow link (alt + click)")
|
: nls.localize('links.navigate.kb.meta', "ctrl + click")
|
||||||
);
|
: platform.isMacintosh
|
||||||
|
? nls.localize('links.navigate.kb.alt.mac', "option + click")
|
||||||
|
: nls.localize('links.navigate.kb.alt', "alt + click");
|
||||||
|
|
||||||
const HOVER_MESSAGE_COMMAND_ALT = new MarkdownString().appendText(
|
if (link.url) {
|
||||||
platform.isMacintosh
|
const hoverMessage = new MarkdownString().appendMarkdown(`[${label}](${link.url.toString()}) (${kb})`);
|
||||||
? nls.localize('links.command.al.mac', "Execute command (option + click)")
|
hoverMessage.isTrusted = true;
|
||||||
: nls.localize('links.command.al', "Execute command (alt + click)")
|
return hoverMessage;
|
||||||
);
|
} else {
|
||||||
|
return new MarkdownString().appendText(`${label} (${kb})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const decoration = {
|
const decoration = {
|
||||||
meta: ModelDecorationOptions.register({
|
general: ModelDecorationOptions.register({
|
||||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||||
collapseOnReplaceEdit: true,
|
collapseOnReplaceEdit: true,
|
||||||
inlineClassName: 'detected-link',
|
inlineClassName: 'detected-link'
|
||||||
hoverMessage: HOVER_MESSAGE_GENERAL_META
|
|
||||||
}),
|
}),
|
||||||
metaActive: ModelDecorationOptions.register({
|
active: ModelDecorationOptions.register({
|
||||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||||
collapseOnReplaceEdit: true,
|
collapseOnReplaceEdit: true,
|
||||||
inlineClassName: 'detected-link-active',
|
inlineClassName: 'detected-link-active'
|
||||||
hoverMessage: HOVER_MESSAGE_GENERAL_META
|
})
|
||||||
}),
|
|
||||||
alt: ModelDecorationOptions.register({
|
|
||||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
|
||||||
collapseOnReplaceEdit: true,
|
|
||||||
inlineClassName: 'detected-link',
|
|
||||||
hoverMessage: HOVER_MESSAGE_GENERAL_ALT
|
|
||||||
}),
|
|
||||||
altActive: ModelDecorationOptions.register({
|
|
||||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
|
||||||
collapseOnReplaceEdit: true,
|
|
||||||
inlineClassName: 'detected-link-active',
|
|
||||||
hoverMessage: HOVER_MESSAGE_GENERAL_ALT
|
|
||||||
}),
|
|
||||||
altCommand: ModelDecorationOptions.register({
|
|
||||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
|
||||||
collapseOnReplaceEdit: true,
|
|
||||||
inlineClassName: 'detected-link',
|
|
||||||
hoverMessage: HOVER_MESSAGE_COMMAND_ALT
|
|
||||||
}),
|
|
||||||
altCommandActive: ModelDecorationOptions.register({
|
|
||||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
|
||||||
collapseOnReplaceEdit: true,
|
|
||||||
inlineClassName: 'detected-link-active',
|
|
||||||
hoverMessage: HOVER_MESSAGE_COMMAND_ALT
|
|
||||||
}),
|
|
||||||
metaCommand: ModelDecorationOptions.register({
|
|
||||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
|
||||||
collapseOnReplaceEdit: true,
|
|
||||||
inlineClassName: 'detected-link',
|
|
||||||
hoverMessage: HOVER_MESSAGE_COMMAND_META
|
|
||||||
}),
|
|
||||||
metaCommandActive: ModelDecorationOptions.register({
|
|
||||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
|
||||||
collapseOnReplaceEdit: true,
|
|
||||||
inlineClassName: 'detected-link-active',
|
|
||||||
hoverMessage: HOVER_MESSAGE_COMMAND_META
|
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -111,38 +75,11 @@ class LinkOccurrence {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static _getOptions(link: Link, useMetaKey: boolean, isActive: boolean): ModelDecorationOptions {
|
private static _getOptions(link: Link, useMetaKey: boolean, isActive: boolean): ModelDecorationOptions {
|
||||||
const options = { ...this._getBaseOptions(link, useMetaKey, isActive) };
|
const options = { ... (isActive ? decoration.active : decoration.general) };
|
||||||
if (typeof link.tooltip === 'string') {
|
options.hoverMessage = getHoverMessage(link, useMetaKey);
|
||||||
const message = new MarkdownString().appendText(
|
|
||||||
platform.isMacintosh
|
|
||||||
? useMetaKey
|
|
||||||
? nls.localize('links.custom.mac', "{0} (cmd + click)", link.tooltip)
|
|
||||||
: nls.localize('links.custom.mac.al', "{0} (option + click)", link.tooltip)
|
|
||||||
: useMetaKey
|
|
||||||
? nls.localize('links.custom', "{0} (ctrl + click)", link.tooltip)
|
|
||||||
: nls.localize('links.custom.al', "{0} (alt + click)", link.tooltip)
|
|
||||||
);
|
|
||||||
options.hoverMessage = message;
|
|
||||||
}
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _getBaseOptions(link: Link, useMetaKey: boolean, isActive: boolean): ModelDecorationOptions {
|
|
||||||
if (link.url && /^command:/i.test(link.url.toString())) {
|
|
||||||
if (useMetaKey) {
|
|
||||||
return (isActive ? decoration.metaCommandActive : decoration.metaCommand);
|
|
||||||
} else {
|
|
||||||
return (isActive ? decoration.altCommandActive : decoration.altCommand);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (useMetaKey) {
|
|
||||||
return (isActive ? decoration.metaActive : decoration.meta);
|
|
||||||
} else {
|
|
||||||
return (isActive ? decoration.altActive : decoration.alt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public decorationId: string;
|
public decorationId: string;
|
||||||
public link: Link;
|
public link: Link;
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,8 @@ export class Colorizer {
|
|||||||
-1,
|
-1,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
return renderResult.html;
|
return renderResult.html;
|
||||||
}
|
}
|
||||||
@@ -195,7 +196,8 @@ function _fakeColorize(lines: string[], tabSize: number): string {
|
|||||||
-1,
|
-1,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
html = html.concat(renderResult.html);
|
html = html.concat(renderResult.html);
|
||||||
@@ -231,7 +233,8 @@ function _actualColorize(lines: string[], tabSize: number, tokenizationSupport:
|
|||||||
-1,
|
-1,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
html = html.concat(renderResult.html);
|
html = html.concat(renderResult.html);
|
||||||
|
|||||||
@@ -710,7 +710,8 @@ suite('Editor Controller - Cursor', () => {
|
|||||||
CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(cursor, {
|
CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(cursor, {
|
||||||
position: new Position(4, 4),
|
position: new Position(4, 4),
|
||||||
viewPosition: new Position(4, 4),
|
viewPosition: new Position(4, 4),
|
||||||
mouseColumn: 15
|
mouseColumn: 15,
|
||||||
|
setAnchorIfNotSet: false
|
||||||
});
|
});
|
||||||
|
|
||||||
let expectedSelections = [
|
let expectedSelections = [
|
||||||
@@ -745,7 +746,8 @@ suite('Editor Controller - Cursor', () => {
|
|||||||
CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(cursor, {
|
CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(cursor, {
|
||||||
position: new Position(4, 1),
|
position: new Position(4, 1),
|
||||||
viewPosition: new Position(4, 1),
|
viewPosition: new Position(4, 1),
|
||||||
mouseColumn: 1
|
mouseColumn: 1,
|
||||||
|
setAnchorIfNotSet: false
|
||||||
});
|
});
|
||||||
|
|
||||||
assertCursor(cursor, [
|
assertCursor(cursor, [
|
||||||
@@ -784,7 +786,8 @@ suite('Editor Controller - Cursor', () => {
|
|||||||
CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(cursor, {
|
CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(cursor, {
|
||||||
position: new Position(1, 1),
|
position: new Position(1, 1),
|
||||||
viewPosition: new Position(1, 1),
|
viewPosition: new Position(1, 1),
|
||||||
mouseColumn: 1
|
mouseColumn: 1,
|
||||||
|
setAnchorIfNotSet: false
|
||||||
});
|
});
|
||||||
assertCursor(cursor, [
|
assertCursor(cursor, [
|
||||||
new Selection(10, 10, 10, 1),
|
new Selection(10, 10, 10, 1),
|
||||||
@@ -802,7 +805,8 @@ suite('Editor Controller - Cursor', () => {
|
|||||||
CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(cursor, {
|
CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(cursor, {
|
||||||
position: new Position(1, 1),
|
position: new Position(1, 1),
|
||||||
viewPosition: new Position(1, 1),
|
viewPosition: new Position(1, 1),
|
||||||
mouseColumn: 1
|
mouseColumn: 1,
|
||||||
|
setAnchorIfNotSet: false
|
||||||
});
|
});
|
||||||
assertCursor(cursor, [
|
assertCursor(cursor, [
|
||||||
new Selection(10, 10, 10, 1),
|
new Selection(10, 10, 10, 1),
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import * as strings from 'vs/base/common/strings';
|
|||||||
import { IViewLineTokens } from 'vs/editor/common/core/lineTokens';
|
import { IViewLineTokens } from 'vs/editor/common/core/lineTokens';
|
||||||
import { MetadataConsts } from 'vs/editor/common/modes';
|
import { MetadataConsts } from 'vs/editor/common/modes';
|
||||||
import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';
|
import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';
|
||||||
import { CharacterMapping, RenderLineInput, renderViewLine2 as renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer';
|
import { CharacterMapping, RenderLineInput, renderViewLine2 as renderViewLine, LineRange } from 'vs/editor/common/viewLayout/viewLineRenderer';
|
||||||
import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel';
|
import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel';
|
||||||
import { ViewLineToken, ViewLineTokens } from 'vs/editor/test/common/core/viewLineToken';
|
import { ViewLineToken, ViewLineTokens } from 'vs/editor/test/common/core/viewLineToken';
|
||||||
|
|
||||||
@@ -41,7 +41,8 @@ suite('viewLineRenderer.renderLine', () => {
|
|||||||
-1,
|
-1,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
assert.equal(_actual.html, '<span><span class="mtk0">' + expected + '</span></span>');
|
assert.equal(_actual.html, '<span><span class="mtk0">' + expected + '</span></span>');
|
||||||
@@ -90,7 +91,8 @@ suite('viewLineRenderer.renderLine', () => {
|
|||||||
-1,
|
-1,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
assert.equal(_actual.html, '<span>' + expected + '</span>');
|
assert.equal(_actual.html, '<span>' + expected + '</span>');
|
||||||
@@ -142,7 +144,8 @@ suite('viewLineRenderer.renderLine', () => {
|
|||||||
6,
|
6,
|
||||||
'boundary',
|
'boundary',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
let expectedOutput = [
|
let expectedOutput = [
|
||||||
@@ -233,7 +236,8 @@ suite('viewLineRenderer.renderLine', () => {
|
|||||||
-1,
|
-1,
|
||||||
'boundary',
|
'boundary',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
assert.equal(_actual.html, '<span>' + expectedOutput + '</span>');
|
assert.equal(_actual.html, '<span>' + expectedOutput + '</span>');
|
||||||
@@ -295,7 +299,8 @@ suite('viewLineRenderer.renderLine', () => {
|
|||||||
-1,
|
-1,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
assert.equal(_actual.html, '<span>' + expectedOutput + '</span>');
|
assert.equal(_actual.html, '<span>' + expectedOutput + '</span>');
|
||||||
@@ -357,7 +362,8 @@ suite('viewLineRenderer.renderLine', () => {
|
|||||||
-1,
|
-1,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
assert.equal(_actual.html, '<span>' + expectedOutput + '</span>');
|
assert.equal(_actual.html, '<span>' + expectedOutput + '</span>');
|
||||||
@@ -396,7 +402,8 @@ suite('viewLineRenderer.renderLine', () => {
|
|||||||
-1,
|
-1,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
assert.equal(_actual.html, '<span>' + expectedOutput + '</span>');
|
assert.equal(_actual.html, '<span>' + expectedOutput + '</span>');
|
||||||
@@ -426,7 +433,8 @@ suite('viewLineRenderer.renderLine', () => {
|
|||||||
-1,
|
-1,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
assert.equal(actual.html, '<span>' + expectedOutput.join('') + '</span>', message);
|
assert.equal(actual.html, '<span>' + expectedOutput.join('') + '</span>', message);
|
||||||
}
|
}
|
||||||
@@ -526,7 +534,8 @@ suite('viewLineRenderer.renderLine', () => {
|
|||||||
-1,
|
-1,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
true
|
true,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
assert.equal(actual.html, '<span>' + expectedOutput.join('') + '</span>', message);
|
assert.equal(actual.html, '<span>' + expectedOutput.join('') + '</span>', message);
|
||||||
}
|
}
|
||||||
@@ -564,7 +573,8 @@ suite('viewLineRenderer.renderLine', () => {
|
|||||||
-1,
|
-1,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
let expectedOutput = [
|
let expectedOutput = [
|
||||||
'<span class="mtk1">a𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷</span>',
|
'<span class="mtk1">a𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷</span>',
|
||||||
@@ -593,7 +603,8 @@ suite('viewLineRenderer.renderLine', () => {
|
|||||||
-1,
|
-1,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
assert.equal(actual.html, '<span>' + expectedOutput.join('') + '</span>');
|
assert.equal(actual.html, '<span>' + expectedOutput.join('') + '</span>');
|
||||||
assert.equal(actual.containsRTL, true);
|
assert.equal(actual.containsRTL, true);
|
||||||
@@ -639,7 +650,8 @@ suite('viewLineRenderer.renderLine', () => {
|
|||||||
-1,
|
-1,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
assert.equal(_actual.html, '<span>' + expectedOutput + '</span>');
|
assert.equal(_actual.html, '<span>' + expectedOutput + '</span>');
|
||||||
@@ -704,7 +716,7 @@ suite('viewLineRenderer.renderLine', () => {
|
|||||||
|
|
||||||
suite('viewLineRenderer.renderLine 2', () => {
|
suite('viewLineRenderer.renderLine 2', () => {
|
||||||
|
|
||||||
function testCreateLineParts(fontIsMonospace: boolean, lineContent: string, tokens: ViewLineToken[], fauxIndentLength: number, renderWhitespace: 'none' | 'boundary' | 'all', expected: string): void {
|
function testCreateLineParts(fontIsMonospace: boolean, lineContent: string, tokens: ViewLineToken[], fauxIndentLength: number, renderWhitespace: 'none' | 'boundary' | 'selection' | 'all', selections: LineRange[] | null, expected: string): void {
|
||||||
let actual = renderViewLine(new RenderLineInput(
|
let actual = renderViewLine(new RenderLineInput(
|
||||||
fontIsMonospace,
|
fontIsMonospace,
|
||||||
true,
|
true,
|
||||||
@@ -720,7 +732,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
-1,
|
-1,
|
||||||
renderWhitespace,
|
renderWhitespace,
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
selections
|
||||||
));
|
));
|
||||||
|
|
||||||
assert.deepEqual(actual.html, expected);
|
assert.deepEqual(actual.html, expected);
|
||||||
@@ -745,7 +758,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
-1,
|
-1,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
@@ -784,7 +798,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
-1,
|
-1,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
@@ -811,6 +826,7 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
],
|
],
|
||||||
0,
|
0,
|
||||||
'none',
|
'none',
|
||||||
|
null,
|
||||||
[
|
[
|
||||||
'<span>',
|
'<span>',
|
||||||
'<span class="mtk1">Hello\u00a0world!</span>',
|
'<span class="mtk1">Hello\u00a0world!</span>',
|
||||||
@@ -828,6 +844,7 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
],
|
],
|
||||||
0,
|
0,
|
||||||
'none',
|
'none',
|
||||||
|
null,
|
||||||
[
|
[
|
||||||
'<span>',
|
'<span>',
|
||||||
'<span class="mtk1">Hello\u00a0</span>',
|
'<span class="mtk1">Hello\u00a0</span>',
|
||||||
@@ -847,6 +864,7 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
],
|
],
|
||||||
0,
|
0,
|
||||||
'boundary',
|
'boundary',
|
||||||
|
null,
|
||||||
[
|
[
|
||||||
'<span>',
|
'<span>',
|
||||||
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||||
@@ -868,6 +886,7 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
],
|
],
|
||||||
0,
|
0,
|
||||||
'boundary',
|
'boundary',
|
||||||
|
null,
|
||||||
[
|
[
|
||||||
'<span>',
|
'<span>',
|
||||||
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||||
@@ -891,6 +910,7 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
],
|
],
|
||||||
0,
|
0,
|
||||||
'boundary',
|
'boundary',
|
||||||
|
null,
|
||||||
[
|
[
|
||||||
'<span>',
|
'<span>',
|
||||||
'<span class="vs-whitespace" style="width:40px">\u2192\u00a0\u00a0\u00a0</span>',
|
'<span class="vs-whitespace" style="width:40px">\u2192\u00a0\u00a0\u00a0</span>',
|
||||||
@@ -913,6 +933,7 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
],
|
],
|
||||||
0,
|
0,
|
||||||
'boundary',
|
'boundary',
|
||||||
|
null,
|
||||||
[
|
[
|
||||||
'<span>',
|
'<span>',
|
||||||
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u2192\u00a0</span>',
|
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u2192\u00a0</span>',
|
||||||
@@ -940,6 +961,7 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
],
|
],
|
||||||
2,
|
2,
|
||||||
'boundary',
|
'boundary',
|
||||||
|
null,
|
||||||
[
|
[
|
||||||
'<span>',
|
'<span>',
|
||||||
'<span class="">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0</span>',
|
'<span class="">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0</span>',
|
||||||
@@ -966,6 +988,7 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
],
|
],
|
||||||
2,
|
2,
|
||||||
'boundary',
|
'boundary',
|
||||||
|
null,
|
||||||
[
|
[
|
||||||
'<span>',
|
'<span>',
|
||||||
'<span class="">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0</span>',
|
'<span class="">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0</span>',
|
||||||
@@ -989,6 +1012,7 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
],
|
],
|
||||||
0,
|
0,
|
||||||
'boundary',
|
'boundary',
|
||||||
|
null,
|
||||||
[
|
[
|
||||||
'<span>',
|
'<span>',
|
||||||
'<span class="mtk1">it</span>',
|
'<span class="mtk1">it</span>',
|
||||||
@@ -1014,6 +1038,7 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
],
|
],
|
||||||
0,
|
0,
|
||||||
'all',
|
'all',
|
||||||
|
null,
|
||||||
[
|
[
|
||||||
'<span>',
|
'<span>',
|
||||||
'<span class="vs-whitespace" style="width:10px">\u00b7</span>',
|
'<span class="vs-whitespace" style="width:10px">\u00b7</span>',
|
||||||
@@ -1027,6 +1052,147 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('createLineParts render whitespace for selection with no selections', () => {
|
||||||
|
testCreateLineParts(
|
||||||
|
false,
|
||||||
|
' Hello world!\t',
|
||||||
|
[
|
||||||
|
createPart(4, 0),
|
||||||
|
createPart(6, 1),
|
||||||
|
createPart(14, 2)
|
||||||
|
],
|
||||||
|
0,
|
||||||
|
'selection',
|
||||||
|
null,
|
||||||
|
[
|
||||||
|
'<span>',
|
||||||
|
'<span class="mtk0">\u00a0Hel</span>',
|
||||||
|
'<span class="mtk1">lo</span>',
|
||||||
|
'<span class="mtk2">\u00a0world!\u00a0\u00a0\u00a0</span>',
|
||||||
|
'</span>',
|
||||||
|
].join('')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('createLineParts render whitespace for selection with whole line selection', () => {
|
||||||
|
testCreateLineParts(
|
||||||
|
false,
|
||||||
|
' Hello world!\t',
|
||||||
|
[
|
||||||
|
createPart(4, 0),
|
||||||
|
createPart(6, 1),
|
||||||
|
createPart(14, 2)
|
||||||
|
],
|
||||||
|
0,
|
||||||
|
'selection',
|
||||||
|
[new LineRange(0, 14)],
|
||||||
|
[
|
||||||
|
'<span>',
|
||||||
|
'<span class="vs-whitespace" style="width:10px">\u00b7</span>',
|
||||||
|
'<span class="mtk0">Hel</span>',
|
||||||
|
'<span class="mtk1">lo</span>',
|
||||||
|
'<span class="vs-whitespace" style="width:10px">\u00b7</span>',
|
||||||
|
'<span class="mtk2">world!</span>',
|
||||||
|
'<span class="vs-whitespace" style="width:30px">\u2192\u00a0\u00a0</span>',
|
||||||
|
'</span>',
|
||||||
|
].join('')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('createLineParts render whitespace for selection with selection spanning part of whitespace', () => {
|
||||||
|
testCreateLineParts(
|
||||||
|
false,
|
||||||
|
' Hello world!\t',
|
||||||
|
[
|
||||||
|
createPart(4, 0),
|
||||||
|
createPart(6, 1),
|
||||||
|
createPart(14, 2)
|
||||||
|
],
|
||||||
|
0,
|
||||||
|
'selection',
|
||||||
|
[new LineRange(0, 5)],
|
||||||
|
[
|
||||||
|
'<span>',
|
||||||
|
'<span class="vs-whitespace" style="width:10px">\u00b7</span>',
|
||||||
|
'<span class="mtk0">Hel</span>',
|
||||||
|
'<span class="mtk1">lo</span>',
|
||||||
|
'<span class="mtk2">\u00a0world!\u00a0\u00a0\u00a0</span>',
|
||||||
|
'</span>',
|
||||||
|
].join('')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('createLineParts render whitespace for selection with multiple selections', () => {
|
||||||
|
testCreateLineParts(
|
||||||
|
false,
|
||||||
|
' Hello world!\t',
|
||||||
|
[
|
||||||
|
createPart(4, 0),
|
||||||
|
createPart(6, 1),
|
||||||
|
createPart(14, 2)
|
||||||
|
],
|
||||||
|
0,
|
||||||
|
'selection',
|
||||||
|
[new LineRange(0, 5), new LineRange(9, 14)],
|
||||||
|
[
|
||||||
|
'<span>',
|
||||||
|
'<span class="vs-whitespace" style="width:10px">\u00b7</span>',
|
||||||
|
'<span class="mtk0">Hel</span>',
|
||||||
|
'<span class="mtk1">lo</span>',
|
||||||
|
'<span class="mtk2">\u00a0world!</span>',
|
||||||
|
'<span class="vs-whitespace" style="width:30px">\u2192\u00a0\u00a0</span>',
|
||||||
|
'</span>',
|
||||||
|
].join('')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('createLineParts render whitespace for selection with multiple, initially unsorted selections', () => {
|
||||||
|
testCreateLineParts(
|
||||||
|
false,
|
||||||
|
' Hello world!\t',
|
||||||
|
[
|
||||||
|
createPart(4, 0),
|
||||||
|
createPart(6, 1),
|
||||||
|
createPart(14, 2)
|
||||||
|
],
|
||||||
|
0,
|
||||||
|
'selection',
|
||||||
|
[new LineRange(9, 14), new LineRange(0, 5)],
|
||||||
|
[
|
||||||
|
'<span>',
|
||||||
|
'<span class="vs-whitespace" style="width:10px">\u00b7</span>',
|
||||||
|
'<span class="mtk0">Hel</span>',
|
||||||
|
'<span class="mtk1">lo</span>',
|
||||||
|
'<span class="mtk2">\u00a0world!</span>',
|
||||||
|
'<span class="vs-whitespace" style="width:30px">\u2192\u00a0\u00a0</span>',
|
||||||
|
'</span>',
|
||||||
|
].join('')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('createLineParts render whitespace for selection with selections next to each other', () => {
|
||||||
|
testCreateLineParts(
|
||||||
|
false,
|
||||||
|
' * S',
|
||||||
|
[
|
||||||
|
createPart(4, 0)
|
||||||
|
],
|
||||||
|
0,
|
||||||
|
'selection',
|
||||||
|
[new LineRange(0, 1), new LineRange(1, 2), new LineRange(2, 3)],
|
||||||
|
[
|
||||||
|
'<span>',
|
||||||
|
'<span class="vs-whitespace" style="width:10px">\u00b7</span>',
|
||||||
|
'<span class="mtk0">*</span>',
|
||||||
|
'<span class="vs-whitespace" style="width:10px">\u00b7</span>',
|
||||||
|
'<span class="mtk0">S</span>',
|
||||||
|
'</span>',
|
||||||
|
].join('')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test('createLineParts can handle unsorted inline decorations', () => {
|
test('createLineParts can handle unsorted inline decorations', () => {
|
||||||
let actual = renderViewLine(new RenderLineInput(
|
let actual = renderViewLine(new RenderLineInput(
|
||||||
false,
|
false,
|
||||||
@@ -1047,7 +1213,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
-1,
|
-1,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
// 01234567890
|
// 01234567890
|
||||||
@@ -1087,7 +1254,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
-1,
|
-1,
|
||||||
'all',
|
'all',
|
||||||
false,
|
false,
|
||||||
true
|
true,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
@@ -1119,7 +1287,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
-1,
|
-1,
|
||||||
'all',
|
'all',
|
||||||
false,
|
false,
|
||||||
true
|
true,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
@@ -1152,7 +1321,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
-1,
|
-1,
|
||||||
'all',
|
'all',
|
||||||
false,
|
false,
|
||||||
true
|
true,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
@@ -1181,7 +1351,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
10000,
|
10000,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
@@ -1214,7 +1385,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
10000,
|
10000,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
@@ -1246,7 +1418,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
10000,
|
10000,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
@@ -1276,7 +1449,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
10000,
|
10000,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
@@ -1305,7 +1479,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
10000,
|
10000,
|
||||||
'all',
|
'all',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
@@ -1340,7 +1515,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
10000,
|
10000,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
@@ -1369,7 +1545,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
10000,
|
10000,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
@@ -1400,7 +1577,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
10000,
|
10000,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
@@ -1430,7 +1608,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
10000,
|
10000,
|
||||||
'boundary',
|
'boundary',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
@@ -1458,7 +1637,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
10000,
|
10000,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
true
|
true,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
@@ -1490,7 +1670,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
10000,
|
10000,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
true
|
true,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
let expected = [
|
let expected = [
|
||||||
@@ -1518,7 +1699,8 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||||||
-1,
|
-1,
|
||||||
'none',
|
'none',
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
|
|
||||||
return (partIndex: number, partLength: number, offset: number, expected: number) => {
|
return (partIndex: number, partLength: number, offset: number, expected: number) => {
|
||||||
|
|||||||
Vendored
+2
-2
@@ -3031,7 +3031,7 @@ declare namespace monaco.editor {
|
|||||||
* Enable rendering of whitespace.
|
* Enable rendering of whitespace.
|
||||||
* Defaults to none.
|
* Defaults to none.
|
||||||
*/
|
*/
|
||||||
renderWhitespace?: 'none' | 'boundary' | 'all';
|
renderWhitespace?: 'none' | 'boundary' | 'selection' | 'all';
|
||||||
/**
|
/**
|
||||||
* Enable rendering of control characters.
|
* Enable rendering of control characters.
|
||||||
* Defaults to false.
|
* Defaults to false.
|
||||||
@@ -3307,7 +3307,7 @@ declare namespace monaco.editor {
|
|||||||
readonly scrollBeyondLastColumn: number;
|
readonly scrollBeyondLastColumn: number;
|
||||||
readonly smoothScrolling: boolean;
|
readonly smoothScrolling: boolean;
|
||||||
readonly stopRenderingLineAfter: number;
|
readonly stopRenderingLineAfter: number;
|
||||||
readonly renderWhitespace: 'none' | 'boundary' | 'all';
|
readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'all';
|
||||||
readonly renderControlCharacters: boolean;
|
readonly renderControlCharacters: boolean;
|
||||||
readonly fontLigatures: boolean;
|
readonly fontLigatures: boolean;
|
||||||
readonly renderIndentGuides: boolean;
|
readonly renderIndentGuides: boolean;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { IServerChannel, IChannel } from 'vs/base/parts/ipc/common/ipc';
|
|||||||
import { IReloadSessionEvent, ICloseSessionEvent, IAttachSessionEvent, ILogToSessionEvent, ITerminateSessionEvent, IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
|
import { IReloadSessionEvent, ICloseSessionEvent, IAttachSessionEvent, ILogToSessionEvent, ITerminateSessionEvent, IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
|
||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
import { IRemoteConsoleLog } from 'vs/base/common/console';
|
import { IRemoteConsoleLog } from 'vs/base/common/console';
|
||||||
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
|
||||||
export class ExtensionHostDebugBroadcastChannel<TContext> implements IServerChannel<TContext> {
|
export class ExtensionHostDebugBroadcastChannel<TContext> implements IServerChannel<TContext> {
|
||||||
|
|
||||||
@@ -51,11 +52,13 @@ export class ExtensionHostDebugBroadcastChannel<TContext> implements IServerChan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ExtensionHostDebugChannelClient implements IExtensionHostDebugService {
|
export class ExtensionHostDebugChannelClient extends Disposable implements IExtensionHostDebugService {
|
||||||
|
|
||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
|
|
||||||
constructor(private channel: IChannel) { }
|
constructor(private channel: IChannel) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
reload(sessionId: string): void {
|
reload(sessionId: string): void {
|
||||||
this.channel.call('reload', [sessionId]);
|
this.channel.call('reload', [sessionId]);
|
||||||
|
|||||||
@@ -13,6 +13,6 @@ export interface IDownloadService {
|
|||||||
|
|
||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
|
|
||||||
download(uri: URI, to?: string, cancellationToken?: CancellationToken): Promise<string>;
|
download(uri: URI, to: URI, cancellationToken?: CancellationToken): Promise<void>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||||
|
import { Event } from 'vs/base/common/event';
|
||||||
|
import { IDownloadService } from 'vs/platform/download/common/download';
|
||||||
|
import { IURITransformer } from 'vs/base/common/uriIpc';
|
||||||
|
|
||||||
|
export class DownloadServiceChannel implements IServerChannel {
|
||||||
|
|
||||||
|
constructor(private readonly service: IDownloadService) { }
|
||||||
|
|
||||||
|
listen(_: unknown, event: string, arg?: any): Event<any> {
|
||||||
|
throw new Error('Invalid listen');
|
||||||
|
}
|
||||||
|
|
||||||
|
call(context: any, command: string, args?: any): Promise<any> {
|
||||||
|
switch (command) {
|
||||||
|
case 'download': return this.service.download(URI.revive(args[0]), URI.revive(args[1]));
|
||||||
|
}
|
||||||
|
throw new Error('Invalid call');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DownloadServiceChannelClient implements IDownloadService {
|
||||||
|
|
||||||
|
_serviceBrand: any;
|
||||||
|
|
||||||
|
constructor(private channel: IChannel, private getUriTransformer: () => IURITransformer | null) { }
|
||||||
|
|
||||||
|
async download(from: URI, to: URI): Promise<void> {
|
||||||
|
const uriTransfomer = this.getUriTransformer();
|
||||||
|
if (uriTransfomer) {
|
||||||
|
from = uriTransfomer.transformOutgoingURI(from);
|
||||||
|
to = uriTransfomer.transformOutgoingURI(to);
|
||||||
|
}
|
||||||
|
await this.channel.call('download', [from, to]);
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-15
@@ -5,14 +5,10 @@
|
|||||||
|
|
||||||
import { IDownloadService } from 'vs/platform/download/common/download';
|
import { IDownloadService } from 'vs/platform/download/common/download';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
|
||||||
import { copy } from 'vs/base/node/pfs';
|
|
||||||
import { IRequestService, asText } from 'vs/platform/request/common/request';
|
import { IRequestService, asText } from 'vs/platform/request/common/request';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { join } from 'vs/base/common/path';
|
|
||||||
import { tmpdir } from 'os';
|
|
||||||
import { generateUuid } from 'vs/base/common/uuid';
|
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
|
import { Schemas } from 'vs/base/common/network';
|
||||||
|
|
||||||
export class DownloadService implements IDownloadService {
|
export class DownloadService implements IDownloadService {
|
||||||
|
|
||||||
@@ -23,18 +19,18 @@ export class DownloadService implements IDownloadService {
|
|||||||
@IFileService private readonly fileService: IFileService
|
@IFileService private readonly fileService: IFileService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
download(uri: URI, target: string = join(tmpdir(), generateUuid()), cancellationToken: CancellationToken = CancellationToken.None): Promise<string> {
|
async download(resource: URI, target: URI, cancellationToken: CancellationToken = CancellationToken.None): Promise<void> {
|
||||||
if (uri.scheme === Schemas.file) {
|
if (resource.scheme === Schemas.file) {
|
||||||
return copy(uri.fsPath, target).then(() => target);
|
await this.fileService.copy(resource, target);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
const options = { type: 'GET', url: uri.toString() };
|
const options = { type: 'GET', url: resource.toString() };
|
||||||
return this.requestService.request(options, cancellationToken)
|
const context = await this.requestService.request(options, cancellationToken);
|
||||||
.then(context => {
|
|
||||||
if (context.res.statusCode === 200) {
|
if (context.res.statusCode === 200) {
|
||||||
return this.fileService.writeFile(URI.file(target), context.stream).then(() => target);
|
await this.fileService.writeFile(target, context.stream);
|
||||||
|
} else {
|
||||||
|
const message = await asText(context);
|
||||||
|
return Promise.reject(new Error(`Expected 200, got back ${context.res.statusCode} instead.\n\n${message}`));
|
||||||
}
|
}
|
||||||
return asText(context)
|
|
||||||
.then(message => Promise.reject(new Error(`Expected 200, got back ${context.res.statusCode} instead.\n\n${message}`)));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,76 +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 { URI } from 'vs/base/common/uri';
|
|
||||||
import * as path from 'vs/base/common/path';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
|
|
||||||
import { Event, Emitter } from 'vs/base/common/event';
|
|
||||||
import { IDownloadService } from 'vs/platform/download/common/download';
|
|
||||||
import { mkdirp } from 'vs/base/node/pfs';
|
|
||||||
import { IURITransformer } from 'vs/base/common/uriIpc';
|
|
||||||
import { tmpdir } from 'os';
|
|
||||||
import { generateUuid } from 'vs/base/common/uuid';
|
|
||||||
|
|
||||||
type UploadResponse = Buffer | string | undefined;
|
|
||||||
|
|
||||||
function upload(uri: URI): Event<UploadResponse> {
|
|
||||||
const stream = new Emitter<UploadResponse>();
|
|
||||||
const readstream = fs.createReadStream(uri.fsPath);
|
|
||||||
readstream.on('data', data => stream.fire(data));
|
|
||||||
readstream.on('error', error => stream.fire(error.toString()));
|
|
||||||
readstream.on('close', () => stream.fire(undefined));
|
|
||||||
return stream.event;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DownloadServiceChannel implements IServerChannel {
|
|
||||||
|
|
||||||
constructor() { }
|
|
||||||
|
|
||||||
listen(_: unknown, event: string, arg?: any): Event<any> {
|
|
||||||
switch (event) {
|
|
||||||
case 'upload': return Event.buffer(upload(URI.revive(arg)));
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(`Event not found: ${event}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
call(_: unknown, command: string): Promise<any> {
|
|
||||||
throw new Error(`Call not found: ${command}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DownloadServiceChannelClient implements IDownloadService {
|
|
||||||
|
|
||||||
_serviceBrand: any;
|
|
||||||
|
|
||||||
constructor(private channel: IChannel, private getUriTransformer: () => IURITransformer) { }
|
|
||||||
|
|
||||||
download(from: URI, to: string = path.join(tmpdir(), generateUuid())): Promise<string> {
|
|
||||||
from = this.getUriTransformer().transformOutgoingURI(from);
|
|
||||||
const dirName = path.dirname(to);
|
|
||||||
let out: fs.WriteStream;
|
|
||||||
return new Promise<string>((c, e) => {
|
|
||||||
return mkdirp(dirName)
|
|
||||||
.then(() => {
|
|
||||||
out = fs.createWriteStream(to);
|
|
||||||
out.once('close', () => c(to));
|
|
||||||
out.once('error', e);
|
|
||||||
const uploadStream = this.channel.listen<UploadResponse>('upload', from);
|
|
||||||
const disposable = uploadStream(result => {
|
|
||||||
if (result === undefined) {
|
|
||||||
disposable.dispose();
|
|
||||||
out.end(() => c(to));
|
|
||||||
} else if (Buffer.isBuffer(result)) {
|
|
||||||
out.write(result);
|
|
||||||
} else if (typeof result === 'string') {
|
|
||||||
disposable.dispose();
|
|
||||||
out.end(() => e(result));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -26,6 +26,7 @@ import { URI } from 'vs/base/common/uri';
|
|||||||
import { joinPath } from 'vs/base/common/resources';
|
import { joinPath } from 'vs/base/common/resources';
|
||||||
import { VSBuffer } from 'vs/base/common/buffer';
|
import { VSBuffer } from 'vs/base/common/buffer';
|
||||||
import { IProductService } from 'vs/platform/product/common/product';
|
import { IProductService } from 'vs/platform/product/common/product';
|
||||||
|
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||||
|
|
||||||
interface IRawGalleryExtensionFile {
|
interface IRawGalleryExtensionFile {
|
||||||
assetType: string;
|
assetType: string;
|
||||||
@@ -388,11 +389,12 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||||||
@IConfigurationService private configurationService: IConfigurationService,
|
@IConfigurationService private configurationService: IConfigurationService,
|
||||||
@IFileService private readonly fileService: IFileService,
|
@IFileService private readonly fileService: IFileService,
|
||||||
@IProductService private readonly productService: IProductService,
|
@IProductService private readonly productService: IProductService,
|
||||||
|
@IStorageService private readonly storageService: IStorageService,
|
||||||
) {
|
) {
|
||||||
const config = productService.extensionsGallery;
|
const config = productService.extensionsGallery;
|
||||||
this.extensionsGalleryUrl = config && config.serviceUrl;
|
this.extensionsGalleryUrl = config && config.serviceUrl;
|
||||||
this.extensionsControlUrl = config && config.controlUrl;
|
this.extensionsControlUrl = config && config.controlUrl;
|
||||||
this.commonHeadersPromise = resolveMarketplaceHeaders(productService.version, this.environmentService, this.fileService);
|
this.commonHeadersPromise = resolveMarketplaceHeaders(productService.version, this.environmentService, this.fileService, this.storageService);
|
||||||
}
|
}
|
||||||
|
|
||||||
private api(path = ''): string {
|
private api(path = ''): string {
|
||||||
@@ -944,7 +946,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function resolveMarketplaceHeaders(version: string, environmentService: IEnvironmentService, fileService: IFileService): Promise<{ [key: string]: string; }> {
|
export async function resolveMarketplaceHeaders(version: string, environmentService: IEnvironmentService, fileService: IFileService, storageService?: IStorageService): Promise<{ [key: string]: string; }> {
|
||||||
const headers: IHeaders = {
|
const headers: IHeaders = {
|
||||||
'X-Market-Client-Id': `VSCode ${version}`,
|
'X-Market-Client-Id': `VSCode ${version}`,
|
||||||
'User-Agent': `VSCode ${version}`
|
'User-Agent': `VSCode ${version}`
|
||||||
@@ -967,8 +969,20 @@ export async function resolveMarketplaceHeaders(version: string, environmentServ
|
|||||||
//noop
|
//noop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (storageService) {
|
||||||
|
uuid = storageService.get('marketplace.userid', StorageScope.GLOBAL) || null;
|
||||||
|
if (!uuid) {
|
||||||
|
uuid = generateUuid();
|
||||||
|
storageService.store('marketplace.userid', uuid, StorageScope.GLOBAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uuid) {
|
||||||
headers['X-Market-User-Id'] = uuid;
|
headers['X-Market-User-Id'] = uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
return headers;
|
return headers;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -261,7 +261,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
|||||||
throw new Error('Download service is not available');
|
throw new Error('Download service is not available');
|
||||||
}
|
}
|
||||||
const downloadedLocation = path.join(tmpdir(), generateUuid());
|
const downloadedLocation = path.join(tmpdir(), generateUuid());
|
||||||
return this.downloadService.download(vsix, downloadedLocation).then(() => URI.file(downloadedLocation));
|
return this.downloadService.download(vsix, URI.file(downloadedLocation)).then(() => URI.file(downloadedLocation));
|
||||||
}
|
}
|
||||||
|
|
||||||
private installFromZipPath(identifierWithVersion: ExtensionIdentifierWithVersion, zipPath: string, metadata: IGalleryMetadata | null, type: ExtensionType, operation: InstallOperation, token: CancellationToken): Promise<ILocalExtension> {
|
private installFromZipPath(identifierWithVersion: ExtensionIdentifierWithVersion, zipPath: string, metadata: IGalleryMetadata | null, type: ExtensionType, operation: InstallOperation, token: CancellationToken): Promise<ILocalExtension> {
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ function sleep(seconds: number): Promise<void> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum PersistenConnectionEventType {
|
export const enum PersistentConnectionEventType {
|
||||||
ConnectionLost,
|
ConnectionLost,
|
||||||
ReconnectionWait,
|
ReconnectionWait,
|
||||||
ReconnectionRunning,
|
ReconnectionRunning,
|
||||||
@@ -264,22 +264,22 @@ export const enum PersistenConnectionEventType {
|
|||||||
ConnectionGain
|
ConnectionGain
|
||||||
}
|
}
|
||||||
export class ConnectionLostEvent {
|
export class ConnectionLostEvent {
|
||||||
public readonly type = PersistenConnectionEventType.ConnectionLost;
|
public readonly type = PersistentConnectionEventType.ConnectionLost;
|
||||||
}
|
}
|
||||||
export class ReconnectionWaitEvent {
|
export class ReconnectionWaitEvent {
|
||||||
public readonly type = PersistenConnectionEventType.ReconnectionWait;
|
public readonly type = PersistentConnectionEventType.ReconnectionWait;
|
||||||
constructor(
|
constructor(
|
||||||
public readonly durationSeconds: number
|
public readonly durationSeconds: number
|
||||||
) { }
|
) { }
|
||||||
}
|
}
|
||||||
export class ReconnectionRunningEvent {
|
export class ReconnectionRunningEvent {
|
||||||
public readonly type = PersistenConnectionEventType.ReconnectionRunning;
|
public readonly type = PersistentConnectionEventType.ReconnectionRunning;
|
||||||
}
|
}
|
||||||
export class ConnectionGainEvent {
|
export class ConnectionGainEvent {
|
||||||
public readonly type = PersistenConnectionEventType.ConnectionGain;
|
public readonly type = PersistentConnectionEventType.ConnectionGain;
|
||||||
}
|
}
|
||||||
export class ReconnectionPermanentFailureEvent {
|
export class ReconnectionPermanentFailureEvent {
|
||||||
public readonly type = PersistenConnectionEventType.ReconnectionPermanentFailure;
|
public readonly type = PersistentConnectionEventType.ReconnectionPermanentFailure;
|
||||||
}
|
}
|
||||||
export type PersistenConnectionEvent = ConnectionGainEvent | ConnectionLostEvent | ReconnectionWaitEvent | ReconnectionRunningEvent | ReconnectionPermanentFailureEvent;
|
export type PersistenConnectionEvent = ConnectionGainEvent | ConnectionLostEvent | ReconnectionWaitEvent | ReconnectionRunningEvent | ReconnectionPermanentFailureEvent;
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -3826,7 +3826,7 @@ declare module 'vscode' {
|
|||||||
/**
|
/**
|
||||||
* Provide selection ranges for the given positions.
|
* Provide selection ranges for the given positions.
|
||||||
*
|
*
|
||||||
* Selection ranges should be computed individually and independend for each position. The editor will merge
|
* Selection ranges should be computed individually and independent for each position. The editor will merge
|
||||||
* and deduplicate ranges but providers must return hierarchies of selection ranges so that a range
|
* and deduplicate ranges but providers must return hierarchies of selection ranges so that a range
|
||||||
* is [contained](#Range.contains) by its parent.
|
* is [contained](#Range.contains) by its parent.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import './mainThreadStorage';
|
|||||||
import './mainThreadTelemetry';
|
import './mainThreadTelemetry';
|
||||||
import './mainThreadTerminalService';
|
import './mainThreadTerminalService';
|
||||||
import './mainThreadTreeViews';
|
import './mainThreadTreeViews';
|
||||||
|
import './mainThreadDownloadService';
|
||||||
import './mainThreadUrls';
|
import './mainThreadUrls';
|
||||||
import './mainThreadWindow';
|
import './mainThreadWindow';
|
||||||
import './mainThreadWebview';
|
import './mainThreadWebview';
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { MainContext, IExtHostContext, MainThreadDownloadServiceShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
|
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||||
|
import { IDownloadService } from 'vs/platform/download/common/download';
|
||||||
|
import { UriComponents, URI } from 'vs/base/common/uri';
|
||||||
|
|
||||||
|
@extHostNamedCustomer(MainContext.MainThreadDownloadService)
|
||||||
|
export class MainThreadDownloadService extends Disposable implements MainThreadDownloadServiceShape {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
extHostContext: IExtHostContext,
|
||||||
|
@IDownloadService private readonly downloadService: IDownloadService
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
$download(uri: UriComponents, to: UriComponents): Promise<void> {
|
||||||
|
return this.downloadService.download(URI.revive(uri), URI.revive(to));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { ExtHostContext, MainThreadTreeViewsShape, ExtHostTreeViewsShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
|
import { ExtHostContext, MainThreadTreeViewsShape, ExtHostTreeViewsShape, MainContext, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeView, IViewsRegistry, ITreeViewDescriptor, IRevealOptions, Extensions } from 'vs/workbench/common/views';
|
import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeView, IViewsRegistry, ITreeViewDescriptor, IRevealOptions, Extensions } from 'vs/workbench/common/views';
|
||||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||||
import { distinct } from 'vs/base/common/arrays';
|
import { distinct } from 'vs/base/common/arrays';
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
|
|||||||
import { extHostNamedCustomer } from '../common/extHostCustomers';
|
import { extHostNamedCustomer } from '../common/extHostCustomers';
|
||||||
import { IProductService } from 'vs/platform/product/common/product';
|
import { IProductService } from 'vs/platform/product/common/product';
|
||||||
import { startsWith } from 'vs/base/common/strings';
|
import { startsWith } from 'vs/base/common/strings';
|
||||||
|
import { Webview } from 'vs/workbench/contrib/webview/common/webview';
|
||||||
|
|
||||||
interface OldMainThreadWebviewState {
|
interface OldMainThreadWebviewState {
|
||||||
readonly viewType: string;
|
readonly viewType: string;
|
||||||
@@ -41,9 +42,9 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
|||||||
|
|
||||||
private static revivalPool = 0;
|
private static revivalPool = 0;
|
||||||
|
|
||||||
|
|
||||||
private readonly _proxy: ExtHostWebviewsShape;
|
private readonly _proxy: ExtHostWebviewsShape;
|
||||||
private readonly _webviews = new Map<WebviewPanelHandle, WebviewEditorInput>();
|
private readonly _webviewEditorInputs = new Map<string, WebviewEditorInput>();
|
||||||
|
private readonly _webviews = new Map<string, Webview>();
|
||||||
private readonly _revivers = new Map<string, IDisposable>();
|
private readonly _revivers = new Map<string, IDisposable>();
|
||||||
|
|
||||||
private _activeWebview: WebviewPanelHandle | undefined = undefined;
|
private _activeWebview: WebviewPanelHandle | undefined = undefined;
|
||||||
@@ -103,7 +104,8 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
|||||||
});
|
});
|
||||||
this.hookupWebviewEventDelegate(handle, webview);
|
this.hookupWebviewEventDelegate(handle, webview);
|
||||||
|
|
||||||
this._webviews.set(handle, webview);
|
this._webviewEditorInputs.set(handle, webview);
|
||||||
|
this._webviews.set(handle, webview.webview);
|
||||||
|
|
||||||
/* __GDPR__
|
/* __GDPR__
|
||||||
"webviews:createWebviewPanel" : {
|
"webviews:createWebviewPanel" : {
|
||||||
@@ -114,32 +116,32 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
|||||||
}
|
}
|
||||||
|
|
||||||
public $disposeWebview(handle: WebviewPanelHandle): void {
|
public $disposeWebview(handle: WebviewPanelHandle): void {
|
||||||
const webview = this.getWebview(handle);
|
const webview = this.getWebviewEditorInput(handle);
|
||||||
webview.dispose();
|
webview.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public $setTitle(handle: WebviewPanelHandle, value: string): void {
|
public $setTitle(handle: WebviewPanelHandle, value: string): void {
|
||||||
const webview = this.getWebview(handle);
|
const webview = this.getWebviewEditorInput(handle);
|
||||||
webview.setName(value);
|
webview.setName(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public $setIconPath(handle: WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents } | undefined): void {
|
public $setIconPath(handle: WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents } | undefined): void {
|
||||||
const webview = this.getWebview(handle);
|
const webview = this.getWebviewEditorInput(handle);
|
||||||
webview.iconPath = reviveWebviewIcon(value);
|
webview.iconPath = reviveWebviewIcon(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public $setHtml(handle: WebviewPanelHandle, value: string): void {
|
public $setHtml(handle: WebviewPanelHandle, value: string): void {
|
||||||
const webview = this.getWebview(handle);
|
const webview = this.getWebview(handle);
|
||||||
webview.webview.html = value;
|
webview.html = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public $setOptions(handle: WebviewPanelHandle, options: modes.IWebviewOptions): void {
|
public $setOptions(handle: WebviewPanelHandle, options: modes.IWebviewOptions): void {
|
||||||
const webview = this.getWebview(handle);
|
const webview = this.getWebview(handle);
|
||||||
webview.webview.contentOptions = reviveWebviewOptions(options as any /*todo@mat */);
|
webview.contentOptions = reviveWebviewOptions(options as any /*todo@mat */);
|
||||||
}
|
}
|
||||||
|
|
||||||
public $reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void {
|
public $reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void {
|
||||||
const webview = this.getWebview(handle);
|
const webview = this.getWebviewEditorInput(handle);
|
||||||
if (webview.isDisposed()) {
|
if (webview.isDisposed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -152,7 +154,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
|||||||
|
|
||||||
public async $postMessage(handle: WebviewPanelHandle, message: any): Promise<boolean> {
|
public async $postMessage(handle: WebviewPanelHandle, message: any): Promise<boolean> {
|
||||||
const webview = this.getWebview(handle);
|
const webview = this.getWebview(handle);
|
||||||
webview.webview.sendMessage(message);
|
webview.sendMessage(message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,8 +175,10 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handle = `revival-${MainThreadWebviews.revivalPool++}`;
|
const handle = `revival-${MainThreadWebviews.revivalPool++}`;
|
||||||
this._webviews.set(handle, webviewEditorInput);
|
this._webviewEditorInputs.set(handle, webviewEditorInput);
|
||||||
|
this._webviews.set(handle, webviewEditorInput.webview);
|
||||||
this.hookupWebviewEventDelegate(handle, webviewEditorInput);
|
this.hookupWebviewEventDelegate(handle, webviewEditorInput);
|
||||||
|
|
||||||
let state = undefined;
|
let state = undefined;
|
||||||
if (webviewEditorInput.webview.state) {
|
if (webviewEditorInput.webview.state) {
|
||||||
try {
|
try {
|
||||||
@@ -229,11 +233,12 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
|||||||
input.webview.onMessage((message: any) => this._proxy.$onMessage(handle, message));
|
input.webview.onMessage((message: any) => this._proxy.$onMessage(handle, message));
|
||||||
input.onDispose(() => {
|
input.onDispose(() => {
|
||||||
this._proxy.$onDidDisposeWebviewPanel(handle).finally(() => {
|
this._proxy.$onDidDisposeWebviewPanel(handle).finally(() => {
|
||||||
|
this._webviewEditorInputs.delete(handle);
|
||||||
this._webviews.delete(handle);
|
this._webviews.delete(handle);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
input.webview.onDidUpdateState((newState: any) => {
|
input.webview.onDidUpdateState((newState: any) => {
|
||||||
const webview = this.tryGetWebview(handle);
|
const webview = this.tryGetWebviewEditorInput(handle);
|
||||||
if (!webview || webview.isDisposed()) {
|
if (!webview || webview.isDisposed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -245,8 +250,8 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
|||||||
const activeEditor = this._editorService.activeControl;
|
const activeEditor = this._editorService.activeControl;
|
||||||
let newActiveWebview: { input: WebviewEditorInput, handle: WebviewPanelHandle } | undefined = undefined;
|
let newActiveWebview: { input: WebviewEditorInput, handle: WebviewPanelHandle } | undefined = undefined;
|
||||||
if (activeEditor && activeEditor.input instanceof WebviewEditorInput) {
|
if (activeEditor && activeEditor.input instanceof WebviewEditorInput) {
|
||||||
for (const handle of map.keys(this._webviews)) {
|
for (const handle of map.keys(this._webviewEditorInputs)) {
|
||||||
const input = this._webviews.get(handle)!;
|
const input = this._webviewEditorInputs.get(handle)!;
|
||||||
if (input.matches(activeEditor.input)) {
|
if (input.matches(activeEditor.input)) {
|
||||||
newActiveWebview = { input, handle };
|
newActiveWebview = { input, handle };
|
||||||
break;
|
break;
|
||||||
@@ -266,7 +271,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
|||||||
|
|
||||||
// Broadcast view state update for currently active
|
// Broadcast view state update for currently active
|
||||||
if (typeof this._activeWebview !== 'undefined') {
|
if (typeof this._activeWebview !== 'undefined') {
|
||||||
const oldActiveWebview = this._webviews.get(this._activeWebview);
|
const oldActiveWebview = this._webviewEditorInputs.get(this._activeWebview);
|
||||||
if (oldActiveWebview) {
|
if (oldActiveWebview) {
|
||||||
this._proxy.$onDidChangeWebviewPanelViewState(this._activeWebview, {
|
this._proxy.$onDidChangeWebviewPanelViewState(this._activeWebview, {
|
||||||
active: false,
|
active: false,
|
||||||
@@ -290,7 +295,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
|||||||
}
|
}
|
||||||
|
|
||||||
private onVisibleEditorsChanged(): void {
|
private onVisibleEditorsChanged(): void {
|
||||||
this._webviews.forEach((input, handle) => {
|
this._webviewEditorInputs.forEach((input, handle) => {
|
||||||
for (const workbenchEditor of this._editorService.visibleControls) {
|
for (const workbenchEditor of this._editorService.visibleControls) {
|
||||||
if (workbenchEditor.input && workbenchEditor.input.matches(input)) {
|
if (workbenchEditor.input && workbenchEditor.input.matches(input)) {
|
||||||
const editorPosition = editorGroupToViewColumn(this._editorGroupService, workbenchEditor.group!);
|
const editorPosition = editorGroupToViewColumn(this._editorGroupService, workbenchEditor.group!);
|
||||||
@@ -312,7 +317,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const webview = this.getWebview(handle);
|
const webview = this.getWebviewEditorInput(handle);
|
||||||
if (this.isSupportedLink(webview, link)) {
|
if (this.isSupportedLink(webview, link)) {
|
||||||
this._openerService.open(link);
|
this._openerService.open(link);
|
||||||
}
|
}
|
||||||
@@ -328,7 +333,19 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
|||||||
return !!webview.webview.contentOptions.enableCommandUris && link.scheme === 'command';
|
return !!webview.webview.contentOptions.enableCommandUris && link.scheme === 'command';
|
||||||
}
|
}
|
||||||
|
|
||||||
private getWebview(handle: WebviewPanelHandle): WebviewEditorInput {
|
private getWebviewEditorInput(handle: WebviewPanelHandle): WebviewEditorInput {
|
||||||
|
const webview = this.tryGetWebviewEditorInput(handle);
|
||||||
|
if (!webview) {
|
||||||
|
throw new Error('Unknown webview handle:' + handle);
|
||||||
|
}
|
||||||
|
return webview;
|
||||||
|
}
|
||||||
|
|
||||||
|
private tryGetWebviewEditorInput(handle: WebviewPanelHandle): WebviewEditorInput | undefined {
|
||||||
|
return this._webviewEditorInputs.get(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getWebview(handle: WebviewPanelHandle): Webview {
|
||||||
const webview = this.tryGetWebview(handle);
|
const webview = this.tryGetWebview(handle);
|
||||||
if (!webview) {
|
if (!webview) {
|
||||||
throw new Error('Unknown webview handle:' + handle);
|
throw new Error('Unknown webview handle:' + handle);
|
||||||
@@ -336,7 +353,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
|||||||
return webview;
|
return webview;
|
||||||
}
|
}
|
||||||
|
|
||||||
private tryGetWebview(handle: WebviewPanelHandle): WebviewEditorInput | undefined {
|
private tryGetWebview(handle: WebviewPanelHandle): Webview | undefined {
|
||||||
return this._webviews.get(handle);
|
return this._webviews.get(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
|||||||
import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService';
|
import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IOpenSettings, IURIToOpen, IWindowService } from 'vs/platform/windows/common/windows';
|
import { IOpenSettings, IURIToOpen, IWindowService } from 'vs/platform/windows/common/windows';
|
||||||
import { IDownloadService } from 'vs/platform/download/common/download';
|
|
||||||
import { IWorkspacesService, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
|
import { IWorkspacesService, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
|
||||||
import { IRecent } from 'vs/platform/history/common/history';
|
import { IRecent } from 'vs/platform/history/common/history';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
@@ -207,8 +206,3 @@ CommandsRegistry.registerCommand({
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
CommandsRegistry.registerCommand('_workbench.downloadResource', function (accessor: ServicesAccessor, resource: URI) {
|
|
||||||
const downloadService = accessor.get(IDownloadService);
|
|
||||||
return downloadService.download(resource).then(location => URI.file(location));
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -249,6 +249,10 @@ export interface MainThreadTreeViewsShape extends IDisposable {
|
|||||||
$setMessage(treeViewId: string, message: string | IMarkdownString): void;
|
$setMessage(treeViewId: string, message: string | IMarkdownString): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MainThreadDownloadServiceShape extends IDisposable {
|
||||||
|
$download(uri: UriComponents, to: UriComponents): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
export interface MainThreadErrorsShape extends IDisposable {
|
export interface MainThreadErrorsShape extends IDisposable {
|
||||||
$onUnexpectedError(err: any | SerializedError): void;
|
$onUnexpectedError(err: any | SerializedError): void;
|
||||||
}
|
}
|
||||||
@@ -815,6 +819,9 @@ export interface ExtHostTreeViewsShape {
|
|||||||
$setVisible(treeViewId: string, visible: boolean): void;
|
$setVisible(treeViewId: string, visible: boolean): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ExtHostDownloadServiceShape {
|
||||||
|
}
|
||||||
|
|
||||||
export interface ExtHostWorkspaceShape {
|
export interface ExtHostWorkspaceShape {
|
||||||
$initializeWorkspace(workspace: IWorkspaceData | null): void;
|
$initializeWorkspace(workspace: IWorkspaceData | null): void;
|
||||||
$acceptWorkspaceData(workspace: IWorkspaceData | null): void;
|
$acceptWorkspaceData(workspace: IWorkspaceData | null): void;
|
||||||
@@ -1312,6 +1319,7 @@ export const MainContext = {
|
|||||||
MainThreadEditorInsets: createMainId<MainThreadEditorInsetsShape>('MainThreadEditorInsets'),
|
MainThreadEditorInsets: createMainId<MainThreadEditorInsetsShape>('MainThreadEditorInsets'),
|
||||||
MainThreadErrors: createMainId<MainThreadErrorsShape>('MainThreadErrors'),
|
MainThreadErrors: createMainId<MainThreadErrorsShape>('MainThreadErrors'),
|
||||||
MainThreadTreeViews: createMainId<MainThreadTreeViewsShape>('MainThreadTreeViews'),
|
MainThreadTreeViews: createMainId<MainThreadTreeViewsShape>('MainThreadTreeViews'),
|
||||||
|
MainThreadDownloadService: createMainId<MainThreadDownloadServiceShape>('MainThreadDownloadService'),
|
||||||
MainThreadKeytar: createMainId<MainThreadKeytarShape>('MainThreadKeytar'),
|
MainThreadKeytar: createMainId<MainThreadKeytarShape>('MainThreadKeytar'),
|
||||||
MainThreadLanguageFeatures: createMainId<MainThreadLanguageFeaturesShape>('MainThreadLanguageFeatures'),
|
MainThreadLanguageFeatures: createMainId<MainThreadLanguageFeaturesShape>('MainThreadLanguageFeatures'),
|
||||||
MainThreadLanguages: createMainId<MainThreadLanguagesShape>('MainThreadLanguages'),
|
MainThreadLanguages: createMainId<MainThreadLanguagesShape>('MainThreadLanguages'),
|
||||||
@@ -1347,6 +1355,7 @@ export const ExtHostContext = {
|
|||||||
ExtHostDocumentSaveParticipant: createExtId<ExtHostDocumentSaveParticipantShape>('ExtHostDocumentSaveParticipant'),
|
ExtHostDocumentSaveParticipant: createExtId<ExtHostDocumentSaveParticipantShape>('ExtHostDocumentSaveParticipant'),
|
||||||
ExtHostEditors: createExtId<ExtHostEditorsShape>('ExtHostEditors'),
|
ExtHostEditors: createExtId<ExtHostEditorsShape>('ExtHostEditors'),
|
||||||
ExtHostTreeViews: createExtId<ExtHostTreeViewsShape>('ExtHostTreeViews'),
|
ExtHostTreeViews: createExtId<ExtHostTreeViewsShape>('ExtHostTreeViews'),
|
||||||
|
ExtHostDownloadService: createExtId<ExtHostDownloadServiceShape>('ExtHostDownloadService'),
|
||||||
ExtHostFileSystem: createExtId<ExtHostFileSystemShape>('ExtHostFileSystem'),
|
ExtHostFileSystem: createExtId<ExtHostFileSystemShape>('ExtHostFileSystem'),
|
||||||
ExtHostFileSystemEventService: createExtId<ExtHostFileSystemEventServiceShape>('ExtHostFileSystemEventService'),
|
ExtHostFileSystemEventService: createExtId<ExtHostFileSystemEventServiceShape>('ExtHostFileSystemEventService'),
|
||||||
ExtHostLanguageFeatures: createExtId<ExtHostLanguageFeaturesShape>('ExtHostLanguageFeatures'),
|
ExtHostLanguageFeatures: createExtId<ExtHostLanguageFeaturesShape>('ExtHostLanguageFeatures'),
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import { ExtHostTask } from 'vs/workbench/api/node/extHostTask';
|
|||||||
import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService';
|
import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService';
|
||||||
import { ExtHostEditors } from 'vs/workbench/api/common/extHostTextEditors';
|
import { ExtHostEditors } from 'vs/workbench/api/common/extHostTextEditors';
|
||||||
import { ExtHostTreeViews } from 'vs/workbench/api/common/extHostTreeViews';
|
import { ExtHostTreeViews } from 'vs/workbench/api/common/extHostTreeViews';
|
||||||
|
import { ExtHostDownloadService } from 'vs/workbench/api/node/extHostDownloadService';
|
||||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||||
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||||
import { ExtHostUrls } from 'vs/workbench/api/common/extHostUrls';
|
import { ExtHostUrls } from 'vs/workbench/api/common/extHostUrls';
|
||||||
@@ -117,6 +118,7 @@ export function createApiFactory(
|
|||||||
const extHostEditors = rpcProtocol.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(rpcProtocol, extHostDocumentsAndEditors));
|
const extHostEditors = rpcProtocol.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(rpcProtocol, extHostDocumentsAndEditors));
|
||||||
const extHostCommands = rpcProtocol.set(ExtHostContext.ExtHostCommands, new ExtHostCommands(rpcProtocol, extHostLogService));
|
const extHostCommands = rpcProtocol.set(ExtHostContext.ExtHostCommands, new ExtHostCommands(rpcProtocol, extHostLogService));
|
||||||
const extHostTreeViews = rpcProtocol.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(rpcProtocol.getProxy(MainContext.MainThreadTreeViews), extHostCommands, extHostLogService));
|
const extHostTreeViews = rpcProtocol.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(rpcProtocol.getProxy(MainContext.MainThreadTreeViews), extHostCommands, extHostLogService));
|
||||||
|
rpcProtocol.set(ExtHostContext.ExtHostDownloadService, new ExtHostDownloadService(rpcProtocol.getProxy(MainContext.MainThreadDownloadService), extHostCommands));
|
||||||
rpcProtocol.set(ExtHostContext.ExtHostWorkspace, extHostWorkspace);
|
rpcProtocol.set(ExtHostContext.ExtHostWorkspace, extHostWorkspace);
|
||||||
rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration);
|
rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration);
|
||||||
const extHostEditorInsets = rpcProtocol.set(ExtHostContext.ExtHostEditorInsets, new ExtHostEditorInsets(rpcProtocol.getProxy(MainContext.MainThreadEditorInsets), extHostEditors, initData.environment));
|
const extHostEditorInsets = rpcProtocol.set(ExtHostContext.ExtHostEditorInsets, new ExtHostEditorInsets(rpcProtocol.getProxy(MainContext.MainThreadEditorInsets), extHostEditors, initData.environment));
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* 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 { tmpdir } from 'os';
|
||||||
|
import { generateUuid } from 'vs/base/common/uuid';
|
||||||
|
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||||
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { MainThreadDownloadServiceShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
|
||||||
|
export class ExtHostDownloadService extends Disposable {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
proxy: MainThreadDownloadServiceShape,
|
||||||
|
commands: ExtHostCommands
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
commands.registerCommand(false, '_workbench.downloadResource', async (resource: URI): Promise<any> => {
|
||||||
|
const location = URI.file(join(tmpdir(), generateUuid()));
|
||||||
|
await proxy.$download(resource, location);
|
||||||
|
return location;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -27,14 +27,13 @@ import { IWindowService, MenuBarVisibility, getTitleBarStyle } from 'vs/platform
|
|||||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||||
import { Sizing, Direction, Grid } from 'vs/base/browser/ui/grid/grid';
|
import { Sizing, Direction, Grid, SerializableGrid, ISerializableView, ISerializedGrid } from 'vs/base/browser/ui/grid/grid';
|
||||||
import { WorkbenchLegacyLayout } from 'vs/workbench/browser/legacyLayout';
|
import { WorkbenchLegacyLayout } from 'vs/workbench/browser/legacyLayout';
|
||||||
import { IDimension } from 'vs/platform/layout/browser/layoutService';
|
import { IDimension } from 'vs/platform/layout/browser/layoutService';
|
||||||
import { Part } from 'vs/workbench/browser/part';
|
import { Part } from 'vs/workbench/browser/part';
|
||||||
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
|
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
|
||||||
import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService';
|
import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
import { IView } from 'vs/base/browser/ui/grid/gridview';
|
|
||||||
|
|
||||||
enum Settings {
|
enum Settings {
|
||||||
MENUBAR_VISIBLE = 'window.menuBarVisibility',
|
MENUBAR_VISIBLE = 'window.menuBarVisibility',
|
||||||
@@ -57,6 +56,8 @@ enum Storage {
|
|||||||
|
|
||||||
ZEN_MODE_ENABLED = 'workbench.zenmode.active',
|
ZEN_MODE_ENABLED = 'workbench.zenmode.active',
|
||||||
CENTERED_LAYOUT_ENABLED = 'workbench.centerededitorlayout.active',
|
CENTERED_LAYOUT_ENABLED = 'workbench.centerededitorlayout.active',
|
||||||
|
|
||||||
|
GRID_LAYOUT = 'workbench.grid.layout'
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class Layout extends Disposable implements IWorkbenchLayoutService {
|
export abstract class Layout extends Disposable implements IWorkbenchLayoutService {
|
||||||
@@ -89,16 +90,16 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
|||||||
|
|
||||||
private parts: Map<string, Part> = new Map<string, Part>();
|
private parts: Map<string, Part> = new Map<string, Part>();
|
||||||
|
|
||||||
private workbenchGrid: Grid | WorkbenchLegacyLayout;
|
private workbenchGrid: SerializableGrid<ISerializableView> | WorkbenchLegacyLayout;
|
||||||
|
|
||||||
private disposed: boolean;
|
private disposed: boolean;
|
||||||
|
|
||||||
private titleBarPartView: IView;
|
private titleBarPartView: ISerializableView;
|
||||||
private activityBarPartView: IView;
|
private activityBarPartView: ISerializableView;
|
||||||
private sideBarPartView: IView;
|
private sideBarPartView: ISerializableView;
|
||||||
private panelPartView: IView;
|
private panelPartView: ISerializableView;
|
||||||
private editorPartView: IView;
|
private editorPartView: ISerializableView;
|
||||||
private statusBarPartView: IView;
|
private statusBarPartView: ISerializableView;
|
||||||
|
|
||||||
private environmentService: IWorkbenchEnvironmentService;
|
private environmentService: IWorkbenchEnvironmentService;
|
||||||
private configurationService: IConfigurationService;
|
private configurationService: IConfigurationService;
|
||||||
@@ -144,8 +145,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
|||||||
hidden: false,
|
hidden: false,
|
||||||
sizeBeforeMaximize: 0,
|
sizeBeforeMaximize: 0,
|
||||||
position: Position.BOTTOM,
|
position: Position.BOTTOM,
|
||||||
height: 350,
|
|
||||||
width: 350,
|
|
||||||
panelToRestore: undefined as string | undefined
|
panelToRestore: undefined as string | undefined
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -706,7 +705,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
|||||||
|
|
||||||
if (this.configurationService.getValue('workbench.useExperimentalGridLayout')) {
|
if (this.configurationService.getValue('workbench.useExperimentalGridLayout')) {
|
||||||
|
|
||||||
// Create view wrappers for all parts
|
// View references for all parts
|
||||||
this.titleBarPartView = titleBar;
|
this.titleBarPartView = titleBar;
|
||||||
this.sideBarPartView = sideBar;
|
this.sideBarPartView = sideBar;
|
||||||
this.activityBarPartView = activityBar;
|
this.activityBarPartView = activityBar;
|
||||||
@@ -714,9 +713,63 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
|||||||
this.panelPartView = panelPart;
|
this.panelPartView = panelPart;
|
||||||
this.statusBarPartView = statusBar;
|
this.statusBarPartView = statusBar;
|
||||||
|
|
||||||
this.workbenchGrid = new Grid(this.editorPartView, { proportionalLayout: false });
|
let workbenchGrid: SerializableGrid<ISerializableView> | undefined;
|
||||||
|
|
||||||
this.container.prepend(this.workbenchGrid.element);
|
const savedGrid = this.storageService.get(Storage.GRID_LAYOUT, StorageScope.GLOBAL, undefined);
|
||||||
|
if (savedGrid) {
|
||||||
|
const parsedGrid: ISerializedGrid = JSON.parse(savedGrid);
|
||||||
|
|
||||||
|
const fromJSON = (serializedPart: { type: Parts } | null) => {
|
||||||
|
if (serializedPart && serializedPart.type) {
|
||||||
|
switch (serializedPart.type) {
|
||||||
|
case Parts.ACTIVITYBAR_PART:
|
||||||
|
return this.activityBarPartView;
|
||||||
|
case Parts.TITLEBAR_PART:
|
||||||
|
return this.titleBarPartView;
|
||||||
|
case Parts.EDITOR_PART:
|
||||||
|
return this.editorPartView;
|
||||||
|
case Parts.PANEL_PART:
|
||||||
|
return this.panelPartView;
|
||||||
|
case Parts.SIDEBAR_PART:
|
||||||
|
return this.sideBarPartView;
|
||||||
|
case Parts.STATUSBAR_PART:
|
||||||
|
return this.statusBarPartView;
|
||||||
|
default:
|
||||||
|
return this.editorPartView;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return this.editorPartView;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
workbenchGrid = SerializableGrid.deserialize(parsedGrid, { fromJSON }, { proportionalLayout: false });
|
||||||
|
|
||||||
|
// Set some layout state
|
||||||
|
this.state.sideBar.position = Position.LEFT;
|
||||||
|
for (let view of workbenchGrid.getNeighborViews(this.sideBarPartView, Direction.Right)) {
|
||||||
|
if (view === this.activityBarPartView) {
|
||||||
|
this.state.sideBar.position = Position.RIGHT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state.panel.position = Position.BOTTOM;
|
||||||
|
for (let view of workbenchGrid.getNeighborViews(this.panelPartView, Direction.Left)) {
|
||||||
|
if (view === this.editorPartView) {
|
||||||
|
this.state.panel.position = Position.RIGHT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!workbenchGrid) {
|
||||||
|
workbenchGrid = new SerializableGrid(this.editorPartView, { proportionalLayout: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.container.prepend(workbenchGrid.element);
|
||||||
|
this.workbenchGrid = workbenchGrid;
|
||||||
|
|
||||||
this._register((this.sideBarPartView as SidebarPart).onDidVisibilityChange((visible) => {
|
this._register((this.sideBarPartView as SidebarPart).onDidVisibilityChange((visible) => {
|
||||||
this.setSideBarHidden(!visible, true);
|
this.setSideBarHidden(!visible, true);
|
||||||
@@ -725,6 +778,17 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
|||||||
this._register((this.panelPartView as PanelPart).onDidVisibilityChange((visible) => {
|
this._register((this.panelPartView as PanelPart).onDidVisibilityChange((visible) => {
|
||||||
this.setPanelHidden(!visible, true);
|
this.setPanelHidden(!visible, true);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
this._register(this.lifecycleService.onBeforeShutdown(beforeShutdownEvent => {
|
||||||
|
beforeShutdownEvent.veto(new Promise((resolve) => {
|
||||||
|
const grid = this.workbenchGrid as SerializableGrid<ISerializableView>;
|
||||||
|
const serializedGrid = grid.serialize();
|
||||||
|
|
||||||
|
this.storageService.store(Storage.GRID_LAYOUT, JSON.stringify(serializedGrid), StorageScope.GLOBAL);
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
}));
|
||||||
|
}));
|
||||||
} else {
|
} else {
|
||||||
this.workbenchGrid = instantiationService.createInstance(
|
this.workbenchGrid = instantiationService.createInstance(
|
||||||
WorkbenchLegacyLayout,
|
WorkbenchLegacyLayout,
|
||||||
@@ -797,7 +861,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!panelInGrid) {
|
if (!panelInGrid) {
|
||||||
this.workbenchGrid.addView(this.panelPartView, this.getPanelDimension(this.state.panel.position) !== undefined ? this.getPanelDimension(this.state.panel.position) : Sizing.Split, this.editorPartView, this.state.panel.position === Position.BOTTOM ? Direction.Down : Direction.Right);
|
this.workbenchGrid.addView(this.panelPartView, Sizing.Split, this.editorPartView, this.state.panel.position === Position.BOTTOM ? Direction.Down : Direction.Right);
|
||||||
panelInGrid = true;
|
panelInGrid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -852,10 +916,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getPanelDimension(position: Position): number {
|
|
||||||
return position === Position.BOTTOM ? this.state.panel.height : this.state.panel.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
isEditorLayoutCentered(): boolean {
|
isEditorLayoutCentered(): boolean {
|
||||||
return this.state.editor.centered;
|
return this.state.editor.centered;
|
||||||
}
|
}
|
||||||
@@ -1148,12 +1208,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
|||||||
|
|
||||||
setPanelPosition(position: Position): void {
|
setPanelPosition(position: Position): void {
|
||||||
const panelPart = this.getPart(Parts.PANEL_PART);
|
const panelPart = this.getPart(Parts.PANEL_PART);
|
||||||
const wasHidden = this.state.panel.hidden;
|
|
||||||
|
|
||||||
if (this.state.panel.hidden) {
|
if (this.state.panel.hidden) {
|
||||||
this.setPanelHidden(false, true /* Skip Layout */);
|
this.setPanelHidden(false, true /* Skip Layout */);
|
||||||
} else {
|
|
||||||
this.savePanelDimension();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const newPositionValue = (position === Position.BOTTOM) ? 'bottom' : 'right';
|
const newPositionValue = (position === Position.BOTTOM) ? 'bottom' : 'right';
|
||||||
@@ -1179,10 +1236,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
|||||||
|
|
||||||
// Layout
|
// Layout
|
||||||
if (this.workbenchGrid instanceof Grid) {
|
if (this.workbenchGrid instanceof Grid) {
|
||||||
if (!wasHidden) {
|
|
||||||
this.savePanelDimension();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.workbenchGrid.removeView(this.panelPartView);
|
this.workbenchGrid.removeView(this.panelPartView);
|
||||||
this.layout();
|
this.layout();
|
||||||
} else {
|
} else {
|
||||||
@@ -1192,18 +1245,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
|||||||
this._onPanelPositionChange.fire(positionToString(this.state.panel.position));
|
this._onPanelPositionChange.fire(positionToString(this.state.panel.position));
|
||||||
}
|
}
|
||||||
|
|
||||||
private savePanelDimension(): void {
|
|
||||||
if (!(this.workbenchGrid instanceof Grid)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.panel.position === Position.BOTTOM) {
|
|
||||||
this.state.panel.height = this.workbenchGrid.getViewSize(this.panelPartView).height;
|
|
||||||
} else {
|
|
||||||
this.state.panel.width = this.workbenchGrid.getViewSize(this.panelPartView).width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,6 @@ import * as browser from 'vs/base/browser/browser';
|
|||||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
// tslint:disable-next-line: import-patterns no-standalone-editor
|
|
||||||
import { IDownloadService } from 'vs/platform/download/common/download';
|
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
|
||||||
import { IGalleryExtension, IExtensionIdentifier, IReportedExtension, IExtensionManagementService, ILocalExtension, IGalleryMetadata } from 'vs/platform/extensionManagement/common/extensionManagement';
|
import { IGalleryExtension, IExtensionIdentifier, IReportedExtension, IExtensionManagementService, ILocalExtension, IGalleryMetadata } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||||
import { IExtensionTipsService, ExtensionRecommendationReason, IExtensionRecommendation } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
import { IExtensionTipsService, ExtensionRecommendationReason, IExtensionRecommendation } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||||
import { ExtensionType, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionType, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||||
@@ -33,7 +30,7 @@ import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/co
|
|||||||
import { pathsToEditors } from 'vs/workbench/common/editor';
|
import { pathsToEditors } from 'vs/workbench/common/editor';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
import { ParsedArgs, IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||||
import { toStoreData, restoreRecentlyOpened } from 'vs/platform/history/common/historyStorage';
|
import { toStoreData, restoreRecentlyOpened } from 'vs/platform/history/common/historyStorage';
|
||||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||||
@@ -41,22 +38,6 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA
|
|||||||
import { IExperimentService, IExperiment, ExperimentActionType, ExperimentState } from 'vs/workbench/contrib/experiments/common/experimentService';
|
import { IExperimentService, IExperiment, ExperimentActionType, ExperimentState } from 'vs/workbench/contrib/experiments/common/experimentService';
|
||||||
import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc';
|
import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc';
|
||||||
|
|
||||||
//#region Download
|
|
||||||
|
|
||||||
export class SimpleDownloadService implements IDownloadService {
|
|
||||||
|
|
||||||
_serviceBrand: any;
|
|
||||||
|
|
||||||
download(uri: URI, to?: string, cancellationToken?: CancellationToken): Promise<string> {
|
|
||||||
// @ts-ignore
|
|
||||||
return Promise.resolve(undefined);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
registerSingleton(IDownloadService, SimpleDownloadService, true);
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region Extension Tips
|
//#region Extension Tips
|
||||||
|
|
||||||
export class SimpleExtensionTipsService implements IExtensionTipsService {
|
export class SimpleExtensionTipsService implements IExtensionTipsService {
|
||||||
@@ -583,7 +564,9 @@ registerSingleton(IWindowService, SimpleWindowService);
|
|||||||
export class SimpleExtensionHostDebugService extends ExtensionHostDebugChannelClient {
|
export class SimpleExtensionHostDebugService extends ExtensionHostDebugChannelClient {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@IRemoteAgentService remoteAgentService: IRemoteAgentService
|
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
|
||||||
|
//@IWindowService windowService: IWindowService,
|
||||||
|
@IEnvironmentService environmentService: IEnvironmentService
|
||||||
) {
|
) {
|
||||||
const connection = remoteAgentService.getConnection();
|
const connection = remoteAgentService.getConnection();
|
||||||
|
|
||||||
@@ -592,6 +575,19 @@ export class SimpleExtensionHostDebugService extends ExtensionHostDebugChannelCl
|
|||||||
}
|
}
|
||||||
|
|
||||||
super(connection.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName));
|
super(connection.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName));
|
||||||
|
|
||||||
|
this._register(this.onReload(event => {
|
||||||
|
if (environmentService.isExtensionDevelopment && environmentService.debugExtensionHost.debugId === event.sessionId) {
|
||||||
|
//windowService.reloadWindow();
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
this._register(this.onClose(event => {
|
||||||
|
if (environmentService.isExtensionDevelopment && environmentService.debugExtensionHost.debugId === event.sessionId) {
|
||||||
|
//this._windowService.closeWindow();
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
registerSingleton(IExtensionHostDebugService, SimpleExtensionHostDebugService);
|
registerSingleton(IExtensionHostDebugService, SimpleExtensionHostDebugService);
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ import { isMacintosh, isWindows, isLinux, isWeb } from 'vs/base/common/platform'
|
|||||||
'workbench.useExperimentalGridLayout': {
|
'workbench.useExperimentalGridLayout': {
|
||||||
'type': 'boolean',
|
'type': 'boolean',
|
||||||
'description': nls.localize('workbench.useExperimentalGridLayout', "Enables the grid layout for the workbench. This setting may enable additional layout options for workbench components."),
|
'description': nls.localize('workbench.useExperimentalGridLayout', "Enables the grid layout for the workbench. This setting may enable additional layout options for workbench components."),
|
||||||
'default': false,
|
'default': true,
|
||||||
'scope': ConfigurationScope.APPLICATION
|
'scope': ConfigurationScope.APPLICATION
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
|
|||||||
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
|
import { DefaultSettingsEditorContribution } from 'vs/workbench/contrib/preferences/browser/preferencesEditor';
|
||||||
|
|
||||||
const transientWordWrapState = 'transientWordWrapState';
|
const transientWordWrapState = 'transientWordWrapState';
|
||||||
const isWordWrapMinifiedKey = 'isWordWrapMinified';
|
const isWordWrapMinifiedKey = 'isWordWrapMinified';
|
||||||
@@ -131,6 +132,10 @@ class ToggleWordWrapAction extends EditorAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
|
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
|
||||||
|
if (editor.getContribution(DefaultSettingsEditorContribution.ID)) {
|
||||||
|
// in the settings editor...
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!editor.hasModel()) {
|
if (!editor.hasModel()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -201,6 +206,10 @@ class ToggleWordWrapController extends Disposable implements IEditorContribution
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const ensureWordWrapSettings = () => {
|
const ensureWordWrapSettings = () => {
|
||||||
|
if (this.editor.getContribution(DefaultSettingsEditorContribution.ID)) {
|
||||||
|
// in the settings editor...
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Ensure correct word wrap settings
|
// Ensure correct word wrap settings
|
||||||
const newModel = this.editor.getModel();
|
const newModel = this.editor.getModel();
|
||||||
if (!newModel) {
|
if (!newModel) {
|
||||||
@@ -267,7 +276,7 @@ function canToggleWordWrap(uri: URI): boolean {
|
|||||||
if (!uri) {
|
if (!uri) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (uri.scheme !== 'output' && uri.scheme !== 'vscode');
|
return (uri.scheme !== 'output');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -311,7 +311,6 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
|
|||||||
let currentComment = commentThread.comments![i];
|
let currentComment = commentThread.comments![i];
|
||||||
let oldCommentNode = this._commentElements.filter(commentNode => commentNode.comment.uniqueIdInThread === currentComment.uniqueIdInThread);
|
let oldCommentNode = this._commentElements.filter(commentNode => commentNode.comment.uniqueIdInThread === currentComment.uniqueIdInThread);
|
||||||
if (oldCommentNode.length) {
|
if (oldCommentNode.length) {
|
||||||
oldCommentNode[0].update(currentComment);
|
|
||||||
lastCommentElement = oldCommentNode[0].domNode;
|
lastCommentElement = oldCommentNode[0].domNode;
|
||||||
newCommentNodeList.unshift(oldCommentNode[0]);
|
newCommentNodeList.unshift(oldCommentNode[0]);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -399,7 +399,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.monaco-editor .review-widget .action-item {
|
.monaco-editor .review-widget .action-item {
|
||||||
min-width: 16px;
|
min-width: 18px;
|
||||||
|
min-height: 18px;
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, IExtension
|
|||||||
import { RatingsWidget, InstallCountWidget, RemoteBadgeWidget } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets';
|
import { RatingsWidget, InstallCountWidget, RemoteBadgeWidget } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets';
|
||||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||||
import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction, SetFileIconThemeAction, SetColorThemeAction, RemoteInstallAction, DisabledLabelAction, SystemDisabledWarningAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction, SetFileIconThemeAction, SetColorThemeAction, RemoteInstallAction, ExtensionToolTipAction, SystemDisabledWarningAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
||||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||||
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
@@ -391,7 +391,7 @@ export class ExtensionEditor extends BaseEditor {
|
|||||||
this.instantiationService.createInstance(LocalInstallAction),
|
this.instantiationService.createInstance(LocalInstallAction),
|
||||||
combinedInstallAction,
|
combinedInstallAction,
|
||||||
systemDisabledWarningAction,
|
systemDisabledWarningAction,
|
||||||
this.instantiationService.createInstance(DisabledLabelAction, systemDisabledWarningAction),
|
this.instantiationService.createInstance(ExtensionToolTipAction, systemDisabledWarningAction, reloadAction),
|
||||||
this.instantiationService.createInstance(MaliciousStatusLabelAction, true),
|
this.instantiationService.createInstance(MaliciousStatusLabelAction, true),
|
||||||
];
|
];
|
||||||
const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets]);
|
const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets]);
|
||||||
|
|||||||
@@ -64,14 +64,15 @@ Registry.as<IQuickOpenRegistry>(Extensions.Quickopen).registerQuickOpenHandler(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Editor
|
// Editor
|
||||||
const editorDescriptor = new EditorDescriptor(
|
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||||
|
new EditorDescriptor(
|
||||||
ExtensionEditor,
|
ExtensionEditor,
|
||||||
ExtensionEditor.ID,
|
ExtensionEditor.ID,
|
||||||
localize('extension', "Extension")
|
localize('extension', "Extension")
|
||||||
);
|
),
|
||||||
|
[
|
||||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors)
|
new SyncDescriptor(ExtensionsInput)
|
||||||
.registerEditor(editorDescriptor, [new SyncDescriptor(ExtensionsInput)]);
|
]);
|
||||||
|
|
||||||
// Viewlet
|
// Viewlet
|
||||||
const viewletDescriptor = new ViewletDescriptor(
|
const viewletDescriptor = new ViewletDescriptor(
|
||||||
|
|||||||
@@ -61,11 +61,11 @@ import { IPreferencesService } from 'vs/workbench/services/preferences/common/pr
|
|||||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { IProductService } from 'vs/platform/product/common/product';
|
import { IProductService } from 'vs/platform/product/common/product';
|
||||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||||
|
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||||
|
|
||||||
// {{SQL CARBON EDIT}}
|
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; // {{SQL CARBON EDIT}}
|
||||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
|
||||||
|
|
||||||
function toExtensionDescription(local: ILocalExtension): IExtensionDescription {
|
export function toExtensionDescription(local: ILocalExtension): IExtensionDescription {
|
||||||
return {
|
return {
|
||||||
identifier: new ExtensionIdentifier(local.identifier.id),
|
identifier: new ExtensionIdentifier(local.identifier.id),
|
||||||
isBuiltin: local.type === ExtensionType.System,
|
isBuiltin: local.type === ExtensionType.System,
|
||||||
@@ -76,7 +76,8 @@ function toExtensionDescription(local: ILocalExtension): IExtensionDescription {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const promptDownloadManually = (extension: IGalleryExtension | undefined, message: string, error: Error, instantiationService: IInstantiationService, notificationService: INotificationService, openerService: IOpenerService, productService: IProductService) => {
|
const promptDownloadManually = (extension: IGalleryExtension | undefined, message: string, error: Error,
|
||||||
|
instantiationService: IInstantiationService, notificationService: INotificationService, openerService: IOpenerService, productService: IProductService) => {
|
||||||
if (!extension || error.name === INSTALL_ERROR_INCOMPATIBLE || error.name === INSTALL_ERROR_MALICIOUS || !productService.extensionsGallery) {
|
if (!extension || error.name === INSTALL_ERROR_INCOMPATIBLE || error.name === INSTALL_ERROR_MALICIOUS || !productService.extensionsGallery) {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
} else {
|
} else {
|
||||||
@@ -1182,9 +1183,7 @@ export class ReloadAction extends ExtensionAction {
|
|||||||
@IWindowService private readonly windowService: IWindowService,
|
@IWindowService private readonly windowService: IWindowService,
|
||||||
@IExtensionService private readonly extensionService: IExtensionService,
|
@IExtensionService private readonly extensionService: IExtensionService,
|
||||||
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService,
|
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService,
|
||||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
|
||||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
|
||||||
@IProductService private readonly productService: IProductService,
|
|
||||||
) {
|
) {
|
||||||
super('extensions.reload', localize('reloadAction', "Reload"), ReloadAction.DisabledClass, false);
|
super('extensions.reload', localize('reloadAction', "Reload"), ReloadAction.DisabledClass, false);
|
||||||
this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this));
|
this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this));
|
||||||
@@ -1232,8 +1231,9 @@ export class ReloadAction extends ExtensionAction {
|
|||||||
}
|
}
|
||||||
if (this.extension.local) {
|
if (this.extension.local) {
|
||||||
const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local);
|
const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local);
|
||||||
|
|
||||||
|
// Extension is runningÎ
|
||||||
if (runningExtension) {
|
if (runningExtension) {
|
||||||
// Extension is running
|
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
if (!this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
|
if (!this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
|
||||||
if (isSameExtensionRunning) {
|
if (isSameExtensionRunning) {
|
||||||
@@ -1259,33 +1259,22 @@ export class ReloadAction extends ExtensionAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
// Extension is not running
|
// Extension is not running
|
||||||
|
else {
|
||||||
if (isEnabled && !this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
|
if (isEnabled && !this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
|
||||||
this.enabled = true;
|
this.enabled = true;
|
||||||
this.label = localize('reloadRequired', "Reload Required");
|
this.label = localize('reloadRequired', "Reload Required");
|
||||||
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension."); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension."); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) {
|
|
||||||
const uiExtension = isUIExtension(this.extension.local.manifest, this.productService, this.configurationService);
|
const otherServer = this.extension.server ? this.extension.server === this.extensionManagementServerService.localExtensionManagementServer ? this.extensionManagementServerService.remoteExtensionManagementServer : this.extensionManagementServerService.localExtensionManagementServer : null;
|
||||||
// Local Workspace Extension
|
if (otherServer && this.extension.enablementState === EnablementState.DisabledByExtensionKind) {
|
||||||
if (!uiExtension && this.extension.server === this.extensionManagementServerService.localExtensionManagementServer) {
|
const extensionInOtherServer = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === otherServer)[0];
|
||||||
const remoteExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)[0];
|
// Same extension in other server exists and
|
||||||
// Extension exist in remote and enabled
|
if (extensionInOtherServer && extensionInOtherServer.local && this.extensionEnablementService.isEnabled(extensionInOtherServer.local)) {
|
||||||
if (remoteExtension && remoteExtension.local && this.extensionEnablementService.isEnabled(remoteExtension.local)) {
|
|
||||||
this.enabled = true;
|
|
||||||
this.label = localize('reloadRequired', "Reload Required");
|
|
||||||
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension.");// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
|
||||||
alert(localize('installExtensionComplete', "Installing extension {0} is completed. Please reload Azure Data Studio to enable it.", this.extension.displayName)); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Remote UI Extension
|
|
||||||
if (uiExtension && this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
|
|
||||||
const localExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.localExtensionManagementServer)[0];
|
|
||||||
// Extension exist in local and enabled
|
|
||||||
if (localExtension && localExtension.local && this.extensionEnablementService.isEnabled(localExtension.local)) {
|
|
||||||
this.enabled = true;
|
this.enabled = true;
|
||||||
this.label = localize('reloadRequired', "Reload Required");
|
this.label = localize('reloadRequired', "Reload Required");
|
||||||
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension."); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension."); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||||
@@ -1296,7 +1285,6 @@ export class ReloadAction extends ExtensionAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
run(): Promise<any> {
|
run(): Promise<any> {
|
||||||
return Promise.resolve(this.windowService.reloadWindow());
|
return Promise.resolve(this.windowService.reloadWindow());
|
||||||
@@ -2548,7 +2536,7 @@ export class MaliciousStatusLabelAction extends ExtensionAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DisabledLabelAction extends ExtensionAction {
|
export class ExtensionToolTipAction extends ExtensionAction {
|
||||||
|
|
||||||
private static readonly Class = 'disable-status';
|
private static readonly Class = 'disable-status';
|
||||||
|
|
||||||
@@ -2557,10 +2545,12 @@ export class DisabledLabelAction extends ExtensionAction {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly warningAction: SystemDisabledWarningAction,
|
private readonly warningAction: SystemDisabledWarningAction,
|
||||||
|
private readonly reloadAction: ReloadAction,
|
||||||
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService,
|
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService,
|
||||||
@IExtensionService private readonly extensionService: IExtensionService,
|
@IExtensionService private readonly extensionService: IExtensionService,
|
||||||
|
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
|
||||||
) {
|
) {
|
||||||
super('extensions.disabledLabel', warningAction.tooltip, `${DisabledLabelAction.Class} hide`, false);
|
super('extensions.tooltip', warningAction.tooltip, `${ExtensionToolTipAction.Class} hide`, false);
|
||||||
this._register(warningAction.onDidChange(() => this.update(), this));
|
this._register(warningAction.onDidChange(() => this.update(), this));
|
||||||
this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this));
|
this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this));
|
||||||
this.updateRunningExtensions();
|
this.updateRunningExtensions();
|
||||||
@@ -2571,25 +2561,51 @@ export class DisabledLabelAction extends ExtensionAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update(): void {
|
update(): void {
|
||||||
this.class = `${DisabledLabelAction.Class} hide`;
|
this.label = this.getTooltip();
|
||||||
this.label = '';
|
this.class = ExtensionToolTipAction.Class;
|
||||||
|
if (!this.label) {
|
||||||
|
this.class = `${ExtensionToolTipAction.Class} hide`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getTooltip(): string {
|
||||||
|
if (!this.extension) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (this.reloadAction.enabled) {
|
||||||
|
return this.reloadAction.tooltip;
|
||||||
|
}
|
||||||
if (this.warningAction.tooltip) {
|
if (this.warningAction.tooltip) {
|
||||||
this.class = DisabledLabelAction.Class;
|
return this.warningAction.tooltip;
|
||||||
this.label = this.warningAction.tooltip;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (this.extension && this.extension.local && isLanguagePackExtension(this.extension.local.manifest)) {
|
if (this.extension && this.extension.local && this.extension.state === ExtensionState.Installed && this._runningExtensions) {
|
||||||
return;
|
const isRunning = this._runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier));
|
||||||
}
|
|
||||||
if (this.extension && this.extension.local && this._runningExtensions) {
|
|
||||||
const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local);
|
const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local);
|
||||||
const isExtensionRunning = this._runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier));
|
|
||||||
if (!isExtensionRunning && !isEnabled && this.extensionEnablementService.canChangeEnablement(this.extension.local)) {
|
if (isEnabled && isRunning) {
|
||||||
this.class = DisabledLabelAction.Class;
|
if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||||
this.label = localize('disabled by user', "This extension is disabled by the user.");
|
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||||
return;
|
return localize('extension enabled on remote', "Extension is enabled on '{0}'", this.extension.server.label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.extension.enablementState === EnablementState.EnabledGlobally) {
|
||||||
|
return localize('globally enabled', "This extension is enabled globally.");
|
||||||
|
}
|
||||||
|
if (this.extension.enablementState === EnablementState.EnabledWorkspace) {
|
||||||
|
return localize('workspace enabled', "This extension is enabled for this workspace by the user.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isEnabled && !isRunning) {
|
||||||
|
if (this.extension.enablementState === EnablementState.DisabledGlobally) {
|
||||||
|
return localize('globally disabled', "This extension is disabled globally by the user.");
|
||||||
|
}
|
||||||
|
if (this.extension.enablementState === EnablementState.DisabledWorkspace) {
|
||||||
|
return localize('workspace disabled', "This extension is disabled for this workspace by the user.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
run(): Promise<any> {
|
run(): Promise<any> {
|
||||||
@@ -2832,6 +2848,7 @@ export class InstallVSIXAction extends Action {
|
|||||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||||
@INotificationService private readonly notificationService: INotificationService,
|
@INotificationService private readonly notificationService: INotificationService,
|
||||||
@IWindowService private readonly windowService: IWindowService,
|
@IWindowService private readonly windowService: IWindowService,
|
||||||
|
@IFileDialogService private readonly fileDialogService: IFileDialogService,
|
||||||
@IExtensionService private readonly extensionService: IExtensionService,
|
@IExtensionService private readonly extensionService: IExtensionService,
|
||||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||||
// {{SQL CARBON EDIT}}
|
// {{SQL CARBON EDIT}}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging';
|
|||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { domEvent } from 'vs/base/browser/event';
|
import { domEvent } from 'vs/base/browser/event';
|
||||||
import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
|
import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||||
import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionViewItem, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction, DisabledLabelAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionViewItem, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction, ExtensionToolTipAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
||||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||||
import { Label, RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, TooltipWidget } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets';
|
import { Label, RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, TooltipWidget } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets';
|
||||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
@@ -103,8 +103,8 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
|||||||
systemDisabledWarningAction,
|
systemDisabledWarningAction,
|
||||||
this.instantiationService.createInstance(ManageExtensionAction)
|
this.instantiationService.createInstance(ManageExtensionAction)
|
||||||
];
|
];
|
||||||
const disabledLabelAction = this.instantiationService.createInstance(DisabledLabelAction, systemDisabledWarningAction);
|
const extensionTooltipAction = this.instantiationService.createInstance(ExtensionToolTipAction, systemDisabledWarningAction, reloadAction);
|
||||||
const tooltipWidget = this.instantiationService.createInstance(TooltipWidget, root, disabledLabelAction, recommendationWidget, reloadAction);
|
const tooltipWidget = this.instantiationService.createInstance(TooltipWidget, root, extensionTooltipAction, recommendationWidget);
|
||||||
const widgets = [
|
const widgets = [
|
||||||
recommendationWidget,
|
recommendationWidget,
|
||||||
iconRemoteBadgeWidget,
|
iconRemoteBadgeWidget,
|
||||||
@@ -115,10 +115,10 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
|||||||
// this.instantiationService.createInstance(InstallCountWidget, installCount, true),
|
// this.instantiationService.createInstance(InstallCountWidget, installCount, true),
|
||||||
this.instantiationService.createInstance(RatingsWidget, ratings, true)
|
this.instantiationService.createInstance(RatingsWidget, ratings, true)
|
||||||
];
|
];
|
||||||
const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets, disabledLabelAction]);
|
const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets, extensionTooltipAction]);
|
||||||
|
|
||||||
actionbar.push(actions, actionOptions);
|
actionbar.push(actions, actionOptions);
|
||||||
const disposables = combinedDisposable(...actions, ...widgets, actionbar, extensionContainers, disabledLabelAction);
|
const disposables = combinedDisposable(...actions, ...widgets, actionbar, extensionContainers, extensionTooltipAction);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// {{SQL CARBON EDIT}}
|
// {{SQL CARBON EDIT}}
|
||||||
|
|||||||
@@ -5,13 +5,13 @@
|
|||||||
|
|
||||||
import 'vs/css!./media/extensionsWidgets';
|
import 'vs/css!./media/extensionsWidgets';
|
||||||
import { Disposable, toDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, toDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { IExtension, IExtensionsWorkbenchService, IExtensionContainer, ExtensionState } from '../common/extensions';
|
import { IExtension, IExtensionsWorkbenchService, IExtensionContainer } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||||
import { append, $, addClass } from 'vs/base/browser/dom';
|
import { append, $, addClass } from 'vs/base/browser/dom';
|
||||||
import * as platform from 'vs/base/common/platform';
|
import * as platform from 'vs/base/common/platform';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { IExtensionTipsService, IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
import { IExtensionTipsService, IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||||
import { ILabelService } from 'vs/platform/label/common/label';
|
import { ILabelService } from 'vs/platform/label/common/label';
|
||||||
import { extensionButtonProminentBackground, extensionButtonProminentForeground, DisabledLabelAction, ReloadAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
import { extensionButtonProminentBackground, extensionButtonProminentForeground, ExtensionToolTipAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
||||||
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
|
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
|
||||||
import { EXTENSION_BADGE_REMOTE_BACKGROUND, EXTENSION_BADGE_REMOTE_FOREGROUND } from 'vs/workbench/common/theme';
|
import { EXTENSION_BADGE_REMOTE_BACKGROUND, EXTENSION_BADGE_REMOTE_FOREGROUND } from 'vs/workbench/common/theme';
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
@@ -145,16 +145,13 @@ export class TooltipWidget extends ExtensionWidget {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly parent: HTMLElement,
|
private readonly parent: HTMLElement,
|
||||||
private readonly disabledLabelAction: DisabledLabelAction,
|
private readonly tooltipAction: ExtensionToolTipAction,
|
||||||
private readonly recommendationWidget: RecommendationWidget,
|
private readonly recommendationWidget: RecommendationWidget,
|
||||||
private readonly reloadAction: ReloadAction,
|
|
||||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
|
||||||
@ILabelService private readonly labelService: ILabelService
|
@ILabelService private readonly labelService: ILabelService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this._register(Event.any<any>(
|
this._register(Event.any<any>(
|
||||||
this.disabledLabelAction.onDidChange,
|
this.tooltipAction.onDidChange,
|
||||||
this.reloadAction.onDidChange,
|
|
||||||
this.recommendationWidget.onDidChangeTooltip,
|
this.recommendationWidget.onDidChangeTooltip,
|
||||||
this.labelService.onDidChangeFormatters
|
this.labelService.onDidChangeFormatters
|
||||||
)(() => this.render()));
|
)(() => this.render()));
|
||||||
@@ -173,17 +170,8 @@ export class TooltipWidget extends ExtensionWidget {
|
|||||||
if (!this.extension) {
|
if (!this.extension) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
if (this.reloadAction.enabled) {
|
if (this.tooltipAction.tooltip) {
|
||||||
return this.reloadAction.tooltip;
|
return this.tooltipAction.tooltip;
|
||||||
}
|
|
||||||
if (this.disabledLabelAction.label) {
|
|
||||||
return this.disabledLabelAction.label;
|
|
||||||
}
|
|
||||||
if (this.extension.local && this.extension.state === ExtensionState.Installed) {
|
|
||||||
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
|
|
||||||
return localize('extension enabled on remote', "Extension is enabled on '{0}'", this.extension.server.label);
|
|
||||||
}
|
|
||||||
return localize('extension enabled locally', "Extension is enabled locally.");
|
|
||||||
}
|
}
|
||||||
return this.recommendationWidget.tooltip;
|
return this.recommendationWidget.tooltip;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -424,7 +424,9 @@ class Extensions extends Disposable {
|
|||||||
const installingExtension = gallery ? this.installing.filter(e => areSameExtensions(e.identifier, gallery.identifier))[0] : null;
|
const installingExtension = gallery ? this.installing.filter(e => areSameExtensions(e.identifier, gallery.identifier))[0] : null;
|
||||||
this.installing = installingExtension ? this.installing.filter(e => e !== installingExtension) : this.installing;
|
this.installing = installingExtension ? this.installing.filter(e => e !== installingExtension) : this.installing;
|
||||||
|
|
||||||
let extension: Extension | undefined = installingExtension ? installingExtension : zipPath ? this.instantiationService.createInstance(Extension, this.stateProvider, this.server, local, undefined) : undefined;
|
let extension: Extension | undefined = installingExtension ? installingExtension
|
||||||
|
: (zipPath || local) ? this.instantiationService.createInstance(Extension, this.stateProvider, this.server, local, undefined)
|
||||||
|
: undefined;
|
||||||
if (extension) {
|
if (extension) {
|
||||||
if (local) {
|
if (local) {
|
||||||
const installed = this.installed.filter(e => areSameExtensions(e.identifier, extension!.identifier))[0];
|
const installed = this.installed.filter(e => areSameExtensions(e.identifier, extension!.identifier))[0];
|
||||||
|
|||||||
+215
-89
@@ -1063,37 +1063,39 @@ suite('ExtensionsActions Test', () => {
|
|||||||
assert.ok(!testObject.enabled);
|
assert.ok(!testObject.enabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test ReloadAction when extension state is installing', () => {
|
test('Test ReloadAction when extension state is installing', async () => {
|
||||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||||
const gallery = aGalleryExtension('a');
|
const gallery = aGalleryExtension('a');
|
||||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||||
return workbenchService.queryGallery(CancellationToken.None)
|
const paged = await workbenchService.queryGallery(CancellationToken.None);
|
||||||
.then((paged) => {
|
|
||||||
testObject.extension = paged.firstPage[0];
|
testObject.extension = paged.firstPage[0];
|
||||||
installEvent.fire({ identifier: gallery.identifier, gallery });
|
installEvent.fire({ identifier: gallery.identifier, gallery });
|
||||||
|
|
||||||
assert.ok(!testObject.enabled);
|
assert.ok(!testObject.enabled);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
test('Test ReloadAction when extension state is uninstalling', () => {
|
test('Test ReloadAction when extension state is uninstalling', async () => {
|
||||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||||
const local = aLocalExtension('a');
|
const local = aLocalExtension('a');
|
||||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||||
|
|
||||||
return instantiationService.get(IExtensionsWorkbenchService).queryLocal()
|
const extensions = await instantiationService.get(IExtensionsWorkbenchService).queryLocal();
|
||||||
.then(extensions => {
|
|
||||||
testObject.extension = extensions[0];
|
testObject.extension = extensions[0];
|
||||||
uninstallEvent.fire(local.identifier);
|
uninstallEvent.fire(local.identifier);
|
||||||
assert.ok(!testObject.enabled);
|
assert.ok(!testObject.enabled);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
test('Test ReloadAction when extension is newly installed', async () => {
|
test('Test ReloadAction when extension is newly installed', async () => {
|
||||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]);
|
const onDidChangeExtensionsEmitter: Emitter<void> = new Emitter<void>();
|
||||||
|
const runningExtensions = [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }];
|
||||||
|
instantiationService.stub(IExtensionService, <Partial<IExtensionService>>{
|
||||||
|
getExtensions: () => Promise.resolve(runningExtensions),
|
||||||
|
onDidChangeExtensions: onDidChangeExtensionsEmitter.event,
|
||||||
|
canAddExtension: (extension) => false
|
||||||
|
});
|
||||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||||
const gallery = aGalleryExtension('a');
|
const gallery = aGalleryExtension('a');
|
||||||
@@ -1103,26 +1105,42 @@ suite('ExtensionsActions Test', () => {
|
|||||||
testObject.extension = paged.firstPage[0];
|
testObject.extension = paged.firstPage[0];
|
||||||
assert.ok(!testObject.enabled);
|
assert.ok(!testObject.enabled);
|
||||||
|
|
||||||
return new Promise(c => {
|
|
||||||
testObject.onDidChange(() => {
|
|
||||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
|
||||||
if (testObject.enabled && testObject.tooltip === 'Please reload Azure Data Studio to enable this extension.') {
|
|
||||||
c();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
installEvent.fire({ identifier: gallery.identifier, gallery });
|
installEvent.fire({ identifier: gallery.identifier, gallery });
|
||||||
didInstallEvent.fire({ identifier: gallery.identifier, gallery, operation: InstallOperation.Install, local: aLocalExtension('a', gallery, gallery) });
|
didInstallEvent.fire({ identifier: gallery.identifier, gallery, operation: InstallOperation.Install, local: aLocalExtension('a', gallery, gallery) });
|
||||||
});
|
assert.ok(testObject.enabled);
|
||||||
|
assert.equal(testObject.tooltip, 'Please reload Azure Data Studio to enable this extension.'); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test ReloadAction when extension is installed and uninstalled', () => {
|
test('Test ReloadAction when extension is newly installed and reload is not required', async () => {
|
||||||
|
const onDidChangeExtensionsEmitter: Emitter<void> = new Emitter<void>();
|
||||||
|
const runningExtensions = [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }];
|
||||||
|
instantiationService.stub(IExtensionService, <Partial<IExtensionService>>{
|
||||||
|
getExtensions: () => Promise.resolve(runningExtensions),
|
||||||
|
onDidChangeExtensions: onDidChangeExtensionsEmitter.event,
|
||||||
|
canAddExtension: (extension) => true
|
||||||
|
});
|
||||||
|
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||||
|
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||||
|
const gallery = aGalleryExtension('a');
|
||||||
|
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||||
|
|
||||||
|
const paged = await instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None);
|
||||||
|
testObject.extension = paged.firstPage[0];
|
||||||
|
assert.ok(!testObject.enabled);
|
||||||
|
|
||||||
|
installEvent.fire({ identifier: gallery.identifier, gallery });
|
||||||
|
didInstallEvent.fire({ identifier: gallery.identifier, gallery, operation: InstallOperation.Install, local: aLocalExtension('a', gallery, gallery) });
|
||||||
|
assert.ok(!testObject.enabled);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Test ReloadAction when extension is installed and uninstalled', async () => {
|
||||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]);
|
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]);
|
||||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||||
const gallery = aGalleryExtension('a');
|
const gallery = aGalleryExtension('a');
|
||||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None)
|
const paged = await instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None);
|
||||||
.then((paged) => {
|
|
||||||
testObject.extension = paged.firstPage[0];
|
testObject.extension = paged.firstPage[0];
|
||||||
const identifier = gallery.identifier;
|
const identifier = gallery.identifier;
|
||||||
installEvent.fire({ identifier, gallery });
|
installEvent.fire({ identifier, gallery });
|
||||||
@@ -1132,7 +1150,6 @@ suite('ExtensionsActions Test', () => {
|
|||||||
|
|
||||||
assert.ok(!testObject.enabled);
|
assert.ok(!testObject.enabled);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
test('Test ReloadAction when extension is uninstalled', async () => {
|
test('Test ReloadAction when extension is uninstalled', async () => {
|
||||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), extensionLocation: URI.file('pub.a'), version: '1.0.0' }]);
|
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), extensionLocation: URI.file('pub.a'), version: '1.0.0' }]);
|
||||||
@@ -1145,8 +1162,7 @@ suite('ExtensionsActions Test', () => {
|
|||||||
|
|
||||||
return new Promise(c => {
|
return new Promise(c => {
|
||||||
testObject.onDidChange(() => {
|
testObject.onDidChange(() => {
|
||||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
if (testObject.enabled && testObject.tooltip === 'Please reload Azure Data Studio to complete the uninstallation of this extension.') { // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||||
if (testObject.enabled && testObject.tooltip === 'Please reload Azure Data Studio to complete the uninstallation of this extension.') {
|
|
||||||
c();
|
c();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1155,14 +1171,14 @@ suite('ExtensionsActions Test', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test ReloadAction when extension is uninstalled and installed', () => {
|
test('Test ReloadAction when extension is uninstalled and installed', async () => {
|
||||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), version: '1.0.0', extensionLocation: URI.file('pub.a') }]);
|
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), version: '1.0.0', extensionLocation: URI.file('pub.a') }]);
|
||||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||||
const local = aLocalExtension('a');
|
const local = aLocalExtension('a');
|
||||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||||
return instantiationService.get(IExtensionsWorkbenchService).queryLocal()
|
const extensions = await instantiationService.get(IExtensionsWorkbenchService).queryLocal();
|
||||||
.then(extensions => {
|
|
||||||
testObject.extension = extensions[0];
|
testObject.extension = extensions[0];
|
||||||
uninstallEvent.fire(local.identifier);
|
uninstallEvent.fire(local.identifier);
|
||||||
didUninstallEvent.fire({ identifier: local.identifier });
|
didUninstallEvent.fire({ identifier: local.identifier });
|
||||||
@@ -1174,7 +1190,6 @@ suite('ExtensionsActions Test', () => {
|
|||||||
|
|
||||||
assert.ok(!testObject.enabled);
|
assert.ok(!testObject.enabled);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
test('Test ReloadAction when extension is updated while running', async () => {
|
test('Test ReloadAction when extension is updated while running', async () => {
|
||||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), version: '1.0.1', extensionLocation: URI.file('pub.a') }]);
|
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), version: '1.0.1', extensionLocation: URI.file('pub.a') }]);
|
||||||
@@ -1188,8 +1203,7 @@ suite('ExtensionsActions Test', () => {
|
|||||||
|
|
||||||
return new Promise(c => {
|
return new Promise(c => {
|
||||||
testObject.onDidChange(() => {
|
testObject.onDidChange(() => {
|
||||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
if (testObject.enabled && testObject.tooltip === 'Please reload Azure Data Studio to enable the updated extension.') { // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||||
if (testObject.enabled && testObject.tooltip === 'Please reload Azure Data Studio to enable the updated extension.') {
|
|
||||||
c();
|
c();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1199,17 +1213,15 @@ suite('ExtensionsActions Test', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test ReloadAction when extension is updated when not running', () => {
|
test('Test ReloadAction when extension is updated when not running', async () => {
|
||||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]);
|
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]);
|
||||||
const local = aLocalExtension('a', { version: '1.0.1' });
|
const local = aLocalExtension('a', { version: '1.0.1' });
|
||||||
return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally)
|
await instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally);
|
||||||
.then(() => {
|
|
||||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||||
return workbenchService.queryLocal()
|
const extensions = await workbenchService.queryLocal();
|
||||||
.then(extensions => {
|
|
||||||
testObject.extension = extensions[0];
|
testObject.extension = extensions[0];
|
||||||
|
|
||||||
const gallery = aGalleryExtension('a', { identifier: local.identifier, version: '1.0.2' });
|
const gallery = aGalleryExtension('a', { identifier: local.identifier, version: '1.0.2' });
|
||||||
@@ -1218,112 +1230,86 @@ suite('ExtensionsActions Test', () => {
|
|||||||
|
|
||||||
assert.ok(!testObject.enabled);
|
assert.ok(!testObject.enabled);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Test ReloadAction when extension is disabled when running', () => {
|
test('Test ReloadAction when extension is disabled when running', async () => {
|
||||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), extensionLocation: URI.file('pub.a') }]);
|
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), extensionLocation: URI.file('pub.a') }]);
|
||||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||||
const local = aLocalExtension('a');
|
const local = aLocalExtension('a');
|
||||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||||
return workbenchService.queryLocal().then(extensions => {
|
const extensions = await workbenchService.queryLocal();
|
||||||
testObject.extension = extensions[0];
|
testObject.extension = extensions[0];
|
||||||
return workbenchService.setEnablement(extensions[0], EnablementState.DisabledGlobally)
|
await workbenchService.setEnablement(extensions[0], EnablementState.DisabledGlobally);
|
||||||
.then(() => testObject.update())
|
await testObject.update();
|
||||||
.then(() => {
|
|
||||||
assert.ok(testObject.enabled);
|
assert.ok(testObject.enabled);
|
||||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
assert.equal('Please reload Azure Data Studio to disable this extension.', testObject.tooltip); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||||
assert.equal('Please reload Azure Data Studio to disable this extension.', testObject.tooltip);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test ReloadAction when extension enablement is toggled when running', () => {
|
test('Test ReloadAction when extension enablement is toggled when running', async () => {
|
||||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), version: '1.0.0', extensionLocation: URI.file('pub.a') }]);
|
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), version: '1.0.0', extensionLocation: URI.file('pub.a') }]);
|
||||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||||
const local = aLocalExtension('a');
|
const local = aLocalExtension('a');
|
||||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||||
return workbenchService.queryLocal().
|
const extensions = await workbenchService.queryLocal();
|
||||||
then(extensions => {
|
|
||||||
testObject.extension = extensions[0];
|
testObject.extension = extensions[0];
|
||||||
return workbenchService.setEnablement(extensions[0], EnablementState.DisabledGlobally)
|
await workbenchService.setEnablement(extensions[0], EnablementState.DisabledGlobally);
|
||||||
.then(() => workbenchService.setEnablement(extensions[0], EnablementState.EnabledGlobally))
|
await workbenchService.setEnablement(extensions[0], EnablementState.EnabledGlobally);
|
||||||
.then(() => assert.ok(!testObject.enabled));
|
assert.ok(!testObject.enabled);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test ReloadAction when extension is enabled when not running', () => {
|
test('Test ReloadAction when extension is enabled when not running', async () => {
|
||||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]);
|
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]);
|
||||||
const local = aLocalExtension('a');
|
const local = aLocalExtension('a');
|
||||||
return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally)
|
await instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally);
|
||||||
.then(() => {
|
|
||||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||||
return workbenchService.queryLocal()
|
const extensions = await workbenchService.queryLocal();
|
||||||
.then(extensions => {
|
|
||||||
testObject.extension = extensions[0];
|
testObject.extension = extensions[0];
|
||||||
return workbenchService.setEnablement(extensions[0], EnablementState.EnabledGlobally)
|
await workbenchService.setEnablement(extensions[0], EnablementState.EnabledGlobally);
|
||||||
.then(() => testObject.update())
|
await testObject.update();
|
||||||
.then(() => {
|
|
||||||
assert.ok(testObject.enabled);
|
assert.ok(testObject.enabled);
|
||||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
assert.equal('Please reload Azure Data Studio to enable this extension.', testObject.tooltip); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||||
assert.equal('Please reload Azure Data Studio to enable this extension.', testObject.tooltip);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test ReloadAction when extension enablement is toggled when not running', () => {
|
test('Test ReloadAction when extension enablement is toggled when not running', async () => {
|
||||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]);
|
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]);
|
||||||
const local = aLocalExtension('a');
|
const local = aLocalExtension('a');
|
||||||
return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally)
|
await instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally);
|
||||||
.then(() => {
|
|
||||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||||
return workbenchService.queryLocal()
|
const extensions = await workbenchService.queryLocal();
|
||||||
.then(extensions => {
|
|
||||||
testObject.extension = extensions[0];
|
testObject.extension = extensions[0];
|
||||||
return workbenchService.setEnablement(extensions[0], EnablementState.EnabledGlobally)
|
await workbenchService.setEnablement(extensions[0], EnablementState.EnabledGlobally);
|
||||||
.then(() => workbenchService.setEnablement(extensions[0], EnablementState.DisabledGlobally))
|
await workbenchService.setEnablement(extensions[0], EnablementState.DisabledGlobally);
|
||||||
.then(() => assert.ok(!testObject.enabled));
|
assert.ok(!testObject.enabled);
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test ReloadAction when extension is updated when not running and enabled', () => {
|
test('Test ReloadAction when extension is updated when not running and enabled', async () => {
|
||||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]);
|
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]);
|
||||||
const local = aLocalExtension('a', { version: '1.0.1' });
|
const local = aLocalExtension('a', { version: '1.0.1' });
|
||||||
return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally)
|
await instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.DisabledGlobally);
|
||||||
.then(() => {
|
|
||||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||||
return workbenchService.queryLocal()
|
const extensions = await workbenchService.queryLocal();
|
||||||
.then(extensions => {
|
|
||||||
testObject.extension = extensions[0];
|
testObject.extension = extensions[0];
|
||||||
|
|
||||||
const gallery = aGalleryExtension('a', { identifier: local.identifier, version: '1.0.2' });
|
const gallery = aGalleryExtension('a', { identifier: local.identifier, version: '1.0.2' });
|
||||||
installEvent.fire({ identifier: gallery.identifier, gallery });
|
installEvent.fire({ identifier: gallery.identifier, gallery });
|
||||||
didInstallEvent.fire({ identifier: gallery.identifier, gallery, operation: InstallOperation.Install, local: aLocalExtension('a', gallery, gallery) });
|
didInstallEvent.fire({ identifier: gallery.identifier, gallery, operation: InstallOperation.Install, local: aLocalExtension('a', gallery, gallery) });
|
||||||
return workbenchService.setEnablement(extensions[0], EnablementState.EnabledGlobally)
|
await workbenchService.setEnablement(extensions[0], EnablementState.EnabledGlobally);
|
||||||
.then(() => testObject.update())
|
await testObject.update();
|
||||||
.then(() => {
|
|
||||||
assert.ok(testObject.enabled);
|
assert.ok(testObject.enabled);
|
||||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
assert.equal('Please reload Azure Data Studio to enable this extension.', testObject.tooltip); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||||
assert.equal('Please reload Azure Data Studio to enable this extension.', testObject.tooltip);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test ReloadAction when a localization extension is newly installed', async () => {
|
test('Test ReloadAction when a localization extension is newly installed', async () => {
|
||||||
@@ -1358,6 +1344,146 @@ suite('ExtensionsActions Test', () => {
|
|||||||
assert.ok(!testObject.enabled);
|
assert.ok(!testObject.enabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Test ReloadAction when extension is not installed but extension from different server is installed and running', async () => {
|
||||||
|
// multi server setup
|
||||||
|
const gallery = aGalleryExtension('a');
|
||||||
|
const localExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file('pub.a') });
|
||||||
|
const remoteExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file('pub.a').with({ scheme: Schemas.vscodeRemote }) });
|
||||||
|
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), createExtensionManagementService([remoteExtension]));
|
||||||
|
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
|
||||||
|
instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
|
||||||
|
const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
|
||||||
|
instantiationService.set(IExtensionsWorkbenchService, workbenchService);
|
||||||
|
|
||||||
|
const onDidChangeExtensionsEmitter: Emitter<void> = new Emitter<void>();
|
||||||
|
const runningExtensions = [ExtensionsActions.toExtensionDescription(remoteExtension)];
|
||||||
|
instantiationService.stub(IExtensionService, <Partial<IExtensionService>>{
|
||||||
|
getExtensions: () => Promise.resolve(runningExtensions),
|
||||||
|
onDidChangeExtensions: onDidChangeExtensionsEmitter.event,
|
||||||
|
canAddExtension: (extension) => false
|
||||||
|
});
|
||||||
|
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||||
|
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||||
|
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||||
|
|
||||||
|
await workbenchService.queryGallery(CancellationToken.None);
|
||||||
|
const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!);
|
||||||
|
testObject.extension = extensions[0];
|
||||||
|
assert.ok(testObject.extension);
|
||||||
|
assert.ok(!testObject.enabled);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Test ReloadAction when extension is uninstalled but extension from different server is installed and running', async () => {
|
||||||
|
// multi server setup
|
||||||
|
const gallery = aGalleryExtension('a');
|
||||||
|
const localExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file('pub.a') });
|
||||||
|
const remoteExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file('pub.a').with({ scheme: Schemas.vscodeRemote }) });
|
||||||
|
const localExtensionManagementService = createExtensionManagementService([localExtension]);
|
||||||
|
const uninstallEvent = new Emitter<IExtensionIdentifier>();
|
||||||
|
const onDidUninstallEvent = new Emitter<{ identifier: IExtensionIdentifier }>();
|
||||||
|
localExtensionManagementService.onUninstallExtension = uninstallEvent.event;
|
||||||
|
localExtensionManagementService.onDidUninstallExtension = onDidUninstallEvent.event;
|
||||||
|
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, localExtensionManagementService, createExtensionManagementService([remoteExtension]));
|
||||||
|
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
|
||||||
|
instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
|
||||||
|
const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
|
||||||
|
instantiationService.set(IExtensionsWorkbenchService, workbenchService);
|
||||||
|
|
||||||
|
const onDidChangeExtensionsEmitter: Emitter<void> = new Emitter<void>();
|
||||||
|
const runningExtensions = [ExtensionsActions.toExtensionDescription(remoteExtension)];
|
||||||
|
instantiationService.stub(IExtensionService, <Partial<IExtensionService>>{
|
||||||
|
getExtensions: () => Promise.resolve(runningExtensions),
|
||||||
|
onDidChangeExtensions: onDidChangeExtensionsEmitter.event,
|
||||||
|
canAddExtension: (extension) => false
|
||||||
|
});
|
||||||
|
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||||
|
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||||
|
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||||
|
|
||||||
|
await workbenchService.queryGallery(CancellationToken.None);
|
||||||
|
const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!);
|
||||||
|
testObject.extension = extensions[0];
|
||||||
|
assert.ok(testObject.extension);
|
||||||
|
assert.ok(!testObject.enabled);
|
||||||
|
|
||||||
|
uninstallEvent.fire(localExtension.identifier);
|
||||||
|
didUninstallEvent.fire({ identifier: localExtension.identifier });
|
||||||
|
|
||||||
|
assert.ok(!testObject.enabled);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Test ReloadAction when workspace extension is disabled on local server and installed in remote server', async () => {
|
||||||
|
// multi server setup
|
||||||
|
const gallery = aGalleryExtension('a');
|
||||||
|
const remoteExtensionManagementService = createExtensionManagementService([]);
|
||||||
|
const onDidInstallEvent = new Emitter<DidInstallExtensionEvent>();
|
||||||
|
remoteExtensionManagementService.onDidInstallExtension = onDidInstallEvent.event;
|
||||||
|
const localExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file('pub.a') });
|
||||||
|
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), remoteExtensionManagementService);
|
||||||
|
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
|
||||||
|
instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
|
||||||
|
const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
|
||||||
|
instantiationService.set(IExtensionsWorkbenchService, workbenchService);
|
||||||
|
|
||||||
|
const onDidChangeExtensionsEmitter: Emitter<void> = new Emitter<void>();
|
||||||
|
instantiationService.stub(IExtensionService, <Partial<IExtensionService>>{
|
||||||
|
getExtensions: () => Promise.resolve([]),
|
||||||
|
onDidChangeExtensions: onDidChangeExtensionsEmitter.event,
|
||||||
|
canAddExtension: (extension) => false
|
||||||
|
});
|
||||||
|
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||||
|
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||||
|
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||||
|
|
||||||
|
await workbenchService.queryGallery(CancellationToken.None);
|
||||||
|
const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!);
|
||||||
|
testObject.extension = extensions[0];
|
||||||
|
assert.ok(testObject.extension);
|
||||||
|
assert.ok(!testObject.enabled);
|
||||||
|
|
||||||
|
const remoteExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file('pub.a').with({ scheme: Schemas.vscodeRemote }) });
|
||||||
|
onDidInstallEvent.fire({ identifier: remoteExtension.identifier, local: remoteExtension, operation: InstallOperation.Install });
|
||||||
|
|
||||||
|
assert.ok(testObject.enabled);
|
||||||
|
assert.equal(testObject.tooltip, 'Please reload Azure Data Studio to enable this extension.'); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Test ReloadAction when ui extension is disabled on remote server and installed in local server', async () => {
|
||||||
|
// multi server setup
|
||||||
|
const gallery = aGalleryExtension('a');
|
||||||
|
const localExtensionManagementService = createExtensionManagementService([]);
|
||||||
|
const onDidInstallEvent = new Emitter<DidInstallExtensionEvent>();
|
||||||
|
localExtensionManagementService.onDidInstallExtension = onDidInstallEvent.event;
|
||||||
|
const remoteExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file('pub.a').with({ scheme: Schemas.vscodeRemote }) });
|
||||||
|
const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, localExtensionManagementService, createExtensionManagementService([remoteExtension]));
|
||||||
|
instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
|
||||||
|
instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
|
||||||
|
const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
|
||||||
|
instantiationService.set(IExtensionsWorkbenchService, workbenchService);
|
||||||
|
|
||||||
|
const onDidChangeExtensionsEmitter: Emitter<void> = new Emitter<void>();
|
||||||
|
instantiationService.stub(IExtensionService, <Partial<IExtensionService>>{
|
||||||
|
getExtensions: () => Promise.resolve([]),
|
||||||
|
onDidChangeExtensions: onDidChangeExtensionsEmitter.event,
|
||||||
|
canAddExtension: (extension) => false
|
||||||
|
});
|
||||||
|
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||||
|
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||||
|
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||||
|
|
||||||
|
await workbenchService.queryGallery(CancellationToken.None);
|
||||||
|
const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!);
|
||||||
|
testObject.extension = extensions[0];
|
||||||
|
assert.ok(testObject.extension);
|
||||||
|
assert.ok(!testObject.enabled);
|
||||||
|
|
||||||
|
const localExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file('pub.a') });
|
||||||
|
onDidInstallEvent.fire({ identifier: localExtension.identifier, local: localExtension, operation: InstallOperation.Install });
|
||||||
|
|
||||||
|
assert.ok(testObject.enabled);
|
||||||
|
assert.equal(testObject.tooltip, 'Please reload Azure Data Studio to enable this extension.'); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||||
|
});
|
||||||
|
|
||||||
test('Test remote install action is enabled for local workspace extension', async () => {
|
test('Test remote install action is enabled for local workspace extension', async () => {
|
||||||
// multi server setup
|
// multi server setup
|
||||||
const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) });
|
const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) });
|
||||||
|
|||||||
@@ -533,8 +533,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
|
|||||||
id: OpenGlobalKeybindingsFileAction.ID,
|
id: OpenGlobalKeybindingsFileAction.ID,
|
||||||
title: OpenGlobalKeybindingsFileAction.LABEL,
|
title: OpenGlobalKeybindingsFileAction.LABEL,
|
||||||
iconLocation: {
|
iconLocation: {
|
||||||
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/edit-json-light.svg`)),
|
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-light.svg`)),
|
||||||
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/edit-json-dark.svg`))
|
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-dark.svg`))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR),
|
when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR),
|
||||||
@@ -817,8 +817,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
|
|||||||
id: SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON,
|
id: SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON,
|
||||||
title: nls.localize('openSettingsJson', "Open Settings (JSON)"),
|
title: nls.localize('openSettingsJson', "Open Settings (JSON)"),
|
||||||
iconLocation: {
|
iconLocation: {
|
||||||
dark: URI.parse(require.toUrl('vs/workbench/contrib/preferences/browser/media/edit-json-dark.svg')),
|
dark: URI.parse(require.toUrl('vs/workbench/contrib/preferences/browser/media/preferences-editor-dark.svg')),
|
||||||
light: URI.parse(require.toUrl('vs/workbench/contrib/preferences/browser/media/edit-json-light.svg'))
|
light: URI.parse(require.toUrl('vs/workbench/contrib/preferences/browser/media/preferences-editor-light.svg'))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
group: 'navigation',
|
group: 'navigation',
|
||||||
|
|||||||
@@ -1154,7 +1154,7 @@ abstract class AbstractSettingsEditorContribution extends Disposable implements
|
|||||||
abstract getId(): string;
|
abstract getId(): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
class DefaultSettingsEditorContribution extends AbstractSettingsEditorContribution implements ISettingsEditorContribution {
|
export class DefaultSettingsEditorContribution extends AbstractSettingsEditorContribution implements ISettingsEditorContribution {
|
||||||
|
|
||||||
static readonly ID: string = 'editor.contrib.defaultsettings';
|
static readonly ID: string = 'editor.contrib.defaultsettings';
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { IModelDeltaDecoration, TrackedRangeStickiness } from 'vs/editor/common/
|
|||||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
import { ConfigurationTarget, IConfigurationService, overrideIdentifierFromKey } from 'vs/platform/configuration/common/configuration';
|
import { ConfigurationTarget, IConfigurationService, overrideIdentifierFromKey } from 'vs/platform/configuration/common/configuration';
|
||||||
import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationPropertySchema, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationPropertySchema, IConfigurationRegistry, IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry';
|
||||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
@@ -29,6 +29,8 @@ import { RangeHighlightDecorations } from 'vs/workbench/browser/parts/editor/ran
|
|||||||
import { DefaultSettingsHeaderWidget, EditPreferenceWidget, SettingsGroupTitleWidget, SettingsHeaderWidget } from 'vs/workbench/contrib/preferences/browser/preferencesWidgets';
|
import { DefaultSettingsHeaderWidget, EditPreferenceWidget, SettingsGroupTitleWidget, SettingsHeaderWidget } from 'vs/workbench/contrib/preferences/browser/preferencesWidgets';
|
||||||
import { IFilterResult, IPreferencesEditorModel, IPreferencesService, ISetting, ISettingsEditorModel, ISettingsGroup } from 'vs/workbench/services/preferences/common/preferences';
|
import { IFilterResult, IPreferencesEditorModel, IPreferencesService, ISetting, ISettingsEditorModel, ISettingsGroup } from 'vs/workbench/services/preferences/common/preferences';
|
||||||
import { DefaultSettingsEditorModel, SettingsEditorModel, WorkspaceConfigurationEditorModel } from 'vs/workbench/services/preferences/common/preferencesModels';
|
import { DefaultSettingsEditorModel, SettingsEditorModel, WorkspaceConfigurationEditorModel } from 'vs/workbench/services/preferences/common/preferencesModels';
|
||||||
|
import { IMarkerService, IMarkerData, MarkerSeverity, MarkerTag } from 'vs/platform/markers/common/markers';
|
||||||
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
|
|
||||||
export interface IPreferencesRenderer<T> extends IDisposable {
|
export interface IPreferencesRenderer<T> extends IDisposable {
|
||||||
readonly preferencesModel: IPreferencesEditorModel<T>;
|
readonly preferencesModel: IPreferencesEditorModel<T>;
|
||||||
@@ -65,6 +67,8 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend
|
|||||||
private readonly _onUpdatePreference = this._register(new Emitter<{ key: string, value: any, source: IIndexedSetting }>());
|
private readonly _onUpdatePreference = this._register(new Emitter<{ key: string, value: any, source: IIndexedSetting }>());
|
||||||
readonly onUpdatePreference: Event<{ key: string, value: any, source: IIndexedSetting }> = this._onUpdatePreference.event;
|
readonly onUpdatePreference: Event<{ key: string, value: any, source: IIndexedSetting }> = this._onUpdatePreference.event;
|
||||||
|
|
||||||
|
private unsupportedSettingsRenderer: UnsupportedSettingsRenderer;
|
||||||
|
|
||||||
private filterResult: IFilterResult | undefined;
|
private filterResult: IFilterResult | undefined;
|
||||||
|
|
||||||
constructor(protected editor: ICodeEditor, readonly preferencesModel: SettingsEditorModel,
|
constructor(protected editor: ICodeEditor, readonly preferencesModel: SettingsEditorModel,
|
||||||
@@ -78,7 +82,7 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend
|
|||||||
this.editSettingActionRenderer = this._register(this.instantiationService.createInstance(EditSettingRenderer, this.editor, this.preferencesModel, this.settingHighlighter));
|
this.editSettingActionRenderer = this._register(this.instantiationService.createInstance(EditSettingRenderer, this.editor, this.preferencesModel, this.settingHighlighter));
|
||||||
this._register(this.editSettingActionRenderer.onUpdateSetting(({ key, value, source }) => this._updatePreference(key, value, source)));
|
this._register(this.editSettingActionRenderer.onUpdateSetting(({ key, value, source }) => this._updatePreference(key, value, source)));
|
||||||
this._register(this.editor.getModel()!.onDidChangeContent(() => this.modelChangeDelayer.trigger(() => this.onModelChanged())));
|
this._register(this.editor.getModel()!.onDidChangeContent(() => this.modelChangeDelayer.trigger(() => this.onModelChanged())));
|
||||||
|
this.unsupportedSettingsRenderer = this._register(instantiationService.createInstance(UnsupportedSettingsRenderer, editor, preferencesModel));
|
||||||
}
|
}
|
||||||
|
|
||||||
getAssociatedPreferencesModel(): IPreferencesEditorModel<ISetting> {
|
getAssociatedPreferencesModel(): IPreferencesEditorModel<ISetting> {
|
||||||
@@ -102,6 +106,7 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend
|
|||||||
if (this.filterResult) {
|
if (this.filterResult) {
|
||||||
this.filterPreferences(this.filterResult);
|
this.filterPreferences(this.filterResult);
|
||||||
}
|
}
|
||||||
|
this.unsupportedSettingsRenderer.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _updatePreference(key: string, value: any, source: IIndexedSetting): void {
|
private _updatePreference(key: string, value: any, source: IIndexedSetting): void {
|
||||||
@@ -946,6 +951,151 @@ class SettingHighlighter extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UnsupportedSettingsRenderer extends Disposable {
|
||||||
|
|
||||||
|
private renderingDelayer: Delayer<void> = new Delayer<void>(200);
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private editor: ICodeEditor,
|
||||||
|
private settingsEditorModel: SettingsEditorModel,
|
||||||
|
@IMarkerService private markerService: IMarkerService,
|
||||||
|
@IWorkbenchEnvironmentService private workbenchEnvironmentService: IWorkbenchEnvironmentService,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
this._register(this.editor.getModel()!.onDidChangeContent(() => this.renderingDelayer.trigger(() => this.render())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(): void {
|
||||||
|
const markerData: IMarkerData[] = this.generateMarkerData();
|
||||||
|
if (markerData.length) {
|
||||||
|
this.markerService.changeOne('preferencesEditor', this.settingsEditorModel.uri, markerData);
|
||||||
|
} else {
|
||||||
|
this.markerService.remove('preferencesEditor', [this.settingsEditorModel.uri]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateMarkerData(): IMarkerData[] {
|
||||||
|
const markerData: IMarkerData[] = [];
|
||||||
|
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).getConfigurationProperties();
|
||||||
|
for (const settingsGroup of this.settingsEditorModel.settingsGroups) {
|
||||||
|
for (const section of settingsGroup.sections) {
|
||||||
|
for (const setting of section.settings) {
|
||||||
|
const configuration = configurationRegistry[setting.key];
|
||||||
|
if (configuration) {
|
||||||
|
switch (this.settingsEditorModel.configurationTarget) {
|
||||||
|
case ConfigurationTarget.USER_LOCAL:
|
||||||
|
this.handleLocalUserConfiguration(setting, configuration, markerData);
|
||||||
|
break;
|
||||||
|
case ConfigurationTarget.USER_REMOTE:
|
||||||
|
this.handleRemoteUserConfiguration(setting, configuration, markerData);
|
||||||
|
break;
|
||||||
|
case ConfigurationTarget.WORKSPACE:
|
||||||
|
this.handleWorkspaceConfiguration(setting, configuration, markerData);
|
||||||
|
break;
|
||||||
|
case ConfigurationTarget.WORKSPACE_FOLDER:
|
||||||
|
this.handleWorkspaceFolderConfiguration(setting, configuration, markerData);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
markerData.push({
|
||||||
|
severity: MarkerSeverity.Hint,
|
||||||
|
tags: [MarkerTag.Unnecessary],
|
||||||
|
startLineNumber: setting.keyRange.startLineNumber,
|
||||||
|
startColumn: setting.keyRange.startColumn,
|
||||||
|
endLineNumber: setting.valueRange.endLineNumber,
|
||||||
|
endColumn: setting.valueRange.endColumn,
|
||||||
|
message: nls.localize('unknown configuration setting', "Unknown Configuration Setting")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return markerData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleLocalUserConfiguration(setting: ISetting, configuration: IConfigurationNode, markerData: IMarkerData[]): void {
|
||||||
|
if (this.workbenchEnvironmentService.configuration.remote && configuration.scope === ConfigurationScope.MACHINE) {
|
||||||
|
markerData.push({
|
||||||
|
severity: MarkerSeverity.Hint,
|
||||||
|
tags: [MarkerTag.Unnecessary],
|
||||||
|
startLineNumber: setting.keyRange.startLineNumber,
|
||||||
|
startColumn: setting.keyRange.startColumn,
|
||||||
|
endLineNumber: setting.valueRange.endLineNumber,
|
||||||
|
endColumn: setting.valueRange.endColumn,
|
||||||
|
message: nls.localize('unsupportedRemoteMachineSetting', "This setting can be applied only in remote machine settings")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleRemoteUserConfiguration(setting: ISetting, configuration: IConfigurationNode, markerData: IMarkerData[]): void {
|
||||||
|
if (configuration.scope === ConfigurationScope.APPLICATION) {
|
||||||
|
markerData.push(this.generateUnsupportedApplicationSettingMarker(setting));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleWorkspaceConfiguration(setting: ISetting, configuration: IConfigurationNode, markerData: IMarkerData[]): void {
|
||||||
|
if (configuration.scope === ConfigurationScope.APPLICATION) {
|
||||||
|
markerData.push(this.generateUnsupportedApplicationSettingMarker(setting));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configuration.scope === ConfigurationScope.MACHINE) {
|
||||||
|
markerData.push(this.generateUnsupportedMachineSettingMarker(setting));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleWorkspaceFolderConfiguration(setting: ISetting, configuration: IConfigurationNode, markerData: IMarkerData[]): void {
|
||||||
|
if (configuration.scope === ConfigurationScope.APPLICATION) {
|
||||||
|
markerData.push(this.generateUnsupportedApplicationSettingMarker(setting));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configuration.scope === ConfigurationScope.MACHINE) {
|
||||||
|
markerData.push(this.generateUnsupportedMachineSettingMarker(setting));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configuration.scope === ConfigurationScope.WINDOW) {
|
||||||
|
markerData.push({
|
||||||
|
severity: MarkerSeverity.Hint,
|
||||||
|
tags: [MarkerTag.Unnecessary],
|
||||||
|
startLineNumber: setting.keyRange.startLineNumber,
|
||||||
|
startColumn: setting.keyRange.startColumn,
|
||||||
|
endLineNumber: setting.valueRange.endLineNumber,
|
||||||
|
endColumn: setting.valueRange.endColumn,
|
||||||
|
message: nls.localize('unsupportedWindowSetting', "This setting cannot be applied now. It will be applied when you open this folder directly.")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateUnsupportedApplicationSettingMarker(setting: ISetting): IMarkerData {
|
||||||
|
return {
|
||||||
|
severity: MarkerSeverity.Hint,
|
||||||
|
tags: [MarkerTag.Unnecessary],
|
||||||
|
startLineNumber: setting.keyRange.startLineNumber,
|
||||||
|
startColumn: setting.keyRange.startColumn,
|
||||||
|
endLineNumber: setting.keyRange.endLineNumber,
|
||||||
|
endColumn: setting.keyRange.endColumn,
|
||||||
|
message: nls.localize('unsupportedApplicationSetting', "This setting can be applied only in application user settings")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateUnsupportedMachineSettingMarker(setting: ISetting): IMarkerData {
|
||||||
|
return {
|
||||||
|
severity: MarkerSeverity.Hint,
|
||||||
|
tags: [MarkerTag.Unnecessary],
|
||||||
|
startLineNumber: setting.keyRange.startLineNumber,
|
||||||
|
startColumn: setting.keyRange.startColumn,
|
||||||
|
endLineNumber: setting.valueRange.endLineNumber,
|
||||||
|
endColumn: setting.valueRange.endColumn,
|
||||||
|
message: nls.localize('unsupportedMachineSetting', "This setting can be applied only in user settings")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void {
|
||||||
|
this.markerService.remove('preferencesEditor', [this.settingsEditorModel.uri]);
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
class WorkspaceConfigurationRenderer extends Disposable {
|
class WorkspaceConfigurationRenderer extends Disposable {
|
||||||
|
|
||||||
private decorationIds: string[] = [];
|
private decorationIds: string[] = [];
|
||||||
|
|||||||
@@ -24,13 +24,13 @@ import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/plat
|
|||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||||
import { DialogChannel } from 'vs/platform/dialogs/node/dialogIpc';
|
import { DialogChannel } from 'vs/platform/dialogs/node/dialogIpc';
|
||||||
import { DownloadServiceChannel } from 'vs/platform/download/node/downloadIpc';
|
import { DownloadServiceChannel } from 'vs/platform/download/common/downloadIpc';
|
||||||
import { LogLevelSetterChannel } from 'vs/platform/log/common/logIpc';
|
import { LogLevelSetterChannel } from 'vs/platform/log/common/logIpc';
|
||||||
import { ipcRenderer as ipc } from 'electron';
|
import { ipcRenderer as ipc } from 'electron';
|
||||||
import { IDiagnosticInfoOptions, IRemoteDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
|
import { IDiagnosticInfoOptions, IRemoteDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
|
||||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
import { IProgressService, IProgress, IProgressStep, ProgressLocation } from 'vs/platform/progress/common/progress';
|
import { IProgressService, IProgress, IProgressStep, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||||
import { PersistenConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection';
|
import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
|
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
|
||||||
import Severity from 'vs/base/common/severity';
|
import Severity from 'vs/base/common/severity';
|
||||||
@@ -38,6 +38,7 @@ import { ReloadWindowAction } from 'vs/workbench/browser/actions/windowActions';
|
|||||||
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||||
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
||||||
import { RemoteConnectionState } from 'vs/workbench/browser/contextkeys';
|
import { RemoteConnectionState } from 'vs/workbench/browser/contextkeys';
|
||||||
|
import { IDownloadService } from 'vs/platform/download/common/download';
|
||||||
|
|
||||||
const WINDOW_ACTIONS_COMMAND_ID = 'remote.showActions';
|
const WINDOW_ACTIONS_COMMAND_ID = 'remote.showActions';
|
||||||
const CLOSE_REMOTE_COMMAND_ID = 'remote.closeRemote';
|
const CLOSE_REMOTE_COMMAND_ID = 'remote.closeRemote';
|
||||||
@@ -100,13 +101,13 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc
|
|||||||
if (connection) {
|
if (connection) {
|
||||||
this._register(connection.onDidStateChange((e) => {
|
this._register(connection.onDidStateChange((e) => {
|
||||||
switch (e.type) {
|
switch (e.type) {
|
||||||
case PersistenConnectionEventType.ConnectionLost:
|
case PersistentConnectionEventType.ConnectionLost:
|
||||||
case PersistenConnectionEventType.ReconnectionPermanentFailure:
|
case PersistentConnectionEventType.ReconnectionPermanentFailure:
|
||||||
case PersistenConnectionEventType.ReconnectionRunning:
|
case PersistentConnectionEventType.ReconnectionRunning:
|
||||||
case PersistenConnectionEventType.ReconnectionWait:
|
case PersistentConnectionEventType.ReconnectionWait:
|
||||||
this.setDisconnected(true);
|
this.setDisconnected(true);
|
||||||
break;
|
break;
|
||||||
case PersistenConnectionEventType.ConnectionGain:
|
case PersistentConnectionEventType.ConnectionGain:
|
||||||
this.setDisconnected(false);
|
this.setDisconnected(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -215,12 +216,13 @@ class RemoteChannelsContribution implements IWorkbenchContribution {
|
|||||||
constructor(
|
constructor(
|
||||||
@ILogService logService: ILogService,
|
@ILogService logService: ILogService,
|
||||||
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
|
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
|
||||||
@IDialogService dialogService: IDialogService
|
@IDialogService dialogService: IDialogService,
|
||||||
|
@IDownloadService downloadService: IDownloadService
|
||||||
) {
|
) {
|
||||||
const connection = remoteAgentService.getConnection();
|
const connection = remoteAgentService.getConnection();
|
||||||
if (connection) {
|
if (connection) {
|
||||||
connection.registerChannel('dialog', new DialogChannel(dialogService));
|
connection.registerChannel('dialog', new DialogChannel(dialogService));
|
||||||
connection.registerChannel('download', new DownloadServiceChannel());
|
connection.registerChannel('download', new DownloadServiceChannel(downloadService));
|
||||||
connection.registerChannel('loglevel', new LogLevelSetterChannel(logService));
|
connection.registerChannel('loglevel', new LogLevelSetterChannel(logService));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -296,7 +298,7 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
|
|||||||
currentTimer = null;
|
currentTimer = null;
|
||||||
}
|
}
|
||||||
switch (e.type) {
|
switch (e.type) {
|
||||||
case PersistenConnectionEventType.ConnectionLost:
|
case PersistentConnectionEventType.ConnectionLost:
|
||||||
if (!currentProgressPromiseResolve) {
|
if (!currentProgressPromiseResolve) {
|
||||||
let promise = new Promise<void>((resolve) => currentProgressPromiseResolve = resolve);
|
let promise = new Promise<void>((resolve) => currentProgressPromiseResolve = resolve);
|
||||||
progressService!.withProgress(
|
progressService!.withProgress(
|
||||||
@@ -313,13 +315,13 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
|
|||||||
|
|
||||||
progressReporter!.report(nls.localize('connectionLost', "Connection Lost"));
|
progressReporter!.report(nls.localize('connectionLost', "Connection Lost"));
|
||||||
break;
|
break;
|
||||||
case PersistenConnectionEventType.ReconnectionWait:
|
case PersistentConnectionEventType.ReconnectionWait:
|
||||||
currentTimer = new ReconnectionTimer(progressReporter!, Date.now() + 1000 * e.durationSeconds);
|
currentTimer = new ReconnectionTimer(progressReporter!, Date.now() + 1000 * e.durationSeconds);
|
||||||
break;
|
break;
|
||||||
case PersistenConnectionEventType.ReconnectionRunning:
|
case PersistentConnectionEventType.ReconnectionRunning:
|
||||||
progressReporter!.report(nls.localize('reconnectionRunning', "Attempting to reconnect..."));
|
progressReporter!.report(nls.localize('reconnectionRunning', "Attempting to reconnect..."));
|
||||||
break;
|
break;
|
||||||
case PersistenConnectionEventType.ReconnectionPermanentFailure:
|
case PersistentConnectionEventType.ReconnectionPermanentFailure:
|
||||||
currentProgressPromiseResolve!();
|
currentProgressPromiseResolve!();
|
||||||
currentProgressPromiseResolve = null;
|
currentProgressPromiseResolve = null;
|
||||||
progressReporter = null;
|
progressReporter = null;
|
||||||
@@ -331,7 +333,7 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case PersistenConnectionEventType.ConnectionGain:
|
case PersistentConnectionEventType.ConnectionGain:
|
||||||
currentProgressPromiseResolve!();
|
currentProgressPromiseResolve!();
|
||||||
currentProgressPromiseResolve = null;
|
currentProgressPromiseResolve = null;
|
||||||
progressReporter = null;
|
progressReporter = null;
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
|
import { Disposable, DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import { IWebviewService, Webview, WebviewContentOptions, WebviewEditorOverlay, WebviewElement, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview';
|
||||||
|
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||||
|
import { memoize } from 'vs/base/common/decorators';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Webview editor overlay that creates and destroys the underlying webview as needed.
|
||||||
|
*/
|
||||||
|
export class DynamicWebviewEditorOverlay extends Disposable implements WebviewEditorOverlay {
|
||||||
|
|
||||||
|
private readonly _pendingMessages = new Set<any>();
|
||||||
|
private readonly _webview = this._register(new MutableDisposable<WebviewElement>());
|
||||||
|
private readonly _webviewEvents = this._register(new DisposableStore());
|
||||||
|
|
||||||
|
private _html: string = '';
|
||||||
|
private _initialScrollProgress: number = 0;
|
||||||
|
private _state: string | undefined = undefined;
|
||||||
|
private _owner: any = undefined;
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
private readonly id: string,
|
||||||
|
public readonly options: WebviewOptions,
|
||||||
|
private _contentOptions: WebviewContentOptions,
|
||||||
|
@IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService,
|
||||||
|
@IWebviewService private readonly _webviewService: IWebviewService
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(toDisposable(() => this.container.remove()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@memoize
|
||||||
|
public get container() {
|
||||||
|
const container = document.createElement('div');
|
||||||
|
container.id = `webview-${this.id}`;
|
||||||
|
this._layoutService.getContainer(Parts.EDITOR_PART).appendChild(container);
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
public claim(owner: any) {
|
||||||
|
this._owner = owner;
|
||||||
|
this.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public release(owner: any) {
|
||||||
|
if (this._owner !== owner) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._owner = undefined;
|
||||||
|
this.container.style.visibility = 'hidden';
|
||||||
|
if (!this.options.retainContextWhenHidden) {
|
||||||
|
this._webview.clear();
|
||||||
|
this._webviewEvents.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private show() {
|
||||||
|
if (!this._webview.value) {
|
||||||
|
const webview = this._webviewService.createWebview(this.id, this.options, this._contentOptions);
|
||||||
|
this._webview.value = webview;
|
||||||
|
webview.state = this._state;
|
||||||
|
webview.html = this._html;
|
||||||
|
if (this.options.tryRestoreScrollPosition) {
|
||||||
|
webview.initialScrollProgress = this._initialScrollProgress;
|
||||||
|
}
|
||||||
|
this._webview.value.mountTo(this.container);
|
||||||
|
this._webviewEvents.clear();
|
||||||
|
|
||||||
|
webview.onDidFocus(() => { this._onDidFocus.fire(); }, undefined, this._webviewEvents);
|
||||||
|
webview.onDidClickLink(x => { this._onDidClickLink.fire(x); }, undefined, this._webviewEvents);
|
||||||
|
webview.onMessage(x => { this._onMessage.fire(x); }, undefined, this._webviewEvents);
|
||||||
|
|
||||||
|
webview.onDidScroll(x => {
|
||||||
|
this._initialScrollProgress = x.scrollYPercentage;
|
||||||
|
this._onDidScroll.fire(x);
|
||||||
|
}, undefined, this._webviewEvents);
|
||||||
|
|
||||||
|
webview.onDidUpdateState(state => {
|
||||||
|
this._state = state;
|
||||||
|
this._onDidUpdateState.fire(state);
|
||||||
|
}, undefined, this._webviewEvents);
|
||||||
|
|
||||||
|
this._pendingMessages.forEach(msg => webview.sendMessage(msg));
|
||||||
|
this._pendingMessages.clear();
|
||||||
|
}
|
||||||
|
this.container.style.visibility = 'visible';
|
||||||
|
}
|
||||||
|
|
||||||
|
public get html(): string { return this._html; }
|
||||||
|
public set html(value: string) {
|
||||||
|
this._html = value;
|
||||||
|
this.withWebview(webview => webview.html = value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get initialScrollProgress(): number { return this._initialScrollProgress; }
|
||||||
|
public set initialScrollProgress(value: number) {
|
||||||
|
this._initialScrollProgress = value;
|
||||||
|
this.withWebview(webview => webview.initialScrollProgress = value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get state(): string | undefined { return this._state; }
|
||||||
|
public set state(value: string | undefined) {
|
||||||
|
this._state = value;
|
||||||
|
this.withWebview(webview => webview.state = value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get contentOptions(): WebviewContentOptions { return this._contentOptions; }
|
||||||
|
public set contentOptions(value: WebviewContentOptions) {
|
||||||
|
this._contentOptions = value;
|
||||||
|
this.withWebview(webview => webview.contentOptions = value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly _onDidFocus = this._register(new Emitter<void>());
|
||||||
|
public readonly onDidFocus: Event<void> = this._onDidFocus.event;
|
||||||
|
|
||||||
|
private readonly _onDidClickLink = this._register(new Emitter<URI>());
|
||||||
|
public readonly onDidClickLink: Event<URI> = this._onDidClickLink.event;
|
||||||
|
|
||||||
|
private readonly _onDidScroll = this._register(new Emitter<{ scrollYPercentage: number; }>());
|
||||||
|
public readonly onDidScroll: Event<{ scrollYPercentage: number; }> = this._onDidScroll.event;
|
||||||
|
|
||||||
|
private readonly _onDidUpdateState = this._register(new Emitter<string | undefined>());
|
||||||
|
public readonly onDidUpdateState: Event<string | undefined> = this._onDidUpdateState.event;
|
||||||
|
|
||||||
|
private readonly _onMessage = this._register(new Emitter<any>());
|
||||||
|
public readonly onMessage: Event<any> = this._onMessage.event;
|
||||||
|
|
||||||
|
sendMessage(data: any): void {
|
||||||
|
if (this._webview.value) {
|
||||||
|
this._webview.value.sendMessage(data);
|
||||||
|
} else {
|
||||||
|
this._pendingMessages.add(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(html: string, options: WebviewContentOptions, retainContextWhenHidden: boolean): void {
|
||||||
|
this._contentOptions = options;
|
||||||
|
this._html = html;
|
||||||
|
this.withWebview(webview => {
|
||||||
|
webview.update(html, options, retainContextWhenHidden);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
layout(): void { this.withWebview(webview => webview.layout()); }
|
||||||
|
focus(): void { this.withWebview(webview => webview.focus()); }
|
||||||
|
reload(): void { this.withWebview(webview => webview.reload()); }
|
||||||
|
showFind(): void { this.withWebview(webview => webview.showFind()); }
|
||||||
|
hideFind(): void { this.withWebview(webview => webview.hideFind()); }
|
||||||
|
|
||||||
|
public getInnerWebview() {
|
||||||
|
return this._webview.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private withWebview(f: (webview: Webview) => void): void {
|
||||||
|
if (this._webview.value) {
|
||||||
|
f(this._webview.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,7 +45,9 @@ export class IFrameWebview extends Disposable implements Webview {
|
|||||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
if (typeof environmentService.webviewEndpoint !== 'string') {
|
const useExternalEndpoint = this._configurationService.getValue<string>('webview.experimental.useExternalEndpoint');
|
||||||
|
|
||||||
|
if (typeof environmentService.webviewEndpoint !== 'string' && !useExternalEndpoint) {
|
||||||
throw new Error('To use iframe based webviews, you must configure `environmentService.webviewEndpoint`');
|
throw new Error('To use iframe based webviews, you must configure `environmentService.webviewEndpoint`');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +144,9 @@ export class IFrameWebview extends Disposable implements Webview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private get endpoint(): string {
|
private get endpoint(): string {
|
||||||
const endpoint = this.environmentService.webviewEndpoint!.replace('{{uuid}}', this.id);
|
const useExternalEndpoint = this._configurationService.getValue<string>('webview.experimental.useExternalEndpoint');
|
||||||
|
const baseEndpoint = useExternalEndpoint ? 'https://{{uuid}}.vscode-webview-test.com/8fa811108f0f0524c473020ef57b6620f6c201e1' : this.environmentService.webviewEndpoint!;
|
||||||
|
const endpoint = baseEndpoint.replace('{{uuid}}', this.id);
|
||||||
if (endpoint[endpoint.length - 1] === '/') {
|
if (endpoint[endpoint.length - 1] === '/') {
|
||||||
return endpoint.slice(0, endpoint.length - 1);
|
return endpoint.slice(0, endpoint.length - 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,10 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
|
||||||
import { Disposable, DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IFrameWebview } from 'vs/workbench/contrib/webview/browser/webviewElement';
|
import { IFrameWebview } from 'vs/workbench/contrib/webview/browser/webviewElement';
|
||||||
import { IWebviewService, Webview, WebviewContentOptions, WebviewEditorOverlay, WebviewElement, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview';
|
import { IWebviewService, WebviewContentOptions, WebviewEditorOverlay, WebviewElement, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview';
|
||||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
import { DynamicWebviewEditorOverlay } from './dynamicWebviewEditorOverlay';
|
||||||
import { memoize } from 'vs/base/common/decorators';
|
|
||||||
|
|
||||||
export class WebviewService implements IWebviewService {
|
export class WebviewService implements IWebviewService {
|
||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
@@ -35,166 +31,3 @@ export class WebviewService implements IWebviewService {
|
|||||||
return this._instantiationService.createInstance(DynamicWebviewEditorOverlay, id, options, contentOptions);
|
return this._instantiationService.createInstance(DynamicWebviewEditorOverlay, id, options, contentOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Webview editor overlay that creates and destroys the underlying webview as needed.
|
|
||||||
*/
|
|
||||||
class DynamicWebviewEditorOverlay extends Disposable implements WebviewEditorOverlay {
|
|
||||||
|
|
||||||
private readonly _pendingMessages = new Set<any>();
|
|
||||||
private readonly _webview = this._register(new MutableDisposable<WebviewElement>());
|
|
||||||
private readonly _webviewEvents = this._register(new DisposableStore());
|
|
||||||
|
|
||||||
private _html: string = '';
|
|
||||||
private _initialScrollProgress: number = 0;
|
|
||||||
private _state: string | undefined = undefined;
|
|
||||||
private _owner: any = undefined;
|
|
||||||
|
|
||||||
public constructor(
|
|
||||||
private readonly id: string,
|
|
||||||
public readonly options: WebviewOptions,
|
|
||||||
private _contentOptions: WebviewContentOptions,
|
|
||||||
@IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService,
|
|
||||||
@IWebviewService private readonly _webviewService: IWebviewService,
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this._register(toDisposable(() => this.container.remove()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@memoize
|
|
||||||
public get container() {
|
|
||||||
const container = document.createElement('div');
|
|
||||||
container.id = `webview-${this.id}`;
|
|
||||||
this._layoutService.getContainer(Parts.EDITOR_PART).appendChild(container);
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
|
|
||||||
public claim(owner: any) {
|
|
||||||
this._owner = owner;
|
|
||||||
this.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
public release(owner: any) {
|
|
||||||
if (this._owner !== owner) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._owner = undefined;
|
|
||||||
this.container.style.visibility = 'hidden';
|
|
||||||
if (!this.options.retainContextWhenHidden) {
|
|
||||||
this._webview.clear();
|
|
||||||
this._webviewEvents.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private show() {
|
|
||||||
if (!this._webview.value) {
|
|
||||||
const webview = this._webviewService.createWebview(this.id, this.options, this._contentOptions);
|
|
||||||
this._webview.value = webview;
|
|
||||||
webview.state = this._state;
|
|
||||||
webview.html = this._html;
|
|
||||||
|
|
||||||
if (this.options.tryRestoreScrollPosition) {
|
|
||||||
webview.initialScrollProgress = this._initialScrollProgress;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._webview.value.mountTo(this.container);
|
|
||||||
|
|
||||||
this._webviewEvents.clear();
|
|
||||||
|
|
||||||
webview.onDidFocus(() => {
|
|
||||||
this._onDidFocus.fire();
|
|
||||||
}, undefined, this._webviewEvents);
|
|
||||||
|
|
||||||
webview.onDidClickLink(x => {
|
|
||||||
this._onDidClickLink.fire(x);
|
|
||||||
}, undefined, this._webviewEvents);
|
|
||||||
|
|
||||||
webview.onDidScroll(x => {
|
|
||||||
this._initialScrollProgress = x.scrollYPercentage;
|
|
||||||
this._onDidScroll.fire(x);
|
|
||||||
}, undefined, this._webviewEvents);
|
|
||||||
|
|
||||||
webview.onDidUpdateState(state => {
|
|
||||||
this._state = state;
|
|
||||||
this._onDidUpdateState.fire(state);
|
|
||||||
}, undefined, this._webviewEvents);
|
|
||||||
|
|
||||||
webview.onMessage(x => {
|
|
||||||
this._onMessage.fire(x);
|
|
||||||
}, undefined, this._webviewEvents);
|
|
||||||
|
|
||||||
this._pendingMessages.forEach(msg => webview.sendMessage(msg));
|
|
||||||
this._pendingMessages.clear();
|
|
||||||
}
|
|
||||||
this.container.style.visibility = 'visible';
|
|
||||||
}
|
|
||||||
|
|
||||||
public get html(): string { return this._html; }
|
|
||||||
public set html(value: string) {
|
|
||||||
this._html = value;
|
|
||||||
this.withWebview(webview => webview.html = value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get initialScrollProgress(): number { return this._initialScrollProgress; }
|
|
||||||
public set initialScrollProgress(value: number) {
|
|
||||||
this._initialScrollProgress = value;
|
|
||||||
this.withWebview(webview => webview.initialScrollProgress = value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get state(): string | undefined { return this._state; }
|
|
||||||
public set state(value: string | undefined) {
|
|
||||||
this._state = value;
|
|
||||||
this.withWebview(webview => webview.state = value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get contentOptions(): WebviewContentOptions { return this._contentOptions; }
|
|
||||||
public set contentOptions(value: WebviewContentOptions) {
|
|
||||||
this._contentOptions = value;
|
|
||||||
this.withWebview(webview => webview.contentOptions = value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly _onDidFocus = this._register(new Emitter<void>());
|
|
||||||
public readonly onDidFocus: Event<void> = this._onDidFocus.event;
|
|
||||||
|
|
||||||
private readonly _onDidClickLink = this._register(new Emitter<URI>());
|
|
||||||
public readonly onDidClickLink: Event<URI> = this._onDidClickLink.event;
|
|
||||||
|
|
||||||
private readonly _onDidScroll = this._register(new Emitter<{ scrollYPercentage: number; }>());
|
|
||||||
public readonly onDidScroll: Event<{ scrollYPercentage: number; }> = this._onDidScroll.event;
|
|
||||||
|
|
||||||
private readonly _onDidUpdateState = this._register(new Emitter<string | undefined>());
|
|
||||||
public readonly onDidUpdateState: Event<string | undefined> = this._onDidUpdateState.event;
|
|
||||||
|
|
||||||
private readonly _onMessage = this._register(new Emitter<any>());
|
|
||||||
public readonly onMessage: Event<any> = this._onMessage.event;
|
|
||||||
|
|
||||||
sendMessage(data: any): void {
|
|
||||||
if (this._webview.value) {
|
|
||||||
this._webview.value.sendMessage(data);
|
|
||||||
} else {
|
|
||||||
this._pendingMessages.add(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
update(html: string, options: WebviewContentOptions, retainContextWhenHidden: boolean): void {
|
|
||||||
this._contentOptions = options;
|
|
||||||
this._html = html;
|
|
||||||
this.withWebview(webview => {
|
|
||||||
webview.update(html, options, retainContextWhenHidden);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
layout(): void { this.withWebview(webview => webview.layout()); }
|
|
||||||
focus(): void { this.withWebview(webview => webview.focus()); }
|
|
||||||
reload(): void { this.withWebview(webview => webview.reload()); }
|
|
||||||
showFind(): void { this.withWebview(webview => webview.showFind()); }
|
|
||||||
hideFind(): void { this.withWebview(webview => webview.hideFind()); }
|
|
||||||
|
|
||||||
private withWebview(f: (webview: Webview) => void): void {
|
|
||||||
if (this._webview.value) {
|
|
||||||
f(this._webview.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -97,6 +97,8 @@ export interface WebviewEditorOverlay extends Webview {
|
|||||||
|
|
||||||
claim(owner: any): void;
|
claim(owner: any): void;
|
||||||
release(owner: any): void;
|
release(owner: any): void;
|
||||||
|
|
||||||
|
getInnerWebview(): Webview | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const webviewDeveloperCategory = nls.localize('developer', "Developer");
|
export const webviewDeveloperCategory = nls.localize('developer', "Developer");
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/wor
|
|||||||
import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEditor';
|
import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEditor';
|
||||||
import { IWebviewService, webviewDeveloperCategory } from 'vs/workbench/contrib/webview/common/webview';
|
import { IWebviewService, webviewDeveloperCategory } from 'vs/workbench/contrib/webview/common/webview';
|
||||||
import * as webviewCommands from 'vs/workbench/contrib/webview/electron-browser/webviewCommands';
|
import * as webviewCommands from 'vs/workbench/contrib/webview/electron-browser/webviewCommands';
|
||||||
import { WebviewService } from 'vs/workbench/contrib/webview/electron-browser/webviewService';
|
import { ElectronWebviewService } from 'vs/workbench/contrib/webview/electron-browser/webviewService';
|
||||||
|
|
||||||
registerSingleton(IWebviewService, WebviewService, true);
|
registerSingleton(IWebviewService, ElectronWebviewService, true);
|
||||||
|
|
||||||
const actionRegistry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
const actionRegistry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { Command, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
|||||||
import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEditor';
|
import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEditor';
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { ElectronWebviewBasedWebview } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
|
import { ElectronWebviewBasedWebview } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
|
||||||
|
import { WebviewEditorOverlay } from 'vs/workbench/contrib/webview/common/webview';
|
||||||
|
|
||||||
export class OpenWebviewDeveloperToolsAction extends Action {
|
export class OpenWebviewDeveloperToolsAction extends Action {
|
||||||
static readonly ID = 'workbench.action.webview.openDeveloperTools';
|
static readonly ID = 'workbench.action.webview.openDeveloperTools';
|
||||||
@@ -92,6 +93,11 @@ function withActiveWebviewBasedWebview(accessor: ServicesAccessor, f: (webview:
|
|||||||
webViewEditor.withWebview(webview => {
|
webViewEditor.withWebview(webview => {
|
||||||
if (webview instanceof ElectronWebviewBasedWebview) {
|
if (webview instanceof ElectronWebviewBasedWebview) {
|
||||||
f(webview);
|
f(webview);
|
||||||
|
} else if ((webview as WebviewEditorOverlay).getInnerWebview) {
|
||||||
|
const innerWebview = (webview as WebviewEditorOverlay).getInnerWebview();
|
||||||
|
if (innerWebview instanceof ElectronWebviewBasedWebview) {
|
||||||
|
f(innerWebview);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,25 +3,39 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { WebviewService as BrowserWebviewService } from 'vs/workbench/contrib/webview/browser/webviewService';
|
import { DynamicWebviewEditorOverlay } from 'vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay';
|
||||||
import { IWebviewService, WebviewContentOptions, WebviewElement, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview';
|
import { IFrameWebview } from 'vs/workbench/contrib/webview/browser/webviewElement';
|
||||||
|
import { IWebviewService, WebviewContentOptions, WebviewEditorOverlay, WebviewElement, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview';
|
||||||
import { ElectronWebviewBasedWebview } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
|
import { ElectronWebviewBasedWebview } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
|
||||||
|
|
||||||
export class WebviewService extends BrowserWebviewService implements IWebviewService {
|
export class ElectronWebviewService implements IWebviewService {
|
||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||||
) {
|
@IConfigurationService private readonly _configService: IConfigurationService,
|
||||||
super(instantiationService);
|
) { }
|
||||||
}
|
|
||||||
|
|
||||||
createWebview(
|
createWebview(
|
||||||
_id: string,
|
id: string,
|
||||||
options: WebviewOptions,
|
options: WebviewOptions,
|
||||||
contentOptions: WebviewContentOptions
|
contentOptions: WebviewContentOptions
|
||||||
): WebviewElement {
|
): WebviewElement {
|
||||||
return this.instantiationService.createInstance(ElectronWebviewBasedWebview, options, contentOptions);
|
const useExternalEndpoint = this._configService.getValue<string>('webview.experimental.useExternalEndpoint');
|
||||||
|
if (useExternalEndpoint) {
|
||||||
|
return this._instantiationService.createInstance(IFrameWebview, id, options, contentOptions);
|
||||||
|
} else {
|
||||||
|
return this._instantiationService.createInstance(ElectronWebviewBasedWebview, options, contentOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createWebviewEditorOverlay(
|
||||||
|
id: string,
|
||||||
|
options: WebviewOptions,
|
||||||
|
contentOptions: WebviewContentOptions,
|
||||||
|
): WebviewEditorOverlay {
|
||||||
|
return this._instantiationService.createInstance(DynamicWebviewEditorOverlay, id, options, contentOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,6 @@ import { ConfigurationEditingService, EditableConfigurationTarget } from 'vs/wor
|
|||||||
import { WorkspaceConfiguration, FolderConfiguration, RemoteUserConfiguration, UserConfiguration } from 'vs/workbench/services/configuration/browser/configuration';
|
import { WorkspaceConfiguration, FolderConfiguration, RemoteUserConfiguration, UserConfiguration } from 'vs/workbench/services/configuration/browser/configuration';
|
||||||
import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService';
|
import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService';
|
||||||
import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';
|
import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';
|
||||||
import { localize } from 'vs/nls';
|
|
||||||
import { isEqual, dirname } from 'vs/base/common/resources';
|
import { isEqual, dirname } from 'vs/base/common/resources';
|
||||||
import { mark } from 'vs/base/common/performance';
|
import { mark } from 'vs/base/common/performance';
|
||||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||||
@@ -507,29 +506,29 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
|
|||||||
private registerConfigurationSchemas(): void {
|
private registerConfigurationSchemas(): void {
|
||||||
if (this.workspace) {
|
if (this.workspace) {
|
||||||
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
|
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
|
||||||
const convertToNotSuggestedProperties = (properties: IJSONSchemaMap, errorMessage: string): IJSONSchemaMap => {
|
const convertToNotSuggestedProperties = (properties: IJSONSchemaMap): IJSONSchemaMap => {
|
||||||
return Object.keys(properties).reduce((result: IJSONSchemaMap, property) => {
|
return Object.keys(properties).reduce((result: IJSONSchemaMap, property) => {
|
||||||
result[property] = deepClone(properties[property]);
|
result[property] = deepClone(properties[property]);
|
||||||
result[property].deprecationMessage = errorMessage;
|
result[property].doNotSuggest = true;
|
||||||
return result;
|
return result;
|
||||||
}, {});
|
}, {});
|
||||||
};
|
};
|
||||||
|
|
||||||
const unsupportedApplicationSettings = convertToNotSuggestedProperties(applicationSettings.properties, localize('unsupportedApplicationSetting', "This setting can be applied only in application user settings"));
|
const unsupportedApplicationSettings = convertToNotSuggestedProperties(applicationSettings.properties);
|
||||||
const unsupportedMachineSettings = convertToNotSuggestedProperties(machineSettings.properties, localize('unsupportedMachineSetting', "This setting can be applied only in user settings"));
|
const unsupportedMachineSettings = convertToNotSuggestedProperties(machineSettings.properties);
|
||||||
const unsupportedRemoteMachineSettings = convertToNotSuggestedProperties(machineSettings.properties, localize('unsupportedRemoteMachineSetting', "This setting can be applied only in remote machine settings"));
|
const unsupportedRemoteMachineSettings = convertToNotSuggestedProperties(machineSettings.properties);
|
||||||
const allSettingsSchema: IJSONSchema = { properties: allSettings.properties, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' };
|
const allSettingsSchema: IJSONSchema = { properties: allSettings.properties, patternProperties: allSettings.patternProperties, additionalProperties: true };
|
||||||
const userSettingsSchema: IJSONSchema = this.remoteUserConfiguration ? { properties: { ...applicationSettings.properties, ...unsupportedRemoteMachineSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' } : allSettingsSchema;
|
const userSettingsSchema: IJSONSchema = this.remoteUserConfiguration ? { properties: { ...applicationSettings.properties, ...unsupportedRemoteMachineSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true } : allSettingsSchema;
|
||||||
const machineSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' };
|
const machineSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true };
|
||||||
const workspaceSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedMachineSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' };
|
const workspaceSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedMachineSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true };
|
||||||
|
|
||||||
jsonRegistry.registerSchema(defaultSettingsSchemaId, allSettingsSchema);
|
jsonRegistry.registerSchema(defaultSettingsSchemaId, allSettingsSchema);
|
||||||
jsonRegistry.registerSchema(userSettingsSchemaId, userSettingsSchema);
|
jsonRegistry.registerSchema(userSettingsSchemaId, userSettingsSchema);
|
||||||
jsonRegistry.registerSchema(machineSettingsSchemaId, machineSettingsSchema);
|
jsonRegistry.registerSchema(machineSettingsSchemaId, machineSettingsSchema);
|
||||||
|
|
||||||
if (WorkbenchState.WORKSPACE === this.getWorkbenchState()) {
|
if (WorkbenchState.WORKSPACE === this.getWorkbenchState()) {
|
||||||
const unsupportedWindowSettings = convertToNotSuggestedProperties(windowSettings.properties, localize('unsupportedWindowSetting', "This setting cannot be applied now. It will be applied when you open this folder directly."));
|
const unsupportedWindowSettings = convertToNotSuggestedProperties(windowSettings.properties);
|
||||||
const folderSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedMachineSettings, ...unsupportedWindowSettings, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' };
|
const folderSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedMachineSettings, ...unsupportedWindowSettings, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true };
|
||||||
jsonRegistry.registerSchema(workspaceSettingsSchemaId, workspaceSettingsSchema);
|
jsonRegistry.registerSchema(workspaceSettingsSchemaId, workspaceSettingsSchema);
|
||||||
jsonRegistry.registerSchema(folderSettingsSchemaId, folderSettingsSchema);
|
jsonRegistry.registerSchema(folderSettingsSchemaId, folderSettingsSchema);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+1
-2
@@ -42,7 +42,6 @@ import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemPro
|
|||||||
import { ConfigurationCache } from 'vs/workbench/services/configuration/node/configurationCache';
|
import { ConfigurationCache } from 'vs/workbench/services/configuration/node/configurationCache';
|
||||||
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
|
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
|
||||||
import { IConfigurationCache } from 'vs/workbench/services/configuration/common/configuration';
|
import { IConfigurationCache } from 'vs/workbench/services/configuration/common/configuration';
|
||||||
// import { VSBuffer } from 'vs/base/common/buffer';
|
|
||||||
import { SignService } from 'vs/platform/sign/browser/signService';
|
import { SignService } from 'vs/platform/sign/browser/signService';
|
||||||
import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider';
|
import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider';
|
||||||
import { IKeybindingEditingService, KeybindingsEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing';
|
import { IKeybindingEditingService, KeybindingsEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing';
|
||||||
@@ -276,7 +275,7 @@ suite('WorkspaceConfigurationService - Remote Folder', () => {
|
|||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
// });
|
// });
|
||||||
// await instantiationService.get(IFileService).writeFile(URI.file(remoteSettingsFile), VSBuffer.fromString('{ "configurationService.remote.machineSetting": "remoteValue" }'));
|
// fs.writeFileSync(remoteSettingsFile, '{ "configurationService.remote.machineSetting": "remoteValue" }');
|
||||||
// return promise;
|
// return promise;
|
||||||
// });
|
// });
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { URI } from 'vs/base/common/uri';
|
|||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
import { IDecorationsService, IDecoration, IResourceDecorationChangeEvent, IDecorationsProvider, IDecorationData } from './decorations';
|
import { IDecorationsService, IDecoration, IResourceDecorationChangeEvent, IDecorationsProvider, IDecorationData } from './decorations';
|
||||||
import { TernarySearchTree } from 'vs/base/common/map';
|
import { TernarySearchTree } from 'vs/base/common/map';
|
||||||
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||||
import { isThenable } from 'vs/base/common/async';
|
import { isThenable } from 'vs/base/common/async';
|
||||||
import { LinkedList } from 'vs/base/common/linkedList';
|
import { LinkedList } from 'vs/base/common/linkedList';
|
||||||
import { createStyleSheet, createCSSRule, removeCSSRulesContainingSelector } from 'vs/base/browser/dom';
|
import { createStyleSheet, createCSSRule, removeCSSRulesContainingSelector } from 'vs/base/browser/dom';
|
||||||
@@ -334,14 +334,15 @@ class DecorationProviderWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FileDecorationsService extends Disposable implements IDecorationsService {
|
export class FileDecorationsService implements IDecorationsService {
|
||||||
|
|
||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
|
|
||||||
private readonly _data = new LinkedList<DecorationProviderWrapper>();
|
private readonly _data = new LinkedList<DecorationProviderWrapper>();
|
||||||
private readonly _onDidChangeDecorationsDelayed = this._register(new Emitter<URI | URI[]>());
|
private readonly _onDidChangeDecorationsDelayed = new Emitter<URI | URI[]>();
|
||||||
private readonly _onDidChangeDecorations = this._register(new Emitter<IResourceDecorationChangeEvent>());
|
private readonly _onDidChangeDecorations = new Emitter<IResourceDecorationChangeEvent>();
|
||||||
private readonly _decorationStyles: DecorationStyles;
|
private readonly _decorationStyles: DecorationStyles;
|
||||||
|
private readonly _disposables: IDisposable[];
|
||||||
|
|
||||||
readonly onDidChangeDecorations: Event<IResourceDecorationChangeEvent> = Event.any(
|
readonly onDidChangeDecorations: Event<IResourceDecorationChangeEvent> = Event.any(
|
||||||
this._onDidChangeDecorations.event,
|
this._onDidChangeDecorations.event,
|
||||||
@@ -355,17 +356,27 @@ export class FileDecorationsService extends Disposable implements IDecorationsSe
|
|||||||
constructor(
|
constructor(
|
||||||
@IThemeService themeService: IThemeService
|
@IThemeService themeService: IThemeService
|
||||||
) {
|
) {
|
||||||
super();
|
this._decorationStyles = new DecorationStyles(themeService);
|
||||||
this._decorationStyles = this._register(new DecorationStyles(themeService));
|
|
||||||
|
|
||||||
// every so many events we check if there are
|
// every so many events we check if there are
|
||||||
// css styles that we don't need anymore
|
// css styles that we don't need anymore
|
||||||
let count = 0;
|
let count = 0;
|
||||||
this._register(this.onDidChangeDecorations(() => {
|
let reg = this.onDidChangeDecorations(() => {
|
||||||
if (++count % 17 === 0) {
|
if (++count % 17 === 0) {
|
||||||
this._decorationStyles.cleanUp(this._data.iterator());
|
this._decorationStyles.cleanUp(this._data.iterator());
|
||||||
}
|
}
|
||||||
}));
|
});
|
||||||
|
|
||||||
|
this._disposables = [
|
||||||
|
reg,
|
||||||
|
this._decorationStyles
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): void {
|
||||||
|
dispose(this._disposables);
|
||||||
|
dispose(this._onDidChangeDecorations);
|
||||||
|
dispose(this._onDidChangeDecorationsDelayed);
|
||||||
}
|
}
|
||||||
|
|
||||||
registerDecorationsProvider(provider: IDecorationsProvider): IDisposable {
|
registerDecorationsProvider(provider: IDecorationsProvider): IDisposable {
|
||||||
|
|||||||
@@ -162,6 +162,11 @@ export class RemoteExtensionHostClient extends Disposable implements IExtensionH
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _onExtHostConnectionLost(): void {
|
private _onExtHostConnectionLost(): void {
|
||||||
|
|
||||||
|
if (this._isExtensionDevHost && this._environmentService.debugExtensionHost.debugId) {
|
||||||
|
this._extensionHostDebugService.close(this._environmentService.debugExtensionHost.debugId);
|
||||||
|
}
|
||||||
|
|
||||||
if (this._terminating) {
|
if (this._terminating) {
|
||||||
// Expected termination path (we asked the process to terminate)
|
// Expected termination path (we asked the process to terminate)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -101,10 +101,6 @@ export class CachedExtensionScanner {
|
|||||||
development.forEach(developedExtension => {
|
development.forEach(developedExtension => {
|
||||||
log.info('', nls.localize('extensionUnderDevelopment', "Loading development extension at {0}", developedExtension.extensionLocation.fsPath));
|
log.info('', nls.localize('extensionUnderDevelopment', "Loading development extension at {0}", developedExtension.extensionLocation.fsPath));
|
||||||
const extensionKey = ExtensionIdentifier.toKey(developedExtension.identifier);
|
const extensionKey = ExtensionIdentifier.toKey(developedExtension.identifier);
|
||||||
const extension = result.get(extensionKey);
|
|
||||||
if (extension) {
|
|
||||||
log.warn(developedExtension.extensionLocation.fsPath, nls.localize('overwritingExtension', "Overwriting extension {0} with {1}.", extension.extensionLocation.fsPath, developedExtension.extensionLocation.fsPath));
|
|
||||||
}
|
|
||||||
result.set(extensionKey, developedExtension);
|
result.set(extensionKey, developedExtension);
|
||||||
});
|
});
|
||||||
let r: IExtensionDescription[] = [];
|
let r: IExtensionDescription[] = [];
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/co
|
|||||||
import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
import { PersistenConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection';
|
import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||||
import { IProductService } from 'vs/platform/product/common/product';
|
import { IProductService } from 'vs/platform/product/common/product';
|
||||||
import { Logger } from 'vs/workbench/services/extensions/common/extensionPoints';
|
import { Logger } from 'vs/workbench/services/extensions/common/extensionPoints';
|
||||||
|
|
||||||
@@ -478,7 +478,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||||||
if (!remoteAuthority) {
|
if (!remoteAuthority) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (e.type === PersistenConnectionEventType.ConnectionLost) {
|
if (e.type === PersistentConnectionEventType.ConnectionLost) {
|
||||||
this._remoteAuthorityResolverService.clearResolvedAuthority(remoteAuthority);
|
this._remoteAuthorityResolverService.clearResolvedAuthority(remoteAuthority);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDeco
|
|||||||
import { IMarkerService } from 'vs/platform/markers/common/markers';
|
import { IMarkerService } from 'vs/platform/markers/common/markers';
|
||||||
import { MarkerService } from 'vs/platform/markers/common/markerService';
|
import { MarkerService } from 'vs/platform/markers/common/markerService';
|
||||||
import { IDownloadService } from 'vs/platform/download/common/download';
|
import { IDownloadService } from 'vs/platform/download/common/download';
|
||||||
import { DownloadService } from 'vs/platform/download/node/downloadService';
|
import { DownloadService } from 'vs/platform/download/common/downloadService';
|
||||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||||
import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService';
|
import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService';
|
||||||
import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService';
|
import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService';
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ import { MarkerDecorationsService } from 'vs/editor/common/services/markerDecora
|
|||||||
import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService';
|
import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService';
|
||||||
import { IMarkerService } from 'vs/platform/markers/common/markers';
|
import { IMarkerService } from 'vs/platform/markers/common/markers';
|
||||||
import { MarkerService } from 'vs/platform/markers/common/markerService';
|
import { MarkerService } from 'vs/platform/markers/common/markerService';
|
||||||
// import { IDownloadService } from 'vs/platform/download/common/download';
|
import { IDownloadService } from 'vs/platform/download/common/download';
|
||||||
// import { DownloadService } from 'vs/platform/download/node/downloadService';
|
import { DownloadService } from 'vs/platform/download/common/downloadService';
|
||||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||||
import { BrowserClipboardService } from 'vs/platform/clipboard/browser/clipboardService';
|
import { BrowserClipboardService } from 'vs/platform/clipboard/browser/clipboardService';
|
||||||
import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService';
|
import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService';
|
||||||
@@ -145,7 +145,7 @@ registerSingleton(IOpenerService, OpenerService, true);
|
|||||||
registerSingleton(IEditorWorkerService, EditorWorkerServiceImpl);
|
registerSingleton(IEditorWorkerService, EditorWorkerServiceImpl);
|
||||||
registerSingleton(IMarkerDecorationsService, MarkerDecorationsService);
|
registerSingleton(IMarkerDecorationsService, MarkerDecorationsService);
|
||||||
registerSingleton(IMarkerService, MarkerService, true);
|
registerSingleton(IMarkerService, MarkerService, true);
|
||||||
// registerSingleton(IDownloadService, DownloadService, true);
|
registerSingleton(IDownloadService, DownloadService, true);
|
||||||
registerSingleton(IClipboardService, BrowserClipboardService, true);
|
registerSingleton(IClipboardService, BrowserClipboardService, true);
|
||||||
registerSingleton(IContextKeyService, ContextKeyService);
|
registerSingleton(IContextKeyService, ContextKeyService);
|
||||||
registerSingleton(IModelService, ModelServiceImpl, true);
|
registerSingleton(IModelService, ModelServiceImpl, true);
|
||||||
|
|||||||
Reference in New Issue
Block a user