Merge from vscode 011858832762aaff245b2336fb1c38166e7a10fb (#4663)

This commit is contained in:
Anthony Dresser
2019-03-22 13:07:54 -07:00
committed by GitHub
parent f5c9174c2f
commit 4a87a24235
296 changed files with 2531 additions and 2472 deletions
@@ -80,10 +80,6 @@ export class ServerTreeActionProvider extends ContributableActionProvider {
return false; return false;
} }
public getSecondaryActions(tree: ITree, element: any): IAction[] {
return super.getSecondaryActions(tree, element);
}
/** /**
* Return actions for connection elements * Return actions for connection elements
*/ */
@@ -40,10 +40,6 @@ export class TaskHistoryActionProvider extends ContributableActionProvider {
return false; return false;
} }
public getSecondaryActions(tree: ITree, element: any): IAction[] {
return super.getSecondaryActions(tree, element);
}
/** /**
* Return actions for history task * Return actions for history task
*/ */
+1 -1
View File
@@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------------------------- /*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. 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.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
// Defined a subset of ES6 built ins that run in IE11 // Defined a subset of ES6 built ins that run in IE11
+9 -9
View File
@@ -6,7 +6,7 @@
declare module 'spdlog' { declare module 'spdlog' {
export const version: string; export const version: string;
export function setAsyncMode(bufferSize: number, flushInterval: number); export function setAsyncMode(bufferSize: number, flushInterval: number): void;
export enum LogLevel { export enum LogLevel {
CRITICAL, CRITICAL,
@@ -21,14 +21,14 @@ declare module 'spdlog' {
export class RotatingLogger { export class RotatingLogger {
constructor(name: string, filename: string, filesize: number, filecount: number); constructor(name: string, filename: string, filesize: number, filecount: number);
trace(message: string); trace(message: string): void;
debug(message: string); debug(message: string): void;
info(message: string); info(message: string): void;
warn(message: string); warn(message: string): void;
error(message: string); error(message: string): void;
critical(message: string); critical(message: string): void;
setLevel(level: number); setLevel(level: number): void;
clearFormatters(); clearFormatters(): void;
/** /**
* A synchronous operation to flush the contents into file * A synchronous operation to flush the contents into file
*/ */
+1 -1
View File
@@ -5,5 +5,5 @@
declare module 'sudo-prompt' { declare module 'sudo-prompt' {
export function exec(cmd: string, options: { name?: string, icns?: string }, callback: (error: string, stdout: string, stderr: string) => void); export function exec(cmd: string, options: { name?: string, icns?: string }, callback: (error: string, stdout: string, stderr: string) => void): void;
} }
+3 -3
View File
@@ -31,9 +31,9 @@ declare module 'yauzl' {
} }
export class ZipFile extends EventEmitter { export class ZipFile extends EventEmitter {
readEntry(); readEntry(): void;
openReadStream(entry: Entry, callback: (err?: Error, stream?: Readable) => void); openReadStream(entry: Entry, callback: (err?: Error, stream?: Readable) => void): void;
close(); close(): void;
isOpen: boolean; isOpen: boolean;
entryCount: number; entryCount: number;
comment: string; comment: string;
+3 -3
View File
@@ -8,8 +8,8 @@ declare module 'yazl' {
class ZipFile { class ZipFile {
outputStream: stream.Stream; outputStream: stream.Stream;
addBuffer(buffer: Buffer, path: string); addBuffer(buffer: Buffer, path: string): void;
addFile(localPath: string, path: string); addFile(localPath: string, path: string): void;
end(); end(): void;
} }
} }
+1 -1
View File
@@ -25,7 +25,7 @@ export class ContextSubMenu extends SubmenuAction {
export interface IContextMenuDelegate { export interface IContextMenuDelegate {
getAnchor(): HTMLElement | { x: number; y: number; width?: number; height?: number; }; getAnchor(): HTMLElement | { x: number; y: number; width?: number; height?: number; };
getActions(): Array<IAction | ContextSubMenu>; getActions(): Array<IAction | ContextSubMenu>;
getActionItem?(action: IAction): IActionItem | null; getActionItem?(action: IAction): IActionItem | undefined;
getActionsContext?(event?: IContextMenuEvent): any; getActionsContext?(event?: IContextMenuEvent): any;
getKeyBinding?(action: IAction): ResolvedKeybinding | undefined; getKeyBinding?(action: IAction): ResolvedKeybinding | undefined;
getMenuClassName?(): string; getMenuClassName?(): string;
@@ -364,7 +364,7 @@ export interface ActionTrigger {
} }
export interface IActionItemProvider { export interface IActionItemProvider {
(action: IAction): IActionItem | null; (action: IAction): IActionItem | undefined;
} }
export interface IActionBarOptions { export interface IActionBarOptions {
@@ -609,7 +609,7 @@ export class ActionBar extends Disposable implements IActionRunner {
e.stopPropagation(); e.stopPropagation();
})); }));
let item: IActionItem | null = null; let item: IActionItem | undefined;
if (this.options.actionItemProvider) { if (this.options.actionItemProvider) {
item = this.options.actionItemProvider(action); item = this.options.actionItemProvider(action);
@@ -118,7 +118,7 @@ export class ContextView extends Disposable {
this._register(toDisposable(() => this.setContainer(null))); this._register(toDisposable(() => this.setContainer(null)));
} }
public setContainer(container: HTMLElement | null): void { setContainer(container: HTMLElement | null): void {
if (this.container) { if (this.container) {
this.toDisposeOnSetContainer = dispose(this.toDisposeOnSetContainer); this.toDisposeOnSetContainer = dispose(this.toDisposeOnSetContainer);
this.container.removeChild(this.view); this.container.removeChild(this.view);
@@ -146,7 +146,7 @@ export class ContextView extends Disposable {
} }
} }
public show(delegate: IDelegate): void { show(delegate: IDelegate): void {
if (this.isVisible()) { if (this.isVisible()) {
this.hide(); this.hide();
} }
@@ -173,7 +173,7 @@ export class ContextView extends Disposable {
} }
} }
public layout(): void { layout(): void {
if (!this.isVisible()) { if (!this.isVisible()) {
return; return;
} }
@@ -258,7 +258,7 @@ export class ContextView extends Disposable {
this.view.style.width = 'initial'; this.view.style.width = 'initial';
} }
public hide(data?: any): void { hide(data?: any): void {
if (this.delegate && this.delegate.onHide) { if (this.delegate && this.delegate.onHide) {
this.delegate.onHide(data); this.delegate.onHide(data);
} }
@@ -288,7 +288,7 @@ export class ContextView extends Disposable {
} }
} }
public dispose(): void { dispose(): void {
this.hide(); this.hide();
super.dispose(); super.dispose();
+1 -1
View File
@@ -247,7 +247,7 @@ export class DropdownMenu extends BaseDropdown {
getAnchor: () => this.element, getAnchor: () => this.element,
getActions: () => this.actions, getActions: () => this.actions,
getActionsContext: () => this.menuOptions ? this.menuOptions.context : null, getActionsContext: () => this.menuOptions ? this.menuOptions.context : null,
getActionItem: action => this.menuOptions && this.menuOptions.actionItemProvider ? this.menuOptions.actionItemProvider(action) : null, getActionItem: action => this.menuOptions && this.menuOptions.actionItemProvider ? this.menuOptions.actionItemProvider(action) : undefined,
getKeyBinding: action => this.menuOptions && this.menuOptions.getKeyBinding ? this.menuOptions.getKeyBinding(action) : undefined, getKeyBinding: action => this.menuOptions && this.menuOptions.getKeyBinding ? this.menuOptions.getKeyBinding(action) : undefined,
getMenuClassName: () => this.menuClassName, getMenuClassName: () => this.menuClassName,
onHide: () => this.onHide(), onHide: () => this.onHide(),
+1 -1
View File
@@ -63,7 +63,7 @@ const DefaultOptions = {
setRowLineHeight: true, setRowLineHeight: true,
supportDynamicHeights: false, supportDynamicHeights: false,
dnd: { dnd: {
getDragElements(e) { return [e]; }, getDragElements<T>(e: T) { return [e]; },
getDragURI() { return null; }, getDragURI() { return null; },
onDragStart(): void { }, onDragStart(): void { },
onDragOver() { return false; }, onDragOver() { return false; },
@@ -860,8 +860,8 @@ export class SelectBoxList implements ISelectBoxDelegate, IListVirtualDelegate<I
this.selectionDetailsPane.innerText = ''; this.selectionDetailsPane.innerText = '';
const selectedIndex = e.indexes[0]; const selectedIndex = e.indexes[0];
const description = this.options[selectedIndex].description || null; const description = this.options[selectedIndex].description;
const descriptionIsMarkdown = this.options[selectedIndex].descriptionIsMarkdown || null; const descriptionIsMarkdown = this.options[selectedIndex].descriptionIsMarkdown;
if (description) { if (description) {
if (descriptionIsMarkdown) { if (descriptionIsMarkdown) {
+2 -2
View File
@@ -75,10 +75,10 @@ export class ToolBar extends Disposable {
); );
this.toggleMenuActionItem!.setActionContext(this.actionBar.context); this.toggleMenuActionItem!.setActionContext(this.actionBar.context);
return this.toggleMenuActionItem || null; return this.toggleMenuActionItem;
} }
return options.actionItemProvider ? options.actionItemProvider(action) : null; return options.actionItemProvider ? options.actionItemProvider(action) : undefined;
} }
})); }));
} }
+3 -3
View File
@@ -805,7 +805,7 @@ class Trait<T> {
onDidModelSplice({ insertedNodes, deletedNodes }: ITreeModelSpliceEvent<T, any>): void { onDidModelSplice({ insertedNodes, deletedNodes }: ITreeModelSpliceEvent<T, any>): void {
if (!this.identityProvider) { if (!this.identityProvider) {
const set = this.createNodeSet(); const set = this.createNodeSet();
const visit = node => set.delete(node); const visit = (node: ITreeNode<T, any>) => set.delete(node);
deletedNodes.forEach(node => dfs(node, visit)); deletedNodes.forEach(node => dfs(node, visit));
this.set(values(set)); this.set(values(set));
return; return;
@@ -816,8 +816,8 @@ class Trait<T> {
this.nodes.forEach(node => nodesByIdentity.set(identityProvider.getId(node.element).toString(), node)); this.nodes.forEach(node => nodesByIdentity.set(identityProvider.getId(node.element).toString(), node));
const toDeleteByIdentity = new Map<string, ITreeNode<T, any>>(); const toDeleteByIdentity = new Map<string, ITreeNode<T, any>>();
const toRemoveSetter = node => toDeleteByIdentity.set(identityProvider.getId(node.element).toString(), node); const toRemoveSetter = (node: ITreeNode<T, any>) => toDeleteByIdentity.set(identityProvider.getId(node.element).toString(), node);
const toRemoveDeleter = node => toDeleteByIdentity.delete(identityProvider.getId(node.element).toString()); const toRemoveDeleter = (node: { element: T; }) => toDeleteByIdentity.delete(identityProvider.getId(node.element).toString());
deletedNodes.forEach(node => dfs(node, toRemoveSetter)); deletedNodes.forEach(node => dfs(node, toRemoveSetter));
insertedNodes.forEach(node => dfs(node, toRemoveDeleter)); insertedNodes.forEach(node => dfs(node, toRemoveDeleter));
+36 -38
View File
@@ -16,6 +16,7 @@ import { IDragAndDropData } from 'vs/base/browser/dnd';
import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView'; import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView';
import { isPromiseCanceledError, onUnexpectedError } from 'vs/base/common/errors'; import { isPromiseCanceledError, onUnexpectedError } from 'vs/base/common/errors';
import { toggleClass } from 'vs/base/browser/dom'; import { toggleClass } from 'vs/base/browser/dom';
import { values } from 'vs/base/common/map';
interface IAsyncDataTreeNode<TInput, T> { interface IAsyncDataTreeNode<TInput, T> {
element: TInput | T; element: TInput | T;
@@ -26,7 +27,6 @@ interface IAsyncDataTreeNode<TInput, T> {
hasChildren: boolean; hasChildren: boolean;
stale: boolean; stale: boolean;
slow: boolean; slow: boolean;
disposed: boolean;
} }
interface IAsyncDataTreeNodeRequiredProps<TInput, T> extends Partial<IAsyncDataTreeNode<TInput, T>> { interface IAsyncDataTreeNodeRequiredProps<TInput, T> extends Partial<IAsyncDataTreeNode<TInput, T>> {
@@ -41,7 +41,6 @@ function createAsyncDataTreeNode<TInput, T>(props: IAsyncDataTreeNodeRequiredPro
children: [], children: [],
loading: false, loading: false,
stale: true, stale: true,
disposed: false,
slow: false slow: false
}; };
} }
@@ -274,6 +273,11 @@ interface IAsyncDataTreeViewStateContext<TInput, T> {
readonly focus: IAsyncDataTreeNode<TInput, T>[]; readonly focus: IAsyncDataTreeNode<TInput, T>[];
} }
function dfs<TInput, T>(node: IAsyncDataTreeNode<TInput, T>, fn: (node: IAsyncDataTreeNode<TInput, T>) => void): void {
fn(node);
node.children.forEach(child => dfs(child, fn));
}
export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable { export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable {
private readonly tree: ObjectTree<IAsyncDataTreeNode<TInput, T>, TFilterData>; private readonly tree: ObjectTree<IAsyncDataTreeNode<TInput, T>, TFilterData>;
@@ -629,11 +633,6 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
} }
private async refreshNode(node: IAsyncDataTreeNode<TInput, T>, recursive: boolean, viewStateContext?: IAsyncDataTreeViewStateContext<TInput, T>): Promise<void> { private async refreshNode(node: IAsyncDataTreeNode<TInput, T>, recursive: boolean, viewStateContext?: IAsyncDataTreeViewStateContext<TInput, T>): Promise<void> {
if (node.disposed) {
console.error('Async data tree node is disposed');
return;
}
let result: Promise<void> | undefined; let result: Promise<void> | undefined;
this.subTreeRefreshPromises.forEach((refreshPromise, refreshNode) => { this.subTreeRefreshPromises.forEach((refreshPromise, refreshNode) => {
@@ -748,38 +747,48 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
return []; return [];
} }
let nodeChildren: Map<string, IAsyncDataTreeNode<TInput, T>> | undefined; const nodesToForget = new Map<T, IAsyncDataTreeNode<TInput, T>>();
const childrenTreeNodesById = new Map<string, ITreeNode<IAsyncDataTreeNode<TInput, T> | null, TFilterData>>();
if (this.identityProvider) {
nodeChildren = new Map();
for (const child of node.children) { for (const child of node.children) {
nodeChildren.set(child.id!, child); nodesToForget.set(child.element as T, child);
if (this.identityProvider) {
childrenTreeNodesById.set(child.id!, this.tree.getNode(child));
} }
} }
let childrenToRefresh: IAsyncDataTreeNode<TInput, T>[] = []; const childrenToRefresh: IAsyncDataTreeNode<TInput, T>[] = [];
const children = childrenElements.map<IAsyncDataTreeNode<TInput, T>>(element => { const children = childrenElements.map<IAsyncDataTreeNode<TInput, T>>(element => {
if (!this.identityProvider) { if (!this.identityProvider) {
return createAsyncDataTreeNode({ return createAsyncDataTreeNode({
element, element,
parent: node, parent: node,
hasChildren: !!this.dataSource.hasChildren(element), hasChildren: !!this.dataSource.hasChildren(element)
}); });
} }
const id = this.identityProvider.getId(element).toString(); const id = this.identityProvider.getId(element).toString();
const asyncDataTreeNode = nodeChildren!.get(id); const childNode = childrenTreeNodesById.get(id);
if (childNode) {
const asyncDataTreeNode = childNode.element!;
nodesToForget.delete(asyncDataTreeNode.element as T);
this.nodes.delete(asyncDataTreeNode.element as T);
this.nodes.set(element, asyncDataTreeNode);
if (asyncDataTreeNode) {
asyncDataTreeNode.element = element; asyncDataTreeNode.element = element;
asyncDataTreeNode.stale = asyncDataTreeNode.stale || recursive;
asyncDataTreeNode.hasChildren = !!this.dataSource.hasChildren(element); asyncDataTreeNode.hasChildren = !!this.dataSource.hasChildren(element);
if (recursive && !this.tree.isCollapsed(asyncDataTreeNode)) { if (recursive) {
if (childNode.collapsed) {
dfs(asyncDataTreeNode, node => node.stale = true);
} else {
childrenToRefresh.push(asyncDataTreeNode); childrenToRefresh.push(asyncDataTreeNode);
} }
}
return asyncDataTreeNode; return asyncDataTreeNode;
} }
@@ -806,33 +815,22 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
return childAsyncDataTreeNode; return childAsyncDataTreeNode;
}); });
for (const node of values(nodesToForget)) {
dfs(node, node => this.nodes.delete(node.element as T));
}
for (const child of children) {
this.nodes.set(child.element as T, child);
}
node.children.splice(0, node.children.length, ...children); node.children.splice(0, node.children.length, ...children);
return childrenToRefresh; return childrenToRefresh;
} }
private render(node: IAsyncDataTreeNode<TInput, T>, viewStateContext?: IAsyncDataTreeViewStateContext<TInput, T>): void { private render(node: IAsyncDataTreeNode<TInput, T>, viewStateContext?: IAsyncDataTreeViewStateContext<TInput, T>): void {
const insertedElements = new Set<T>();
const onDidCreateNode = (treeNode: ITreeNode<IAsyncDataTreeNode<TInput, T>, TFilterData>) => {
if (treeNode.element.element) {
insertedElements.add(treeNode.element.element as T);
this.nodes.set(treeNode.element.element as T, treeNode.element);
}
};
const onDidDeleteNode = (treeNode: ITreeNode<IAsyncDataTreeNode<TInput, T>, TFilterData>) => {
if (treeNode.element.element) {
if (!insertedElements.has(treeNode.element.element as T)) {
treeNode.element.disposed = true;
this.nodes.delete(treeNode.element.element as T);
}
}
};
const children = node.children.map(c => asTreeElement(c, viewStateContext)); const children = node.children.map(c => asTreeElement(c, viewStateContext));
this.tree.setChildren(node === this.root ? null : node, children, onDidCreateNode, onDidDeleteNode); this.tree.setChildren(node === this.root ? null : node, children);
this._onDidRender.fire(); this._onDidRender.fire();
} }
+11 -2
View File
@@ -198,8 +198,17 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
} }
getNode(element: T | null = null): ITreeNode<T | null, TFilterData> { getNode(element: T | null = null): ITreeNode<T | null, TFilterData> {
const location = this.getElementLocation(element); if (element === null) {
return this.model.getNode(location); return this.model.getNode(this.model.rootRef);
}
const node = this.nodes.get(element);
if (!node) {
throw new Error(`Tree element not found: ${element}`);
}
return node;
} }
getNodeLocation(node: ITreeNode<T, TFilterData>): T { getNodeLocation(node: ITreeNode<T, TFilterData>): T {
+2 -3
View File
@@ -404,9 +404,8 @@ export function firstIndex<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean)
} }
export function first<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean, notFoundValue: T): T; export function first<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean, notFoundValue: T): T;
export function first<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean): T | null; export function first<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean): T | undefined;
export function first<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean, notFoundValue: T | null): T | null; export function first<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean, notFoundValue: T | undefined = undefined): T | undefined {
export function first<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean, notFoundValue: T | null = null): T | null {
const index = firstIndex(array, fn); const index = firstIndex(array, fn);
return index < 0 ? notFoundValue : array[index]; return index < 0 ? notFoundValue : array[index];
} }
+6 -6
View File
@@ -178,7 +178,7 @@ export class Delayer<T> implements IDisposable {
private timeout: any; private timeout: any;
private completionPromise: Promise<any> | null; private completionPromise: Promise<any> | null;
private doResolve: ((value?: any | Promise<any>) => void) | null; private doResolve: ((value?: any | Promise<any>) => void) | null;
private doReject: (err: any) => void; private doReject?: (err: any) => void;
private task: ITask<T | Promise<T>> | null; private task: ITask<T | Promise<T>> | null;
constructor(public defaultDelay: number) { constructor(public defaultDelay: number) {
@@ -222,7 +222,7 @@ export class Delayer<T> implements IDisposable {
this.cancelTimeout(); this.cancelTimeout();
if (this.completionPromise) { if (this.completionPromise) {
this.doReject(errors.canceled()); this.doReject!(errors.canceled());
this.completionPromise = null; this.completionPromise = null;
} }
} }
@@ -282,7 +282,7 @@ export class Barrier {
private _isOpen: boolean; private _isOpen: boolean;
private _promise: Promise<boolean>; private _promise: Promise<boolean>;
private _completePromise: (v: boolean) => void; private _completePromise!: (v: boolean) => void;
constructor() { constructor() {
this._isOpen = false; this._isOpen = false;
@@ -731,8 +731,8 @@ export class IdleValue<T> {
private readonly _executor: () => void; private readonly _executor: () => void;
private readonly _handle: IDisposable; private readonly _handle: IDisposable;
private _didRun: boolean; private _didRun: boolean = false;
private _value: T; private _value?: T;
private _error: any; private _error: any;
constructor(executor: () => T) { constructor(executor: () => T) {
@@ -760,7 +760,7 @@ export class IdleValue<T> {
if (this._error) { if (this._error) {
throw this._error; throw this._error;
} }
return this._value; return this._value!;
} }
} }
+1 -1
View File
@@ -87,7 +87,7 @@ class MutableToken implements CancellationToken {
export class CancellationTokenSource { export class CancellationTokenSource {
private _token: CancellationToken; private _token?: CancellationToken;
get token(): CancellationToken { get token(): CancellationToken {
if (!this._token) { if (!this._token) {
+2 -2
View File
@@ -260,7 +260,7 @@ export class Color {
} }
readonly rgba: RGBA; readonly rgba: RGBA;
private _hsla: HSLA; private _hsla?: HSLA;
get hsla(): HSLA { get hsla(): HSLA {
if (this._hsla) { if (this._hsla) {
return this._hsla; return this._hsla;
@@ -269,7 +269,7 @@ export class Color {
} }
} }
private _hsva: HSVA; private _hsva?: HSVA;
get hsva(): HSVA { get hsva(): HSVA {
if (this._hsva) { if (this._hsva) {
return this._hsva; return this._hsva;
+11 -1
View File
@@ -119,6 +119,15 @@ function isWhitespace(code: number): boolean {
); );
} }
const wordSeparators = new Set<number>();
'`~!@#$%^&*()-=+[{]}\\|;:\'",.<>/?'
.split('')
.forEach(s => wordSeparators.add(s.charCodeAt(0)));
function isWordSeparator(code: number): boolean {
return wordSeparators.has(code);
}
function isAlphanumeric(code: number): boolean { function isAlphanumeric(code: number): boolean {
return isLower(code) || isUpper(code) || isNumber(code); return isLower(code) || isUpper(code) || isNumber(code);
} }
@@ -308,7 +317,8 @@ function _matchesWords(word: string, target: string, i: number, j: number, conti
function nextWord(word: string, start: number): number { function nextWord(word: string, start: number): number {
for (let i = start; i < word.length; i++) { for (let i = start; i < word.length; i++) {
const c = word.charCodeAt(i); const c = word.charCodeAt(i);
if (isWhitespace(c) || (i > 0 && isWhitespace(word.charCodeAt(i - 1)))) { if (isWhitespace(c) || (i > 0 && isWhitespace(word.charCodeAt(i - 1))) ||
isWordSeparator(c) || (i > 0 && isWordSeparator(word.charCodeAt(i - 1)))) {
return i; return i;
} }
} }
+11 -12
View File
@@ -43,7 +43,7 @@ const CHAR_QUESTION_MARK = 63; /* ? */
class ErrorInvalidArgType extends Error { class ErrorInvalidArgType extends Error {
code: 'ERR_INVALID_ARG_TYPE'; code: 'ERR_INVALID_ARG_TYPE';
constructor(name: string, expected: string, actual: string) { constructor(name: string, expected: string, actual: any) {
// determiner: 'must be' or 'must not be' // determiner: 'must be' or 'must not be'
let determiner; let determiner;
if (typeof expected === 'string' && expected.indexOf('not ') === 0) { if (typeof expected === 'string' && expected.indexOf('not ') === 0) {
@@ -53,36 +53,35 @@ class ErrorInvalidArgType extends Error {
determiner = 'must be'; determiner = 'must be';
} }
let msg;
const type = name.indexOf('.') !== -1 ? 'property' : 'argument'; const type = name.indexOf('.') !== -1 ? 'property' : 'argument';
msg = `The "${name}" ${type} ${determiner} of type ${expected}`; let msg = `The "${name}" ${type} ${determiner} of type ${expected}`;
msg += `. Received type ${typeof actual}`; msg += `. Received type ${typeof actual}`;
super(msg); super(msg);
} }
} }
function validateString(value: string, name) { function validateString(value: string, name: string) {
if (typeof value !== 'string') { if (typeof value !== 'string') {
throw new ErrorInvalidArgType(name, 'string', value); throw new ErrorInvalidArgType(name, 'string', value);
} }
} }
function isPathSeparator(code) { function isPathSeparator(code: number) {
return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
} }
function isPosixPathSeparator(code) { function isPosixPathSeparator(code: number) {
return code === CHAR_FORWARD_SLASH; return code === CHAR_FORWARD_SLASH;
} }
function isWindowsDeviceRoot(code) { function isWindowsDeviceRoot(code: number) {
return code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z || return code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z ||
code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z; code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z;
} }
// Resolves . and .. elements in a path with directory names // Resolves . and .. elements in a path with directory names
function normalizeString(path, allowAboveRoot, separator, isPathSeparator) { function normalizeString(path: string, allowAboveRoot: boolean, separator: string, isPathSeparator: (code?: number) => boolean) {
let res = ''; let res = '';
let lastSegmentLength = 0; let lastSegmentLength = 0;
let lastSlash = -1; let lastSlash = -1;
@@ -155,7 +154,7 @@ function normalizeString(path, allowAboveRoot, separator, isPathSeparator) {
return res; return res;
} }
function _format(sep, pathObject) { function _format(sep: string, pathObject: ParsedPath) {
const dir = pathObject.dir || pathObject.root; const dir = pathObject.dir || pathObject.root;
const base = pathObject.base || const base = pathObject.base ||
((pathObject.name || '') + (pathObject.ext || '')); ((pathObject.name || '') + (pathObject.ext || ''));
@@ -185,7 +184,7 @@ interface IPath {
dirname(path: string): string; dirname(path: string): string;
basename(path: string, ext?: string): string; basename(path: string, ext?: string): string;
extname(path: string): string; extname(path: string): string;
format(pathObject): string; format(pathObject: ParsedPath): string;
parse(path: string): ParsedPath; parse(path: string): ParsedPath;
toNamespacedPath(path: string): string; toNamespacedPath(path: string): string;
sep: '\\' | '/'; sep: '\\' | '/';
@@ -501,7 +500,7 @@ export const win32: IPath = {
} }
let joined; let joined;
let firstPart; let firstPart: string | undefined;
for (let i = 0; i < paths.length; ++i) { for (let i = 0; i < paths.length; ++i) {
const arg = paths[i]; const arg = paths[i];
validateString(arg, 'path'); validateString(arg, 'path');
@@ -534,7 +533,7 @@ export const win32: IPath = {
// path.join('//server', 'share') -> '\\\\server\\share\\') // path.join('//server', 'share') -> '\\\\server\\share\\')
let needsReplace = true; let needsReplace = true;
let slashCount = 0; let slashCount = 0;
if (isPathSeparator(firstPart.charCodeAt(0))) { if (typeof firstPart === 'string' && isPathSeparator(firstPart.charCodeAt(0))) {
++slashCount; ++slashCount;
const firstLen = firstPart.length; const firstLen = firstPart.length;
if (firstLen > 1) { if (firstLen > 1) {
+2 -2
View File
@@ -377,8 +377,8 @@ export class SmoothScrollingOperation {
private readonly _startTime: number; private readonly _startTime: number;
public animationFrameDisposable: IDisposable | null; public animationFrameDisposable: IDisposable | null;
private scrollLeft: IAnimation; private scrollLeft!: IAnimation;
private scrollTop: IAnimation; private scrollTop!: IAnimation;
protected constructor(from: ISmoothScrollPosition, to: ISmoothScrollPosition, startTime: number, duration: number) { protected constructor(from: ISmoothScrollPosition, to: ISmoothScrollPosition, startTime: number, duration: number) {
this.from = from; this.from = from;
+1 -1
View File
@@ -174,7 +174,7 @@ export function create(ctor: Function, ...args: any[]): any {
} }
// https://stackoverflow.com/a/32235645/1499159 // https://stackoverflow.com/a/32235645/1499159
function isNativeClass(thing): boolean { function isNativeClass(thing: any): boolean {
return typeof thing === 'function' return typeof thing === 'function'
&& thing.hasOwnProperty('prototype') && thing.hasOwnProperty('prototype')
&& !thing.hasOwnProperty('arguments'); && !thing.hasOwnProperty('arguments');
+2 -2
View File
@@ -20,8 +20,8 @@ import { TernarySearchTree } from 'vs/base/common/map';
// Sun xVM VirtualBox 08-00-27 // Sun xVM VirtualBox 08-00-27
export const virtualMachineHint: { value(): number } = new class { export const virtualMachineHint: { value(): number } = new class {
private _virtualMachineOUIs: TernarySearchTree<boolean>; private _virtualMachineOUIs?: TernarySearchTree<boolean>;
private _value: number; private _value?: number;
private _isVirtualMachineMacAdress(mac: string): boolean { private _isVirtualMachineMacAdress(mac: string): boolean {
if (!this._virtualMachineOUIs) { if (!this._virtualMachineOUIs) {
+4
View File
@@ -59,6 +59,10 @@ export function lstat(path: string): Promise<fs.Stats> {
return nfcall(fs.lstat, path); return nfcall(fs.lstat, path);
} }
export function move(oldPath: string, newPath: string): Promise<void> {
return nfcall(extfs.mv, oldPath, newPath);
}
export function rename(oldPath: string, newPath: string): Promise<void> { export function rename(oldPath: string, newPath: string): Promise<void> {
return nfcall(fs.rename, oldPath, newPath); return nfcall(fs.rename, oldPath, newPath);
} }
@@ -9,7 +9,7 @@ import { URI } from 'vs/base/common/uri';
import { ITree, IActionProvider } from 'vs/base/parts/tree/browser/tree'; import { ITree, IActionProvider } from 'vs/base/parts/tree/browser/tree';
import { IconLabel, IIconLabelValueOptions } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { IconLabel, IIconLabelValueOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';
import { IQuickNavigateConfiguration, IModel, IDataSource, IFilter, IAccessiblityProvider, IRenderer, IRunner, Mode, IEntryRunContext } from 'vs/base/parts/quickopen/common/quickOpen'; import { IQuickNavigateConfiguration, IModel, IDataSource, IFilter, IAccessiblityProvider, IRenderer, IRunner, Mode, IEntryRunContext } from 'vs/base/parts/quickopen/common/quickOpen';
import { Action, IAction, IActionRunner, IActionItem } from 'vs/base/common/actions'; import { IAction, IActionRunner } from 'vs/base/common/actions';
import { compareAnything } from 'vs/base/common/comparers'; import { compareAnything } from 'vs/base/common/comparers';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
@@ -291,18 +291,6 @@ class NoActionProvider implements IActionProvider {
getActions(tree: ITree, element: any): IAction[] | null { getActions(tree: ITree, element: any): IAction[] | null {
return null; return null;
} }
hasSecondaryActions(tree: ITree, element: any): boolean {
return false;
}
getSecondaryActions(tree: ITree, element: any): IAction[] | null {
return null;
}
getActionItem(tree: ITree, element: any, action: Action): IActionItem | null {
return null;
}
} }
export interface IQuickOpenEntryTemplateData { export interface IQuickOpenEntryTemplateData {
+9 -91
View File
@@ -9,7 +9,7 @@ import * as Keyboard from 'vs/base/browser/keyboardEvent';
import { INavigator } from 'vs/base/common/iterator'; import { INavigator } from 'vs/base/common/iterator';
import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import { ScrollbarVisibility } from 'vs/base/common/scrollable';
import { Event } from 'vs/base/common/event'; import { Event } from 'vs/base/common/event';
import { IAction, IActionItem } from 'vs/base/common/actions'; import { IAction } from 'vs/base/common/actions';
import { Color } from 'vs/base/common/color'; import { Color } from 'vs/base/common/color';
import { IItemCollapseEvent, IItemExpandEvent } from 'vs/base/parts/tree/browser/treeModel'; import { IItemCollapseEvent, IItemExpandEvent } from 'vs/base/parts/tree/browser/treeModel';
import { IDragAndDropData } from 'vs/base/browser/dnd'; import { IDragAndDropData } from 'vs/base/browser/dnd';
@@ -169,81 +169,21 @@ export interface ITree {
*/ */
getHighlight(includeHidden?: boolean): any; getHighlight(includeHidden?: boolean): any;
/**
* Returns whether an element is highlighted or not.
*/
isHighlighted(element: any): boolean;
/** /**
* Clears the highlight. * Clears the highlight.
*/ */
clearHighlight(eventPayload?: any): void; clearHighlight(eventPayload?: any): void;
/**
* Selects an element.
*/
select(element: any, eventPayload?: any): void;
/**
* Selects a range of elements.
*/
selectRange(fromElement: any, toElement: any, eventPayload?: any): void;
/**
* Deselects a range of elements.
*/
deselectRange(fromElement: any, toElement: any, eventPayload?: any): void;
/**
* Selects several elements.
*/
selectAll(elements: any[], eventPayload?: any): void;
/**
* Deselects an element.
*/
deselect(element: any, eventPayload?: any): void;
/**
* Deselects several elements.
*/
deselectAll(elements: any[], eventPayload?: any): void;
/** /**
* Replaces the current selection with the given elements. * Replaces the current selection with the given elements.
*/ */
setSelection(elements: any[], eventPayload?: any): void; setSelection(elements: any[], eventPayload?: any): void;
/**
* Toggles the element's selection.
*/
toggleSelection(element: any, eventPayload?: any): void;
/** /**
* Returns the currently selected elements. * Returns the currently selected elements.
*/ */
getSelection(includeHidden?: boolean): any[]; getSelection(includeHidden?: boolean): any[];
/**
* Returns whether an element is selected or not.
*/
isSelected(element: any): boolean;
/**
* Selects the next `count`-nth element, in visible order.
*/
selectNext(count?: number, clearSelection?: boolean, eventPayload?: any): void;
/**
* Selects the previous `count`-nth element, in visible order.
*/
selectPrevious(count?: number, clearSelection?: boolean, eventPayload?: any): void;
/**
* Selects the currently selected element's parent.
*/
selectParent(clearSelection?: boolean, eventPayload?: any): void;
/** /**
* Clears the selection. * Clears the selection.
*/ */
@@ -254,11 +194,6 @@ export interface ITree {
*/ */
setFocus(element?: any, eventPayload?: any): void; setFocus(element?: any, eventPayload?: any): void;
/**
* Returns whether an element is focused or not.
*/
isFocused(element: any): boolean;
/** /**
* Returns focused element. * Returns focused element.
*/ */
@@ -316,6 +251,7 @@ export interface ITree {
*/ */
clearFocus(eventPayload?: any): void; clearFocus(eventPayload?: any): void;
// {{SQL CARBON EDIT}} @todo anthonydresser we need to refactor our code to not need these methods
/** /**
* Adds the trait to elements. * Adds the trait to elements.
*/ */
@@ -327,14 +263,15 @@ export interface ITree {
removeTraits(trait: string, elements: any[]): void; removeTraits(trait: string, elements: any[]): void;
/** /**
* Toggles the element's trait. * Selects an element.
*/ */
toggleTrait(trait: string, element: any): void; select(element: any, eventPayload?: any): void;
/** /**
* Returns whether the element has the trait or not. * Deselects an element.
*/ */
hasTrait(trait: string, element: any): boolean; deselect(element: any, eventPayload?: any): void;
// {{SQL CARBON EDIT}} END
/** /**
* Returns a navigator which allows to discover the visible and * Returns a navigator which allows to discover the visible and
@@ -582,12 +519,14 @@ export interface IDragOverReaction {
autoExpand?: boolean; autoExpand?: boolean;
} }
// {{SQL CARBON EDIT}} @todo anthonydresser refactor to not need this
export const DRAG_OVER_REJECT: IDragOverReaction = { accept: false }; export const DRAG_OVER_REJECT: IDragOverReaction = { accept: false };
export const DRAG_OVER_ACCEPT: IDragOverReaction = { accept: true }; export const DRAG_OVER_ACCEPT: IDragOverReaction = { accept: true };
export const DRAG_OVER_ACCEPT_BUBBLE_UP: IDragOverReaction = { accept: true, bubble: DragOverBubble.BUBBLE_UP }; export const DRAG_OVER_ACCEPT_BUBBLE_UP: IDragOverReaction = { accept: true, bubble: DragOverBubble.BUBBLE_UP };
export const DRAG_OVER_ACCEPT_BUBBLE_DOWN = (autoExpand = false) => ({ accept: true, bubble: DragOverBubble.BUBBLE_DOWN, autoExpand }); export const DRAG_OVER_ACCEPT_BUBBLE_DOWN = (autoExpand = false) => ({ accept: true, bubble: DragOverBubble.BUBBLE_DOWN, autoExpand });
export const DRAG_OVER_ACCEPT_BUBBLE_UP_COPY: IDragOverReaction = { accept: true, bubble: DragOverBubble.BUBBLE_UP, effect: DragOverEffect.COPY }; export const DRAG_OVER_ACCEPT_BUBBLE_UP_COPY: IDragOverReaction = { accept: true, bubble: DragOverBubble.BUBBLE_UP, effect: DragOverEffect.COPY };
export const DRAG_OVER_ACCEPT_BUBBLE_DOWN_COPY = (autoExpand = false) => ({ accept: true, bubble: DragOverBubble.BUBBLE_DOWN, effect: DragOverEffect.COPY, autoExpand }); export const DRAG_OVER_ACCEPT_BUBBLE_DOWN_COPY = (autoExpand = false) => ({ accept: true, bubble: DragOverBubble.BUBBLE_DOWN, effect: DragOverEffect.COPY, autoExpand });
// {{SQL CARBON EDIT}} END
export interface IDragAndDrop { export interface IDragAndDrop {
@@ -635,12 +574,6 @@ export interface IFilter {
isVisible(tree: ITree, element: any): boolean; isVisible(tree: ITree, element: any): boolean;
} }
export interface IElementCallback {
(tree: ITree, element: any): void;
}
export type ICallback = () => void;
export interface ISorter { export interface ISorter {
/** /**
@@ -730,19 +663,4 @@ export interface IActionProvider {
* Returns a promise of an array with the actions of the element that should show up in place right to the element in the tree. * Returns a promise of an array with the actions of the element that should show up in place right to the element in the tree.
*/ */
getActions(tree: ITree | null, element: any): IAction[] | null; getActions(tree: ITree | null, element: any): IAction[] | null;
/**
* Returns whether or not the element has secondary actions. These show up once the user has expanded the element's action bar.
*/
hasSecondaryActions(tree: ITree, element: any): boolean;
/**
* Returns a promise of an array with the secondary actions of the element that should show up once the user has expanded the element's action bar.
*/
getSecondaryActions(tree: ITree, element: any): IAction[] | null;
/**
* Returns an action item to render an action.
*/
getActionItem(tree: ITree, element: any, action: IAction): IActionItem | null;
} }
+6 -57
View File
@@ -230,50 +230,14 @@ export class Tree implements _.ITree {
return this.model.getHighlight(); return this.model.getHighlight();
} }
public isHighlighted(element: any): boolean {
return this.model.isFocused(element);
}
public clearHighlight(eventPayload?: any): void { public clearHighlight(eventPayload?: any): void {
this.model.setHighlight(null, eventPayload); this.model.setHighlight(null, eventPayload);
} }
public select(element: any, eventPayload?: any): void {
this.model.select(element, eventPayload);
}
public selectRange(fromElement: any, toElement: any, eventPayload?: any): void {
this.model.selectRange(fromElement, toElement, eventPayload);
}
public deselectRange(fromElement: any, toElement: any, eventPayload?: any): void {
this.model.deselectRange(fromElement, toElement, eventPayload);
}
public selectAll(elements: any[], eventPayload?: any): void {
this.model.selectAll(elements, eventPayload);
}
public deselect(element: any, eventPayload?: any): void {
this.model.deselect(element, eventPayload);
}
public deselectAll(elements: any[], eventPayload?: any): void {
this.model.deselectAll(elements, eventPayload);
}
public setSelection(elements: any[], eventPayload?: any): void { public setSelection(elements: any[], eventPayload?: any): void {
this.model.setSelection(elements, eventPayload); this.model.setSelection(elements, eventPayload);
} }
public toggleSelection(element: any, eventPayload?: any): void {
this.model.toggleSelection(element, eventPayload);
}
public isSelected(element: any): boolean {
return this.model.isSelected(element);
}
public getSelection(): any[] { public getSelection(): any[] {
return this.model.getSelection(); return this.model.getSelection();
} }
@@ -282,26 +246,10 @@ export class Tree implements _.ITree {
this.model.setSelection([], eventPayload); this.model.setSelection([], eventPayload);
} }
public selectNext(count?: number, clearSelection?: boolean, eventPayload?: any): void {
this.model.selectNext(count, clearSelection, eventPayload);
}
public selectPrevious(count?: number, clearSelection?: boolean, eventPayload?: any): void {
this.model.selectPrevious(count, clearSelection, eventPayload);
}
public selectParent(clearSelection?: boolean, eventPayload?: any): void {
this.model.selectParent(clearSelection, eventPayload);
}
public setFocus(element?: any, eventPayload?: any): void { public setFocus(element?: any, eventPayload?: any): void {
this.model.setFocus(element, eventPayload); this.model.setFocus(element, eventPayload);
} }
public isFocused(element: any): boolean {
return this.model.isFocused(element);
}
public getFocus(): any { public getFocus(): any {
return this.model.getFocus(); return this.model.getFocus();
} }
@@ -346,6 +294,7 @@ export class Tree implements _.ITree {
this.model.setFocus(null, eventPayload); this.model.setFocus(null, eventPayload);
} }
// {{SQL CARBON EDIT}} @todo anthonydresser we need to refactor our code to not need these methods
public addTraits(trait: string, elements: any[]): void { public addTraits(trait: string, elements: any[]): void {
this.model.addTraits(trait, elements); this.model.addTraits(trait, elements);
} }
@@ -354,14 +303,14 @@ export class Tree implements _.ITree {
this.model.removeTraits(trait, elements); this.model.removeTraits(trait, elements);
} }
public toggleTrait(trait: string, element: any): void { public select(element: any, eventPayload?: any): void {
this.model.hasTrait(trait, element) ? this.model.removeTraits(trait, [element]) this.model.select(element, eventPayload);
: this.model.addTraits(trait, [element]);
} }
public hasTrait(trait: string, element: any): boolean { public deselect(element: any, eventPayload?: any): void {
return this.model.hasTrait(trait, element); this.model.deselect(element, eventPayload);
} }
// {{SQL CARBON EDIT}} end
getNavigator(fromElement?: any, subTreeOnly?: boolean): INavigator<any> { getNavigator(fromElement?: any, subTreeOnly?: boolean): INavigator<any> {
return new MappedNavigator(this.model.getNavigator(fromElement, subTreeOnly), i => i && i.getElement()); return new MappedNavigator(this.model.getNavigator(fromElement, subTreeOnly), i => i && i.getElement());
@@ -6,7 +6,6 @@
import * as Assert from 'vs/base/common/assert'; import * as Assert from 'vs/base/common/assert';
import { onUnexpectedError } from 'vs/base/common/errors'; import { onUnexpectedError } from 'vs/base/common/errors';
import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
import * as arrays from 'vs/base/common/arrays';
import { INavigator } from 'vs/base/common/iterator'; import { INavigator } from 'vs/base/common/iterator';
import * as _ from './tree'; import * as _ from './tree';
import { Event, Emitter, EventMultiplexer, Relay } from 'vs/base/common/event'; import { Event, Emitter, EventMultiplexer, Relay } from 'vs/base/common/event';
@@ -872,42 +871,6 @@ export class TreeNavigator implements INavigator<Item> {
} }
} }
function getRange(one: Item, other: Item): Item[] {
let oneHierarchy = one.getHierarchy();
let otherHierarchy = other.getHierarchy();
let length = arrays.commonPrefixLength(oneHierarchy, otherHierarchy);
let item: Item | null = oneHierarchy[length - 1];
let nav = item.getNavigator();
let oneIndex: number | null = null;
let otherIndex: number | null = null;
let index = 0;
let result: Item[] = [];
while (item && (oneIndex === null || otherIndex === null)) {
result.push(item);
if (item === one) {
oneIndex = index;
}
if (item === other) {
otherIndex = index;
}
index++;
item = nav.next();
}
if (oneIndex === null || otherIndex === null) {
return [];
}
let min = Math.min(oneIndex, otherIndex);
let max = Math.max(oneIndex, otherIndex);
return result.slice(min, max + 1);
}
export interface IBaseEvent { export interface IBaseEvent {
item: Item | null; item: Item | null;
} }
@@ -1205,28 +1168,6 @@ export class TreeModel {
this.selectAll([element], eventPayload); this.selectAll([element], eventPayload);
} }
public selectRange(fromElement: any, toElement: any, eventPayload?: any): void {
let fromItem = this.getItem(fromElement);
let toItem = this.getItem(toElement);
if (!fromItem || !toItem) {
return;
}
this.selectAll(getRange(fromItem, toItem), eventPayload);
}
public deselectRange(fromElement: any, toElement: any, eventPayload?: any): void {
let fromItem = this.getItem(fromElement);
let toItem = this.getItem(toElement);
if (!fromItem || !toItem) {
return;
}
this.deselectAll(getRange(fromItem, toItem), eventPayload);
}
public selectAll(elements: any[], eventPayload?: any): void { public selectAll(elements: any[], eventPayload?: any): void {
this.addTraits('selected', elements); this.addTraits('selected', elements);
let eventData: _.ISelectionEvent = { selection: this.getSelection(), payload: eventPayload }; let eventData: _.ISelectionEvent = { selection: this.getSelection(), payload: eventPayload };
@@ -1249,12 +1190,6 @@ export class TreeModel {
this._onDidSelect.fire(eventData); this._onDidSelect.fire(eventData);
} }
public toggleSelection(element: any, eventPayload?: any): void {
this.toggleTrait('selected', element);
let eventData: _.ISelectionEvent = { selection: this.getSelection(), payload: eventPayload };
this._onDidSelect.fire(eventData);
}
public isSelected(element: any): boolean { public isSelected(element: any): boolean {
let item = this.getItem(element); let item = this.getItem(element);
@@ -1324,21 +1259,6 @@ export class TreeModel {
} }
} }
public selectParent(eventPayload?: any, clearSelection: boolean = true): void {
let selection = this.getSelection();
let item: Item = selection.length > 0 ? selection[0] : this.input;
let nav = this.getNavigator(item, false);
let parent = nav.parent();
if (parent) {
if (clearSelection) {
this.setSelection([parent], eventPayload);
} else {
this.select(parent, eventPayload);
}
}
}
public setFocus(element?: any, eventPayload?: any): void { public setFocus(element?: any, eventPayload?: any): void {
this.setTraits('focused', element ? [element] : []); this.setTraits('focused', element ? [element] : []);
let eventData: _.IFocusEvent = { focus: this.getFocus(), payload: eventPayload }; let eventData: _.IFocusEvent = { focus: this.getFocus(), payload: eventPayload };
@@ -1513,25 +1433,6 @@ export class TreeModel {
} }
} }
public hasTrait(trait: string, element: any): boolean {
const item = this.getItem(element);
return !!(item && item.hasTrait(trait));
}
private toggleTrait(trait: string, element: any): void {
let item = this.getItem(element);
if (!item) {
return;
}
if (item.hasTrait(trait)) {
this.removeTraits(trait, [element]);
} else {
this.addTraits(trait, [element]);
}
}
private setTraits(trait: string, elements: any[]): void { private setTraits(trait: string, elements: any[]): void {
if (elements.length === 0) { if (elements.length === 0) {
this.removeTraits(trait, elements); this.removeTraits(trait, elements);
@@ -161,19 +161,19 @@ const SAMPLE: any = {
}; };
class TestDataSource implements _.IDataSource { class TestDataSource implements _.IDataSource {
public getId(tree, element): string { public getId(tree: _.ITree, element: any): string {
return element.id; return element.id;
} }
public hasChildren(tree, element): boolean { public hasChildren(tree: _.ITree, element: any): boolean {
return !!element.children; return !!element.children;
} }
public getChildren(tree, element): Promise<any> { public getChildren(tree: _.ITree, element: any): Promise<any> {
return Promise.resolve(element.children); return Promise.resolve(element.children);
} }
public getParent(tree, element): Promise<any> { public getParent(tree: _.ITree, element: any): Promise<any> {
throw new Error('Not implemented'); throw new Error('Not implemented');
} }
} }
@@ -700,13 +700,13 @@ suite('TreeModel - Expansion', () => {
class TestFilter implements _.IFilter { class TestFilter implements _.IFilter {
public fn: (any) => boolean; public fn: (element: any) => boolean;
constructor() { constructor() {
this.fn = () => true; this.fn = () => true;
} }
public isVisible(tree, element): boolean { public isVisible(tree: _.ITree, element: any): boolean {
return this.fn(element); return this.fn(element);
} }
} }
@@ -1092,39 +1092,39 @@ class DynamicModel implements _.IDataSource {
this.promiseFactory = null; this.promiseFactory = null;
} }
public addChild(parent, child): void { public addChild(parent: string, child: string): void {
if (!this.data[parent]) { if (!this.data[parent]) {
this.data[parent] = []; this.data[parent] = [];
} }
this.data[parent].push(child); this.data[parent].push(child);
} }
public removeChild(parent, child): void { public removeChild(parent: string, child: string): void {
this.data[parent].splice(this.data[parent].indexOf(child), 1); this.data[parent].splice(this.data[parent].indexOf(child), 1);
if (this.data[parent].length === 0) { if (this.data[parent].length === 0) {
delete this.data[parent]; delete this.data[parent];
} }
} }
public move(element, oldParent, newParent): void { public move(element: string, oldParent: string, newParent: string): void {
this.removeChild(oldParent, element); this.removeChild(oldParent, element);
this.addChild(newParent, element); this.addChild(newParent, element);
} }
public rename(parent, oldName, newName): void { public rename(parent: string, oldName: string, newName: string): void {
this.removeChild(parent, oldName); this.removeChild(parent, oldName);
this.addChild(parent, newName); this.addChild(parent, newName);
} }
public getId(tree, element): string { public getId(tree: _.ITree, element: any): string {
return element; return element;
} }
public hasChildren(tree, element): boolean { public hasChildren(tree: _.ITree, element: any): boolean {
return !!this.data[element]; return !!this.data[element];
} }
public getChildren(tree, element): Promise<any> { public getChildren(tree: _.ITree, element: any): Promise<any> {
this._onGetChildren.fire(element); this._onGetChildren.fire(element);
const result = this.promiseFactory ? this.promiseFactory() : Promise.resolve(null); const result = this.promiseFactory ? this.promiseFactory() : Promise.resolve(null);
return result.then(() => { return result.then(() => {
@@ -1133,7 +1133,7 @@ class DynamicModel implements _.IDataSource {
}); });
} }
public getParent(tree, element): Promise<any> { public getParent(tree: _.ITree, element: any): Promise<any> {
throw new Error('Not implemented'); throw new Error('Not implemented');
} }
} }
@@ -1395,7 +1395,7 @@ suite('TreeModel - Dynamic data model', () => {
assert.equal(getTimes, 2); assert.equal(getTimes, 2);
assert.equal(gotTimes, 1); assert.equal(gotTimes, 1);
let p2Complete; let p2Complete: () => void;
dataModel.promiseFactory = () => { return new Promise((c) => { p2Complete = c; }); }; dataModel.promiseFactory = () => { return new Promise((c) => { p2Complete = c; }); };
const p2 = model.refresh('father'); const p2 = model.refresh('father');
@@ -1412,7 +1412,7 @@ suite('TreeModel - Dynamic data model', () => {
assert.equal(getTimes, 3); assert.equal(getTimes, 3);
assert.equal(gotTimes, 2); assert.equal(gotTimes, 2);
p2Complete(); p2Complete!();
// all good // all good
assert.equal(refreshTimes, 5); // (+1) second son request assert.equal(refreshTimes, 5); // (+1) second son request
@@ -7,7 +7,7 @@ import * as assert from 'assert';
import { ArrayIterator } from 'vs/base/common/iterator'; import { ArrayIterator } from 'vs/base/common/iterator';
import { HeightMap, IViewItem } from 'vs/base/parts/tree/browser/treeViewModel'; import { HeightMap, IViewItem } from 'vs/base/parts/tree/browser/treeViewModel';
function makeItem(id, height): any { function makeItem(id: any, height: any): any {
return { return {
id: id, id: id,
getHeight: function () { return height; }, getHeight: function () { return height; },
@@ -59,7 +59,7 @@ class TestView implements IView {
} }
function getSashes(splitview: SplitView): Sash[] { function getSashes(splitview: SplitView): Sash[] {
return (splitview as any).sashItems.map(i => i.sash) as Sash[]; return (splitview as any).sashItems.map((i: any) => i.sash) as Sash[];
} }
suite('Splitview', () => { suite('Splitview', () => {
+3 -3
View File
@@ -143,12 +143,12 @@ suite('Paths (Node Implementation)', () => {
] ]
) )
]); ]);
joinTests.forEach((test) => { joinTests.forEach((test: any[]) => {
if (!Array.isArray(test[0])) { if (!Array.isArray(test[0])) {
test[0] = [test[0]]; test[0] = [test[0]];
} }
test[0].forEach((join) => { test[0].forEach((join: any) => {
test[1].forEach((test) => { test[1].forEach((test: any) => {
const actual = join.apply(null, test[0]); const actual = join.apply(null, test[0]);
const expected = test[1]; const expected = test[1];
// For non-Windows specific tests with the Windows join(), we need to try // For non-Windows specific tests with the Windows join(), we need to try
+7 -7
View File
@@ -176,14 +176,14 @@ suite('Types', () => {
types.validateConstraints([undefined], [types.isUndefined]); types.validateConstraints([undefined], [types.isUndefined]);
types.validateConstraints([1], [types.isNumber]); types.validateConstraints([1], [types.isNumber]);
function foo() { } class Foo { }
types.validateConstraints([new foo()], [foo]); types.validateConstraints([new Foo()], [Foo]);
function isFoo(f) { } function isFoo(f: any) { }
assert.throws(() => types.validateConstraints([new foo()], [isFoo])); assert.throws(() => types.validateConstraints([new Foo()], [isFoo]));
function isFoo2(f) { return true; } function isFoo2(f: any) { return true; }
types.validateConstraints([new foo()], [isFoo2]); types.validateConstraints([new Foo()], [isFoo2]);
assert.throws(() => types.validateConstraints([1, true], [types.isNumber, types.isString])); assert.throws(() => types.validateConstraints([1, true], [types.isNumber, types.isString]));
assert.throws(() => types.validateConstraints(['2'], [types.isNumber])); assert.throws(() => types.validateConstraints(['2'], [types.isNumber]));
@@ -196,7 +196,7 @@ suite('Types', () => {
assert(types.create(zeroConstructor) instanceof zeroConstructor); assert(types.create(zeroConstructor) instanceof zeroConstructor);
assert(types.isObject(types.create(zeroConstructor))); assert(types.isObject(types.create(zeroConstructor)));
let manyArgConstructor = function (this: any, foo, bar) { let manyArgConstructor = function (this: any, foo: any, bar: any) {
this.foo = foo; this.foo = foo;
this.bar = bar; this.bar = bar;
}; };
@@ -132,13 +132,13 @@ suite('Encoding', () => {
assert.equal(mimes.encoding, 'windows1252'); assert.equal(mimes.encoding, 'windows1252');
}); });
async function readAndDecodeFromDisk(path, _encoding) { async function readAndDecodeFromDisk(path: string, fileEncoding: string | null) {
return new Promise<string>((resolve, reject) => { return new Promise<string>((resolve, reject) => {
fs.readFile(path, (err, data) => { fs.readFile(path, (err, data) => {
if (err) { if (err) {
reject(err); reject(err);
} else { } else {
resolve(encoding.decode(data, _encoding)); resolve(encoding.decode(data, fileEncoding!));
} }
}); });
}); });
+1 -1
View File
@@ -17,7 +17,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation';
const ignore = () => { }; const ignore = () => { };
const mkdirp = (path: string, mode: number, callback: (error) => void) => { const mkdirp = (path: string, mode: number, callback: (error: any) => void) => {
extfs.mkdirp(path, mode).then(() => callback(null), error => callback(error)); extfs.mkdirp(path, mode).then(() => callback(null), error => callback(error));
}; };
+6 -6
View File
@@ -431,7 +431,7 @@ suite('Glob', () => {
test('expression support (single)', function () { test('expression support (single)', function () {
let siblings = ['test.html', 'test.txt', 'test.ts', 'test.js']; let siblings = ['test.html', 'test.txt', 'test.ts', 'test.js'];
let hasSibling = name => siblings.indexOf(name) !== -1; let hasSibling = (name: string) => siblings.indexOf(name) !== -1;
// { "**/*.js": { "when": "$(basename).ts" } } // { "**/*.js": { "when": "$(basename).ts" } }
let expression: glob.IExpression = { let expression: glob.IExpression = {
@@ -467,7 +467,7 @@ suite('Glob', () => {
test('expression support (multiple)', function () { test('expression support (multiple)', function () {
let siblings = ['test.html', 'test.txt', 'test.ts', 'test.js']; let siblings = ['test.html', 'test.txt', 'test.ts', 'test.js'];
let hasSibling = name => siblings.indexOf(name) !== -1; let hasSibling = (name: string) => siblings.indexOf(name) !== -1;
// { "**/*.js": { "when": "$(basename).ts" } } // { "**/*.js": { "when": "$(basename).ts" } }
let expression: glob.IExpression = { let expression: glob.IExpression = {
@@ -717,7 +717,7 @@ suite('Glob', () => {
}; };
let siblings = ['foo.ts', 'foo.js', 'foo', 'bar']; let siblings = ['foo.ts', 'foo.js', 'foo', 'bar'];
let hasSibling = name => siblings.indexOf(name) !== -1; let hasSibling = (name: string) => siblings.indexOf(name) !== -1;
assert.strictEqual(glob.match(expr, 'bar', hasSibling), '**/bar'); assert.strictEqual(glob.match(expr, 'bar', hasSibling), '**/bar');
assert.strictEqual(glob.match(expr, 'foo', hasSibling), null); assert.strictEqual(glob.match(expr, 'foo', hasSibling), null);
@@ -774,7 +774,7 @@ suite('Glob', () => {
let expr = { '**/*.js': { when: '$(basename).ts' } }; let expr = { '**/*.js': { when: '$(basename).ts' } };
let siblings = ['foo.ts', 'foo.js']; let siblings = ['foo.ts', 'foo.js'];
let hasSibling = name => siblings.indexOf(name) !== -1; let hasSibling = (name: string) => siblings.indexOf(name) !== -1;
assert.strictEqual(glob.parse(expr)('bar/baz.js', 'baz.js', hasSibling), null); assert.strictEqual(glob.parse(expr)('bar/baz.js', 'baz.js', hasSibling), null);
assert.strictEqual(glob.parse(expr)('bar/foo.js', 'foo.js', hasSibling), '**/*.js'); assert.strictEqual(glob.parse(expr)('bar/foo.js', 'foo.js', hasSibling), '**/*.js');
@@ -818,7 +818,7 @@ suite('Glob', () => {
]); ]);
const siblings = ['baz', 'baz.zip', 'nope']; const siblings = ['baz', 'baz.zip', 'nope'];
const hasSibling = name => siblings.indexOf(name) !== -1; const hasSibling = (name: string) => siblings.indexOf(name) !== -1;
testOptimizationForBasenames({ testOptimizationForBasenames({
'**/foo/**': { when: '$(basename).zip' }, '**/foo/**': { when: '$(basename).zip' },
'**/bar/**': true '**/bar/**': true
@@ -924,7 +924,7 @@ suite('Glob', () => {
]); ]);
const siblings = ['baz', 'baz.zip', 'nope']; const siblings = ['baz', 'baz.zip', 'nope'];
let hasSibling = name => siblings.indexOf(name) !== -1; let hasSibling = (name: string) => siblings.indexOf(name) !== -1;
testOptimizationForPaths({ testOptimizationForPaths({
'**/foo/123/**': { when: '$(basename).zip' }, '**/foo/123/**': { when: '$(basename).zip' },
'**/bar/123/**': true '**/bar/123/**': true
@@ -293,7 +293,7 @@ suite('SQLite Storage Library', () => {
return set; return set;
} }
async function testDBBasics(path, logError?: (error) => void) { async function testDBBasics(path: string, logError?: (error: Error) => void) {
let options!: ISQLiteStorageDatabaseOptions; let options!: ISQLiteStorageDatabaseOptions;
if (logError) { if (logError) {
options = { options = {
@@ -39,6 +39,7 @@ import { ILogService, getLogLevel } from 'vs/platform/log/common/log';
import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel';
import { normalizeGitHubUrl } from 'vs/code/electron-browser/issue/issueReporterUtil'; import { normalizeGitHubUrl } from 'vs/code/electron-browser/issue/issueReporterUtil';
import { Button } from 'vs/base/browser/ui/button/button'; import { Button } from 'vs/base/browser/ui/button/button';
import { withUndefinedAsNull } from 'vs/base/common/types';
const MAX_URL_LENGTH = platform.isWindows ? 2081 : 5400; const MAX_URL_LENGTH = platform.isWindows ? 2081 : 5400;
@@ -211,7 +212,7 @@ export class IssueReporter extends Disposable {
styleTag.innerHTML = content.join('\n'); styleTag.innerHTML = content.join('\n');
document.head.appendChild(styleTag); document.head.appendChild(styleTag);
document.body.style.color = styles.color || null; document.body.style.color = withUndefinedAsNull(styles.color);
} }
private handleExtensionData(extensions: IssueReporterExtensionData[]) { private handleExtensionData(extensions: IssueReporterExtensionData[]) {
@@ -99,7 +99,7 @@ function attachTo(item: ProcessItem) {
ipcRenderer.send('vscode:workbenchCommand', { id: 'debug.startFromConfig', from: 'processExplorer', args: [config] }); ipcRenderer.send('vscode:workbenchCommand', { id: 'debug.startFromConfig', from: 'processExplorer', args: [config] });
} }
function getProcessIdWithHighestProperty(processList, propertyName: string) { function getProcessIdWithHighestProperty(processList: any[], propertyName: string) {
let max = 0; let max = 0;
let maxProcessId; let maxProcessId;
processList.forEach(process => { processList.forEach(process => {
@@ -112,7 +112,7 @@ function getProcessIdWithHighestProperty(processList, propertyName: string) {
return maxProcessId; return maxProcessId;
} }
function updateProcessInfo(processList): void { function updateProcessInfo(processList: any[]): void {
const container = document.getElementById('process-list'); const container = document.getElementById('process-list');
if (!container) { if (!container) {
return; return;
@@ -199,12 +199,12 @@ function applyZoom(zoomLevel: number): void {
browser.setZoomLevel(webFrame.getZoomLevel(), /*isTrusted*/false); browser.setZoomLevel(webFrame.getZoomLevel(), /*isTrusted*/false);
} }
function showContextMenu(e) { function showContextMenu(e: MouseEvent) {
e.preventDefault(); e.preventDefault();
const items: IContextMenuItem[] = []; const items: IContextMenuItem[] = [];
const pid = parseInt(e.currentTarget.id); const pid = parseInt((e.currentTarget as HTMLElement).id);
if (pid && typeof pid === 'number') { if (pid && typeof pid === 'number') {
items.push({ items.push({
label: localize('killProcess', "Kill Process"), label: localize('killProcess', "Kill Process"),
@@ -277,7 +277,7 @@ export function startup(data: ProcessExplorerData): void {
applyZoom(data.zoomLevel); applyZoom(data.zoomLevel);
// Map window process pids to titles, annotate process names with this when rendering to distinguish between them // Map window process pids to titles, annotate process names with this when rendering to distinguish between them
ipcRenderer.on('vscode:windowsInfoResponse', (event, windows) => { ipcRenderer.on('vscode:windowsInfoResponse', (_event: unknown, windows: any[]) => {
mapPidToWindowTitle = new Map<number, string>(); mapPidToWindowTitle = new Map<number, string>();
windows.forEach(window => mapPidToWindowTitle.set(window.pid, window.title)); windows.forEach(window => mapPidToWindowTitle.set(window.pid, window.title));
}); });
+5 -4
View File
@@ -388,7 +388,7 @@ export class CodeApplication extends Disposable {
this.logService.info(`Tracing: waiting for windows to get ready...`); this.logService.info(`Tracing: waiting for windows to get ready...`);
let recordingStopped = false; let recordingStopped = false;
const stopRecording = (timeout) => { const stopRecording = (timeout: boolean) => {
if (recordingStopped) { if (recordingStopped) {
return; return;
} }
@@ -574,16 +574,17 @@ export class CodeApplication extends Disposable {
const hasCliArgs = hasArgs(args._); const hasCliArgs = hasArgs(args._);
const hasFolderURIs = hasArgs(args['folder-uri']); const hasFolderURIs = hasArgs(args['folder-uri']);
const hasFileURIs = hasArgs(args['file-uri']); const hasFileURIs = hasArgs(args['file-uri']);
const noRecentEntry = args['skip-add-to-recently-opened'] === true;
if (args['new-window'] && !hasCliArgs && !hasFolderURIs && !hasFileURIs) { if (args['new-window'] && !hasCliArgs && !hasFolderURIs && !hasFileURIs) {
return this.windowsMainService.open({ context, cli: args, forceNewWindow: true, forceEmpty: true, initialStartup: true }); // new window if "-n" was used without paths return this.windowsMainService.open({ context, cli: args, forceNewWindow: true, forceEmpty: true, noRecentEntry, initialStartup: true }); // new window if "-n" was used without paths
} }
if (macOpenFiles && macOpenFiles.length && !hasCliArgs && !hasFolderURIs && !hasFileURIs) { if (macOpenFiles && macOpenFiles.length && !hasCliArgs && !hasFolderURIs && !hasFileURIs) {
return this.windowsMainService.open({ context: OpenContext.DOCK, cli: args, urisToOpen: macOpenFiles.map(file => ({ uri: URI.file(file) })), initialStartup: true }); // mac: open-file event received on startup return this.windowsMainService.open({ context: OpenContext.DOCK, cli: args, urisToOpen: macOpenFiles.map(file => ({ uri: URI.file(file) })), noRecentEntry, initialStartup: true }); // mac: open-file event received on startup
} }
return this.windowsMainService.open({ context, cli: args, forceNewWindow: args['new-window'] || (!hasCliArgs && args['unity-launch']), diffMode: args.diff, initialStartup: true }); // default: read paths from cli return this.windowsMainService.open({ context, cli: args, forceNewWindow: args['new-window'] || (!hasCliArgs && args['unity-launch']), diffMode: args.diff, noRecentEntry, initialStartup: true }); // default: read paths from cli
} }
private afterWindowOpen(accessor: ServicesAccessor): void { private afterWindowOpen(accessor: ServicesAccessor): void {
+27 -9
View File
@@ -489,7 +489,7 @@ export class WindowsManager implements IWindowsMainService {
// Remember in recent document list (unless this opens for extension development) // Remember in recent document list (unless this opens for extension development)
// Also do not add paths when files are opened for diffing, only if opened individually // Also do not add paths when files are opened for diffing, only if opened individually
if (!usedWindows.some(w => w.isExtensionDevelopmentHost) && !openConfig.diffMode && !this.environmentService.skipAddToRecentlyOpened) { if (!usedWindows.some(w => w.isExtensionDevelopmentHost) && !openConfig.diffMode && !openConfig.noRecentEntry) {
const recents: IRecent[] = []; const recents: IRecent[] = [];
for (let pathToOpen of pathsToOpen) { for (let pathToOpen of pathsToOpen) {
if (pathToOpen.workspace) { if (pathToOpen.workspace) {
@@ -746,7 +746,7 @@ export class WindowsManager implements IWindowsMainService {
private doOpenFilesInExistingWindow(configuration: IOpenConfiguration, window: ICodeWindow, fileInputs?: IFileInputs): ICodeWindow { private doOpenFilesInExistingWindow(configuration: IOpenConfiguration, window: ICodeWindow, fileInputs?: IFileInputs): ICodeWindow {
window.focus(); // make sure window has focus window.focus(); // make sure window has focus
const params: { filesToOpen?, filesToCreate?, filesToDiff?, filesToWait?, termProgram?} = {}; const params: { filesToOpen?: IPath[], filesToCreate?: IPath[], filesToDiff?: IPath[], filesToWait?: IPathsToWaitFor, termProgram?: string } = {};
if (fileInputs) { if (fileInputs) {
params.filesToOpen = fileInputs.filesToOpen; params.filesToOpen = fileInputs.filesToOpen;
params.filesToCreate = fileInputs.filesToCreate; params.filesToCreate = fileInputs.filesToCreate;
@@ -1216,7 +1216,7 @@ export class WindowsManager implements IWindowsMainService {
} }
// Open it // Open it
this.open({ context: openConfig.context, cli: openConfig.cli, forceNewWindow: true, forceEmpty: !cliArgs.length && !folderUris.length && !fileUris.length, userEnv: openConfig.userEnv }); this.open({ context: openConfig.context, cli: openConfig.cli, forceNewWindow: true, forceEmpty: !cliArgs.length && !folderUris.length && !fileUris.length, userEnv: openConfig.userEnv, noRecentEntry: true });
} }
private openInBrowserWindow(options: IOpenBrowserWindowOptions): ICodeWindow { private openInBrowserWindow(options: IOpenBrowserWindowOptions): ICodeWindow {
@@ -1897,9 +1897,15 @@ class Dialogs {
showMessageBox(options: Electron.MessageBoxOptions, window?: ICodeWindow): Promise<IMessageBoxResult> { showMessageBox(options: Electron.MessageBoxOptions, window?: ICodeWindow): Promise<IMessageBoxResult> {
return this.getDialogQueue(window).queue(() => { return this.getDialogQueue(window).queue(() => {
return new Promise(resolve => { return new Promise(resolve => {
dialog.showMessageBox(window ? window.win : undefined!, options, (response: number, checkboxChecked: boolean) => { const callback = (response: number, checkboxChecked: boolean) => {
resolve({ button: response, checkboxChecked }); resolve({ button: response, checkboxChecked });
}); };
if (window) {
dialog.showMessageBox(window.win, options, callback);
} else {
dialog.showMessageBox(options, callback);
}
}); });
}); });
} }
@@ -1916,9 +1922,15 @@ class Dialogs {
return this.getDialogQueue(window).queue(() => { return this.getDialogQueue(window).queue(() => {
return new Promise(resolve => { return new Promise(resolve => {
dialog.showSaveDialog(window ? window.win : undefined!, options, path => { const callback = (path: string) => {
resolve(normalizePath(path)); resolve(normalizePath(path));
}); };
if (window) {
dialog.showSaveDialog(window.win, options, callback);
} else {
dialog.showSaveDialog(options, callback);
}
}); });
}); });
} }
@@ -1948,9 +1960,15 @@ class Dialogs {
// Show dialog and wrap as promise // Show dialog and wrap as promise
validatePathPromise.then(() => { validatePathPromise.then(() => {
dialog.showOpenDialog(window ? window.win : undefined!, options, paths => { const callback = (paths: string[]) => {
resolve(normalizePaths(paths)); resolve(normalizePaths(paths));
}); };
if (window) {
dialog.showOpenDialog(window.win, options, callback);
} else {
dialog.showOpenDialog(options, callback);
}
}); });
}); });
}); });
+3 -2
View File
@@ -20,6 +20,7 @@ import { IConstructorSignature1, ServicesAccessor } from 'vs/platform/instantiat
import { IKeybindings, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IKeybindings, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { Registry } from 'vs/platform/registry/common/platform'; import { Registry } from 'vs/platform/registry/common/platform';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { withNullAsUndefined } from 'vs/base/common/types';
export type ServicesAccessor = ServicesAccessor; export type ServicesAccessor = ServicesAccessor;
export type IEditorContributionCtor = IConstructorSignature1<ICodeEditor, IEditorContribution>; export type IEditorContributionCtor = IConstructorSignature1<ICodeEditor, IEditorContribution>;
@@ -88,7 +89,7 @@ export abstract class Command {
id: this.id, id: this.id,
handler: (accessor, args) => this.runCommand(accessor, args), handler: (accessor, args) => this.runCommand(accessor, args),
weight: this._kbOpts.weight, weight: this._kbOpts.weight,
when: kbWhen || null, when: kbWhen,
primary: this._kbOpts.primary, primary: this._kbOpts.primary,
secondary: this._kbOpts.secondary, secondary: this._kbOpts.secondary,
win: this._kbOpts.win, win: this._kbOpts.win,
@@ -156,7 +157,7 @@ export abstract class EditorCommand extends Command {
return editor.invokeWithinContext((editorAccessor) => { return editor.invokeWithinContext((editorAccessor) => {
const kbService = editorAccessor.get(IContextKeyService); const kbService = editorAccessor.get(IContextKeyService);
if (!kbService.contextMatchesRules(this.precondition)) { if (!kbService.contextMatchesRules(withNullAsUndefined(this.precondition))) {
// precondition does not hold // precondition does not hold
return; return;
} }
@@ -272,7 +272,7 @@ class Widget {
public setPosition(position: IPosition | null | undefined, range: IRange | null | undefined, preference: ContentWidgetPositionPreference[] | null | undefined): void { public setPosition(position: IPosition | null | undefined, range: IRange | null | undefined, preference: ContentWidgetPositionPreference[] | null | undefined): void {
this._setPosition(position, range); this._setPosition(position, range);
this._preference = preference || null; this._preference = withUndefinedAsNull(preference);
this._cachedDomNodeClientWidth = -1; this._cachedDomNodeClientWidth = -1;
this._cachedDomNodeClientHeight = -1; this._cachedDomNodeClientHeight = -1;
} }
@@ -49,6 +49,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
import { INotificationService } from 'vs/platform/notification/common/notification'; import { INotificationService } from 'vs/platform/notification/common/notification';
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { withNullAsUndefined } from 'vs/base/common/types';
let EDITOR_ID = 0; let EDITOR_ID = 0;
@@ -308,7 +309,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
action.id, action.id,
action.label, action.label,
action.alias, action.alias,
action.precondition, withNullAsUndefined(action.precondition),
(): Promise<void> => { (): Promise<void> => {
return this._instantiationService.invokeFunction((accessor) => { return this._instantiationService.invokeFunction((accessor) => {
return Promise.resolve(action.runEditorCommand(accessor, this, null)); return Promise.resolve(action.runEditorCommand(accessor, this, null));
@@ -1644,6 +1645,8 @@ export class EditorModeContext extends Disposable {
private readonly _hasRenameProvider: IContextKey<boolean>; private readonly _hasRenameProvider: IContextKey<boolean>;
private readonly _hasDocumentFormattingProvider: IContextKey<boolean>; private readonly _hasDocumentFormattingProvider: IContextKey<boolean>;
private readonly _hasDocumentSelectionFormattingProvider: IContextKey<boolean>; private readonly _hasDocumentSelectionFormattingProvider: IContextKey<boolean>;
private readonly _hasMultipleDocumentFormattingProvider: IContextKey<boolean>;
private readonly _hasMultipleDocumentSelectionFormattingProvider: IContextKey<boolean>;
private readonly _hasSignatureHelpProvider: IContextKey<boolean>; private readonly _hasSignatureHelpProvider: IContextKey<boolean>;
private readonly _isInWalkThrough: IContextKey<boolean>; private readonly _isInWalkThrough: IContextKey<boolean>;
@@ -1667,9 +1670,11 @@ export class EditorModeContext extends Disposable {
this._hasDocumentSymbolProvider = EditorContextKeys.hasDocumentSymbolProvider.bindTo(contextKeyService); this._hasDocumentSymbolProvider = EditorContextKeys.hasDocumentSymbolProvider.bindTo(contextKeyService);
this._hasReferenceProvider = EditorContextKeys.hasReferenceProvider.bindTo(contextKeyService); this._hasReferenceProvider = EditorContextKeys.hasReferenceProvider.bindTo(contextKeyService);
this._hasRenameProvider = EditorContextKeys.hasRenameProvider.bindTo(contextKeyService); this._hasRenameProvider = EditorContextKeys.hasRenameProvider.bindTo(contextKeyService);
this._hasSignatureHelpProvider = EditorContextKeys.hasSignatureHelpProvider.bindTo(contextKeyService);
this._hasDocumentFormattingProvider = EditorContextKeys.hasDocumentFormattingProvider.bindTo(contextKeyService); this._hasDocumentFormattingProvider = EditorContextKeys.hasDocumentFormattingProvider.bindTo(contextKeyService);
this._hasDocumentSelectionFormattingProvider = EditorContextKeys.hasDocumentSelectionFormattingProvider.bindTo(contextKeyService); this._hasDocumentSelectionFormattingProvider = EditorContextKeys.hasDocumentSelectionFormattingProvider.bindTo(contextKeyService);
this._hasSignatureHelpProvider = EditorContextKeys.hasSignatureHelpProvider.bindTo(contextKeyService); this._hasMultipleDocumentFormattingProvider = EditorContextKeys.hasMultipleDocumentFormattingProvider.bindTo(contextKeyService);
this._hasMultipleDocumentSelectionFormattingProvider = EditorContextKeys.hasMultipleDocumentSelectionFormattingProvider.bindTo(contextKeyService);
this._isInWalkThrough = EditorContextKeys.isInEmbeddedEditor.bindTo(contextKeyService); this._isInWalkThrough = EditorContextKeys.isInEmbeddedEditor.bindTo(contextKeyService);
const update = () => this._update(); const update = () => this._update();
@@ -1744,6 +1749,8 @@ export class EditorModeContext extends Disposable {
this._hasSignatureHelpProvider.set(modes.SignatureHelpProviderRegistry.has(model)); this._hasSignatureHelpProvider.set(modes.SignatureHelpProviderRegistry.has(model));
this._hasDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.has(model) || modes.DocumentRangeFormattingEditProviderRegistry.has(model)); this._hasDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.has(model) || modes.DocumentRangeFormattingEditProviderRegistry.has(model));
this._hasDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.has(model)); this._hasDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.has(model));
this._hasMultipleDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.all(model).length > 1 || modes.DocumentRangeFormattingEditProviderRegistry.all(model).length > 1);
this._hasMultipleDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.all(model).length > 1);
this._isInWalkThrough.set(model.uri.scheme === Schemas.walkThroughSnippet); this._isInWalkThrough.set(model.uri.scheme === Schemas.walkThroughSnippet);
} }
} }
+2 -2
View File
@@ -12,7 +12,7 @@ export class InternalEditorAction implements IEditorAction {
public readonly label: string; public readonly label: string;
public readonly alias: string; public readonly alias: string;
private readonly _precondition: ContextKeyExpr | null; private readonly _precondition: ContextKeyExpr | undefined;
private readonly _run: () => Promise<void>; private readonly _run: () => Promise<void>;
private readonly _contextKeyService: IContextKeyService; private readonly _contextKeyService: IContextKeyService;
@@ -20,7 +20,7 @@ export class InternalEditorAction implements IEditorAction {
id: string, id: string,
label: string, label: string,
alias: string, alias: string,
precondition: ContextKeyExpr | null, precondition: ContextKeyExpr | undefined,
run: () => Promise<void>, run: () => Promise<void>,
contextKeyService: IContextKeyService contextKeyService: IContextKeyService
) { ) {
+6 -1
View File
@@ -46,7 +46,12 @@ export namespace EditorContextKeys {
export const hasDocumentSymbolProvider = new RawContextKey<boolean>('editorHasDocumentSymbolProvider', false); export const hasDocumentSymbolProvider = new RawContextKey<boolean>('editorHasDocumentSymbolProvider', false);
export const hasReferenceProvider = new RawContextKey<boolean>('editorHasReferenceProvider', false); export const hasReferenceProvider = new RawContextKey<boolean>('editorHasReferenceProvider', false);
export const hasRenameProvider = new RawContextKey<boolean>('editorHasRenameProvider', false); export const hasRenameProvider = new RawContextKey<boolean>('editorHasRenameProvider', false);
export const hasSignatureHelpProvider = new RawContextKey<boolean>('editorHasSignatureHelpProvider', false);
// -- mode context keys: formatting
export const hasDocumentFormattingProvider = new RawContextKey<boolean>('editorHasDocumentFormattingProvider', false); export const hasDocumentFormattingProvider = new RawContextKey<boolean>('editorHasDocumentFormattingProvider', false);
export const hasDocumentSelectionFormattingProvider = new RawContextKey<boolean>('editorHasDocumentSelectionFormattingProvider', false); export const hasDocumentSelectionFormattingProvider = new RawContextKey<boolean>('editorHasDocumentSelectionFormattingProvider', false);
export const hasSignatureHelpProvider = new RawContextKey<boolean>('editorHasSignatureHelpProvider', false); export const hasMultipleDocumentFormattingProvider = new RawContextKey<boolean>('editorHasMultipleDocumentFormattingProvider', false);
export const hasMultipleDocumentSelectionFormattingProvider = new RawContextKey<boolean>('editorHasMultipleDocumentSelectionFormattingProvider', false);
} }
+3 -2
View File
@@ -32,6 +32,7 @@ import { ignoreBracketsInToken } from 'vs/editor/common/modes/supports';
import { BracketsUtils, RichEditBracket, RichEditBrackets } from 'vs/editor/common/modes/supports/richEditBrackets'; import { BracketsUtils, RichEditBracket, RichEditBrackets } from 'vs/editor/common/modes/supports/richEditBrackets';
import { IStringStream, ITextSnapshot } from 'vs/platform/files/common/files'; import { IStringStream, ITextSnapshot } from 'vs/platform/files/common/files';
import { ITheme, ThemeColor } from 'vs/platform/theme/common/themeService'; import { ITheme, ThemeColor } from 'vs/platform/theme/common/themeService';
import { withUndefinedAsNull } from 'vs/base/common/types';
const CHEAP_TOKENIZATION_LENGTH_LIMIT = 2048; const CHEAP_TOKENIZATION_LENGTH_LIMIT = 2048;
@@ -2877,8 +2878,8 @@ export class ModelDecorationOptions implements model.IModelDecorationOptions {
this.stickiness = options.stickiness || model.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges; this.stickiness = options.stickiness || model.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges;
this.zIndex = options.zIndex || 0; this.zIndex = options.zIndex || 0;
this.className = options.className ? cleanClassName(options.className) : null; this.className = options.className ? cleanClassName(options.className) : null;
this.hoverMessage = options.hoverMessage || null; this.hoverMessage = withUndefinedAsNull(options.hoverMessage);
this.glyphMarginHoverMessage = options.glyphMarginHoverMessage || null; this.glyphMarginHoverMessage = withUndefinedAsNull(options.glyphMarginHoverMessage);
this.isWholeLine = options.isWholeLine || false; this.isWholeLine = options.isWholeLine || false;
this.showIfCollapsed = options.showIfCollapsed || false; this.showIfCollapsed = options.showIfCollapsed || false;
this.collapseOnReplaceEdit = options.collapseOnReplaceEdit || false; this.collapseOnReplaceEdit = options.collapseOnReplaceEdit || false;
+22 -2
View File
@@ -929,6 +929,8 @@ export interface DocumentFormattingEditProvider {
*/ */
readonly extensionId?: ExtensionIdentifier; readonly extensionId?: ExtensionIdentifier;
readonly displayName?: string;
/** /**
* Provide formatting edits for a whole document. * Provide formatting edits for a whole document.
*/ */
@@ -939,13 +941,13 @@ export interface DocumentFormattingEditProvider {
* the formatting-feature. * the formatting-feature.
*/ */
export interface DocumentRangeFormattingEditProvider { export interface DocumentRangeFormattingEditProvider {
/** /**
* @internal * @internal
*/ */
readonly extensionId?: ExtensionIdentifier; readonly extensionId?: ExtensionIdentifier;
readonly displayName?: string;
/** /**
* Provide formatting edits for a range in a document. * Provide formatting edits for a range in a document.
* *
@@ -1396,6 +1398,24 @@ export interface WorkspaceCommentProvider {
onDidChangeCommentThreads(): Event<CommentThreadChangedEvent>; onDidChangeCommentThreads(): Event<CommentThreadChangedEvent>;
} }
/**
* @internal
*/
export interface IWebviewOptions {
readonly enableScripts?: boolean;
readonly enableCommandUris?: boolean;
readonly localResourceRoots?: ReadonlyArray<URI>;
readonly portMapping?: ReadonlyArray<{ port: number, resolvedPort: number }>;
}
/**
* @internal
*/
export interface IWebviewPanelOptions {
readonly enableFindWidget?: boolean;
readonly retainContextWhenHidden?: boolean;
}
export interface ICodeLensSymbol { export interface ICodeLensSymbol {
range: IRange; range: IRange;
id?: string; id?: string;
@@ -26,7 +26,7 @@ export interface IEditorWorkerService {
canComputeDirtyDiff(original: URI, modified: URI): boolean; canComputeDirtyDiff(original: URI, modified: URI): boolean;
computeDirtyDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise<IChange[] | null>; computeDirtyDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise<IChange[] | null>;
computeMoreMinimalEdits(resource: URI, edits: TextEdit[] | null | undefined): Promise<TextEdit[] | null | undefined>; computeMoreMinimalEdits(resource: URI, edits: TextEdit[] | null | undefined): Promise<TextEdit[] | undefined>;
canComputeWordRanges(resource: URI): boolean; canComputeWordRanges(resource: URI): boolean;
computeWordRanges(resource: URI, range: IRange): Promise<{ [word: string]: IRange[] } | null>; computeWordRanges(resource: URI, range: IRange): Promise<{ [word: string]: IRange[] } | null>;
@@ -20,6 +20,7 @@ import { IDiffComputationResult, IEditorWorkerService } from 'vs/editor/common/s
import { IModelService } from 'vs/editor/common/services/modelService'; import { IModelService } from 'vs/editor/common/services/modelService';
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
import { regExpFlags } from 'vs/base/common/strings'; import { regExpFlags } from 'vs/base/common/strings';
import { isNonEmptyArray } from 'vs/base/common/arrays';
/** /**
* Stop syncing a model to the worker if it was not needed for 1 min. * Stop syncing a model to the worker if it was not needed for 1 min.
@@ -88,14 +89,15 @@ export class EditorWorkerServiceImpl extends Disposable implements IEditorWorker
return this._workerManager.withWorker().then(client => client.computeDirtyDiff(original, modified, ignoreTrimWhitespace)); return this._workerManager.withWorker().then(client => client.computeDirtyDiff(original, modified, ignoreTrimWhitespace));
} }
public computeMoreMinimalEdits(resource: URI, edits: modes.TextEdit[] | null | undefined): Promise<modes.TextEdit[] | null | undefined> { public computeMoreMinimalEdits(resource: URI, edits: modes.TextEdit[] | null | undefined): Promise<modes.TextEdit[] | undefined> {
if (!Array.isArray(edits) || edits.length === 0) { if (isNonEmptyArray(edits)) {
return Promise.resolve(edits);
} else {
if (!canSyncModel(this._modelService, resource)) { if (!canSyncModel(this._modelService, resource)) {
return Promise.resolve(edits); // File too large return Promise.resolve(edits); // File too large
} }
return this._workerManager.withWorker().then(client => client.computeMoreMinimalEdits(resource, edits)); return this._workerManager.withWorker().then(client => client.computeMoreMinimalEdits(resource, edits));
} else {
return Promise.resolve(undefined);
} }
} }
@@ -15,6 +15,7 @@ import { NULL_LANGUAGE_IDENTIFIER, NULL_MODE_ID } from 'vs/editor/common/modes/n
import { ILanguageExtensionPoint } from 'vs/editor/common/services/modeService'; import { ILanguageExtensionPoint } from 'vs/editor/common/services/modeService';
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
import { Registry } from 'vs/platform/registry/common/platform'; import { Registry } from 'vs/platform/registry/common/platform';
import { withUndefinedAsNull } from 'vs/base/common/types';
const hasOwnProperty = Object.prototype.hasOwnProperty; const hasOwnProperty = Object.prototype.hasOwnProperty;
@@ -267,7 +268,7 @@ export class LanguagesRegistry extends Disposable {
return null; return null;
} }
const language = this._languages[modeId]; const language = this._languages[modeId];
return (language.mimetypes[0] || null); return withUndefinedAsNull(language.mimetypes[0]);
} }
public extractModeIds(commaSeparatedMimetypesOrCommaSeparatedIds: string | undefined): string[] { public extractModeIds(commaSeparatedMimetypesOrCommaSeparatedIds: string | undefined): string[] {
@@ -16,6 +16,7 @@ import { keys } from 'vs/base/common/map';
import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService'; import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService';
import { Schemas } from 'vs/base/common/network'; import { Schemas } from 'vs/base/common/network';
import { Emitter, Event } from 'vs/base/common/event'; import { Emitter, Event } from 'vs/base/common/event';
import { withUndefinedAsNull } from 'vs/base/common/types';
function MODEL_ID(resource: URI): string { function MODEL_ID(resource: URI): string {
return resource.toString(); return resource.toString();
@@ -80,7 +81,7 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor
getMarker(model: ITextModel, decoration: IModelDecoration): IMarker | null { getMarker(model: ITextModel, decoration: IModelDecoration): IMarker | null {
const markerDecorations = this._markerDecorations.get(MODEL_ID(model.uri)); const markerDecorations = this._markerDecorations.get(MODEL_ID(model.uri));
return markerDecorations ? markerDecorations.getMarker(decoration) || null : null; return markerDecorations ? withUndefinedAsNull(markerDecorations.getMarker(decoration)) : null;
} }
getLiveMarkers(model: ITextModel): [Range, IMarker][] { getLiveMarkers(model: ITextModel): [Range, IMarker][] {
@@ -163,7 +163,7 @@ export class LightBulbWidget extends Disposable implements IContentWidget {
const lineContent = model.getLineContent(lineNumber); const lineContent = model.getLineContent(lineNumber);
const indent = TextModel.computeIndentLevel(lineContent, tabSize); const indent = TextModel.computeIndentLevel(lineContent, tabSize);
const lineHasSpace = config.fontInfo.spaceWidth * indent > 22; const lineHasSpace = config.fontInfo.spaceWidth * indent > 22;
const isFolded = (lineNumber) => { const isFolded = (lineNumber: number) => {
return lineNumber > 2 && this._editor.getTopForLineNumber(lineNumber) === this._editor.getTopForLineNumber(lineNumber - 1); return lineNumber > 2 && this._editor.getTopForLineNumber(lineNumber) === this._editor.getTopForLineNumber(lineNumber - 1);
}; };
@@ -25,7 +25,7 @@ class CodeLensViewZone implements editorBrowser.IViewZone {
afterLineNumber: number; afterLineNumber: number;
private _lastHeight: number; private _lastHeight?: number;
private readonly _onHeight: Function; private readonly _onHeight: Function;
constructor(afterLineNumber: number, onHeight: Function) { constructor(afterLineNumber: number, onHeight: Function) {
@@ -67,7 +67,7 @@ suite('FindController', () => {
getBoolean: (key: string) => !!queryState[key], getBoolean: (key: string) => !!queryState[key],
getNumber: (key: string) => undefined, getNumber: (key: string) => undefined,
store: (key: string, value: any) => { queryState[key] = value; return Promise.resolve(); }, store: (key: string, value: any) => { queryState[key] = value; return Promise.resolve(); },
remove: (key) => undefined remove: () => undefined
} as any); } as any);
if (platform.isMacintosh) { if (platform.isMacintosh) {
@@ -442,7 +442,7 @@ suite('FindController query options persistence', () => {
getBoolean: (key: string) => !!queryState[key], getBoolean: (key: string) => !!queryState[key],
getNumber: (key: string) => undefined, getNumber: (key: string) => undefined,
store: (key: string, value: any) => { queryState[key] = value; return Promise.resolve(); }, store: (key: string, value: any) => { queryState[key] = value; return Promise.resolve(); },
remove: (key) => undefined remove: () => undefined
} as any); } as any);
test('matchCase', () => { test('matchCase', () => {
@@ -66,7 +66,7 @@ export class FoldingModel {
public update(newRegions: FoldingRegions, blockedLineNumers: number[] = []): void { public update(newRegions: FoldingRegions, blockedLineNumers: number[] = []): void {
let newEditorDecorations: IModelDeltaDecoration[] = []; let newEditorDecorations: IModelDeltaDecoration[] = [];
let isBlocked = (startLineNumber, endLineNumber) => { let isBlocked = (startLineNumber: number, endLineNumber: number) => {
for (let blockedLineNumber of blockedLineNumers) { for (let blockedLineNumber of blockedLineNumers) {
if (startLineNumber < blockedLineNumber && blockedLineNumber <= endLineNumber) { // first line is visible if (startLineNumber < blockedLineNumber && blockedLineNumber <= endLineNumber) { // first line is visible
return true; return true;
+218 -113
View File
@@ -3,138 +3,258 @@
* 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 { alert } from 'vs/base/browser/ui/aria/aria';
import { isNonEmptyArray } from 'vs/base/common/arrays';
import { CancellationToken } from 'vs/base/common/cancellation';
import { illegalArgument, onUnexpectedExternalError } from 'vs/base/common/errors'; import { illegalArgument, onUnexpectedExternalError } from 'vs/base/common/errors';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { isNonEmptyArray } from 'vs/base/common/arrays'; import { CodeEditorStateFlag, EditorState } from 'vs/editor/browser/core/editorState';
import { Range } from 'vs/editor/common/core/range'; import { IActiveCodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { ITextModel } from 'vs/editor/common/model'; import { registerLanguageCommand, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { registerLanguageCommand } from 'vs/editor/browser/editorExtensions';
import { DocumentFormattingEditProviderRegistry, DocumentRangeFormattingEditProviderRegistry, OnTypeFormattingEditProviderRegistry, FormattingOptions, TextEdit } from 'vs/editor/common/modes';
import { IModelService } from 'vs/editor/common/services/modelService';
import { first } from 'vs/base/common/async';
import { Position } from 'vs/editor/common/core/position'; import { Position } from 'vs/editor/common/core/position';
import { CancellationToken } from 'vs/base/common/cancellation'; import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { ISingleEditOperation, ITextModel } from 'vs/editor/common/model';
import { DocumentFormattingEditProvider, DocumentFormattingEditProviderRegistry, DocumentRangeFormattingEditProvider, DocumentRangeFormattingEditProviderRegistry, FormattingOptions, OnTypeFormattingEditProviderRegistry, TextEdit } from 'vs/editor/common/modes';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IModelService } from 'vs/editor/common/services/modelService';
import { FormattingEdit } from 'vs/editor/contrib/format/formattingEdit';
import * as nls from 'vs/nls';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { IDisposable } from 'vs/base/common/lifecycle';
export const enum FormatMode { export function alertFormattingEdits(edits: ISingleEditOperation[]): void {
Auto = 1,
Manual = 2, edits = edits.filter(edit => edit.range);
if (!edits.length) {
return;
}
let { range } = edits[0];
for (let i = 1; i < edits.length; i++) {
range = Range.plusRange(range, edits[i].range);
}
const { startLineNumber, endLineNumber } = range;
if (startLineNumber === endLineNumber) {
if (edits.length === 1) {
alert(nls.localize('hint11', "Made 1 formatting edit on line {0}", startLineNumber));
} else {
alert(nls.localize('hintn1', "Made {0} formatting edits on line {1}", edits.length, startLineNumber));
}
} else {
if (edits.length === 1) {
alert(nls.localize('hint1n', "Made 1 formatting edit between lines {0} and {1}", startLineNumber, endLineNumber));
} else {
alert(nls.localize('hintnn', "Made {0} formatting edits between lines {1} and {2}", edits.length, startLineNumber, endLineNumber));
}
}
} }
export const enum FormatKind { export function getRealAndSyntheticDocumentFormattersOrdered(model: ITextModel): DocumentFormattingEditProvider[] {
Document = 8, const result: DocumentFormattingEditProvider[] = [];
Range = 16, const seen = new Set<string>();
OnType = 32,
// (1) add all document formatter
const docFormatter = DocumentFormattingEditProviderRegistry.ordered(model);
for (const formatter of docFormatter) {
result.push(formatter);
if (formatter.extensionId) {
seen.add(ExtensionIdentifier.toKey(formatter.extensionId));
}
}
// (2) add all range formatter as document formatter (unless the same extension already did that)
const rangeFormatter = DocumentRangeFormattingEditProviderRegistry.ordered(model);
for (const formatter of rangeFormatter) {
if (formatter.extensionId) {
if (seen.has(ExtensionIdentifier.toKey(formatter.extensionId))) {
continue;
}
seen.add(ExtensionIdentifier.toKey(formatter.extensionId));
}
result.push({
displayName: formatter.displayName,
extensionId: formatter.extensionId,
provideDocumentFormattingEdits(model, options, token) {
return formatter.provideDocumentRangeFormattingEdits(model, model.getFullModelRange(), options, token);
}
});
}
return result;
} }
export interface IFormatterConflictCallback { export async function formatDocumentRangeWithProvider(
(extensionIds: (ExtensionIdentifier | undefined)[], model: ITextModel, mode: number): void; accessor: ServicesAccessor,
} provider: DocumentRangeFormattingEditProvider,
editorOrModel: ITextModel | IActiveCodeEditor,
range: Range,
token: CancellationToken
): Promise<boolean> {
const workerService = accessor.get(IEditorWorkerService);
let _conflictResolver: IFormatterConflictCallback | undefined; let model: ITextModel;
let validate: () => boolean;
if (isCodeEditor(editorOrModel)) {
model = editorOrModel.getModel();
const state = new EditorState(editorOrModel, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position);
validate = () => state.validate(editorOrModel);
} else {
model = editorOrModel;
const versionNow = editorOrModel.getVersionId();
validate = () => versionNow === editorOrModel.getVersionId();
}
export function setFormatterConflictCallback(callback: IFormatterConflictCallback): IDisposable { const rawEdits = await provider.provideDocumentRangeFormattingEdits(
let oldCallback = _conflictResolver; model,
_conflictResolver = callback; range,
model.getFormattingOptions(),
token
);
const edits = await workerService.computeMoreMinimalEdits(model.uri, rawEdits);
if (!validate()) {
return true;
}
if (!edits || edits.length === 0) {
return false;
}
if (isCodeEditor(editorOrModel)) {
// use editor to apply edits
FormattingEdit.execute(editorOrModel, edits);
alertFormattingEdits(edits);
editorOrModel.pushUndoStop();
editorOrModel.focus();
editorOrModel.revealPositionInCenterIfOutsideViewport(editorOrModel.getPosition(), editorCommon.ScrollType.Immediate);
} else {
// use model to apply edits
const [{ range }] = edits;
const initialSelection = new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);
model.pushEditOperations([initialSelection], edits.map(edit => {
return { return {
dispose() { text: edit.text,
if (oldCallback) { range: Range.lift(edit.range),
_conflictResolver = oldCallback; forceMoveMarkers: true
oldCallback = undefined;
}
}
}; };
} }), undoEdits => {
for (const { range } of undoEdits) {
function invokeFormatterCallback<T extends { extensionId?: ExtensionIdentifier }>(formatter: T[], model: ITextModel, mode: number): void { if (Range.areIntersectingOrTouching(range, initialSelection)) {
if (_conflictResolver) { return [new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn)];
const ids = formatter.map(formatter => formatter.extensionId);
_conflictResolver(ids, model, mode);
} }
}
return null;
});
}
return true;
} }
export async function getDocumentRangeFormattingEdits( export async function formatDocumentWithProvider(
telemetryService: ITelemetryService, accessor: ServicesAccessor,
provider: DocumentFormattingEditProvider,
editorOrModel: ITextModel | IActiveCodeEditor,
token: CancellationToken
): Promise<boolean> {
const workerService = accessor.get(IEditorWorkerService);
let model: ITextModel;
let validate: () => boolean;
if (isCodeEditor(editorOrModel)) {
model = editorOrModel.getModel();
const state = new EditorState(editorOrModel, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position);
validate = () => state.validate(editorOrModel);
} else {
model = editorOrModel;
const versionNow = editorOrModel.getVersionId();
validate = () => versionNow === editorOrModel.getVersionId();
}
const rawEdits = await provider.provideDocumentFormattingEdits(
model,
model.getFormattingOptions(),
token
);
const edits = await workerService.computeMoreMinimalEdits(model.uri, rawEdits);
if (!validate()) {
return true;
}
if (!edits || edits.length === 0) {
return false;
}
if (isCodeEditor(editorOrModel)) {
// use editor to apply edits
FormattingEdit.execute(editorOrModel, edits);
alertFormattingEdits(edits);
editorOrModel.pushUndoStop();
editorOrModel.focus();
editorOrModel.revealPositionInCenterIfOutsideViewport(editorOrModel.getPosition(), editorCommon.ScrollType.Immediate);
} else {
// use model to apply edits
const [{ range }] = edits;
const initialSelection = new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);
model.pushEditOperations([initialSelection], edits.map(edit => {
return {
text: edit.text,
range: Range.lift(edit.range),
forceMoveMarkers: true
};
}), undoEdits => {
for (const { range } of undoEdits) {
if (Range.areIntersectingOrTouching(range, initialSelection)) {
return [new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn)];
}
}
return null;
});
}
return true;
}
export async function getDocumentRangeFormattingEditsUntilResult(
workerService: IEditorWorkerService, workerService: IEditorWorkerService,
model: ITextModel, model: ITextModel,
range: Range, range: Range,
options: FormattingOptions, options: FormattingOptions,
mode: FormatMode,
token: CancellationToken token: CancellationToken
): Promise<TextEdit[] | undefined | null> { ): Promise<TextEdit[] | undefined> {
const providers = DocumentRangeFormattingEditProviderRegistry.ordered(model); const providers = DocumentRangeFormattingEditProviderRegistry.ordered(model);
for (const provider of providers) {
/* __GDPR__ let rawEdits = await Promise.resolve(provider.provideDocumentRangeFormattingEdits(model, range, options, token)).catch(onUnexpectedExternalError);
"formatterInfo" : { if (isNonEmptyArray(rawEdits)) {
"type" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, return await workerService.computeMoreMinimalEdits(model.uri, rawEdits);
"language" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"extensions" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
} }
*/ }
telemetryService.publicLog('formatterInfo', { return undefined;
type: 'range',
language: model.getLanguageIdentifier().language,
count: providers.length,
extensions: providers.map(p => p.extensionId ? ExtensionIdentifier.toKey(p.extensionId) : 'unknown')
});
invokeFormatterCallback(providers, model, mode | FormatKind.Range);
return first(providers.map(provider => () => {
return Promise.resolve(provider.provideDocumentRangeFormattingEdits(model, range, options, token)).catch(onUnexpectedExternalError);
}), isNonEmptyArray).then(edits => {
// break edits into smaller edits
return workerService.computeMoreMinimalEdits(model.uri, edits);
});
} }
export function getDocumentFormattingEdits( export async function getDocumentFormattingEditsUntilResult(
telemetryService: ITelemetryService,
workerService: IEditorWorkerService, workerService: IEditorWorkerService,
model: ITextModel, model: ITextModel,
options: FormattingOptions, options: FormattingOptions,
mode: FormatMode,
token: CancellationToken token: CancellationToken
): Promise<TextEdit[] | null | undefined> { ): Promise<TextEdit[] | undefined> {
const docFormattingProviders = DocumentFormattingEditProviderRegistry.ordered(model); const providers = getRealAndSyntheticDocumentFormattersOrdered(model);
for (const provider of providers) {
/* __GDPR__ let rawEdits = await Promise.resolve(provider.provideDocumentFormattingEdits(model, options, token)).catch(onUnexpectedExternalError);
"formatterInfo" : { if (isNonEmptyArray(rawEdits)) {
"type" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, return await workerService.computeMoreMinimalEdits(model.uri, rawEdits);
"language" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"extensions" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
} }
*/
telemetryService.publicLog('formatterInfo', {
type: 'document',
language: model.getLanguageIdentifier().language,
count: docFormattingProviders.length,
extensions: docFormattingProviders.map(p => p.extensionId ? ExtensionIdentifier.toKey(p.extensionId) : 'unknown')
});
if (docFormattingProviders.length > 0) {
return first(docFormattingProviders.map(provider => () => {
// first with result wins...
return Promise.resolve(provider.provideDocumentFormattingEdits(model, options, token)).catch(onUnexpectedExternalError);
}), isNonEmptyArray).then(edits => {
// break edits into smaller edits
return workerService.computeMoreMinimalEdits(model.uri, edits);
});
} else {
// try range formatters when no document formatter is registered
return getDocumentRangeFormattingEdits(telemetryService, workerService, model, model.getFullModelRange(), options, mode | FormatKind.Document, token);
} }
return undefined;
} }
export function getOnTypeFormattingEdits( export function getOnTypeFormattingEdits(
telemetryService: ITelemetryService,
workerService: IEditorWorkerService, workerService: IEditorWorkerService,
model: ITextModel, model: ITextModel,
position: Position, position: Position,
@@ -144,21 +264,6 @@ export function getOnTypeFormattingEdits(
const providers = OnTypeFormattingEditProviderRegistry.ordered(model); const providers = OnTypeFormattingEditProviderRegistry.ordered(model);
/* __GDPR__
"formatterInfo" : {
"type" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"language" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"extensions" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
telemetryService.publicLog('formatterInfo', {
type: 'ontype',
language: model.getLanguageIdentifier().language,
count: providers.length,
extensions: providers.map(p => p.extensionId ? ExtensionIdentifier.toKey(p.extensionId) : 'unknown')
});
if (providers.length === 0) { if (providers.length === 0) {
return Promise.resolve(undefined); return Promise.resolve(undefined);
} }
@@ -181,7 +286,7 @@ registerLanguageCommand('_executeFormatRangeProvider', function (accessor, args)
if (!model) { if (!model) {
throw illegalArgument('resource'); throw illegalArgument('resource');
} }
return getDocumentRangeFormattingEdits(accessor.get(ITelemetryService), accessor.get(IEditorWorkerService), model, Range.lift(range), options, FormatMode.Auto, CancellationToken.None); return getDocumentRangeFormattingEditsUntilResult(accessor.get(IEditorWorkerService), model, Range.lift(range), options, CancellationToken.None);
}); });
registerLanguageCommand('_executeFormatDocumentProvider', function (accessor, args) { registerLanguageCommand('_executeFormatDocumentProvider', function (accessor, args) {
@@ -194,7 +299,7 @@ registerLanguageCommand('_executeFormatDocumentProvider', function (accessor, ar
throw illegalArgument('resource'); throw illegalArgument('resource');
} }
return getDocumentFormattingEdits(accessor.get(ITelemetryService), accessor.get(IEditorWorkerService), model, options, FormatMode.Auto, CancellationToken.None); return getDocumentFormattingEditsUntilResult(accessor.get(IEditorWorkerService), model, options, CancellationToken.None);
}); });
registerLanguageCommand('_executeFormatOnTypeProvider', function (accessor, args) { registerLanguageCommand('_executeFormatOnTypeProvider', function (accessor, args) {
@@ -207,5 +312,5 @@ registerLanguageCommand('_executeFormatOnTypeProvider', function (accessor, args
throw illegalArgument('resource'); throw illegalArgument('resource');
} }
return getOnTypeFormattingEdits(accessor.get(ITelemetryService), accessor.get(IEditorWorkerService), model, Position.lift(position), ch, options); return getOnTypeFormattingEdits(accessor.get(IEditorWorkerService), model, Position.lift(position), ch, options);
}); });
+79 -173
View File
@@ -3,122 +3,27 @@
* 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 { alert } from 'vs/base/browser/ui/aria/aria';
import { isNonEmptyArray } from 'vs/base/common/arrays'; import { isNonEmptyArray } from 'vs/base/common/arrays';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { CodeEditorStateFlag, EditorState } from 'vs/editor/browser/core/editorState'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IActiveCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorAction, registerEditorAction, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { EditorAction, registerEditorAction, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { CharacterSet } from 'vs/editor/common/core/characterClassifier'; import { CharacterSet } from 'vs/editor/common/core/characterClassifier';
import { Range } from 'vs/editor/common/core/range'; import { Range } from 'vs/editor/common/core/range';
import * as editorCommon from 'vs/editor/common/editorCommon'; import * as editorCommon from 'vs/editor/common/editorCommon';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { ISingleEditOperation } from 'vs/editor/common/model'; import { DocumentRangeFormattingEditProviderRegistry, OnTypeFormattingEditProviderRegistry } from 'vs/editor/common/modes';
import { DocumentRangeFormattingEditProviderRegistry, FormattingOptions, OnTypeFormattingEditProviderRegistry } from 'vs/editor/common/modes';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
import { getOnTypeFormattingEdits, getDocumentFormattingEdits, getDocumentRangeFormattingEdits, FormatMode } from 'vs/editor/contrib/format/format'; import { getOnTypeFormattingEdits, formatDocumentWithProvider, formatDocumentRangeWithProvider, alertFormattingEdits, getRealAndSyntheticDocumentFormattersOrdered } from 'vs/editor/contrib/format/format';
import { FormattingEdit } from 'vs/editor/contrib/format/formattingEdit'; import { FormattingEdit } from 'vs/editor/contrib/format/formattingEdit';
import * as nls from 'vs/nls'; import * as nls from 'vs/nls';
import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { onUnexpectedError } from 'vs/base/common/errors';
function alertFormattingEdits(edits: ISingleEditOperation[]): void {
edits = edits.filter(edit => edit.range);
if (!edits.length) {
return;
}
let { range } = edits[0];
for (let i = 1; i < edits.length; i++) {
range = Range.plusRange(range, edits[i].range);
}
const { startLineNumber, endLineNumber } = range;
if (startLineNumber === endLineNumber) {
if (edits.length === 1) {
alert(nls.localize('hint11', "Made 1 formatting edit on line {0}", startLineNumber));
} else {
alert(nls.localize('hintn1', "Made {0} formatting edits on line {1}", edits.length, startLineNumber));
}
} else {
if (edits.length === 1) {
alert(nls.localize('hint1n', "Made 1 formatting edit between lines {0} and {1}", startLineNumber, endLineNumber));
} else {
alert(nls.localize('hintnn', "Made {0} formatting edits between lines {1} and {2}", edits.length, startLineNumber, endLineNumber));
}
}
}
const enum FormatRangeType {
Full,
Selection,
}
function formatDocumentRange(
telemetryService: ITelemetryService,
workerService: IEditorWorkerService,
editor: IActiveCodeEditor,
rangeOrRangeType: Range | FormatRangeType,
options: FormattingOptions,
token: CancellationToken
): Promise<void> {
const state = new EditorState(editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position);
const model = editor.getModel();
let range: Range;
if (rangeOrRangeType === FormatRangeType.Full) {
// full
range = model.getFullModelRange();
} else if (rangeOrRangeType === FormatRangeType.Selection) {
// selection or line (when empty)
range = editor.getSelection();
if (range.isEmpty()) {
range = new Range(range.startLineNumber, 1, range.endLineNumber, model.getLineMaxColumn(range.endLineNumber));
}
} else {
// as is
range = rangeOrRangeType;
}
return getDocumentRangeFormattingEdits(telemetryService, workerService, model, range, options, FormatMode.Manual, token).then(edits => {
// make edit only when the editor didn't change while
// computing and only when there are edits
if (state.validate(editor) && isNonEmptyArray(edits)) {
FormattingEdit.execute(editor, edits);
alertFormattingEdits(edits);
editor.focus();
editor.revealPositionInCenterIfOutsideViewport(editor.getPosition(), editorCommon.ScrollType.Immediate);
}
});
}
function formatDocument(telemetryService: ITelemetryService, workerService: IEditorWorkerService, editor: IActiveCodeEditor, options: FormattingOptions, token: CancellationToken): Promise<void> {
const allEdits: ISingleEditOperation[] = [];
const state = new EditorState(editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position);
return getDocumentFormattingEdits(telemetryService, workerService, editor.getModel(), options, FormatMode.Manual, token).then(edits => {
// make edit only when the editor didn't change while
// computing and only when there are edits
if (state.validate(editor) && isNonEmptyArray(edits)) {
FormattingEdit.execute(editor, edits);
alertFormattingEdits(allEdits);
editor.pushUndoStop();
editor.focus();
editor.revealPositionInCenterIfOutsideViewport(editor.getPosition(), editorCommon.ScrollType.Immediate);
}
});
}
class FormatOnType implements editorCommon.IEditorContribution { class FormatOnType implements editorCommon.IEditorContribution {
@@ -130,17 +35,25 @@ class FormatOnType implements editorCommon.IEditorContribution {
constructor( constructor(
editor: ICodeEditor, editor: ICodeEditor,
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@IEditorWorkerService private readonly _workerService: IEditorWorkerService @IEditorWorkerService private readonly _workerService: IEditorWorkerService
) { ) {
this._editor = editor; this._editor = editor;
this._callOnDispose.push(editor.onDidChangeConfiguration(() => this.update())); this._callOnDispose.push(editor.onDidChangeConfiguration(() => this._update()));
this._callOnDispose.push(editor.onDidChangeModel(() => this.update())); this._callOnDispose.push(editor.onDidChangeModel(() => this._update()));
this._callOnDispose.push(editor.onDidChangeModelLanguage(() => this.update())); this._callOnDispose.push(editor.onDidChangeModelLanguage(() => this._update()));
this._callOnDispose.push(OnTypeFormattingEditProviderRegistry.onDidChange(this.update, this)); this._callOnDispose.push(OnTypeFormattingEditProviderRegistry.onDidChange(this._update, this));
} }
private update(): void { getId(): string {
return FormatOnType.ID;
}
dispose(): void {
this._callOnDispose = dispose(this._callOnDispose);
this._callOnModel = dispose(this._callOnModel);
}
private _update(): void {
// clean up // clean up
this._callOnModel = dispose(this._callOnModel); this._callOnModel = dispose(this._callOnModel);
@@ -171,12 +84,12 @@ class FormatOnType implements editorCommon.IEditorContribution {
this._callOnModel.push(this._editor.onDidType((text: string) => { this._callOnModel.push(this._editor.onDidType((text: string) => {
let lastCharCode = text.charCodeAt(text.length - 1); let lastCharCode = text.charCodeAt(text.length - 1);
if (triggerChars.has(lastCharCode)) { if (triggerChars.has(lastCharCode)) {
this.trigger(String.fromCharCode(lastCharCode)); this._trigger(String.fromCharCode(lastCharCode));
} }
})); }));
} }
private trigger(ch: string): void { private _trigger(ch: string): void {
if (!this._editor.hasModel()) { if (!this._editor.hasModel()) {
return; return;
} }
@@ -214,7 +127,6 @@ class FormatOnType implements editorCommon.IEditorContribution {
}); });
getOnTypeFormattingEdits( getOnTypeFormattingEdits(
this._telemetryService,
this._workerService, this._workerService,
model, model,
position, position,
@@ -238,42 +150,41 @@ class FormatOnType implements editorCommon.IEditorContribution {
throw err; throw err;
}); });
} }
public getId(): string {
return FormatOnType.ID;
}
public dispose(): void {
this._callOnDispose = dispose(this._callOnDispose);
this._callOnModel = dispose(this._callOnModel);
}
} }
class FormatOnPaste implements editorCommon.IEditorContribution { class FormatOnPaste implements editorCommon.IEditorContribution {
private static readonly ID = 'editor.contrib.formatOnPaste'; private static readonly ID = 'editor.contrib.formatOnPaste';
private callOnDispose: IDisposable[]; private _callOnDispose: IDisposable[];
private callOnModel: IDisposable[]; private _callOnModel: IDisposable[];
constructor( constructor(
private readonly editor: ICodeEditor, private readonly editor: ICodeEditor,
@IEditorWorkerService private readonly workerService: IEditorWorkerService, @IInstantiationService private readonly _instantiationService: IInstantiationService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
) { ) {
this.callOnDispose = []; this._callOnDispose = [];
this.callOnModel = []; this._callOnModel = [];
this.callOnDispose.push(editor.onDidChangeConfiguration(() => this.update())); this._callOnDispose.push(editor.onDidChangeConfiguration(() => this._update()));
this.callOnDispose.push(editor.onDidChangeModel(() => this.update())); this._callOnDispose.push(editor.onDidChangeModel(() => this._update()));
this.callOnDispose.push(editor.onDidChangeModelLanguage(() => this.update())); this._callOnDispose.push(editor.onDidChangeModelLanguage(() => this._update()));
this.callOnDispose.push(DocumentRangeFormattingEditProviderRegistry.onDidChange(this.update, this)); this._callOnDispose.push(DocumentRangeFormattingEditProviderRegistry.onDidChange(this._update, this));
} }
private update(): void { getId(): string {
return FormatOnPaste.ID;
}
dispose(): void {
this._callOnDispose = dispose(this._callOnDispose);
this._callOnModel = dispose(this._callOnModel);
}
private _update(): void {
// clean up // clean up
this.callOnModel = dispose(this.callOnModel); this._callOnModel = dispose(this._callOnModel);
// we are disabled // we are disabled
if (!this.editor.getConfiguration().contribInfo.formatOnPaste) { if (!this.editor.getConfiguration().contribInfo.formatOnPaste) {
@@ -285,53 +196,41 @@ class FormatOnPaste implements editorCommon.IEditorContribution {
return; return;
} }
let model = this.editor.getModel(); // no formatter
if (!DocumentRangeFormattingEditProviderRegistry.has(this.editor.getModel())) {
// no support
if (!DocumentRangeFormattingEditProviderRegistry.has(model)) {
return; return;
} }
this.callOnModel.push(this.editor.onDidPaste((range: Range) => { this._callOnModel.push(this.editor.onDidPaste(range => this._trigger(range)));
this.trigger(range);
}));
} }
private trigger(range: Range): void { private _trigger(range: Range): void {
if (!this.editor.hasModel()) { if (!this.editor.hasModel()) {
return; return;
} }
if (this.editor.getSelections().length > 1) { if (this.editor.getSelections().length > 1) {
return; return;
} }
const provider = DocumentRangeFormattingEditProviderRegistry.ordered(this.editor.getModel());
const model = this.editor.getModel(); if (provider.length !== 1) {
formatDocumentRange(this.telemetryService, this.workerService, this.editor, range, model.getFormattingOptions(), CancellationToken.None); // print status in n>1 case?
return;
} }
this._instantiationService.invokeFunction(formatDocumentRangeWithProvider, provider[0], this.editor, range, CancellationToken.None).catch(onUnexpectedError);
public getId(): string {
return FormatOnPaste.ID;
}
public dispose(): void {
this.callOnDispose = dispose(this.callOnDispose);
this.callOnModel = dispose(this.callOnModel);
} }
} }
export class FormatDocumentAction extends EditorAction { class FormatDocumentAction extends EditorAction {
constructor() { constructor() {
super({ super({
id: 'editor.action.formatDocument', id: 'editor.action.formatDocument',
label: nls.localize('formatDocument.label', "Format Document"), label: nls.localize('formatDocument.label', "Format Document"),
alias: 'Format Document', alias: 'Format Document',
precondition: EditorContextKeys.writable, precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasDocumentFormattingProvider, EditorContextKeys.hasMultipleDocumentFormattingProvider.toNegated()),
kbOpts: { kbOpts: {
kbExpr: EditorContextKeys.editorTextFocus, kbExpr: ContextKeyExpr.and(EditorContextKeys.editorTextFocus, EditorContextKeys.hasDocumentFormattingProvider),
primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_F, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_F,
// secondary: [KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_D)],
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_I }, linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_I },
weight: KeybindingWeight.EditorContrib weight: KeybindingWeight.EditorContrib
}, },
@@ -343,26 +242,29 @@ export class FormatDocumentAction extends EditorAction {
}); });
} }
run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> | void { async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
if (!editor.hasModel()) { if (!editor.hasModel()) {
return; return;
} }
const workerService = accessor.get(IEditorWorkerService); const instaService = accessor.get(IInstantiationService);
const telemetryService = accessor.get(ITelemetryService); const model = editor.getModel();
return formatDocument(telemetryService, workerService, editor, editor.getModel().getFormattingOptions(), CancellationToken.None); const [provider] = getRealAndSyntheticDocumentFormattersOrdered(model);
if (provider) {
await instaService.invokeFunction(formatDocumentWithProvider, provider, editor, CancellationToken.None);
}
} }
} }
export class FormatSelectionAction extends EditorAction { class FormatSelectionAction extends EditorAction {
constructor() { constructor() {
super({ super({
id: 'editor.action.formatSelection', id: 'editor.action.formatSelection',
label: nls.localize('formatSelection.label', "Format Selection"), label: nls.localize('formatSelection.label', "Format Selection"),
alias: 'Format Code', alias: 'Format Code',
precondition: ContextKeyExpr.and(EditorContextKeys.writable), precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasDocumentSelectionFormattingProvider, EditorContextKeys.hasMultipleDocumentSelectionFormattingProvider.toNegated()),
kbOpts: { kbOpts: {
kbExpr: EditorContextKeys.editorTextFocus, kbExpr: ContextKeyExpr.and(EditorContextKeys.editorTextFocus, EditorContextKeys.hasDocumentSelectionFormattingProvider),
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_F), primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_F),
weight: KeybindingWeight.EditorContrib weight: KeybindingWeight.EditorContrib
}, },
@@ -374,13 +276,19 @@ export class FormatSelectionAction extends EditorAction {
}); });
} }
run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> | void { async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
if (!editor.hasModel()) { if (!editor.hasModel()) {
return; return;
} }
const workerService = accessor.get(IEditorWorkerService); const instaService = accessor.get(IInstantiationService);
const telemetryService = accessor.get(ITelemetryService); const [best] = DocumentRangeFormattingEditProviderRegistry.ordered(editor.getModel());
return formatDocumentRange(telemetryService, workerService, editor, FormatRangeType.Selection, editor.getModel().getFormattingOptions(), CancellationToken.None); if (best) {
let range: Range = editor.getSelection();
if (range.isEmpty()) {
range = new Range(range.startLineNumber, 1, range.startLineNumber, editor.getModel().getLineMaxColumn(range.startLineNumber));
}
await instaService.invokeFunction(formatDocumentRangeWithProvider, best, editor, range, CancellationToken.None);
}
} }
} }
@@ -391,17 +299,15 @@ registerEditorAction(FormatSelectionAction);
// this is the old format action that does both (format document OR format selection) // this is the old format action that does both (format document OR format selection)
// and we keep it here such that existing keybinding configurations etc will still work // and we keep it here such that existing keybinding configurations etc will still work
CommandsRegistry.registerCommand('editor.action.format', accessor => { CommandsRegistry.registerCommand('editor.action.format', async accessor => {
const editor = accessor.get(ICodeEditorService).getFocusedCodeEditor(); const editor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
if (!editor || !editor.hasModel()) { if (!editor || !editor.hasModel()) {
return undefined; return;
} }
const workerService = accessor.get(IEditorWorkerService); const commandService = accessor.get(ICommandService);
const telemetryService = accessor.get(ITelemetryService);
if (editor.getSelection().isEmpty()) { if (editor.getSelection().isEmpty()) {
return formatDocument(telemetryService, workerService, editor, editor.getModel().getFormattingOptions(), CancellationToken.None); await commandService.executeCommand('editor.action.formatDocument');
} else { } else {
return formatDocumentRange(telemetryService, workerService, editor, FormatRangeType.Selection, editor.getModel().getFormattingOptions(), CancellationToken.None); await commandService.executeCommand('editor.action.formatSelection');
} }
}); });
+2 -2
View File
@@ -203,8 +203,8 @@ export class MarkerController implements editorCommon.IEditorContribution {
} }
private readonly _editor: ICodeEditor; private readonly _editor: ICodeEditor;
private _model: MarkerModel | null; private _model: MarkerModel | null = null;
private _widget: MarkerNavigationWidget | null; private _widget: MarkerNavigationWidget | null = null;
private readonly _widgetVisible: IContextKey<boolean>; private readonly _widgetVisible: IContextKey<boolean>;
private _disposeOnClose: IDisposable[] = []; private _disposeOnClose: IDisposable[] = [];
@@ -21,7 +21,7 @@ export class MoveLinesCommand implements ICommand {
private readonly _autoIndent: boolean; private readonly _autoIndent: boolean;
private _selectionId: string; private _selectionId: string;
private _moveEndPositionDown: boolean; private _moveEndPositionDown?: boolean;
private _moveEndLineSelectionShrink: boolean; private _moveEndLineSelectionShrink: boolean;
constructor(selection: Selection, isMovingDown: boolean, autoIndent: boolean) { constructor(selection: Selection, isMovingDown: boolean, autoIndent: boolean) {
@@ -196,10 +196,9 @@ suite('Editor Contrib - Line Operations', () => {
const endOfNonono = new Selection(5, 11, 5, 11); const endOfNonono = new Selection(5, 11, 5, 11);
editor.setSelections([beforeSecondWasoSelection, endOfBCCSelection, endOfNonono]); editor.setSelections([beforeSecondWasoSelection, endOfBCCSelection, endOfNonono]);
let selections;
deleteAllLeftAction.run(null!, editor); deleteAllLeftAction.run(null!, editor);
selections = editor.getSelections(); let selections = editor.getSelections()!;
assert.equal(model.getLineContent(2), ''); assert.equal(model.getLineContent(2), '');
assert.equal(model.getLineContent(3), ' waso waso'); assert.equal(model.getLineContent(3), ' waso waso');
@@ -227,7 +226,7 @@ suite('Editor Contrib - Line Operations', () => {
], [5, 1, 5, 1]); ], [5, 1, 5, 1]);
deleteAllLeftAction.run(null!, editor); deleteAllLeftAction.run(null!, editor);
selections = editor.getSelections(); selections = editor.getSelections()!;
assert.equal(model.getLineContent(1), 'hi my name is Carlos Matos waso waso'); assert.equal(model.getLineContent(1), 'hi my name is Carlos Matos waso waso');
assert.equal(selections.length, 2); assert.equal(selections.length, 2);
@@ -21,6 +21,7 @@ import { Choice, Placeholder, SnippetParser, Text, TextmateSnippet } from './sni
import { ClipboardBasedVariableResolver, CompositeSnippetVariableResolver, ModelBasedVariableResolver, SelectionBasedVariableResolver, TimeBasedVariableResolver, CommentBasedVariableResolver, WorkspaceBasedVariableResolver } from './snippetVariables'; import { ClipboardBasedVariableResolver, CompositeSnippetVariableResolver, ModelBasedVariableResolver, SelectionBasedVariableResolver, TimeBasedVariableResolver, CommentBasedVariableResolver, WorkspaceBasedVariableResolver } from './snippetVariables';
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import * as colors from 'vs/platform/theme/common/colorRegistry'; import * as colors from 'vs/platform/theme/common/colorRegistry';
import { withNullAsUndefined } from 'vs/base/common/types';
registerThemingParticipant((theme, collector) => { registerThemingParticipant((theme, collector) => {
@@ -281,7 +282,7 @@ export class OneSnippet {
let result: Range | undefined; let result: Range | undefined;
const model = this._editor.getModel(); const model = this._editor.getModel();
this._placeholderDecorations.forEach((decorationId) => { this._placeholderDecorations.forEach((decorationId) => {
const placeholderRange = model.getDecorationRange(decorationId) || undefined; const placeholderRange = withNullAsUndefined(model.getDecorationRange(decorationId));
if (!result) { if (!result) {
result = placeholderRange; result = placeholderRange;
} else { } else {
@@ -18,8 +18,8 @@ export class SuggestAlternatives {
private _index: number; private _index: number;
private _model: CompletionModel | undefined; private _model: CompletionModel | undefined;
private _acceptNext: ((selected: ISelectedSuggestion) => any) | undefined; private _acceptNext: ((selected: ISelectedSuggestion) => any) | undefined;
private _listener: IDisposable; private _listener: IDisposable | undefined;
private _ignore: boolean; private _ignore: boolean | undefined;
constructor( constructor(
private readonly _editor: ICodeEditor, private readonly _editor: ICodeEditor,
@@ -63,16 +63,16 @@ export class Colorizer {
// Send out the event to create the mode // Send out the event to create the mode
modeService.triggerMode(language); modeService.triggerMode(language);
let tokenizationSupport = TokenizationRegistry.get(language); const tokenizationSupport = TokenizationRegistry.get(language);
if (tokenizationSupport) { if (tokenizationSupport) {
return _colorize(lines, tabSize, tokenizationSupport); return _colorize(lines, tabSize, tokenizationSupport);
} }
let tokenizationSupportPromise = TokenizationRegistry.getPromise(language); const tokenizationSupportPromise = TokenizationRegistry.getPromise(language);
if (tokenizationSupportPromise) { if (tokenizationSupportPromise) {
// A tokenizer will be registered soon // A tokenizer will be registered soon
return new Promise<string>((resolve, reject) => { return new Promise<string>((resolve, reject) => {
tokenizationSupportPromise!.then(tokenizationSupport => { tokenizationSupportPromise.then(tokenizationSupport => {
_colorize(lines, tabSize, tokenizationSupport).then(resolve, reject); _colorize(lines, tabSize, tokenizationSupport).then(resolve, reject);
}, reject); }, reject);
}); });
@@ -280,7 +280,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService {
})); }));
} }
public addDynamicKeybinding(commandId: string, _keybinding: number, handler: ICommandHandler, when: ContextKeyExpr | null): IDisposable { public addDynamicKeybinding(commandId: string, _keybinding: number, handler: ICommandHandler, when: ContextKeyExpr | undefined): IDisposable {
const keybinding = createKeybinding(_keybinding, OS); const keybinding = createKeybinding(_keybinding, OS);
if (!keybinding) { if (!keybinding) {
throw new Error(`Invalid keybinding`); throw new Error(`Invalid keybinding`);
@@ -342,7 +342,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService {
private _toNormalizedKeybindingItems(items: IKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] { private _toNormalizedKeybindingItems(items: IKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] {
let result: ResolvedKeybindingItem[] = [], resultLen = 0; let result: ResolvedKeybindingItem[] = [], resultLen = 0;
for (const item of items) { for (const item of items) {
const when = (item.when ? item.when.normalize() : null); const when = (item.when ? item.when.normalize() : undefined);
const keybinding = item.keybinding; const keybinding = item.keybinding;
if (!keybinding) { if (!keybinding) {
@@ -665,9 +665,5 @@ export class SimpleLayoutService implements ILayoutService {
return this._container; return this._container;
} }
get hasWorkbench(): boolean {
return false;
}
constructor(private _container: HTMLElement) { } constructor(private _container: HTMLElement) { }
} }
@@ -202,7 +202,12 @@ export class DynamicStandaloneServices extends Disposable {
let contextViewService = ensure(IContextViewService, () => this._register(new ContextViewService(layoutService))); let contextViewService = ensure(IContextViewService, () => this._register(new ContextViewService(layoutService)));
ensure(IContextMenuService, () => this._register(new ContextMenuService(layoutService, telemetryService, notificationService, contextViewService, keybindingService, themeService))); ensure(IContextMenuService, () => {
const contextMenuService = new ContextMenuService(telemetryService, notificationService, contextViewService, keybindingService, themeService);
contextMenuService.configure({ blockMouse: false }); // we do not want that in the standalone editor
return this._register(contextMenuService);
});
ensure(IMenuService, () => new MenuService(commandService)); ensure(IMenuService, () => new MenuService(commandService));
@@ -39,7 +39,7 @@ suite('StandaloneKeybindingService', () => {
let commandInvoked = false; let commandInvoked = false;
keybindingService.addDynamicKeybinding('testCommand', KeyCode.F9, () => { keybindingService.addDynamicKeybinding('testCommand', KeyCode.F9, () => {
commandInvoked = true; commandInvoked = true;
}, null); }, undefined);
keybindingService.testDispatch({ keybindingService.testDispatch({
_standardKeyboardEventBrand: true, _standardKeyboardEventBrand: true,
@@ -13,7 +13,7 @@ import { IResourceInput } from 'vs/platform/editor/common/editor';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
export class TestCodeEditorService extends AbstractCodeEditorService { export class TestCodeEditorService extends AbstractCodeEditorService {
public lastInput: IResourceInput; public lastInput?: IResourceInput;
public getActiveCodeEditor(): ICodeEditor | null { return null; } public getActiveCodeEditor(): ICodeEditor | null { return null; }
public openCodeEditor(input: IResourceInput, source: ICodeEditor | null, sideBySide?: boolean): Promise<ICodeEditor | null> { public openCodeEditor(input: IResourceInput, source: ICodeEditor | null, sideBySide?: boolean): Promise<ICodeEditor | null> {
this.lastInput = input; this.lastInput = input;
@@ -30,7 +30,7 @@ suite('OpenerService', function () {
test('delegate to editorService, scheme:///fff', function () { test('delegate to editorService, scheme:///fff', function () {
const openerService = new OpenerService(editorService, NullCommandService); const openerService = new OpenerService(editorService, NullCommandService);
openerService.open(URI.parse('another:///somepath')); openerService.open(URI.parse('another:///somepath'));
assert.equal(editorService.lastInput.options!.selection, undefined); assert.equal(editorService.lastInput!.options!.selection, undefined);
}); });
test('delegate to editorService, scheme:///fff#L123', function () { test('delegate to editorService, scheme:///fff#L123', function () {
@@ -38,22 +38,22 @@ suite('OpenerService', function () {
const openerService = new OpenerService(editorService, NullCommandService); const openerService = new OpenerService(editorService, NullCommandService);
openerService.open(URI.parse('file:///somepath#L23')); openerService.open(URI.parse('file:///somepath#L23'));
assert.equal(editorService.lastInput.options!.selection!.startLineNumber, 23); assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23);
assert.equal(editorService.lastInput.options!.selection!.startColumn, 1); assert.equal(editorService.lastInput!.options!.selection!.startColumn, 1);
assert.equal(editorService.lastInput.options!.selection!.endLineNumber, undefined); assert.equal(editorService.lastInput!.options!.selection!.endLineNumber, undefined);
assert.equal(editorService.lastInput.options!.selection!.endColumn, undefined); assert.equal(editorService.lastInput!.options!.selection!.endColumn, undefined);
assert.equal(editorService.lastInput.resource.fragment, ''); assert.equal(editorService.lastInput!.resource.fragment, '');
openerService.open(URI.parse('another:///somepath#L23')); openerService.open(URI.parse('another:///somepath#L23'));
assert.equal(editorService.lastInput.options!.selection!.startLineNumber, 23); assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23);
assert.equal(editorService.lastInput.options!.selection!.startColumn, 1); assert.equal(editorService.lastInput!.options!.selection!.startColumn, 1);
openerService.open(URI.parse('another:///somepath#L23,45')); openerService.open(URI.parse('another:///somepath#L23,45'));
assert.equal(editorService.lastInput.options!.selection!.startLineNumber, 23); assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23);
assert.equal(editorService.lastInput.options!.selection!.startColumn, 45); assert.equal(editorService.lastInput!.options!.selection!.startColumn, 45);
assert.equal(editorService.lastInput.options!.selection!.endLineNumber, undefined); assert.equal(editorService.lastInput!.options!.selection!.endLineNumber, undefined);
assert.equal(editorService.lastInput.options!.selection!.endColumn, undefined); assert.equal(editorService.lastInput!.options!.selection!.endColumn, undefined);
assert.equal(editorService.lastInput.resource.fragment, ''); assert.equal(editorService.lastInput!.resource.fragment, '');
}); });
test('delegate to editorService, scheme:///fff#123,123', function () { test('delegate to editorService, scheme:///fff#123,123', function () {
@@ -61,18 +61,18 @@ suite('OpenerService', function () {
const openerService = new OpenerService(editorService, NullCommandService); const openerService = new OpenerService(editorService, NullCommandService);
openerService.open(URI.parse('file:///somepath#23')); openerService.open(URI.parse('file:///somepath#23'));
assert.equal(editorService.lastInput.options!.selection!.startLineNumber, 23); assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23);
assert.equal(editorService.lastInput.options!.selection!.startColumn, 1); assert.equal(editorService.lastInput!.options!.selection!.startColumn, 1);
assert.equal(editorService.lastInput.options!.selection!.endLineNumber, undefined); assert.equal(editorService.lastInput!.options!.selection!.endLineNumber, undefined);
assert.equal(editorService.lastInput.options!.selection!.endColumn, undefined); assert.equal(editorService.lastInput!.options!.selection!.endColumn, undefined);
assert.equal(editorService.lastInput.resource.fragment, ''); assert.equal(editorService.lastInput!.resource.fragment, '');
openerService.open(URI.parse('file:///somepath#23,45')); openerService.open(URI.parse('file:///somepath#23,45'));
assert.equal(editorService.lastInput.options!.selection!.startLineNumber, 23); assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23);
assert.equal(editorService.lastInput.options!.selection!.startColumn, 45); assert.equal(editorService.lastInput!.options!.selection!.startColumn, 45);
assert.equal(editorService.lastInput.options!.selection!.endLineNumber, undefined); assert.equal(editorService.lastInput!.options!.selection!.endLineNumber, undefined);
assert.equal(editorService.lastInput.options!.selection!.endColumn, undefined); assert.equal(editorService.lastInput!.options!.selection!.endColumn, undefined);
assert.equal(editorService.lastInput.resource.fragment, ''); assert.equal(editorService.lastInput!.resource.fragment, '');
}); });
test('delegate to commandsService, command:someid', function () { test('delegate to commandsService, command:someid', function () {
+2
View File
@@ -5205,6 +5205,7 @@ declare namespace monaco.languages {
* the formatting-feature. * the formatting-feature.
*/ */
export interface DocumentFormattingEditProvider { export interface DocumentFormattingEditProvider {
readonly displayName?: string;
/** /**
* Provide formatting edits for a whole document. * Provide formatting edits for a whole document.
*/ */
@@ -5216,6 +5217,7 @@ declare namespace monaco.languages {
* the formatting-feature. * the formatting-feature.
*/ */
export interface DocumentRangeFormattingEditProvider { export interface DocumentRangeFormattingEditProvider {
readonly displayName?: string;
/** /**
* Provide formatting edits for a range in a document. * Provide formatting edits for a range in a document.
* *
@@ -110,7 +110,7 @@ class Menu implements IMenu {
const [id, items] = group; const [id, items] = group;
const activeActions: Array<MenuItemAction | SubmenuItemAction> = []; const activeActions: Array<MenuItemAction | SubmenuItemAction> = [];
for (const item of items) { for (const item of items) {
if (this._contextKeyService.contextMatchesRules(item.when || null)) { if (this._contextKeyService.contextMatchesRules(item.when)) {
const action = isIMenuItem(item) ? new MenuItemAction(item.command, item.alt, options, this._contextKeyService, this._commandService) : new SubmenuItemAction(item); const action = isIMenuItem(item) ? new MenuItemAction(item.command, item.alt, options, this._contextKeyService, this._commandService) : new SubmenuItemAction(item);
activeActions.push(action); activeActions.push(action);
} }
@@ -454,7 +454,7 @@ export class Configuration {
if (workspace && resource) { if (workspace && resource) {
const root = workspace.getFolder(resource); const root = workspace.getFolder(resource);
if (root) { if (root) {
return this._folderConfigurations.get(root.uri) || null; return types.withUndefinedAsNull(this._folderConfigurations.get(root.uri));
} }
} }
return null; return null;
@@ -19,7 +19,7 @@ import { testFile } from 'vs/base/test/node/utils';
class SettingsTestEnvironmentService extends EnvironmentService { class SettingsTestEnvironmentService extends EnvironmentService {
constructor(args: ParsedArgs, _execPath: string, private customAppSettingsHome) { constructor(args: ParsedArgs, _execPath: string, private customAppSettingsHome: string) {
super(args, _execPath); super(args, _execPath);
} }
@@ -252,7 +252,7 @@ export abstract class AbstractContextKeyService implements IContextKeyService {
return new ScopedContextKeyService(this, this._onDidChangeContextKey, domNode); return new ScopedContextKeyService(this, this._onDidChangeContextKey, domNode);
} }
public contextMatchesRules(rules: ContextKeyExpr | null): boolean { public contextMatchesRules(rules: ContextKeyExpr | undefined): boolean {
if (this._isDisposed) { if (this._isDisposed) {
throw new Error(`AbstractContextKeyService has been disposed`); throw new Error(`AbstractContextKeyService has been disposed`);
} }
@@ -58,14 +58,15 @@ export abstract class ContextKeyExpr {
public static greaterThanEquals(key: string, value: any): ContextKeyExpr { public static greaterThanEquals(key: string, value: any): ContextKeyExpr {
return new ContextKeyGreaterThanEqualsExpr(key, value); return new ContextKeyGreaterThanEqualsExpr(key, value);
} }
public static lessThanEquals(key: string, value: any): ContextKeyExpr { public static lessThanEquals(key: string, value: any): ContextKeyExpr {
return new ContextKeyLessThanEqualsExpr(key, value); return new ContextKeyLessThanEqualsExpr(key, value);
} }
// //
public static deserialize(serialized: string | null | undefined, strict: boolean = false): ContextKeyExpr | null { public static deserialize(serialized: string | null | undefined, strict: boolean = false): ContextKeyExpr | undefined {
if (!serialized) { if (!serialized) {
return null; return undefined;
} }
let pieces = serialized.split('&&'); let pieces = serialized.split('&&');
@@ -167,7 +168,7 @@ export abstract class ContextKeyExpr {
public abstract getType(): ContextKeyExprType; public abstract getType(): ContextKeyExprType;
public abstract equals(other: ContextKeyExpr): boolean; public abstract equals(other: ContextKeyExpr): boolean;
public abstract evaluate(context: IContext): boolean; public abstract evaluate(context: IContext): boolean;
public abstract normalize(): ContextKeyExpr | null; public abstract normalize(): ContextKeyExpr | undefined;
public abstract serialize(): string; public abstract serialize(): string;
public abstract keys(): string[]; public abstract keys(): string[];
public abstract map(mapFnc: IContextKeyExprMapper): ContextKeyExpr; public abstract map(mapFnc: IContextKeyExprMapper): ContextKeyExpr;
@@ -549,9 +550,9 @@ export class ContextKeyAndExpr implements ContextKeyExpr {
return expr; return expr;
} }
public normalize(): ContextKeyExpr | null { public normalize(): ContextKeyExpr | undefined {
if (this.expr.length === 0) { if (this.expr.length === 0) {
return null; return undefined;
} }
if (this.expr.length === 1) { if (this.expr.length === 1) {
@@ -762,7 +763,7 @@ export interface IContextKeyService {
onDidChangeContext: Event<IContextKeyChangeEvent>; onDidChangeContext: Event<IContextKeyChangeEvent>;
createKey<T>(key: string, defaultValue: T | undefined): IContextKey<T>; createKey<T>(key: string, defaultValue: T | undefined): IContextKey<T>;
contextMatchesRules(rules: ContextKeyExpr | null): boolean; contextMatchesRules(rules: ContextKeyExpr | undefined): boolean;
getContextKeyValue<T>(key: string): T | undefined; getContextKeyValue<T>(key: string): T | undefined;
createScoped(target?: IContextKeyServiceTarget): IContextKeyService; createScoped(target?: IContextKeyServiceTarget): IContextKeyService;
@@ -5,50 +5,38 @@
import 'vs/css!./contextMenuHandler'; import 'vs/css!./contextMenuHandler';
import { combinedDisposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { combinedDisposable, IDisposable } from 'vs/base/common/lifecycle';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { ActionRunner, IRunEvent } from 'vs/base/common/actions'; import { ActionRunner, IRunEvent } from 'vs/base/common/actions';
import { Menu } from 'vs/base/browser/ui/menu/menu'; import { Menu } from 'vs/base/browser/ui/menu/menu';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { INotificationService } from 'vs/platform/notification/common/notification'; import { INotificationService } from 'vs/platform/notification/common/notification';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IContextMenuDelegate } from 'vs/base/browser/contextmenu'; import { IContextMenuDelegate } from 'vs/base/browser/contextmenu';
import { addDisposableListener, EventType, $, removeNode } from 'vs/base/browser/dom'; import { EventType, $, removeNode } from 'vs/base/browser/dom';
import { attachMenuStyler } from 'vs/platform/theme/common/styler'; import { attachMenuStyler } from 'vs/platform/theme/common/styler';
import { domEvent } from 'vs/base/browser/event'; import { domEvent } from 'vs/base/browser/event';
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
export interface IContextMenuHandlerOptions {
blockMouse: boolean;
}
export class ContextMenuHandler { export class ContextMenuHandler {
private element: HTMLElement | null;
private elementDisposable: IDisposable;
private menuContainerElement: HTMLElement | null;
private focusToReturn: HTMLElement; private focusToReturn: HTMLElement;
private block: HTMLElement | null; private block: HTMLElement | null;
private options: IContextMenuHandlerOptions = { blockMouse: true };
constructor( constructor(
private layoutService: ILayoutService,
private contextViewService: IContextViewService, private contextViewService: IContextViewService,
private telemetryService: ITelemetryService, private telemetryService: ITelemetryService,
private notificationService: INotificationService, private notificationService: INotificationService,
private keybindingService: IKeybindingService, private keybindingService: IKeybindingService,
private themeService: IThemeService private themeService: IThemeService
) { ) { }
this.setContainer(this.layoutService.container);
}
setContainer(container: HTMLElement | null): void { configure(options: IContextMenuHandlerOptions): void {
if (this.element) { this.options = options;
this.elementDisposable = dispose(this.elementDisposable);
this.element = null;
}
if (container) {
this.element = container;
this.elementDisposable = addDisposableListener(this.element, EventType.MOUSE_DOWN, (e) => this.onMouseDown(e as MouseEvent));
}
} }
showContextMenu(delegate: IContextMenuDelegate): void { showContextMenu(delegate: IContextMenuDelegate): void {
@@ -67,8 +55,6 @@ export class ContextMenuHandler {
anchorAlignment: delegate.anchorAlignment, anchorAlignment: delegate.anchorAlignment,
render: (container) => { render: (container) => {
this.menuContainerElement = container;
let className = delegate.getMenuClassName ? delegate.getMenuClassName() : ''; let className = delegate.getMenuClassName ? delegate.getMenuClassName() : '';
if (className) { if (className) {
@@ -76,7 +62,7 @@ export class ContextMenuHandler {
} }
// Render invisible div to block mouse interaction in the rest of the UI // Render invisible div to block mouse interaction in the rest of the UI
if (this.layoutService.hasWorkbench) { if (this.options.blockMouse) {
this.block = container.appendChild($('.context-view-block')); this.block = container.appendChild($('.context-view-block'));
} }
@@ -120,8 +106,6 @@ export class ContextMenuHandler {
if (this.focusToReturn) { if (this.focusToReturn) {
this.focusToReturn.focus(); this.focusToReturn.focus();
} }
this.menuContainerElement = null;
} }
}); });
} }
@@ -150,27 +134,4 @@ export class ContextMenuHandler {
this.notificationService.error(e.error); this.notificationService.error(e.error);
} }
} }
private onMouseDown(e: MouseEvent): void {
if (!this.menuContainerElement) {
return;
}
let event = new StandardMouseEvent(e);
let element: HTMLElement | null = event.target;
while (element) {
if (element === this.menuContainerElement) {
return;
}
element = element.parentElement;
}
this.contextViewService.hideContextView();
}
dispose(): void {
this.setContainer(null);
}
} }
@@ -3,7 +3,7 @@
* 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 { ContextMenuHandler } from './contextMenuHandler'; import { ContextMenuHandler, IContextMenuHandlerOptions } from './contextMenuHandler';
import { IContextViewService, IContextMenuService } from './contextView'; import { IContextViewService, IContextMenuService } from './contextView';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { Event, Emitter } from 'vs/base/common/event'; import { Event, Emitter } from 'vs/base/common/event';
@@ -12,7 +12,6 @@ import { IContextMenuDelegate } from 'vs/base/browser/contextmenu';
import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { Disposable } from 'vs/base/common/lifecycle'; import { Disposable } from 'vs/base/common/lifecycle';
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
export class ContextMenuService extends Disposable implements IContextMenuService { export class ContextMenuService extends Disposable implements IContextMenuService {
_serviceBrand: any; _serviceBrand: any;
@@ -23,7 +22,6 @@ export class ContextMenuService extends Disposable implements IContextMenuServic
private contextMenuHandler: ContextMenuHandler; private contextMenuHandler: ContextMenuHandler;
constructor( constructor(
@ILayoutService layoutService: ILayoutService,
@ITelemetryService telemetryService: ITelemetryService, @ITelemetryService telemetryService: ITelemetryService,
@INotificationService notificationService: INotificationService, @INotificationService notificationService: INotificationService,
@IContextViewService contextViewService: IContextViewService, @IContextViewService contextViewService: IContextViewService,
@@ -32,15 +30,11 @@ export class ContextMenuService extends Disposable implements IContextMenuServic
) { ) {
super(); super();
this.contextMenuHandler = this._register(new ContextMenuHandler(layoutService, contextViewService, telemetryService, notificationService, keybindingService, themeService)); this.contextMenuHandler = new ContextMenuHandler(contextViewService, telemetryService, notificationService, keybindingService, themeService);
} }
dispose(): void { configure(options: IContextMenuHandlerOptions): void {
this.contextMenuHandler.dispose(); this.contextMenuHandler.configure(options);
}
setContainer(container: HTMLElement): void {
this.contextMenuHandler.setContainer(container);
} }
// ContextMenu // ContextMenu
@@ -391,7 +391,7 @@ function collectWorkspaceStats(folder: string, filter: string[]): Promise<Worksp
const MAX_FILES = 20000; const MAX_FILES = 20000;
function walk(dir: string, filter: string[], token, done: (allFiles: string[]) => void): void { function walk(dir: string, filter: string[], token: { count: any; maxReached: any; }, done: (allFiles: string[]) => void): void {
let results: string[] = []; let results: string[] = [];
readdir(dir, async (err, files) => { readdir(dir, async (err, files) => {
// Ignore folders that can't be read // Ignore folders that can't be read
@@ -11,7 +11,7 @@ import { parseExtensionHostPort, parseUserDataDir } from 'vs/platform/environmen
suite('EnvironmentService', () => { suite('EnvironmentService', () => {
test('parseExtensionHostPort when built', () => { test('parseExtensionHostPort when built', () => {
const parse = a => parseExtensionHostPort(parseArgs(a), true); const parse = (a: string[]) => parseExtensionHostPort(parseArgs(a), true);
assert.deepEqual(parse([]), { port: null, break: false, debugId: undefined }); assert.deepEqual(parse([]), { port: null, break: false, debugId: undefined });
assert.deepEqual(parse(['--debugPluginHost']), { port: null, break: false, debugId: undefined }); assert.deepEqual(parse(['--debugPluginHost']), { port: null, break: false, debugId: undefined });
@@ -28,7 +28,7 @@ suite('EnvironmentService', () => {
}); });
test('parseExtensionHostPort when unbuilt', () => { test('parseExtensionHostPort when unbuilt', () => {
const parse = a => parseExtensionHostPort(parseArgs(a), false); const parse = (a: string[]) => parseExtensionHostPort(parseArgs(a), false);
assert.deepEqual(parse([]), { port: 5870, break: false, debugId: undefined }); assert.deepEqual(parse([]), { port: 5870, break: false, debugId: undefined });
assert.deepEqual(parse(['--debugPluginHost']), { port: 5870, break: false, debugId: undefined }); assert.deepEqual(parse(['--debugPluginHost']), { port: 5870, break: false, debugId: undefined });
@@ -45,7 +45,7 @@ suite('EnvironmentService', () => {
}); });
test('userDataPath', () => { test('userDataPath', () => {
const parse = (a, b: { cwd: () => string, env: { [key: string]: string } }) => parseUserDataDir(parseArgs(a), <any>b); const parse = (a: string[], b: { cwd: () => string, env: { [key: string]: string } }) => parseUserDataDir(parseArgs(a), <any>b);
assert.equal(parse(['--user-data-dir', './dir'], { cwd: () => '/foo', env: {} }), path.resolve('/foo/dir'), assert.equal(parse(['--user-data-dir', './dir'], { cwd: () => '/foo', env: {} }), path.resolve('/foo/dir'),
'should use cwd when --user-data-dir is specified'); 'should use cwd when --user-data-dir is specified');
@@ -26,7 +26,7 @@ export function getGalleryExtensionId(publisher: string, name: string): string {
export function groupByExtension<T>(extensions: T[], getExtensionIdentifier: (t: T) => IExtensionIdentifier): T[][] { export function groupByExtension<T>(extensions: T[], getExtensionIdentifier: (t: T) => IExtensionIdentifier): T[][] {
const byExtension: T[][] = []; const byExtension: T[][] = [];
const findGroup = extension => { const findGroup = (extension: T) => {
for (const group of byExtension) { for (const group of byExtension) {
if (group.some(e => areSameExtensions(getExtensionIdentifier(e), getExtensionIdentifier(extension)))) { if (group.some(e => areSameExtensions(getExtensionIdentifier(e), getExtensionIdentifier(extension)))) {
return group; return group;
@@ -13,7 +13,7 @@ export interface ITranslations {
} }
export function localizeManifest(manifest: IExtensionManifest, translations: ITranslations): IExtensionManifest { export function localizeManifest(manifest: IExtensionManifest, translations: ITranslations): IExtensionManifest {
const patcher = value => { const patcher = (value: string) => {
if (typeof value !== 'string') { if (typeof value !== 'string') {
return undefined; return undefined;
} }
@@ -54,7 +54,7 @@ export class ExtensionsLifecycle extends Disposable {
return new Promise<void>((c, e) => { return new Promise<void>((c, e) => {
const extensionLifecycleProcess = this.start(lifecycleHook, lifecycleType, args, extension); const extensionLifecycleProcess = this.start(lifecycleHook, lifecycleType, args, extension);
let timeoutHandler; let timeoutHandler: any;
const onexit = (error?: string) => { const onexit = (error?: string) => {
if (timeoutHandler) { if (timeoutHandler) {
@@ -44,7 +44,7 @@ export class ExtensionManagementChannel implements IServerChannel {
this.onDidUninstallExtension = Event.buffer(service.onDidUninstallExtension, true); this.onDidUninstallExtension = Event.buffer(service.onDidUninstallExtension, true);
} }
listen(context, event: string): Event<any> { listen(context: any, event: string): Event<any> {
const uriTransformer = this.getUriTransformer(context); const uriTransformer = this.getUriTransformer(context);
switch (event) { switch (event) {
case 'onInstallExtension': return this.onInstallExtension; case 'onInstallExtension': return this.onInstallExtension;
@@ -56,7 +56,7 @@ export class ExtensionManagementChannel implements IServerChannel {
throw new Error('Invalid listen'); throw new Error('Invalid listen');
} }
call(context, command: string, args?: any): Promise<any> { call(context: any, command: string, args?: any): Promise<any> {
const uriTransformer: IURITransformer | null = this.getUriTransformer(context); const uriTransformer: IURITransformer | null = this.getUriTransformer(context);
switch (command) { switch (command) {
case 'zip': return this.service.zip(transformIncomingExtension(args[0], uriTransformer)).then(uri => transformOutgoingURI(uri, uriTransformer)); case 'zip': return this.service.zip(transformIncomingExtension(args[0], uriTransformer)).then(uri => transformOutgoingURI(uri, uriTransformer));
@@ -170,7 +170,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
private collectFiles(extension: ILocalExtension): Promise<IFile[]> { private collectFiles(extension: ILocalExtension): Promise<IFile[]> {
const collectFilesFromDirectory = async (dir): Promise<string[]> => { const collectFilesFromDirectory = async (dir: string): Promise<string[]> => {
let entries = await pfs.readdir(dir); let entries = await pfs.readdir(dir);
entries = entries.map(e => path.join(dir, e)); entries = entries.map(e => path.join(dir, e));
const stats = await Promise.all(entries.map(e => pfs.stat(e))); const stats = await Promise.all(entries.map(e => pfs.stat(e)));
@@ -288,7 +288,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
this.reportTelemetry(this.getTelemetryEvent(operation), getGalleryExtensionTelemetryData(extension), new Date().getTime() - startTime, undefined); this.reportTelemetry(this.getTelemetryEvent(operation), getGalleryExtensionTelemetryData(extension), new Date().getTime() - startTime, undefined);
}; };
const onDidInstallExtensionFailure = (extension: IGalleryExtension, operation: InstallOperation, error) => { const onDidInstallExtensionFailure = (extension: IGalleryExtension, operation: InstallOperation, error: Error) => {
const errorCode = error && (<ExtensionManagementError>error).code ? (<ExtensionManagementError>error).code : ERROR_UNKNOWN; const errorCode = error && (<ExtensionManagementError>error).code ? (<ExtensionManagementError>error).code : ERROR_UNKNOWN;
this.logService.error(`Failed to install extension:`, extension.identifier.id, error ? error.message : errorCode); this.logService.error(`Failed to install extension:`, extension.identifier.id, error ? error.message : errorCode);
this._onDidInstallExtension.fire({ identifier: extension.identifier, gallery: extension, operation, error: errorCode }); this._onDidInstallExtension.fire({ identifier: extension.identifier, gallery: extension, operation, error: errorCode });
+69 -21
View File
@@ -84,13 +84,18 @@ export interface IFileService {
* If the optional parameter "resolveSingleChildDescendants" is specified in options, * If the optional parameter "resolveSingleChildDescendants" is specified in options,
* the stat service is asked to automatically resolve child folders that only * the stat service is asked to automatically resolve child folders that only
* contain a single element. * contain a single element.
*
* If the optional parameter "resolveMetadata" is specified in options,
* the stat will contain metadata information such as size, mtime and etag.
*/ */
resolveFile(resource: URI, options: IResolveMetadataFileOptions): Promise<IFileStatWithMetadata>;
resolveFile(resource: URI, options?: IResolveFileOptions): Promise<IFileStat>; resolveFile(resource: URI, options?: IResolveFileOptions): Promise<IFileStat>;
/** /**
* Same as resolveFile but supports resolving multiple resources in parallel. * Same as resolveFile but supports resolving multiple resources in parallel.
* If one of the resolve targets fails to resolve returns a fake IFileStat instead of making the whole call fail. * If one of the resolve targets fails to resolve returns a fake IFileStat instead of making the whole call fail.
*/ */
resolveFiles(toResolve: { resource: URI, options: IResolveMetadataFileOptions }[]): Promise<IResolveFileResult[]>;
resolveFiles(toResolve: { resource: URI, options?: IResolveFileOptions }[]): Promise<IResolveFileResult[]>; resolveFiles(toResolve: { resource: URI, options?: IResolveFileOptions }[]): Promise<IResolveFileResult[]>;
/** /**
@@ -115,21 +120,21 @@ export interface IFileService {
/** /**
* Updates the content replacing its previous value. * Updates the content replacing its previous value.
*/ */
updateContent(resource: URI, value: string | ITextSnapshot, options?: IUpdateContentOptions): Promise<IFileStat>; updateContent(resource: URI, value: string | ITextSnapshot, options?: IUpdateContentOptions): Promise<IFileStatWithMetadata>;
/** /**
* Moves the file to a new path identified by the resource. * Moves the file to a new path identified by the resource.
* *
* The optional parameter overwrite can be set to replace an existing file at the location. * The optional parameter overwrite can be set to replace an existing file at the location.
*/ */
moveFile(source: URI, target: URI, overwrite?: boolean): Promise<IFileStat>; moveFile(source: URI, target: URI, overwrite?: boolean): Promise<IFileStatWithMetadata>;
/** /**
* Copies the file to a path identified by the resource. * Copies the file to a path identified by the resource.
* *
* The optional parameter overwrite can be set to replace an existing file at the location. * The optional parameter overwrite can be set to replace an existing file at the location.
*/ */
copyFile(source: URI, target: URI, overwrite?: boolean): Promise<IFileStat>; copyFile(source: URI, target: URI, overwrite?: boolean): Promise<IFileStatWithMetadata>;
/** /**
* Creates a new file with the given path. The returned promise * Creates a new file with the given path. The returned promise
@@ -137,13 +142,13 @@ export interface IFileService {
* *
* The optional parameter content can be used as value to fill into the new file. * The optional parameter content can be used as value to fill into the new file.
*/ */
createFile(resource: URI, content?: string, options?: ICreateFileOptions): Promise<IFileStat>; createFile(resource: URI, content?: string, options?: ICreateFileOptions): Promise<IFileStatWithMetadata>;
/** /**
* Creates a new folder with the given path. The returned promise * Creates a new folder with the given path. The returned promise
* will have the stat model object as a result. * will have the stat model object as a result.
*/ */
createFolder(resource: URI): Promise<IFileStat>; createFolder(resource: URI): Promise<IFileStatWithMetadata>;
/** /**
* Deletes the provided file. The optional useTrash parameter allows to * Deletes the provided file. The optional useTrash parameter allows to
@@ -194,9 +199,9 @@ export enum FileType {
export interface IStat { export interface IStat {
type: FileType; type: FileType;
mtime: number; mtime?: number;
ctime: number; ctime?: number;
size: number; size?: number;
} }
export interface IWatchOptions { export interface IWatchOptions {
@@ -329,7 +334,7 @@ export const enum FileOperation {
export class FileOperationEvent { export class FileOperationEvent {
constructor(private _resource: URI, private _operation: FileOperation, private _target?: IFileStat) { constructor(private _resource: URI, private _operation: FileOperation, private _target?: IFileStatWithMetadata) {
} }
get resource(): URI { get resource(): URI {
@@ -481,7 +486,7 @@ export function isParent(path: string, candidate: string, ignoreCase?: boolean):
return path.indexOf(candidate) === 0; return path.indexOf(candidate) === 0;
} }
export interface IBaseStat { interface IBaseStat {
/** /**
* The unified resource identifier of this file or folder. * The unified resource identifier of this file or folder.
@@ -494,15 +499,29 @@ export interface IBaseStat {
*/ */
name: string; name: string;
/**
* The size of the file.
*
* The value may or may not be resolved as
* it is optional.
*/
size?: number;
/** /**
* The last modifictaion date represented * The last modifictaion date represented
* as millis from unix epoch. * as millis from unix epoch.
*
* The value may or may not be resolved as
* it is optional.
*/ */
mtime: number; mtime?: number;
/** /**
* A unique identifier thet represents the * A unique identifier thet represents the
* current state of the file or directory. * current state of the file or directory.
*
* The value may or may not be resolved as
* it is optional.
*/ */
etag?: string; etag?: string;
@@ -512,6 +531,12 @@ export interface IBaseStat {
isReadonly?: boolean; isReadonly?: boolean;
} }
export interface IBaseStatWithMetadata extends IBaseStat {
mtime: number;
etag: string;
size: number;
}
/** /**
* A file resource with meta information. * A file resource with meta information.
*/ */
@@ -532,11 +557,13 @@ export interface IFileStat extends IBaseStat {
* The children of the file stat or undefined if none. * The children of the file stat or undefined if none.
*/ */
children?: IFileStat[]; children?: IFileStat[];
}
/** export interface IFileStatWithMetadata extends IFileStat, IBaseStatWithMetadata {
* The size of the file if known. mtime: number;
*/ etag: string;
size?: number; size: number;
children?: IFileStatWithMetadata[];
} }
export interface IResolveFileResult { export interface IResolveFileResult {
@@ -544,10 +571,14 @@ export interface IResolveFileResult {
success: boolean; success: boolean;
} }
export interface IResolveFileResultWithMetadata extends IResolveFileResult {
stat?: IFileStatWithMetadata;
}
/** /**
* Content and meta information of a file. * Content and meta information of a file.
*/ */
export interface IContent extends IBaseStat { export interface IContent extends IBaseStatWithMetadata {
/** /**
* The content of a text file. * The content of a text file.
@@ -614,7 +645,7 @@ export function snapshotToString(snapshot: ITextSnapshot): string {
/** /**
* Streamable content and meta information of a file. * Streamable content and meta information of a file.
*/ */
export interface IStreamContent extends IBaseStat { export interface IStreamContent extends IBaseStatWithMetadata {
/** /**
* The streamable content of a text file. * The streamable content of a text file.
@@ -712,6 +743,16 @@ export interface IResolveFileOptions {
* Automatically continue resolving children of a directory if the number of children is 1. * Automatically continue resolving children of a directory if the number of children is 1.
*/ */
resolveSingleChildDescendants?: boolean; resolveSingleChildDescendants?: boolean;
/**
* Will resolve mtime, size and etag of files if enabled. This can have a negative impact
* on performance and thus should only be used when these values are required.
*/
resolveMetadata?: boolean;
}
export interface IResolveMetadataFileOptions extends IResolveFileOptions {
resolveMetadata: true;
} }
export interface ICreateFileOptions { export interface ICreateFileOptions {
@@ -1033,6 +1074,17 @@ export enum FileKind {
export const MIN_MAX_MEMORY_SIZE_MB = 2048; export const MIN_MAX_MEMORY_SIZE_MB = 2048;
export const FALLBACK_MAX_MEMORY_SIZE_MB = 4096; export const FALLBACK_MAX_MEMORY_SIZE_MB = 4096;
export function etag(mtime: number, size: number): string;
export function etag(mtime: number | undefined, size: number | undefined): string | undefined;
export function etag(mtime: number | undefined, size: number | undefined): string | undefined {
if (typeof size !== 'number' || typeof mtime !== 'number') {
return undefined;
}
return mtime.toString(29) + size.toString(31);
}
// TODO@ben remove traces of legacy file service // TODO@ben remove traces of legacy file service
export const ILegacyFileService = createDecorator<ILegacyFileService>('legacyFileService'); export const ILegacyFileService = createDecorator<ILegacyFileService>('legacyFileService');
export interface ILegacyFileService { export interface ILegacyFileService {
@@ -1049,10 +1101,6 @@ export interface ILegacyFileService {
updateContent(resource: URI, value: string | ITextSnapshot, options?: IUpdateContentOptions): Promise<IFileStat>; updateContent(resource: URI, value: string | ITextSnapshot, options?: IUpdateContentOptions): Promise<IFileStat>;
moveFile(source: URI, target: URI, overwrite?: boolean): Promise<IFileStat>;
copyFile(source: URI, target: URI, overwrite?: boolean): Promise<IFileStat>;
createFile(resource: URI, content?: string, options?: ICreateFileOptions): Promise<IFileStat>; createFile(resource: URI, content?: string, options?: ICreateFileOptions): Promise<IFileStat>;
del(resource: URI, options?: { useTrash?: boolean, recursive?: boolean }): Promise<void>; del(resource: URI, options?: { useTrash?: boolean, recursive?: boolean }): Promise<void>;
@@ -71,7 +71,7 @@ class Service1Consumer {
class Target2Dep { class Target2Dep {
constructor(@IService1 service1: IService1, @IService2 service2) { constructor(@IService1 service1: IService1, @IService2 service2: Service2) {
assert.ok(service1 instanceof Service1); assert.ok(service1 instanceof Service1);
assert.ok(service2 instanceof Service2); assert.ok(service2 instanceof Service2);
} }
@@ -99,7 +99,7 @@ class TargetOptional {
} }
class DependentServiceTarget { class DependentServiceTarget {
constructor(@IDependentService d) { constructor(@IDependentService d: IDependentService) {
assert.ok(d); assert.ok(d);
assert.equal(d.name, 'farboo'); assert.equal(d.name, 'farboo');
} }
@@ -72,7 +72,7 @@ export class IssueService implements IIssueService {
} }
}); });
ipcMain.on('vscode:workbenchCommand', (_: unknown, commandInfo) => { ipcMain.on('vscode:workbenchCommand', (_: unknown, commandInfo: { id: any; from: any; args: any; }) => {
const { id, from, args } = commandInfo; const { id, from, args } = commandInfo;
let parentWindow: BrowserWindow | null; let parentWindow: BrowserWindow | null;
@@ -92,7 +92,7 @@ export class IssueService implements IIssueService {
} }
}); });
ipcMain.on('vscode:openExternal', (_: unknown, arg) => { ipcMain.on('vscode:openExternal', (_: unknown, arg: string) => {
this.windowsService.openExternal(arg); this.windowsService.openExternal(arg);
}); });
@@ -50,7 +50,7 @@ export class KeybindingResolver {
} }
} }
private static _isTargetedForRemoval(defaultKb: ResolvedKeybindingItem, keypressFirstPart: string | null, keypressChordPart: string | null, command: string, when: ContextKeyExpr | null): boolean { private static _isTargetedForRemoval(defaultKb: ResolvedKeybindingItem, keypressFirstPart: string | null, keypressChordPart: string | null, command: string, when: ContextKeyExpr | undefined): boolean {
if (defaultKb.command !== command) { if (defaultKb.command !== command) {
return false; return false;
} }
@@ -172,7 +172,7 @@ export class KeybindingResolver {
* Returns true if it is provable `a` implies `b`. * Returns true if it is provable `a` implies `b`.
* **Precondition**: Assumes `a` and `b` are normalized! * **Precondition**: Assumes `a` and `b` are normalized!
*/ */
public static whenIsEntirelyIncluded(a: ContextKeyExpr | null, b: ContextKeyExpr | null): boolean { public static whenIsEntirelyIncluded(a: ContextKeyExpr | null | undefined, b: ContextKeyExpr | null | undefined): boolean {
if (!b) { if (!b) {
return true; return true;
} }
@@ -304,7 +304,7 @@ export class KeybindingResolver {
return null; return null;
} }
public static contextMatchesRules(context: IContext, rules: ContextKeyExpr | null): boolean { public static contextMatchesRules(context: IContext, rules: ContextKeyExpr | null | undefined): boolean {
if (!rules) { if (!rules) {
return true; return true;
} }
@@ -49,7 +49,7 @@ export interface IKeybindingRule2 {
id: string; id: string;
args?: any; args?: any;
weight: number; weight: number;
when: ContextKeyExpr | null; when: ContextKeyExpr | undefined;
} }
export const enum KeybindingWeight { export const enum KeybindingWeight {
@@ -15,10 +15,10 @@ export class ResolvedKeybindingItem {
public readonly bubble: boolean; public readonly bubble: boolean;
public readonly command: string | null; public readonly command: string | null;
public readonly commandArgs: any; public readonly commandArgs: any;
public readonly when: ContextKeyExpr | null; public readonly when: ContextKeyExpr | undefined;
public readonly isDefault: boolean; public readonly isDefault: boolean;
constructor(resolvedKeybinding: ResolvedKeybinding | null, command: string | null, commandArgs: any, when: ContextKeyExpr | null, isDefault: boolean) { constructor(resolvedKeybinding: ResolvedKeybinding | null, command: string | null, commandArgs: any, when: ContextKeyExpr | undefined, isDefault: boolean) {
this.resolvedKeybinding = resolvedKeybinding; this.resolvedKeybinding = resolvedKeybinding;
this.keypressParts = resolvedKeybinding ? removeElementsAfterNulls(resolvedKeybinding.getDispatchParts()) : []; this.keypressParts = resolvedKeybinding ? removeElementsAfterNulls(resolvedKeybinding.getDispatchParts()) : [];
this.bubble = (command ? command.charCodeAt(0) === CharCode.Caret : false); this.bubble = (command ? command.charCodeAt(0) === CharCode.Caret : false);
@@ -178,7 +178,7 @@ suite('AbstractKeybindingService', () => {
statusMessageCallsDisposed = null; statusMessageCallsDisposed = null;
}); });
function kbItem(keybinding: number, command: string, when: ContextKeyExpr | null = null): ResolvedKeybindingItem { function kbItem(keybinding: number, command: string, when?: ContextKeyExpr): ResolvedKeybindingItem {
const resolvedKeybinding = (keybinding !== 0 ? new USLayoutResolvedKeybinding(createKeybinding(keybinding, OS)!, OS) : null); const resolvedKeybinding = (keybinding !== 0 ? new USLayoutResolvedKeybinding(createKeybinding(keybinding, OS)!, OS) : null);
return new ResolvedKeybindingItem( return new ResolvedKeybindingItem(
resolvedKeybinding, resolvedKeybinding,
@@ -26,7 +26,7 @@ suite('KeybindingResolver', () => {
resolvedKeybinding, resolvedKeybinding,
command, command,
commandArgs, commandArgs,
when ? when.normalize() : null, when ? when.normalize() : undefined,
isDefault isDefault
); );
} }
@@ -215,7 +215,8 @@ export class LaunchService implements ILaunchService {
preferNewWindow: !args['reuse-window'] && !args.wait, preferNewWindow: !args['reuse-window'] && !args.wait,
forceReuseWindow: args['reuse-window'], forceReuseWindow: args['reuse-window'],
diffMode: args.diff, diffMode: args.diff,
addMode: args.add addMode: args.add,
noRecentEntry: !!args['skip-add-to-recently-opened']
}); });
} }
@@ -32,10 +32,4 @@ export interface ILayoutService {
* event carries the dimensions of the container as part of it. * event carries the dimensions of the container as part of it.
*/ */
readonly onLayout: Event<IDimension>; readonly onLayout: Event<IDimension>;
/**
* Indicates if the layout has a workbench surrounding the editor
*/
readonly hasWorkbench: boolean;
} }
@@ -56,7 +56,7 @@ export class LifecycleService extends AbstractLifecycleService {
const windowId = this.windowService.getCurrentWindowId(); const windowId = this.windowService.getCurrentWindowId();
// Main side indicates that window is about to unload, check for vetos // Main side indicates that window is about to unload, check for vetos
ipc.on('vscode:onBeforeUnload', (event, reply: { okChannel: string, cancelChannel: string, reason: ShutdownReason }) => { ipc.on('vscode:onBeforeUnload', (_event: unknown, reply: { okChannel: string, cancelChannel: string, reason: ShutdownReason }) => {
this.logService.trace(`lifecycle: onBeforeUnload (reason: ${reply.reason})`); this.logService.trace(`lifecycle: onBeforeUnload (reason: ${reply.reason})`);
// trigger onBeforeShutdown events and veto collecting // trigger onBeforeShutdown events and veto collecting
@@ -75,7 +75,7 @@ export class LifecycleService extends AbstractLifecycleService {
}); });
// Main side indicates that we will indeed shutdown // Main side indicates that we will indeed shutdown
ipc.on('vscode:onWillUnload', (event, reply: { replyChannel: string, reason: ShutdownReason }) => { ipc.on('vscode:onWillUnload', (_event: unknown, reply: { replyChannel: string, reason: ShutdownReason }) => {
this.logService.trace(`lifecycle: onWillUnload (reason: ${reply.reason})`); this.logService.trace(`lifecycle: onWillUnload (reason: ${reply.reason})`);
// trigger onWillShutdown events and joining // trigger onWillShutdown events and joining
@@ -276,7 +276,7 @@ export class LifecycleService extends Disposable implements ILifecycleService {
}); });
// Window After Closing // Window After Closing
window.win.on('closed', e => { window.win.on('closed', () => {
this.logService.trace(`Lifecycle#window.on('closed') - window ID ${window.id}`); this.logService.trace(`Lifecycle#window.on('closed') - window ID ${window.id}`);
// update window count // update window count
@@ -11,6 +11,7 @@ export interface IRemoteAgentEnvironment {
pid: number; pid: number;
appRoot: URI; appRoot: URI;
appSettingsHome: URI; appSettingsHome: URI;
appSettingsPath: URI;
logsPath: URI; logsPath: URI;
extensionsPath: URI; extensionsPath: URI;
extensionHostLogsPath: URI; extensionHostLogsPath: URI;

Some files were not shown because too many files have changed in this diff Show More