From 928f32c8c41bc228fb3043af5a3a6b53234f411a Mon Sep 17 00:00:00 2001 From: jeanp413 Date: Sun, 2 Feb 2020 03:56:53 -0500 Subject: [PATCH 001/235] Fixes #89484 --- src/vs/editor/contrib/links/links.ts | 2 +- src/vs/workbench/contrib/scm/browser/repositoryPane.ts | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/links/links.ts b/src/vs/editor/contrib/links/links.ts index bf5399f274a..3035b2d276c 100644 --- a/src/vs/editor/contrib/links/links.ts +++ b/src/vs/editor/contrib/links/links.ts @@ -97,7 +97,7 @@ class LinkOccurrence { } } -class LinkDetector implements IEditorContribution { +export class LinkDetector implements IEditorContribution { public static readonly ID: string = 'editor.linkDetector'; diff --git a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts index 41e20df5115..5e6f08efbea 100644 --- a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts +++ b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts @@ -65,6 +65,9 @@ import { format } from 'vs/base/common/strings'; import { inputPlaceholderForeground, inputValidationInfoBorder, inputValidationWarningBorder, inputValidationErrorBorder, inputValidationInfoBackground, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningForeground, inputValidationErrorBackground, inputValidationErrorForeground, inputBackground, inputForeground, inputBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry'; import { Schemas } from 'vs/base/common/network'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; +import { ModesHoverController } from 'vs/editor/contrib/hover/hover'; +import { ColorDetector } from 'vs/editor/contrib/colorPicker/colorDetector'; +import { LinkDetector } from 'vs/editor/contrib/links/links'; type TreeElement = ISCMResourceGroup | IResourceNode | ISCMResource; @@ -734,6 +737,9 @@ export class RepositoryPane extends ViewPane { MenuPreventer.ID, SelectionClipboardContributionID, ContextMenuController.ID, + ColorDetector.ID, + ModesHoverController.ID, + LinkDetector.ID ]) }; From 1da42812e85210469ee53cbb1bb3c9615ace5025 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Fri, 14 Feb 2020 11:27:45 +0100 Subject: [PATCH 002/235] remove custom d.ts-files, update tsconfig-files, fix new compile errors --- src/tsconfig.base.json | 8 +- src/tsconfig.json | 8 - src/tsconfig.monaco.json | 4 +- src/typings/es2015-proxy.d.ts | 29 - src/typings/es6-promise.d.ts | 89 -- src/typings/lib.ie11_safe_es6.d.ts | 821 ------------------ .../extensions/common/extensionHostMain.ts | 2 +- 7 files changed, 9 insertions(+), 952 deletions(-) delete mode 100644 src/typings/es2015-proxy.d.ts delete mode 100644 src/typings/es6-promise.d.ts delete mode 100644 src/typings/lib.ie11_safe_es6.d.ts diff --git a/src/tsconfig.base.json b/src/tsconfig.base.json index 44595cf5246..c58519bddad 100644 --- a/src/tsconfig.base.json +++ b/src/tsconfig.base.json @@ -17,6 +17,12 @@ "vs/*": [ "./vs/*" ] - } + }, + "lib": [ + "ES2015", + "DOM", + "DOM.Iterable", + "WebWorker.ImportScripts" + ] } } diff --git a/src/tsconfig.json b/src/tsconfig.json index b8cc1caf2cd..9419d9af0f4 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -6,11 +6,6 @@ "sourceMap": false, "outDir": "../out", "target": "es2017", - "lib": [ - "dom", - "es5", - "es2015.iterable" - ], "types": [ "keytar", "mocha", @@ -22,8 +17,5 @@ "include": [ "./typings", "./vs" - ], - "exclude": [ - "./typings/es6-promise.d.ts" ] } diff --git a/src/tsconfig.monaco.json b/src/tsconfig.monaco.json index a6430a44ccb..61377a881ff 100644 --- a/src/tsconfig.monaco.json +++ b/src/tsconfig.monaco.json @@ -8,17 +8,15 @@ "moduleResolution": "classic", "removeComments": false, "preserveConstEnums": true, - "target": "es5", + "target": "es6", "sourceMap": false, "declaration": true }, "include": [ "typings/require.d.ts", "typings/thenable.d.ts", - "typings/es6-promise.d.ts", "typings/lib.es2018.promise.d.ts", "typings/lib.array-ext.d.ts", - "typings/lib.ie11_safe_es6.d.ts", "vs/css.d.ts", "vs/monaco.d.ts", "vs/nls.d.ts", diff --git a/src/typings/es2015-proxy.d.ts b/src/typings/es2015-proxy.d.ts deleted file mode 100644 index 00f7c2b0642..00000000000 --- a/src/typings/es2015-proxy.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -// from TypeScript: lib.es2015.proxy.d.ts - -interface ProxyHandler { - getPrototypeOf?(target: T): object | null; - setPrototypeOf?(target: T, v: any): boolean; - isExtensible?(target: T): boolean; - preventExtensions?(target: T): boolean; - getOwnPropertyDescriptor?(target: T, p: PropertyKey): PropertyDescriptor | undefined; - has?(target: T, p: PropertyKey): boolean; - get?(target: T, p: PropertyKey, receiver: any): any; - set?(target: T, p: PropertyKey, value: any, receiver: any): boolean; - deleteProperty?(target: T, p: PropertyKey): boolean; - defineProperty?(target: T, p: PropertyKey, attributes: PropertyDescriptor): boolean; - enumerate?(target: T): PropertyKey[]; - ownKeys?(target: T): PropertyKey[]; - apply?(target: T, thisArg: any, argArray?: any): any; - construct?(target: T, argArray: any, newTarget?: any): object; -} - -interface ProxyConstructor { - revocable(target: T, handler: ProxyHandler): { proxy: T; revoke: () => void; }; - new (target: T, handler: ProxyHandler): T; -} -declare var Proxy: ProxyConstructor; diff --git a/src/typings/es6-promise.d.ts b/src/typings/es6-promise.d.ts deleted file mode 100644 index 2d3271e2848..00000000000 --- a/src/typings/es6-promise.d.ts +++ /dev/null @@ -1,89 +0,0 @@ -// Type definitions for es6-promise -// Project: https://github.com/jakearchibald/ES6-Promise -// Definitions by: François de Campredon , vvakame -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped - -interface Thenable { - then(onFulfilled?: (value: T) => U | Thenable, onRejected?: (error: any) => U | Thenable): Thenable; - then(onFulfilled?: (value: T) => U | Thenable, onRejected?: (error: any) => void): Thenable; -} - -declare class Promise implements Thenable { - /** - * If you call resolve in the body of the callback passed to the constructor, - * your promise is fulfilled with result object passed to resolve. - * If you call reject your promise is rejected with the object passed to reject. - * For consistency and debugging (eg stack traces), obj should be an instanceof Error. - * Any errors thrown in the constructor callback will be implicitly passed to reject(). - */ - constructor(callback: (resolve: (value?: T | Thenable) => void, reject: (error?: any) => void) => void); - - /** - * onFulfilled is called when/if "promise" resolves. onRejected is called when/if "promise" rejects. - * Both are optional, if either/both are omitted the next onFulfilled/onRejected in the chain is called. - * Both callbacks have a single parameter , the fulfillment value or rejection reason. - * "then" returns a new promise equivalent to the value you return from onFulfilled/onRejected after being passed through Promise.resolve. - * If an error is thrown in the callback, the returned promise rejects with that error. - * - * @param onFulfilled called when/if "promise" resolves - * @param onRejected called when/if "promise" rejects - */ - then(onFulfilled?: (value: T) => U | Thenable, onRejected?: (error: any) => U | Thenable): Promise; - then(onFulfilled?: (value: T) => U | Thenable, onRejected?: (error: any) => void): Promise; - - /** - * Sugar for promise.then(undefined, onRejected) - * - * @param onRejected called when/if "promise" rejects - */ - catch(onRejected?: (error: any) => U | Thenable): Promise; -} - -declare namespace Promise { - /** - * Make a new promise from the thenable. - * A thenable is promise-like in as far as it has a "then" method. - */ - function resolve(value: T | Thenable): Promise; - - /** - * - */ - function resolve(): Promise; - - /** - * Make a promise that rejects to obj. For consistency and debugging (eg stack traces), obj should be an instanceof Error - */ - function reject(error: any): Promise; - function reject(error: T): Promise; - - /** - * Make a promise that fulfills when every item in the array fulfills, and rejects if (and when) any item rejects. - * the array passed to all can be a mixture of promise-like objects and other objects. - * The fulfillment value is an array (in order) of fulfillment values. The rejection value is the first rejection value. - */ - function all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable, T5 | Thenable, T6 | Thenable, T7 | Thenable, T8 | Thenable, T9 | Thenable, T10 | Thenable]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>; - function all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable, T5 | Thenable, T6 | Thenable, T7 | Thenable, T8 | Thenable, T9 | Thenable]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>; - function all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable, T5 | Thenable, T6 | Thenable, T7 | Thenable, T8 | Thenable]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>; - function all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable, T5 | Thenable, T6 | Thenable, T7 | Thenable]): Promise<[T1, T2, T3, T4, T5, T6, T7]>; - function all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable, T5 | Thenable, T6 | Thenable]): Promise<[T1, T2, T3, T4, T5, T6]>; - function all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable, T5 | Thenable]): Promise<[T1, T2, T3, T4, T5]>; - function all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable]): Promise<[T1, T2, T3, T4]>; - function all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable]): Promise<[T1, T2, T3]>; - function all(values: [T1 | Thenable, T2 | Thenable]): Promise<[T1, T2]>; - function all(values: (T | Thenable)[]): Promise; - - /** - * Make a Promise that fulfills when any item fulfills, and rejects if any item rejects. - */ - function race(promises: (T | Thenable)[]): Promise; -} - -declare module 'es6-promise' { - var foo: typeof Promise; // Temp variable to reference Promise in local context - namespace rsvp { - export var Promise: typeof foo; - export function polyfill(): void; - } - export = rsvp; -} diff --git a/src/typings/lib.ie11_safe_es6.d.ts b/src/typings/lib.ie11_safe_es6.d.ts deleted file mode 100644 index 4d54d3c08ef..00000000000 --- a/src/typings/lib.ie11_safe_es6.d.ts +++ /dev/null @@ -1,821 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -// Defined a subset of ES6 built ins that run in IE11 -// CHECK WITH http://kangax.github.io/compat-table/es6/#ie11 - -interface Map { - clear(): void; - delete(key: K): boolean; - forEach(callbackfn: (value: V, index: K, map: Map) => void, thisArg?: any): void; - get(key: K): V | undefined; - has(key: K): boolean; - set(key: K, value: V): Map; - readonly size: number; - - // not supported on IE11: - // entries(): IterableIterator<[K, V]>; - // keys(): IterableIterator; - // values(): IterableIterator; - // [Symbol.iterator]():IterableIterator<[K,V]>; - // [Symbol.toStringTag]: string; -} - -interface MapConstructor { - new (): Map; - readonly prototype: Map; - - // not supported on IE11: - // new (iterable: Iterable<[K, V]>): Map; -} -declare var Map: MapConstructor; - - -interface Set { - add(value: T): Set; - clear(): void; - delete(value: T): boolean; - forEach(callbackfn: (value: T, index: T, set: Set) => void, thisArg?: any): void; - has(value: T): boolean; - readonly size: number; - - // not supported on IE11: - // entries(): IterableIterator<[T, T]>; - // keys(): IterableIterator; - // values(): IterableIterator; - // [Symbol.iterator]():IterableIterator; - // [Symbol.toStringTag]: string; -} - -interface SetConstructor { - new (): Set; - readonly prototype: Set; - - // not supported on IE11: - // new (iterable: Iterable): Set; -} -declare var Set: SetConstructor; - - -interface WeakMap { - delete(key: K): boolean; - get(key: K): V | undefined; - has(key: K): boolean; - // IE11 doesn't return this - // set(key: K, value?: V): this; - set(key: K, value?: V): undefined; -} - -interface WeakMapConstructor { - new(): WeakMap; - new (): WeakMap; - // new (entries?: [K, V][]): WeakMap; - readonly prototype: WeakMap; -} -declare var WeakMap: WeakMapConstructor; - - -// /** -// * Represents a raw buffer of binary data, which is used to store data for the -// * different typed arrays. ArrayBuffers cannot be read from or written to directly, -// * but can be passed to a typed array or DataView Object to interpret the raw -// * buffer as needed. -// */ -// interface ArrayBuffer { -// /** -// * Read-only. The length of the ArrayBuffer (in bytes). -// */ -// readonly byteLength: number; - -// /** -// * Returns a section of an ArrayBuffer. -// */ -// slice(begin: number, end?: number): ArrayBuffer; -// } - -// interface ArrayBufferConstructor { -// readonly prototype: ArrayBuffer; -// new (byteLength: number): ArrayBuffer; -// isView(arg: any): arg is ArrayBufferView; -// } -// declare const ArrayBuffer: ArrayBufferConstructor; - -// interface ArrayBufferView { -// /** -// * The ArrayBuffer instance referenced by the array. -// */ -// buffer: ArrayBuffer; - -// /** -// * The length in bytes of the array. -// */ -// byteLength: number; - -// /** -// * The offset in bytes of the array. -// */ -// byteOffset: number; -// } - -// interface DataView { -// readonly buffer: ArrayBuffer; -// readonly byteLength: number; -// readonly byteOffset: number; -// /** -// * Gets the Float32 value at the specified byte offset from the start of the view. There is -// * no alignment constraint; multi-byte values may be fetched from any offset. -// * @param byteOffset The place in the buffer at which the value should be retrieved. -// */ -// getFloat32(byteOffset: number, littleEndian?: boolean): number; - -// /** -// * Gets the Float64 value at the specified byte offset from the start of the view. There is -// * no alignment constraint; multi-byte values may be fetched from any offset. -// * @param byteOffset The place in the buffer at which the value should be retrieved. -// */ -// getFloat64(byteOffset: number, littleEndian?: boolean): number; - -// /** -// * Gets the Int8 value at the specified byte offset from the start of the view. There is -// * no alignment constraint; multi-byte values may be fetched from any offset. -// * @param byteOffset The place in the buffer at which the value should be retrieved. -// */ -// getInt8(byteOffset: number): number; - -// /** -// * Gets the Int16 value at the specified byte offset from the start of the view. There is -// * no alignment constraint; multi-byte values may be fetched from any offset. -// * @param byteOffset The place in the buffer at which the value should be retrieved. -// */ -// getInt16(byteOffset: number, littleEndian?: boolean): number; -// /** -// * Gets the Int32 value at the specified byte offset from the start of the view. There is -// * no alignment constraint; multi-byte values may be fetched from any offset. -// * @param byteOffset The place in the buffer at which the value should be retrieved. -// */ -// getInt32(byteOffset: number, littleEndian?: boolean): number; - -// /** -// * Gets the Uint8 value at the specified byte offset from the start of the view. There is -// * no alignment constraint; multi-byte values may be fetched from any offset. -// * @param byteOffset The place in the buffer at which the value should be retrieved. -// */ -// getUint8(byteOffset: number): number; - -// /** -// * Gets the Uint16 value at the specified byte offset from the start of the view. There is -// * no alignment constraint; multi-byte values may be fetched from any offset. -// * @param byteOffset The place in the buffer at which the value should be retrieved. -// */ -// getUint16(byteOffset: number, littleEndian?: boolean): number; - -// /** -// * Gets the Uint32 value at the specified byte offset from the start of the view. There is -// * no alignment constraint; multi-byte values may be fetched from any offset. -// * @param byteOffset The place in the buffer at which the value should be retrieved. -// */ -// getUint32(byteOffset: number, littleEndian?: boolean): number; - -// /** -// * Stores an Float32 value at the specified byte offset from the start of the view. -// * @param byteOffset The place in the buffer at which the value should be set. -// * @param value The value to set. -// * @param littleEndian If false or undefined, a big-endian value should be written, -// * otherwise a little-endian value should be written. -// */ -// setFloat32(byteOffset: number, value: number, littleEndian?: boolean): void; - -// /** -// * Stores an Float64 value at the specified byte offset from the start of the view. -// * @param byteOffset The place in the buffer at which the value should be set. -// * @param value The value to set. -// * @param littleEndian If false or undefined, a big-endian value should be written, -// * otherwise a little-endian value should be written. -// */ -// setFloat64(byteOffset: number, value: number, littleEndian?: boolean): void; - -// /** -// * Stores an Int8 value at the specified byte offset from the start of the view. -// * @param byteOffset The place in the buffer at which the value should be set. -// * @param value The value to set. -// */ -// setInt8(byteOffset: number, value: number): void; - -// /** -// * Stores an Int16 value at the specified byte offset from the start of the view. -// * @param byteOffset The place in the buffer at which the value should be set. -// * @param value The value to set. -// * @param littleEndian If false or undefined, a big-endian value should be written, -// * otherwise a little-endian value should be written. -// */ -// setInt16(byteOffset: number, value: number, littleEndian?: boolean): void; - -// /** -// * Stores an Int32 value at the specified byte offset from the start of the view. -// * @param byteOffset The place in the buffer at which the value should be set. -// * @param value The value to set. -// * @param littleEndian If false or undefined, a big-endian value should be written, -// * otherwise a little-endian value should be written. -// */ -// setInt32(byteOffset: number, value: number, littleEndian?: boolean): void; - -// /** -// * Stores an Uint8 value at the specified byte offset from the start of the view. -// * @param byteOffset The place in the buffer at which the value should be set. -// * @param value The value to set. -// */ -// setUint8(byteOffset: number, value: number): void; - -// /** -// * Stores an Uint16 value at the specified byte offset from the start of the view. -// * @param byteOffset The place in the buffer at which the value should be set. -// * @param value The value to set. -// * @param littleEndian If false or undefined, a big-endian value should be written, -// * otherwise a little-endian value should be written. -// */ -// setUint16(byteOffset: number, value: number, littleEndian?: boolean): void; - -// /** -// * Stores an Uint32 value at the specified byte offset from the start of the view. -// * @param byteOffset The place in the buffer at which the value should be set. -// * @param value The value to set. -// * @param littleEndian If false or undefined, a big-endian value should be written, -// * otherwise a little-endian value should be written. -// */ -// setUint32(byteOffset: number, value: number, littleEndian?: boolean): void; -// } - -// interface DataViewConstructor { -// new (buffer: ArrayBuffer, byteOffset?: number, byteLength?: number): DataView; -// } -// declare const DataView: DataViewConstructor; - - -// /** -// * A typed array of 8-bit integer values. The contents are initialized to 0. If the requested -// * number of bytes could not be allocated an exception is raised. -// */ -// interface Int8Array { -// /** -// * The size in bytes of each element in the array. -// */ -// readonly BYTES_PER_ELEMENT: number; - -// /** -// * The ArrayBuffer instance referenced by the array. -// */ -// readonly buffer: ArrayBuffer; - -// /** -// * The length in bytes of the array. -// */ -// readonly byteLength: number; - -// /** -// * The offset in bytes of the array. -// */ -// readonly byteOffset: number; - -// /** -// * The length of the array. -// */ -// readonly length: number; - -// /** -// * Sets a value or an array of values. -// * @param index The index of the location to set. -// * @param value The value to set. -// */ -// set(index: number, value: number): void; - -// /** -// * Sets a value or an array of values. -// * @param array A typed or untyped array of values to set. -// * @param offset The index in the current array at which the values are to be written. -// */ -// set(array: ArrayLike, offset?: number): void; - -// /** -// * Converts a number to a string by using the current locale. -// */ -// toLocaleString(): string; - -// /** -// * Returns a string representation of an array. -// */ -// toString(): string; - -// [index: number]: number; -// } -// interface Int8ArrayConstructor { -// readonly prototype: Int8Array; -// new (length: number): Int8Array; -// new (array: ArrayLike): Int8Array; -// new (buffer: ArrayBuffer, byteOffset?: number, length?: number): Int8Array; - -// /** -// * The size in bytes of each element in the array. -// */ -// readonly BYTES_PER_ELEMENT: number; - -// } -// declare const Int8Array: Int8ArrayConstructor; - -// /** -// * A typed array of 8-bit unsigned integer values. The contents are initialized to 0. If the -// * requested number of bytes could not be allocated an exception is raised. -// */ -// interface Uint8Array { -// /** -// * The size in bytes of each element in the array. -// */ -// readonly BYTES_PER_ELEMENT: number; - -// /** -// * The ArrayBuffer instance referenced by the array. -// */ -// readonly buffer: ArrayBuffer; - -// /** -// * The length in bytes of the array. -// */ -// readonly byteLength: number; - -// /** -// * The offset in bytes of the array. -// */ -// readonly byteOffset: number; - -// /** -// * The length of the array. -// */ -// readonly length: number; - -// /** -// * Sets a value or an array of values. -// * @param index The index of the location to set. -// * @param value The value to set. -// */ -// set(index: number, value: number): void; - -// /** -// * Sets a value or an array of values. -// * @param array A typed or untyped array of values to set. -// * @param offset The index in the current array at which the values are to be written. -// */ -// set(array: ArrayLike, offset?: number): void; - -// /** -// * Converts a number to a string by using the current locale. -// */ -// toLocaleString(): string; - -// /** -// * Returns a string representation of an array. -// */ -// toString(): string; - -// [index: number]: number; -// } - -// interface Uint8ArrayConstructor { -// readonly prototype: Uint8Array; -// new (length: number): Uint8Array; -// new (array: ArrayLike): Uint8Array; -// new (buffer: ArrayBuffer, byteOffset?: number, length?: number): Uint8Array; - -// /** -// * The size in bytes of each element in the array. -// */ -// readonly BYTES_PER_ELEMENT: number; - -// } -// declare const Uint8Array: Uint8ArrayConstructor; - - -// /** -// * A typed array of 16-bit signed integer values. The contents are initialized to 0. If the -// * requested number of bytes could not be allocated an exception is raised. -// */ -// interface Int16Array { -// /** -// * The size in bytes of each element in the array. -// */ -// readonly BYTES_PER_ELEMENT: number; - -// /** -// * The ArrayBuffer instance referenced by the array. -// */ -// readonly buffer: ArrayBuffer; - -// /** -// * The length in bytes of the array. -// */ -// readonly byteLength: number; - -// /** -// * The offset in bytes of the array. -// */ -// readonly byteOffset: number; - -// /** -// * The length of the array. -// */ -// readonly length: number; - -// /** -// * Sets a value or an array of values. -// * @param index The index of the location to set. -// * @param value The value to set. -// */ -// set(index: number, value: number): void; - -// /** -// * Sets a value or an array of values. -// * @param array A typed or untyped array of values to set. -// * @param offset The index in the current array at which the values are to be written. -// */ -// set(array: ArrayLike, offset?: number): void; - -// /** -// * Converts a number to a string by using the current locale. -// */ -// toLocaleString(): string; - -// /** -// * Returns a string representation of an array. -// */ -// toString(): string; - -// [index: number]: number; -// } - -// interface Int16ArrayConstructor { -// readonly prototype: Int16Array; -// new (length: number): Int16Array; -// new (array: ArrayLike): Int16Array; -// new (buffer: ArrayBuffer, byteOffset?: number, length?: number): Int16Array; - -// /** -// * The size in bytes of each element in the array. -// */ -// readonly BYTES_PER_ELEMENT: number; - -// } -// declare const Int16Array: Int16ArrayConstructor; - -// /** -// * A typed array of 16-bit unsigned integer values. The contents are initialized to 0. If the -// * requested number of bytes could not be allocated an exception is raised. -// */ -// interface Uint16Array { -// /** -// * The size in bytes of each element in the array. -// */ -// readonly BYTES_PER_ELEMENT: number; - -// /** -// * The ArrayBuffer instance referenced by the array. -// */ -// readonly buffer: ArrayBuffer; - -// /** -// * The length in bytes of the array. -// */ -// readonly byteLength: number; - -// /** -// * The offset in bytes of the array. -// */ -// readonly byteOffset: number; - -// /** -// * The length of the array. -// */ -// readonly length: number; - -// /** -// * Sets a value or an array of values. -// * @param index The index of the location to set. -// * @param value The value to set. -// */ -// set(index: number, value: number): void; - -// /** -// * Sets a value or an array of values. -// * @param array A typed or untyped array of values to set. -// * @param offset The index in the current array at which the values are to be written. -// */ -// set(array: ArrayLike, offset?: number): void; - -// /** -// * Converts a number to a string by using the current locale. -// */ -// toLocaleString(): string; - -// /** -// * Returns a string representation of an array. -// */ -// toString(): string; - -// [index: number]: number; -// } - -// interface Uint16ArrayConstructor { -// readonly prototype: Uint16Array; -// new (length: number): Uint16Array; -// new (array: ArrayLike): Uint16Array; -// new (buffer: ArrayBuffer, byteOffset?: number, length?: number): Uint16Array; - -// /** -// * The size in bytes of each element in the array. -// */ -// readonly BYTES_PER_ELEMENT: number; - -// } -// declare const Uint16Array: Uint16ArrayConstructor; -// /** -// * A typed array of 32-bit signed integer values. The contents are initialized to 0. If the -// * requested number of bytes could not be allocated an exception is raised. -// */ -// interface Int32Array { -// /** -// * The size in bytes of each element in the array. -// */ -// readonly BYTES_PER_ELEMENT: number; - -// /** -// * The ArrayBuffer instance referenced by the array. -// */ -// readonly buffer: ArrayBuffer; - -// /** -// * The length in bytes of the array. -// */ -// readonly byteLength: number; - -// /** -// * The offset in bytes of the array. -// */ -// readonly byteOffset: number; - -// /** -// * The length of the array. -// */ -// readonly length: number; - -// /** -// * Sets a value or an array of values. -// * @param index The index of the location to set. -// * @param value The value to set. -// */ -// set(index: number, value: number): void; - -// /** -// * Sets a value or an array of values. -// * @param array A typed or untyped array of values to set. -// * @param offset The index in the current array at which the values are to be written. -// */ -// set(array: ArrayLike, offset?: number): void; - -// /** -// * Converts a number to a string by using the current locale. -// */ -// toLocaleString(): string; - -// /** -// * Returns a string representation of an array. -// */ -// toString(): string; - -// [index: number]: number; -// } - -// interface Int32ArrayConstructor { -// readonly prototype: Int32Array; -// new (length: number): Int32Array; -// new (array: ArrayLike): Int32Array; -// new (buffer: ArrayBuffer, byteOffset?: number, length?: number): Int32Array; - -// /** -// * The size in bytes of each element in the array. -// */ -// readonly BYTES_PER_ELEMENT: number; -// } - -// declare const Int32Array: Int32ArrayConstructor; - -// /** -// * A typed array of 32-bit unsigned integer values. The contents are initialized to 0. If the -// * requested number of bytes could not be allocated an exception is raised. -// */ -// interface Uint32Array { -// /** -// * The size in bytes of each element in the array. -// */ -// readonly BYTES_PER_ELEMENT: number; - -// /** -// * The ArrayBuffer instance referenced by the array. -// */ -// readonly buffer: ArrayBuffer; - -// /** -// * The length in bytes of the array. -// */ -// readonly byteLength: number; - -// /** -// * The offset in bytes of the array. -// */ -// readonly byteOffset: number; - -// /** -// * The length of the array. -// */ -// readonly length: number; - -// /** -// * Sets a value or an array of values. -// * @param index The index of the location to set. -// * @param value The value to set. -// */ -// set(index: number, value: number): void; - -// /** -// * Sets a value or an array of values. -// * @param array A typed or untyped array of values to set. -// * @param offset The index in the current array at which the values are to be written. -// */ -// set(array: ArrayLike, offset?: number): void; - -// /** -// * Converts a number to a string by using the current locale. -// */ -// toLocaleString(): string; - -// /** -// * Returns a string representation of an array. -// */ -// toString(): string; - -// [index: number]: number; -// } - -// interface Uint32ArrayConstructor { -// readonly prototype: Uint32Array; -// new (length: number): Uint32Array; -// new (array: ArrayLike): Uint32Array; -// new (buffer: ArrayBuffer, byteOffset?: number, length?: number): Uint32Array; - -// /** -// * The size in bytes of each element in the array. -// */ -// readonly BYTES_PER_ELEMENT: number; -// } - -// declare const Uint32Array: Uint32ArrayConstructor; - -// /** -// * A typed array of 32-bit float values. The contents are initialized to 0. If the requested number -// * of bytes could not be allocated an exception is raised. -// */ -// interface Float32Array { -// /** -// * The size in bytes of each element in the array. -// */ -// readonly BYTES_PER_ELEMENT: number; - -// /** -// * The ArrayBuffer instance referenced by the array. -// */ -// readonly buffer: ArrayBuffer; - -// /** -// * The length in bytes of the array. -// */ -// readonly byteLength: number; - -// /** -// * The offset in bytes of the array. -// */ -// readonly byteOffset: number; - -// /** -// * The length of the array. -// */ -// readonly length: number; - -// /** -// * Sets a value or an array of values. -// * @param index The index of the location to set. -// * @param value The value to set. -// */ -// set(index: number, value: number): void; - -// /** -// * Sets a value or an array of values. -// * @param array A typed or untyped array of values to set. -// * @param offset The index in the current array at which the values are to be written. -// */ -// set(array: ArrayLike, offset?: number): void; - -// /** -// * Converts a number to a string by using the current locale. -// */ -// toLocaleString(): string; - -// /** -// * Returns a string representation of an array. -// */ -// toString(): string; - -// [index: number]: number; -// } - -// interface Float32ArrayConstructor { -// readonly prototype: Float32Array; -// new (length: number): Float32Array; -// new (array: ArrayLike): Float32Array; -// new (buffer: ArrayBuffer, byteOffset?: number, length?: number): Float32Array; - -// /** -// * The size in bytes of each element in the array. -// */ -// readonly BYTES_PER_ELEMENT: number; - -// } -// declare const Float32Array: Float32ArrayConstructor; - -// /** -// * A typed array of 64-bit float values. The contents are initialized to 0. If the requested -// * number of bytes could not be allocated an exception is raised. -// */ -// interface Float64Array { -// /** -// * The size in bytes of each element in the array. -// */ -// readonly BYTES_PER_ELEMENT: number; - -// /** -// * The ArrayBuffer instance referenced by the array. -// */ -// readonly buffer: ArrayBuffer; - -// /** -// * The length in bytes of the array. -// */ -// readonly byteLength: number; - -// /** -// * The offset in bytes of the array. -// */ -// readonly byteOffset: number; - -// /** -// * The length of the array. -// */ -// readonly length: number; - -// /** -// * Sets a value or an array of values. -// * @param index The index of the location to set. -// * @param value The value to set. -// */ -// set(index: number, value: number): void; - -// /** -// * Sets a value or an array of values. -// * @param array A typed or untyped array of values to set. -// * @param offset The index in the current array at which the values are to be written. -// */ -// set(array: ArrayLike, offset?: number): void; - -// /** -// * Converts a number to a string by using the current locale. -// */ -// toLocaleString(): string; - -// /** -// * Returns a string representation of an array. -// */ -// toString(): string; - -// [index: number]: number; -// } - -// interface Float64ArrayConstructor { -// readonly prototype: Float64Array; -// new (length: number): Float64Array; -// new (array: ArrayLike): Float64Array; -// new (buffer: ArrayBuffer, byteOffset?: number, length?: number): Float64Array; - -// /** -// * The size in bytes of each element in the array. -// */ -// readonly BYTES_PER_ELEMENT: number; -// } - -// declare const Float64Array: Float64ArrayConstructor; diff --git a/src/vs/workbench/services/extensions/common/extensionHostMain.ts b/src/vs/workbench/services/extensions/common/extensionHostMain.ts index caebe7634f3..93d9a1d107d 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostMain.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostMain.ts @@ -76,7 +76,7 @@ export class ExtensionHostMain { // error forwarding and stack trace scanning Error.stackTraceLimit = 100; // increase number of stack frames (from 10, https://github.com/v8/v8/wiki/Stack-Trace-API) - const extensionErrors = new WeakMap(); + const extensionErrors = new WeakMap(); this._extensionService.getExtensionPathIndex().then(map => { (Error).prepareStackTrace = (error: Error, stackTrace: errors.V8CallSite[]) => { let stackTraceMessage = ''; From eb36a76298b9fca0c63e62f4ebf754fd1eba6ec3 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 21 Feb 2020 16:35:22 +0100 Subject: [PATCH 003/235] List items should have role 'listitem' fixes #90876 --- src/vs/base/browser/ui/list/listView.ts | 2 +- src/vs/base/browser/ui/tree/abstractTree.ts | 2 +- src/vs/base/browser/ui/tree/asyncDataTree.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index 7b520501582..4209457c0f0 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -554,7 +554,7 @@ export class ListView implements ISpliceable, IDisposable { if (!item.row) { item.row = this.cache.alloc(item.templateId); - const role = this.ariaProvider.getRole ? this.ariaProvider.getRole(item.element) : 'treeitem'; + const role = this.ariaProvider.getRole ? this.ariaProvider.getRole(item.element) : 'listitem'; item.row!.domNode!.setAttribute('role', role); const checked = this.ariaProvider.isChecked ? this.ariaProvider.isChecked(item.element) : undefined; if (typeof checked !== 'undefined') { diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 9e584efcc56..fc78cfe1c28 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -196,7 +196,7 @@ function asListOptions(modelProvider: () => ITreeModel { return options.ariaProvider!.getRole!(node.element); - } : undefined + } : () => 'treeitem' } }; } diff --git a/src/vs/base/browser/ui/tree/asyncDataTree.ts b/src/vs/base/browser/ui/tree/asyncDataTree.ts index 6ddb3fe5cb8..0cd13de8079 100644 --- a/src/vs/base/browser/ui/tree/asyncDataTree.ts +++ b/src/vs/base/browser/ui/tree/asyncDataTree.ts @@ -267,7 +267,7 @@ function asObjectTreeOptions(options?: IAsyncDataTreeOpt }, getRole: options.ariaProvider!.getRole ? (el) => { return options.ariaProvider!.getRole!(el.element as T); - } : undefined, + } : () => 'treeitem', isChecked: options.ariaProvider!.isChecked ? (e) => { return options.ariaProvider?.isChecked!(e.element as T); } : undefined From a10080241273194235d20efbcebc14a56143a560 Mon Sep 17 00:00:00 2001 From: Sergio Schvezov Date: Fri, 21 Feb 2020 15:57:30 -0300 Subject: [PATCH 004/235] snap launcher: fix quoting in script Avoid any potential issue with globbing or word splitting. Signed-off-by: Sergio Schvezov --- resources/linux/snap/electron-launch | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/resources/linux/snap/electron-launch b/resources/linux/snap/electron-launch index 2a1c4395187..8a294975147 100755 --- a/resources/linux/snap/electron-launch +++ b/resources/linux/snap/electron-launch @@ -2,7 +2,7 @@ # On Fedora $SNAP is under /var and there is some magic to map it to /snap. # We need to handle that case and reset $SNAP -SNAP=$(echo $SNAP | sed -e "s|/var/lib/snapd||g") +SNAP=$(echo "$SNAP" | sed -e "s|/var/lib/snapd||g") if [ "$SNAP_ARCH" == "amd64" ]; then ARCH="x86_64-linux-gnu" @@ -14,21 +14,21 @@ else ARCH="$SNAP_ARCH-linux-gnu" fi -export XDG_CACHE_HOME=$SNAP_USER_COMMON/.cache -if [[ -d $SNAP_USER_DATA/.cache && ! -e $XDG_CACHE_HOME ]]; then +export XDG_CACHE_HOME="$SNAP_USER_COMMON/.cache" +if [[ -d "$SNAP_USER_DATA/.cache" && ! -e "$XDG_CACHE_HOME" ]]; then # the .cache directory used to be stored under $SNAP_USER_DATA, migrate it - mv $SNAP_USER_DATA/.cache $SNAP_USER_COMMON/ + mv "$SNAP_USER_DATA/.cache" "$SNAP_USER_COMMON/" fi -mkdir -p $XDG_CACHE_HOME +mkdir -p "$XDG_CACHE_HOME" # Gdk-pixbuf loaders -export GDK_PIXBUF_MODULE_FILE=$XDG_CACHE_HOME/gdk-pixbuf-loaders.cache -export GDK_PIXBUF_MODULEDIR=$SNAP/usr/lib/$ARCH/gdk-pixbuf-2.0/2.10.0/loaders -if [ -f $SNAP/usr/lib/$ARCH/gdk-pixbuf-2.0/gdk-pixbuf-query-loaders ]; then - $SNAP/usr/lib/$ARCH/gdk-pixbuf-2.0/gdk-pixbuf-query-loaders > $GDK_PIXBUF_MODULE_FILE +export GDK_PIXBUF_MODULE_FILE="$XDG_CACHE_HOME/gdk-pixbuf-loaders.cache" +export GDK_PIXBUF_MODULEDIR="$SNAP/usr/lib/$ARCH/gdk-pixbuf-2.0/2.10.0/loaders" +if [ -f "$SNAP/usr/lib/$ARCH/gdk-pixbuf-2.0/gdk-pixbuf-query-loaders" ]; then + "$SNAP/usr/lib/$ARCH/gdk-pixbuf-2.0/gdk-pixbuf-query-loaders" > "$GDK_PIXBUF_MODULE_FILE" fi # Create $XDG_RUNTIME_DIR if not exists (to be removed when https://pad.lv/1656340 is fixed) -[ -n "$XDG_RUNTIME_DIR" ] && mkdir -p $XDG_RUNTIME_DIR -m 700 +[ -n "$XDG_RUNTIME_DIR" ] && mkdir -p "$XDG_RUNTIME_DIR" -m 700 exec "$@" From d4da28357f193bd2d44eb5bd50ff877b8742b22c Mon Sep 17 00:00:00 2001 From: Sergio Schvezov Date: Fri, 21 Feb 2020 17:26:57 -0300 Subject: [PATCH 005/235] snap launcher: avoid exporting XDG_CACHE_HOME Exporting XDG_CACHE_HOME affects applications launched from within the context of code. Rename it to GDK_CACHE_DIR and do not export it. Also test for existence before creating to avoid shelling out to mkdir if not needed. Signed-off-by: Sergio Schvezov --- resources/linux/snap/electron-launch | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/linux/snap/electron-launch b/resources/linux/snap/electron-launch index 8a294975147..9f4eb6a23b8 100755 --- a/resources/linux/snap/electron-launch +++ b/resources/linux/snap/electron-launch @@ -14,15 +14,15 @@ else ARCH="$SNAP_ARCH-linux-gnu" fi -export XDG_CACHE_HOME="$SNAP_USER_COMMON/.cache" -if [[ -d "$SNAP_USER_DATA/.cache" && ! -e "$XDG_CACHE_HOME" ]]; then +GDK_CACHE_DIR="$SNAP_USER_COMMON/.cache" +if [[ -d "$SNAP_USER_DATA/.cache" && ! -e "$GDK_CACHE_DIR" ]]; then # the .cache directory used to be stored under $SNAP_USER_DATA, migrate it mv "$SNAP_USER_DATA/.cache" "$SNAP_USER_COMMON/" fi -mkdir -p "$XDG_CACHE_HOME" +[ ! -d "$GDK_CACHE_DIR" ] && mkdir -p "$GDK_CACHE_DIR" # Gdk-pixbuf loaders -export GDK_PIXBUF_MODULE_FILE="$XDG_CACHE_HOME/gdk-pixbuf-loaders.cache" +export GDK_PIXBUF_MODULE_FILE="$GDK_CACHE_DIR/gdk-pixbuf-loaders.cache" export GDK_PIXBUF_MODULEDIR="$SNAP/usr/lib/$ARCH/gdk-pixbuf-2.0/2.10.0/loaders" if [ -f "$SNAP/usr/lib/$ARCH/gdk-pixbuf-2.0/gdk-pixbuf-query-loaders" ]; then "$SNAP/usr/lib/$ARCH/gdk-pixbuf-2.0/gdk-pixbuf-query-loaders" > "$GDK_PIXBUF_MODULE_FILE" From d4c2e7d8c51345982f9d4fa92f4844b21a1ea346 Mon Sep 17 00:00:00 2001 From: Matej Urbas Date: Thu, 30 Jan 2020 19:53:13 +0000 Subject: [PATCH 006/235] file search: include workspace folder in filter "Go to File..." search can now filter files based on the workspace folder name. This feature is activated only when the workspace contains more than one folder. This is particularly useful when your workspace contains multiple files with the same name, each of them in another workspace folder. A common example is the `README.md` file. Say you want to find a `README.md` file from a particular folder, say `my-folder`. Before this change you'd have to press the `Down` button a few times before you could get to the file. With this change you'd instead search for `mfREADME.md`. The desired readme file should now appear closer to the top of the file search popup. --- src/vs/platform/workspace/common/workspace.ts | 2 +- .../api/browser/mainThreadWorkspace.ts | 6 ++-- .../contrib/search/browser/openFileHandler.ts | 11 ++++--- .../contrib/search/common/queryBuilder.ts | 26 ++++++++------- .../search/test/browser/queryBuilder.test.ts | 19 +++++++---- .../services/search/common/search.ts | 20 +++++++++++- .../services/search/node/fileSearch.ts | 32 +++++++++++++++---- .../services/search/node/rawSearchService.ts | 4 +-- 8 files changed, 83 insertions(+), 37 deletions(-) diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index 7e31738058d..6ccb03fa620 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -115,7 +115,7 @@ export interface IWorkspaceFolderData { /** * The name of this workspace folder. Defaults to - * the basename its [uri-path](#Uri.path) + * the basename of its [uri-path](#Uri.path) */ readonly name: string; diff --git a/src/vs/workbench/api/browser/mainThreadWorkspace.ts b/src/vs/workbench/api/browser/mainThreadWorkspace.ts index 7d67852018a..bf9dc7b1088 100644 --- a/src/vs/workbench/api/browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/browser/mainThreadWorkspace.ts @@ -12,7 +12,7 @@ import { isNative } from 'vs/base/common/platform'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILabelService } from 'vs/platform/label/common/label'; import { IFileMatch, IPatternInfo, ISearchProgressItem, ISearchService } from 'vs/workbench/services/search/common/search'; -import { IWorkspaceContextService, WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState, IWorkspace, toWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { ITextQueryBuilderOptions, QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -138,7 +138,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { } const query = this._queryBuilder.file( - includeFolder ? [includeFolder] : workspace.folders.map(f => f.uri), + includeFolder ? [toWorkspaceFolder(includeFolder)] : workspace.folders, { maxResults: withNullAsUndefined(maxResults), disregardExcludeSettings: (excludePatternOrDisregardExcludes === false) || undefined, @@ -190,7 +190,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { $checkExists(folders: UriComponents[], includes: string[], token: CancellationToken): Promise { const queryBuilder = this._instantiationService.createInstance(QueryBuilder); - const query = queryBuilder.file(folders.map(folder => URI.revive(folder)), { + const query = queryBuilder.file(folders.map(folder => toWorkspaceFolder(URI.revive(folder))), { _reason: 'checkExists', includePattern: includes.join(', '), expandPatterns: true, diff --git a/src/vs/workbench/contrib/search/browser/openFileHandler.ts b/src/vs/workbench/contrib/search/browser/openFileHandler.ts index e3c5e565472..f4a5f62c36a 100644 --- a/src/vs/workbench/contrib/search/browser/openFileHandler.ts +++ b/src/vs/workbench/contrib/search/browser/openFileHandler.ts @@ -167,7 +167,11 @@ export class OpenFileHandler extends QuickOpenHandler { } else { - complete = await this.searchService.fileSearch(this.queryBuilder.file(this.contextService.getWorkspace().folders.map(folder => folder.uri), queryOptions), token); + let fileQuery = this.queryBuilder.file( + this.contextService.getWorkspace().folders, + queryOptions + ); + complete = await this.searchService.fileSearch(fileQuery, token); } const results: QuickOpenEntry[] = []; @@ -238,10 +242,7 @@ export class OpenFileHandler extends QuickOpenHandler { sortByScore: true, }; - const folderResources = this.contextService.getWorkspace().folders.map(folder => folder.uri); - const query = this.queryBuilder.file(folderResources, options); - - return query; + return this.queryBuilder.file(this.contextService.getWorkspace().folders, options); } get isCacheLoaded(): boolean { diff --git a/src/vs/workbench/contrib/search/common/queryBuilder.ts b/src/vs/workbench/contrib/search/common/queryBuilder.ts index ee91d6edcf2..92c69e2691d 100644 --- a/src/vs/workbench/contrib/search/common/queryBuilder.ts +++ b/src/vs/workbench/contrib/search/common/queryBuilder.ts @@ -16,7 +16,7 @@ import { isMultilineRegexSource } from 'vs/editor/common/model/textModelSearch'; import * as nls from 'vs/nls'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState, toWorkspaceFolder, IWorkspaceFolderData } from 'vs/platform/workspace/common/workspace'; import { getExcludes, ICommonQueryProps, IFileQuery, IFolderQuery, IPatternInfo, ISearchConfiguration, ITextQuery, ITextSearchPreviewOptions, pathIncludedInQuery, QueryType } from 'vs/workbench/services/search/common/search'; import { Schemas } from 'vs/base/common/network'; @@ -94,7 +94,7 @@ export class QueryBuilder { return !folderConfig.search.useRipgrep; }); - const commonQuery = this.commonQuery(folderResources, options); + const commonQuery = this.commonQuery(folderResources?.map(toWorkspaceFolder), options); return { ...commonQuery, type: QueryType.Text, @@ -134,8 +134,8 @@ export class QueryBuilder { return newPattern; } - file(folderResources: uri[] | undefined, options: IFileQueryBuilderOptions = {}): IFileQuery { - const commonQuery = this.commonQuery(folderResources, options); + file(folders: IWorkspaceFolderData[], options: IFileQueryBuilderOptions = {}): IFileQuery { + const commonQuery = this.commonQuery(folders, options); return { ...commonQuery, type: QueryType.File, @@ -144,11 +144,11 @@ export class QueryBuilder { : options.filePattern, exists: options.exists, sortByScore: options.sortByScore, - cacheKey: options.cacheKey + cacheKey: options.cacheKey, }; } - private commonQuery(folderResources: uri[] = [], options: ICommonQueryBuilderOptions = {}): ICommonQueryProps { + private commonQuery(folderResources: IWorkspaceFolderData[] = [], options: ICommonQueryBuilderOptions = {}): ICommonQueryProps { let includeSearchPathsInfo: ISearchPathsInfo = {}; if (options.includePattern) { const includePattern = normalizeSlashes(options.includePattern); @@ -166,9 +166,10 @@ export class QueryBuilder { } // Build folderQueries from searchPaths, if given, otherwise folderResources + const includeFolderName = folderResources.length > 1; const folderQueries = (includeSearchPathsInfo.searchPaths && includeSearchPathsInfo.searchPaths.length ? includeSearchPathsInfo.searchPaths.map(searchPath => this.getFolderQueryForSearchPath(searchPath, options, excludeSearchPathsInfo)) : - folderResources.map(uri => this.getFolderQueryForRoot(uri, options, excludeSearchPathsInfo))) + folderResources.map(folder => this.getFolderQueryForRoot(folder, options, excludeSearchPathsInfo, includeFolderName))) .filter(query => !!query) as IFolderQuery[]; const queryProps: ICommonQueryProps = { @@ -403,7 +404,7 @@ export class QueryBuilder { } private getFolderQueryForSearchPath(searchPath: ISearchPathPattern, options: ICommonQueryBuilderOptions, searchPathExcludes: ISearchPathsInfo): IFolderQuery | null { - const rootConfig = this.getFolderQueryForRoot(searchPath.searchPath, options, searchPathExcludes); + const rootConfig = this.getFolderQueryForRoot(toWorkspaceFolder(searchPath.searchPath), options, searchPathExcludes, false); if (!rootConfig) { return null; } @@ -416,10 +417,10 @@ export class QueryBuilder { }; } - private getFolderQueryForRoot(folder: uri, options: ICommonQueryBuilderOptions, searchPathExcludes: ISearchPathsInfo): IFolderQuery | null { + private getFolderQueryForRoot(folder: IWorkspaceFolderData, options: ICommonQueryBuilderOptions, searchPathExcludes: ISearchPathsInfo, includeFolderName: boolean): IFolderQuery | null { let thisFolderExcludeSearchPathPattern: glob.IExpression | undefined; if (searchPathExcludes.searchPaths) { - const thisFolderExcludeSearchPath = searchPathExcludes.searchPaths.filter(sp => isEqual(sp.searchPath, folder))[0]; + const thisFolderExcludeSearchPath = searchPathExcludes.searchPaths.filter(sp => isEqual(sp.searchPath, folder.uri))[0]; if (thisFolderExcludeSearchPath && !thisFolderExcludeSearchPath.pattern) { // entire folder is excluded return null; @@ -428,7 +429,7 @@ export class QueryBuilder { } } - const folderConfig = this.configurationService.getValue({ resource: folder }); + const folderConfig = this.configurationService.getValue({ resource: folder.uri }); const settingExcludes = this.getExcludesForFolder(folderConfig, options); const excludePattern: glob.IExpression = { ...(settingExcludes || {}), @@ -436,7 +437,8 @@ export class QueryBuilder { }; return { - folder, + folder: folder.uri, + folderName: includeFolderName ? folder.name : undefined, excludePattern: Object.keys(excludePattern).length > 0 ? excludePattern : undefined, fileEncoding: folderConfig.files && folderConfig.files.encoding, disregardIgnoreFiles: typeof options.disregardIgnoreFiles === 'boolean' ? options.disregardIgnoreFiles : !folderConfig.search.useIgnoreFiles, diff --git a/src/vs/workbench/contrib/search/test/browser/queryBuilder.test.ts b/src/vs/workbench/contrib/search/test/browser/queryBuilder.test.ts index 26f6e129337..621cf435ac4 100644 --- a/src/vs/workbench/contrib/search/test/browser/queryBuilder.test.ts +++ b/src/vs/workbench/contrib/search/test/browser/queryBuilder.test.ts @@ -25,6 +25,7 @@ suite('QueryBuilder', () => { const PATTERN_INFO: IPatternInfo = { pattern: 'a' }; const ROOT_1 = fixPath('/foo/root1'); const ROOT_1_URI = getUri(ROOT_1); + const ROOT_1_NAMED_FOLDER = toWorkspaceFolder(ROOT_1_URI); const WS_CONFIG_PATH = getUri('/bar/test.code-workspace'); // location of the workspace file (not important except that it is a file URI) let instantiationService: TestInstantiationService; @@ -89,7 +90,10 @@ suite('QueryBuilder', () => { test('does not split glob pattern when expandPatterns disabled', () => { assertEqualQueries( - queryBuilder.file([ROOT_1_URI], { includePattern: '**/foo, **/bar' }), + queryBuilder.file( + [ROOT_1_NAMED_FOLDER], + { includePattern: '**/foo, **/bar' }, + ), { folderQueries: [{ folder: ROOT_1_URI @@ -362,7 +366,7 @@ suite('QueryBuilder', () => { const content = 'content'; assertEqualQueries( queryBuilder.file( - undefined, + [], { filePattern: ` ${content} ` } ), { @@ -902,10 +906,13 @@ suite('QueryBuilder', () => { suite('file', () => { test('simple file query', () => { const cacheKey = 'asdf'; - const query = queryBuilder.file([ROOT_1_URI], { - cacheKey, - sortByScore: true - }); + const query = queryBuilder.file( + [ROOT_1_NAMED_FOLDER], + { + cacheKey, + sortByScore: true + }, + ); assert.equal(query.folderQueries.length, 1); assert.equal(query.cacheKey, cacheKey); diff --git a/src/vs/workbench/services/search/common/search.ts b/src/vs/workbench/services/search/common/search.ts index e646364a885..24b80d78385 100644 --- a/src/vs/workbench/services/search/common/search.ts +++ b/src/vs/workbench/services/search/common/search.ts @@ -9,7 +9,7 @@ import * as glob from 'vs/base/common/glob'; import { IDisposable } from 'vs/base/common/lifecycle'; import * as objects from 'vs/base/common/objects'; import * as extpath from 'vs/base/common/extpath'; -import { getNLines } from 'vs/base/common/strings'; +import { fuzzyContains, getNLines } from 'vs/base/common/strings'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IFilesConfiguration } from 'vs/platform/files/common/files'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; @@ -50,6 +50,7 @@ export interface ISearchResultProvider { export interface IFolderQuery { folder: U; + folderName?: string; excludePattern?: glob.IExpression; includePattern?: glob.IExpression; fileEncoding?: string; @@ -437,9 +438,21 @@ export interface IRawSearchService { export interface IRawFileMatch { base?: string; + /** + * The path of the file relative to the containing `base` folder. + * This path is exactly as it appears on the filesystem. + */ relativePath: string; basename: string; size?: number; + /** + * This path is transformed for search purposes. For example, this could be + * the `relativePath` with the workspace folder name prepended. This way the + * search algorithm would also match against the name of the containing folder. + * + * If not given, the search algorithm should use `relativePath`. + */ + searchPath?: string; } export interface ISearchEngine { @@ -486,6 +499,11 @@ export function isSerializedFileMatch(arg: ISerializedSearchProgressItem): arg i return !!(arg).path; } +export function isFilePatternMatch(candidate: IRawFileMatch, normalizedFilePatternLowercase: string): boolean { + const pathToMatch = candidate.searchPath ? candidate.searchPath : candidate.relativePath; + return fuzzyContains(pathToMatch, normalizedFilePatternLowercase); +} + export interface ISerializedFileMatch { path: string; results?: ITextSearchResult[]; diff --git a/src/vs/workbench/services/search/node/fileSearch.ts b/src/vs/workbench/services/search/node/fileSearch.ts index e4d0dbbc75b..a3be0c1ad46 100644 --- a/src/vs/workbench/services/search/node/fileSearch.ts +++ b/src/vs/workbench/services/search/node/fileSearch.ts @@ -20,7 +20,7 @@ import * as strings from 'vs/base/common/strings'; import * as types from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import { readdir } from 'vs/base/node/pfs'; -import { IFileQuery, IFolderQuery, IProgressMessage, ISearchEngineStats, IRawFileMatch, ISearchEngine, ISearchEngineSuccess } from 'vs/workbench/services/search/common/search'; +import { IFileQuery, IFolderQuery, IProgressMessage, ISearchEngineStats, IRawFileMatch, ISearchEngine, ISearchEngineSuccess, isFilePatternMatch } from 'vs/workbench/services/search/common/search'; import { spawnRipgrepCmd } from './ripgrepFileSearch'; import { prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer'; @@ -247,7 +247,7 @@ export class FileWalker { if (noSiblingsClauses) { for (const relativePath of relativeFiles) { const basename = path.basename(relativePath); - this.matchFile(onResult, { base: rootFolder, relativePath, basename }); + this.matchFile(onResult, { base: rootFolder, relativePath, searchPath: this.getSearchPath(folderQuery, relativePath), basename }); if (this.isLimitHit) { killCmd(); break; @@ -540,7 +540,13 @@ export class FileWalker { return clb(null, undefined); // ignore file if max file size is hit } - this.matchFile(onResult, { base: rootFolder.fsPath, relativePath: currentRelativePath, basename: file, size: stat.size }); + this.matchFile(onResult, { + base: rootFolder.fsPath, + relativePath: currentRelativePath, + searchPath: this.getSearchPath(folderQuery, currentRelativePath), + basename: file, + size: stat.size, + }); } // Unwind @@ -554,7 +560,7 @@ export class FileWalker { } private matchFile(onResult: (result: IRawFileMatch) => void, candidate: IRawFileMatch): void { - if (this.isFilePatternMatch(candidate.relativePath) && (!this.includePattern || this.includePattern(candidate.relativePath, candidate.basename))) { + if (this.isFileMatch(candidate) && (!this.includePattern || this.includePattern(candidate.relativePath, candidate.basename))) { this.resultCount++; if (this.exists || (this.maxResults && this.resultCount > this.maxResults)) { @@ -567,8 +573,7 @@ export class FileWalker { } } - private isFilePatternMatch(path: string): boolean { - + private isFileMatch(candidate: IRawFileMatch): boolean { // Check for search pattern if (this.filePattern) { if (this.filePattern === '*') { @@ -576,7 +581,7 @@ export class FileWalker { } if (this.normalizedFilePatternLowercase) { - return strings.fuzzyContains(path, this.normalizedFilePatternLowercase); + return isFilePatternMatch(candidate, this.normalizedFilePatternLowercase); } } @@ -605,6 +610,19 @@ export class FileWalker { return clb(null, path); } + + /** + * If we're searching for files in multiple workspace folders, then better prepend the + * name of the workspace folder to the path of the file. This way we'll be able to + * better filter files that are all on the top of a workspace folder and have all the + * same name. A typical example are `package.json` or `README.md` files. + */ + private getSearchPath(folderQuery: IFolderQuery, relativePath: string): string { + if (folderQuery.folderName) { + return path.join(folderQuery.folderName, relativePath); + } + return relativePath; + } } export class Engine implements ISearchEngine { diff --git a/src/vs/workbench/services/search/node/rawSearchService.ts b/src/vs/workbench/services/search/node/rawSearchService.ts index 336d4cd0350..92bb48351e0 100644 --- a/src/vs/workbench/services/search/node/rawSearchService.ts +++ b/src/vs/workbench/services/search/node/rawSearchService.ts @@ -17,7 +17,7 @@ import * as strings from 'vs/base/common/strings'; import { URI, UriComponents } from 'vs/base/common/uri'; import { compareItemsByScore, IItemAccessor, prepareQuery, ScorerCache } from 'vs/base/parts/quickopen/common/quickOpenScorer'; import { MAX_FILE_SIZE } from 'vs/base/node/pfs'; -import { ICachedSearchStats, IFileQuery, IFileSearchStats, IFolderQuery, IProgressMessage, IRawFileQuery, IRawQuery, IRawTextQuery, ITextQuery, IFileSearchProgressItem, IRawFileMatch, IRawSearchService, ISearchEngine, ISearchEngineSuccess, ISerializedFileMatch, ISerializedSearchComplete, ISerializedSearchProgressItem, ISerializedSearchSuccess } from 'vs/workbench/services/search/common/search'; +import { ICachedSearchStats, IFileQuery, IFileSearchStats, IFolderQuery, IProgressMessage, IRawFileQuery, IRawQuery, IRawTextQuery, ITextQuery, IFileSearchProgressItem, IRawFileMatch, IRawSearchService, ISearchEngine, ISearchEngineSuccess, ISerializedFileMatch, ISerializedSearchComplete, ISerializedSearchProgressItem, ISerializedSearchSuccess, isFilePatternMatch } from 'vs/workbench/services/search/common/search'; import { Engine as FileSearchEngine } from 'vs/workbench/services/search/node/fileSearch'; import { TextSearchEngineAdapter } from 'vs/workbench/services/search/node/textSearchAdapter'; @@ -316,7 +316,7 @@ export class SearchService implements IRawSearchService { for (const entry of cachedEntries) { // Check if this entry is a match for the search value - if (!strings.fuzzyContains(entry.relativePath, normalizedSearchValueLowercase)) { + if (!isFilePatternMatch(entry, normalizedSearchValueLowercase)) { continue; } From 04d468b1d51e2ca39d4e12f6c9f5873dca54f66c Mon Sep 17 00:00:00 2001 From: jaqra Date: Tue, 25 Feb 2020 09:33:54 -0800 Subject: [PATCH 007/235] fix search view 'Toggle Search Detail' padding --- src/vs/workbench/contrib/search/browser/media/searchview.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/search/browser/media/searchview.css b/src/vs/workbench/contrib/search/browser/media/searchview.css index c8f01bd98a3..75b34a17bdb 100644 --- a/src/vs/workbench/contrib/search/browser/media/searchview.css +++ b/src/vs/workbench/contrib/search/browser/media/searchview.css @@ -6,6 +6,7 @@ .search-view .search-widgets-container { margin: 0px 12px 0 2px; padding-top: 6px; + padding-bottom: 6px; } .search-view .search-widget .toggle-replace-button { @@ -132,7 +133,7 @@ } .search-view .query-details.more .file-types:last-child { - padding-bottom: 10px; + padding-bottom: 4px; } .search-view .query-details.more h4 { From d9507c90f6c60ed351eb8ab4c12530a563d18949 Mon Sep 17 00:00:00 2001 From: Gordey Levchenko Date: Wed, 26 Feb 2020 01:46:51 +0600 Subject: [PATCH 008/235] Add separator for sync setting --- src/vs/workbench/contrib/preferences/browser/settingsTree.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts index c1a674828f9..dedf95bbe56 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts @@ -1205,6 +1205,7 @@ export class SettingTreeRenderers { new Separator(), this._instantiationService.createInstance(CopySettingIdAction), this._instantiationService.createInstance(CopySettingAsJSONAction), + new Separator(), ]; const actionFactory = (setting: ISetting) => this.getActionsForSetting(setting); From eb354fa8c3ba6d290199de2bfe52f98ad9475f39 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 25 Feb 2020 12:10:35 -0800 Subject: [PATCH 009/235] Move 'reopen with' to end of context menu Fixes #91397 --- src/vs/workbench/contrib/customEditor/browser/commands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/customEditor/browser/commands.ts b/src/vs/workbench/contrib/customEditor/browser/commands.ts index 87c12f0e206..7741a847772 100644 --- a/src/vs/workbench/contrib/customEditor/browser/commands.ts +++ b/src/vs/workbench/contrib/customEditor/browser/commands.ts @@ -89,7 +89,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { title: REOPEN_WITH_TITLE, category: viewCategory, }, - group: '3_open', + group: '6_reopen', order: 20, when: CONTEXT_HAS_CUSTOM_EDITORS, }); From 8bb8f214e7ce0f9c779a3f24ae35789927c1ff1d Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 25 Feb 2020 12:24:55 -0800 Subject: [PATCH 010/235] Use a customEditors context key that lists custom editors This allows commands/contributions to enable/disable themselves based matching against the list of custom editors --- .../workbench/contrib/customEditor/browser/commands.ts | 8 ++++---- .../contrib/customEditor/browser/customEditors.ts | 10 +++++----- .../contrib/customEditor/common/customEditor.ts | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/customEditor/browser/commands.ts b/src/vs/workbench/contrib/customEditor/browser/commands.ts index 7741a847772..a6b3efb63be 100644 --- a/src/vs/workbench/contrib/customEditor/browser/commands.ts +++ b/src/vs/workbench/contrib/customEditor/browser/commands.ts @@ -17,7 +17,7 @@ import { EditorViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/comm import { IEditorCommandsContext } from 'vs/workbench/common/editor'; import { CustomEditorInput } from 'vs/workbench/contrib/customEditor/browser/customEditorInput'; import { defaultEditorId } from 'vs/workbench/contrib/customEditor/browser/customEditors'; -import { CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE, CONTEXT_HAS_CUSTOM_EDITORS, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; +import { CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE, CONTEXT_CUSTOM_EDITORS, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import type { ITextEditorOptions } from 'vs/platform/editor/common/editor'; @@ -80,7 +80,7 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, { title: REOPEN_WITH_TITLE, category: viewCategory, }, - when: CONTEXT_HAS_CUSTOM_EDITORS, + when: CONTEXT_CUSTOM_EDITORS.notEqualsTo(''), }); MenuRegistry.appendMenuItem(MenuId.EditorTitle, { @@ -91,7 +91,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { }, group: '6_reopen', order: 20, - when: CONTEXT_HAS_CUSTOM_EDITORS, + when: CONTEXT_CUSTOM_EDITORS.notEqualsTo(''), }); // #endregion @@ -155,7 +155,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { constructor() { super({ id: ToggleCustomEditorCommand.ID, - precondition: CONTEXT_HAS_CUSTOM_EDITORS, + precondition: CONTEXT_CUSTOM_EDITORS, }); } diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts index 7ce0a933cb7..e69de1daeb0 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts @@ -25,7 +25,7 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { EditorInput, EditorOptions, IEditor, IEditorInput } from 'vs/workbench/common/editor'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { webviewEditorsExtensionPoint } from 'vs/workbench/contrib/customEditor/browser/extensionPoint'; -import { CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE, CONTEXT_HAS_CUSTOM_EDITORS, CustomEditorInfo, CustomEditorInfoCollection, CustomEditorPriority, CustomEditorSelector, ICustomEditor, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; +import { CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE, CONTEXT_CUSTOM_EDITORS, CustomEditorInfo, CustomEditorInfoCollection, CustomEditorPriority, CustomEditorSelector, ICustomEditor, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; import { CustomEditorModelManager } from 'vs/workbench/contrib/customEditor/common/customEditorModelManager'; import { IWebviewService, webviewHasOwnEditFunctionsContext } from 'vs/workbench/contrib/webview/browser/webview'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -98,7 +98,7 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ private readonly _models: CustomEditorModelManager; - private readonly _hasCustomEditor: IContextKey; + private readonly _customEditorContextKey: IContextKey; private readonly _focusedCustomEditorIsEditable: IContextKey; private readonly _webviewHasOwnEditFunctions: IContextKey; @@ -118,7 +118,7 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ this._models = new CustomEditorModelManager(workingCopyService, labelService); - this._hasCustomEditor = CONTEXT_HAS_CUSTOM_EDITORS.bindTo(contextKeyService); + this._customEditorContextKey = CONTEXT_CUSTOM_EDITORS.bindTo(contextKeyService); this._focusedCustomEditorIsEditable = CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE.bindTo(contextKeyService); this._webviewHasOwnEditFunctions = webviewHasOwnEditFunctionsContext.bindTo(contextKeyService); @@ -310,7 +310,7 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ const activeControl = this.editorService.activeControl; const resource = activeControl?.input.resource; if (!resource) { - this._hasCustomEditor.reset(); + this._customEditorContextKey.reset(); this._focusedCustomEditorIsEditable.reset(); this._webviewHasOwnEditFunctions.reset(); return; @@ -320,7 +320,7 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ ...this.getContributedCustomEditors(resource).allEditors, ...this.getUserConfiguredCustomEditors(resource).allEditors, ]; - this._hasCustomEditor.set(possibleEditors.length > 0); + this._customEditorContextKey.set(possibleEditors.map(x => x.id).join(',')); this._focusedCustomEditorIsEditable.set(activeControl?.input instanceof CustomEditorInput); this._webviewHasOwnEditFunctions.set(possibleEditors.length > 0); } diff --git a/src/vs/workbench/contrib/customEditor/common/customEditor.ts b/src/vs/workbench/contrib/customEditor/common/customEditor.ts index 96247937c20..a0e84261e3a 100644 --- a/src/vs/workbench/contrib/customEditor/common/customEditor.ts +++ b/src/vs/workbench/contrib/customEditor/common/customEditor.ts @@ -18,7 +18,7 @@ import { IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCo export const ICustomEditorService = createDecorator('customEditorService'); -export const CONTEXT_HAS_CUSTOM_EDITORS = new RawContextKey('hasCustomEditors', false); +export const CONTEXT_CUSTOM_EDITORS = new RawContextKey('customEditors', ''); export const CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE = new RawContextKey('focusedCustomEditorIsEditable', false); export interface ICustomEditor { From 14cf2b82bf1e1e2e1e229cb16d7bf2ebae790434 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 25 Feb 2020 13:45:31 -0800 Subject: [PATCH 011/235] Always dispatch to keybinding service when in chord mode in terminal Fixes #91238 --- .../platform/keybinding/common/abstractKeybindingService.ts | 4 ++++ src/vs/platform/keybinding/common/keybinding.ts | 2 ++ src/vs/platform/keybinding/common/keybindingResolver.ts | 5 +++++ .../platform/keybinding/test/common/mockKeybindingService.ts | 2 ++ .../workbench/contrib/terminal/browser/terminalInstance.ts | 4 ++-- 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/keybinding/common/abstractKeybindingService.ts b/src/vs/platform/keybinding/common/abstractKeybindingService.ts index 6440a346f59..1fce530772a 100644 --- a/src/vs/platform/keybinding/common/abstractKeybindingService.ts +++ b/src/vs/platform/keybinding/common/abstractKeybindingService.ts @@ -35,6 +35,10 @@ export abstract class AbstractKeybindingService extends Disposable implements IK private _currentChordChecker: IntervalTimer; private _currentChordStatusMessage: IDisposable | null; + public get inChordMode(): boolean { + return !!this._currentChord; + } + constructor( private _contextKeyService: IContextKeyService, protected _commandService: ICommandService, diff --git a/src/vs/platform/keybinding/common/keybinding.ts b/src/vs/platform/keybinding/common/keybinding.ts index e11bd846c43..17ab82b8184 100644 --- a/src/vs/platform/keybinding/common/keybinding.ts +++ b/src/vs/platform/keybinding/common/keybinding.ts @@ -50,6 +50,8 @@ export const IKeybindingService = createDecorator('keybindin export interface IKeybindingService { _serviceBrand: undefined; + readonly inChordMode: boolean; + onDidUpdateKeybindings: Event; /** diff --git a/src/vs/platform/keybinding/common/keybindingResolver.ts b/src/vs/platform/keybinding/common/keybindingResolver.ts index 2ae709887b3..439e42d9948 100644 --- a/src/vs/platform/keybinding/common/keybindingResolver.ts +++ b/src/vs/platform/keybinding/common/keybindingResolver.ts @@ -11,7 +11,10 @@ import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKe import { keys } from 'vs/base/common/map'; export interface IResolveResult { + /** Whether the resolved keybinding is entering a chord */ enterChord: boolean; + /** Whether the resolved keybinding is leaving (and executing) a chord */ + leaveChord: boolean; commandId: string | null; commandArgs: any; bubble: boolean; @@ -285,6 +288,7 @@ export class KeybindingResolver { if (currentChord === null && result.keypressParts.length > 1 && result.keypressParts[1] !== null) { return { enterChord: true, + leaveChord: false, commandId: null, commandArgs: null, bubble: false @@ -293,6 +297,7 @@ export class KeybindingResolver { return { enterChord: false, + leaveChord: result.keypressParts.length > 1, commandId: result.command, commandArgs: result.commandArgs, bubble: result.bubble diff --git a/src/vs/platform/keybinding/test/common/mockKeybindingService.ts b/src/vs/platform/keybinding/test/common/mockKeybindingService.ts index c2062a4e4b4..8fcb795eda0 100644 --- a/src/vs/platform/keybinding/test/common/mockKeybindingService.ts +++ b/src/vs/platform/keybinding/test/common/mockKeybindingService.ts @@ -71,6 +71,8 @@ export class MockContextKeyService implements IContextKeyService { export class MockKeybindingService implements IKeybindingService { public _serviceBrand: undefined; + public readonly inChordMode: boolean = false; + public get onDidUpdateKeybindings(): Event { return Event.None; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index cec072d72b3..a391706e51f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -602,8 +602,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // Respect chords if the allowChords setting is set and it's not Escape. Escape is // handled specially for Zen Mode's Escape, Escape chord, plus it's important in // terminals generally - const allowChords = resolveResult && resolveResult.enterChord && this._configHelper.config.allowChords && event.key !== 'Escape'; - if (allowChords || resolveResult && this._skipTerminalCommands.some(k => k === resolveResult.commandId)) { + const allowChords = resolveResult?.enterChord && this._configHelper.config.allowChords && event.key !== 'Escape'; + if (this._keybindingService.inChordMode || allowChords || resolveResult && this._skipTerminalCommands.some(k => k === resolveResult.commandId)) { event.preventDefault(); return false; } From a0dbbaa4559af59969f81d790506c7fce97ec8f0 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Tue, 25 Feb 2020 15:44:38 -0800 Subject: [PATCH 012/235] pluralization support to re close #89463 --- .../searchEditor/browser/searchEditorSerialization.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditorSerialization.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditorSerialization.ts index eca8524c25f..0e89108e1e8 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditorSerialization.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditorSerialization.ts @@ -211,9 +211,12 @@ export const serializeSearchResultForEditor = ? contentPatternToSearchResultHeader(searchResult.query, rawIncludePattern, rawExcludePattern, contextLines) : []; + const filecount = searchResult.fileCount() > 1 ? localize('numFiles', "{0} files", searchResult.fileCount()) : localize('oneFile', "1 file"); + const resultcount = searchResult.count() > 1 ? localize('numResults', "{0} results", searchResult.count()) : localize('oneResult', "1 result"); + const info = [ searchResult.count() - ? localize('resultCount', "{0} results in {1} files", searchResult.count(), searchResult.fileCount()) + ? `${filecount} - ${resultcount}` : localize('noResults', "No Results"), '']; From dbe62be3266ffb6772a7f3db0bf61d63f4aa7f65 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Tue, 25 Feb 2020 17:21:59 -0800 Subject: [PATCH 013/235] Fix #91343 --- src/vs/workbench/contrib/search/common/searchModel.ts | 9 +++++++++ .../searchEditor/browser/searchEditorSerialization.ts | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/search/common/searchModel.ts b/src/vs/workbench/contrib/search/common/searchModel.ts index bea090b9701..1505579db92 100644 --- a/src/vs/workbench/contrib/search/common/searchModel.ts +++ b/src/vs/workbench/contrib/search/common/searchModel.ts @@ -141,6 +141,15 @@ export class Match { return thisMatchPreviewLines.join('\n'); } + rangeInPreview() { + // convert to editor's base 1 positions. + return { + ...this._fullPreviewRange, + startColumn: this._fullPreviewRange.startColumn + 1, + endColumn: this._fullPreviewRange.endColumn + 1 + }; + } + fullPreviewLines(): string[] { return this._fullPreviewLines.slice(this._fullPreviewRange.startLineNumber, this._fullPreviewRange.endLineNumber + 1); } diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditorSerialization.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditorSerialization.ts index 0e89108e1e8..389faee3931 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditorSerialization.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditorSerialization.ts @@ -42,7 +42,7 @@ const matchToSearchResultFormat = (match: Match): { line: string, ranges: Range[ const rangeOnThisLine = ({ start, end }: { start?: number; end?: number; }) => new Range(1, (start ?? 1) + prefixOffset, 1, (end ?? sourceLine.length + 1) + prefixOffset); - const matchRange = match.range(); + const matchRange = match.rangeInPreview(); const matchIsSingleLine = matchRange.startLineNumber === matchRange.endLineNumber; let lineRange; From b0be0672c210f1fa76109ce675365bb785657e84 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Tue, 25 Feb 2020 20:28:18 -0800 Subject: [PATCH 014/235] Fix #91344. --- .../contrib/searchEditor/browser/constants.ts | 1 + .../browser/searchEditor.contribution.ts | 15 ++++++++++----- .../searchEditor/browser/searchEditorInput.ts | 4 ++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/searchEditor/browser/constants.ts b/src/vs/workbench/contrib/searchEditor/browser/constants.ts index 7b1b1d34825..3de68eda5a0 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/constants.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/constants.ts @@ -19,5 +19,6 @@ export const SelectAllSearchEditorMatchesCommandId = 'selectAllSearchEditorMatch export const InSearchEditor = new RawContextKey('inSearchEditor', false); export const SearchEditorScheme = 'search-editor'; +export const SearchEditorBodyScheme = 'search-editor-body'; export const SearchEditorFindMatchClass = 'seaarchEditorFindMatch'; diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts index 1f10071bcfd..57b857a860d 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts @@ -21,7 +21,6 @@ import { EditorDescriptor, Extensions as EditorExtensions, IEditorRegistry } fro import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { Extensions as EditorInputExtensions, IEditorInputFactory, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor'; -import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; import * as SearchConstants from 'vs/workbench/contrib/search/common/constants'; import * as SearchEditorConstants from 'vs/workbench/contrib/searchEditor/browser/constants'; import { SearchEditor } from 'vs/workbench/contrib/searchEditor/browser/searchEditor'; @@ -30,6 +29,7 @@ import { getOrMakeSearchEditorInput, SearchEditorInput } from 'vs/workbench/cont import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; +import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; //#region Editor Descriptior Registry.as(EditorExtensions.Editors).registerEditor( @@ -54,10 +54,15 @@ class SearchEditorContribution implements IWorkbenchContribution { ) { this.editorService.overrideOpenEditor((editor, options, group) => { - const resource = editor.resource; - if (!resource || - !(endsWith(resource.path, '.code-search') || resource.scheme === SearchEditorConstants.SearchEditorScheme) || - !(editor instanceof FileEditorInput || (resource.scheme === SearchEditorConstants.SearchEditorScheme))) { + let resource = editor.resource; + if (!resource) { return undefined; } + + if (resource.scheme === SearchEditorConstants.SearchEditorBodyScheme) { + resource = resource.with({ scheme: SearchEditorConstants.SearchEditorScheme }); + } + + if (resource.scheme !== SearchEditorConstants.SearchEditorScheme + && !(endsWith(resource.path, '.code-search') && editor instanceof FileEditorInput)) { return undefined; } diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditorInput.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditorInput.ts index 389caf35844..44b819f8abc 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditorInput.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditorInput.ts @@ -18,7 +18,7 @@ import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { EditorInput, GroupIdentifier, IEditorInput, IRevertOptions, ISaveOptions, IMoveResult } from 'vs/workbench/common/editor'; -import { SearchEditorFindMatchClass, SearchEditorScheme } from 'vs/workbench/contrib/searchEditor/browser/constants'; +import { SearchEditorFindMatchClass, SearchEditorScheme, SearchEditorBodyScheme } from 'vs/workbench/contrib/searchEditor/browser/constants'; import { extractSearchQuery, serializeSearchConfiguration } from 'vs/workbench/contrib/searchEditor/browser/searchEditorSerialization'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -339,7 +339,7 @@ export const getOrMakeSearchEditorInput = ( } } - const contentsModelURI = uri.with({ scheme: 'search-editor-body' }); + const contentsModelURI = uri.with({ scheme: SearchEditorBodyScheme }); const headerModelURI = uri.with({ scheme: 'search-editor-header' }); const contentsModel = modelService.getModel(contentsModelURI) ?? modelService.createModel('', modeService.create('search-result'), contentsModelURI); const headerModel = modelService.getModel(headerModelURI) ?? modelService.createModel('', modeService.create('search-result'), headerModelURI); From 091b317bc64dc9252dafe6c1c96fddc692da847d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 26 Feb 2020 07:37:29 +0100 Subject: [PATCH 015/235] Notification bell with badge and "no notifications" hover (fix #91444) --- .../browser/parts/notifications/notificationsStatus.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts b/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts index 71a82ef3aae..1bdde771ccb 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts @@ -46,7 +46,7 @@ export class NotificationsStatus extends Disposable { if (!this.isNotificationsCenterVisible) { if (e.kind === NotificationChangeType.ADD) { this.newNotificationsCount++; - } else if (e.kind === NotificationChangeType.REMOVE) { + } else if (e.kind === NotificationChangeType.REMOVE && this.newNotificationsCount > 0) { this.newNotificationsCount--; } } From 7cfbe2e6af6ab5e33864cae5242488d1cff8464c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 26 Feb 2020 07:52:49 +0100 Subject: [PATCH 016/235] Notification: X button shows up if progress is collapsed (fix #91414) --- .../notification/common/notification.ts | 24 +++++++++++++++++++ src/vs/workbench/common/notifications.ts | 21 ++++++++++++++-- .../progress/browser/progressService.ts | 3 ++- .../test/common/notifications.test.ts | 9 +++++-- 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/vs/platform/notification/common/notification.ts b/src/vs/platform/notification/common/notification.ts index aff1675b214..a81672c8311 100644 --- a/src/vs/platform/notification/common/notification.ts +++ b/src/vs/platform/notification/common/notification.ts @@ -101,6 +101,12 @@ export interface INotification extends INotificationProperties { * this usecase and much easier to use! */ actions?: INotificationActions; + + /** + * The initial set of progress properties for the notification. To update progress + * later on, access the `INotificationHandle.progress` property. + */ + progress?: INotificationProgressProperties; } export interface INotificationActions { @@ -119,6 +125,24 @@ export interface INotificationActions { secondary?: ReadonlyArray; } +export interface INotificationProgressProperties { + + /** + * Causes the progress bar to spin infinitley. + */ + infinite?: boolean; + + /** + * Indicate the total amount of work. + */ + total?: number; + + /** + * Indicate that a specific chunk of work is done. + */ + worked?: number; +} + export interface INotificationProgress { /** diff --git a/src/vs/workbench/common/notifications.ts b/src/vs/workbench/common/notifications.ts index 353baa3bd6e..73f0ef74053 100644 --- a/src/vs/workbench/common/notifications.ts +++ b/src/vs/workbench/common/notifications.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { INotification, INotificationHandle, INotificationActions, INotificationProgress, NoOpNotification, Severity, NotificationMessage, IPromptChoice, IStatusMessageOptions, NotificationsFilter } from 'vs/platform/notification/common/notification'; +import { INotification, INotificationHandle, INotificationActions, INotificationProgress, NoOpNotification, Severity, NotificationMessage, IPromptChoice, IStatusMessageOptions, NotificationsFilter, INotificationProgressProperties } from 'vs/platform/notification/common/notification'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { Event, Emitter } from 'vs/base/common/event'; import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; @@ -435,7 +435,7 @@ export class NotificationViewItem extends Disposable implements INotificationVie actions = { primary: notification.message.actions }; } - return new NotificationViewItem(severity, notification.sticky, notification.silent || filter === NotificationsFilter.SILENT || (filter === NotificationsFilter.ERROR && notification.severity !== Severity.Error), message, notification.source, actions); + return new NotificationViewItem(severity, notification.sticky, notification.silent || filter === NotificationsFilter.SILENT || (filter === NotificationsFilter.ERROR && notification.severity !== Severity.Error), message, notification.source, notification.progress, actions); } private static parseNotificationMessage(input: NotificationMessage): INotificationMessage | undefined { @@ -472,13 +472,30 @@ export class NotificationViewItem extends Disposable implements INotificationVie private _silent: boolean | undefined, private _message: INotificationMessage, private _source: string | undefined, + progress: INotificationProgressProperties | undefined, actions?: INotificationActions ) { super(); + if (progress) { + this.setProgress(progress); + } + this.setActions(actions); } + private setProgress(progress: INotificationProgressProperties): void { + if (progress.infinite) { + this.progress.infinite(); + } else if (progress.total) { + this.progress.total(progress.total); + + if (progress.worked) { + this.progress.worked(progress.worked); + } + } + } + private setActions(actions: INotificationActions = { primary: [], secondary: [] }): void { if (!Array.isArray(actions.primary)) { actions.primary = []; diff --git a/src/vs/workbench/services/progress/browser/progressService.ts b/src/vs/workbench/services/progress/browser/progressService.ts index 296e4f47bf5..6d4723b34e3 100644 --- a/src/vs/workbench/services/progress/browser/progressService.ts +++ b/src/vs/workbench/services/progress/browser/progressService.ts @@ -233,7 +233,8 @@ export class ProgressService extends Disposable implements IProgressService { severity: Severity.Info, message, source: options.source, - actions: { primary: primaryActions, secondary: secondaryActions } + actions: { primary: primaryActions, secondary: secondaryActions }, + progress: typeof increment === 'number' && increment >= 0 ? { total: 100, worked: increment } : { infinite: true } }); updateProgress(handle, increment); diff --git a/src/vs/workbench/test/common/notifications.test.ts b/src/vs/workbench/test/common/notifications.test.ts index 8984e0ab869..7eefd25cb8e 100644 --- a/src/vs/workbench/test/common/notifications.test.ts +++ b/src/vs/workbench/test/common/notifications.test.ts @@ -23,6 +23,7 @@ suite('Notifications', () => { let item3 = NotificationViewItem.create({ severity: Severity.Info, message: 'Info Message' })!; let item4 = NotificationViewItem.create({ severity: Severity.Error, message: 'Error Message', source: 'Source' })!; let item5 = NotificationViewItem.create({ severity: Severity.Error, message: 'Error Message', actions: { primary: [new Action('id', 'label')] } })!; + let item6 = NotificationViewItem.create({ severity: Severity.Error, message: 'Error Message', actions: { primary: [new Action('id', 'label')] }, progress: { infinite: true } })!; assert.equal(item1.equals(item1), true); assert.equal(item2.equals(item2), true); @@ -35,6 +36,10 @@ suite('Notifications', () => { assert.equal(item1.equals(item4), false); assert.equal(item1.equals(item5), false); + // Progress + assert.equal(item1.hasProgress, false); + assert.equal(item6.hasProgress, true); + // Message Box assert.equal(item5.canCollapse, false); assert.equal(item5.expanded, true); @@ -102,8 +107,8 @@ suite('Notifications', () => { assert.equal(called, 1); // Error with Action - let item6 = NotificationViewItem.create({ severity: Severity.Error, message: createErrorWithActions('Hello Error', { actions: [new Action('id', 'label')] }) })!; - assert.equal(item6.actions!.primary!.length, 1); + let item7 = NotificationViewItem.create({ severity: Severity.Error, message: createErrorWithActions('Hello Error', { actions: [new Action('id', 'label')] }) })!; + assert.equal(item7.actions!.primary!.length, 1); // Filter let item8 = NotificationViewItem.create({ severity: Severity.Error, message: 'Error Message' }, NotificationsFilter.SILENT)!; From 3de5a8a6a2ea77f08174f1c5341248401a377973 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 26 Feb 2020 08:36:51 +0100 Subject: [PATCH 017/235] Adding already disposed disposable to DisposableStore in textFileEditorModel.ts (fix #91396) --- .../textfile/common/textFileEditorModel.ts | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 7afb0645e24..67332750e50 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -251,6 +251,13 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil async load(options?: ITextFileLoadOptions): Promise { this.logService.trace('[text file model] load() - enter', this.resource.toString(true)); + // Return early if we are disposed + if (this.isDisposed()) { + this.logService.trace('[text file model] load() - exit - without loading because model is disposed', this.resource.toString(true)); + + return this; + } + // It is very important to not reload the model when the model is dirty. // We also only want to reload the model from the disk if no save is pending // to avoid data loss. @@ -359,7 +366,14 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } private loadFromContent(content: ITextFileStreamContent, options?: ITextFileLoadOptions, fromBackup?: boolean): TextFileEditorModel { - this.logService.trace('[text file model] load() - resolved content', this.resource.toString(true)); + this.logService.trace('[text file model] loadFromContent() - enter', this.resource.toString(true)); + + // Return early if we are disposed + if (this.isDisposed()) { + this.logService.trace('[text file model] loadFromContent() - exit - because model is disposed', this.resource.toString(true)); + + return this; + } // Update our resolved disk stat model this.updateLastResolvedFileStat({ @@ -405,7 +419,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } private doCreateTextModel(resource: URI, value: ITextBufferFactory, fromBackup: boolean): void { - this.logService.trace('[text file model] load() - created text editor model', this.resource.toString(true)); + this.logService.trace('[text file model] doCreateTextModel()', this.resource.toString(true)); // Create model const textModel = this.createTextEditorModel(value, resource, this.preferredMode); @@ -420,7 +434,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } private doUpdateTextModel(value: ITextBufferFactory): void { - this.logService.trace('[text file model] load() - updated text editor model', this.resource.toString(true)); + this.logService.trace('[text file model] doUpdateTextModel()', this.resource.toString(true)); // Update model value in a block that ignores content change events for dirty tracking this.ignoreDirtyOnModelContentChange = true; @@ -703,7 +717,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } private handleSaveSuccess(stat: IFileStatWithMetadata, versionId: number, options: ITextFileSaveOptions): void { - this.logService.trace(`[text file model] doSave(${versionId}) - after write()`, this.resource.toString(true)); // Updated resolved stat with updated stat this.updateLastResolvedFileStat(stat); From afcaaa613186832493bb1813dee048890a3c2a2f Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 26 Feb 2020 09:04:03 +0100 Subject: [PATCH 018/235] smoke - use tree kill also here --- test/automation/package.json | 3 ++- test/automation/src/playwrightDriver.ts | 12 +++++------- test/automation/yarn.lock | 5 +++++ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/test/automation/package.json b/test/automation/package.json index a3f3baf2f40..8fced3ba824 100644 --- a/test/automation/package.json +++ b/test/automation/package.json @@ -28,7 +28,8 @@ "concurrently": "^3.5.1", "cpx": "^1.5.0", "typescript": "3.7.5", - "watch": "^1.0.2" + "watch": "^1.0.2", + "tree-kill": "1.2.2" }, "dependencies": { "mkdirp": "^0.5.1", diff --git a/test/automation/src/playwrightDriver.ts b/test/automation/src/playwrightDriver.ts index 40ee4c82851..cc0c5547db3 100644 --- a/test/automation/src/playwrightDriver.ts +++ b/test/automation/src/playwrightDriver.ts @@ -10,6 +10,7 @@ import { mkdir } from 'fs'; import { promisify } from 'util'; import { IDriver, IDisposable } from './driver'; import { URI } from 'vscode-uri'; +import * as kill from 'tree-kill'; const width = 1200; const height = 800; @@ -93,6 +94,7 @@ let workspacePath: string | undefined; export async function launch(userDataDir: string, _workspacePath: string, codeServerPath = process.env.VSCODE_REMOTE_SERVER_PATH): Promise { workspacePath = _workspacePath; + const agentFolder = userDataDir; await promisify(mkdir)(agentFolder); const env = { @@ -121,7 +123,7 @@ export async function launch(userDataDir: string, _workspacePath: string, codeSe function teardown(): void { if (server) { - server.kill(); + kill(server.pid); server = undefined; } } @@ -137,13 +139,9 @@ function waitForEndpoint(): Promise { }); } -export function connect(engine: 'chromium' | 'webkit' | 'firefox' = 'chromium'): Promise<{ client: IDisposable, driver: IDriver }> { +export function connect(browserType: 'chromium' | 'webkit' | 'firefox' = 'chromium'): Promise<{ client: IDisposable, driver: IDriver }> { return new Promise(async (c) => { - const browser = await playwright[engine].launch({ - // Run in Edge dev on macOS - // executablePath: '/Applications/Microsoft\ Edge\ Dev.app/Contents/MacOS/Microsoft\ Edge\ Dev', - headless: false - }); + const browser = await playwright[browserType].launch({ headless: false, dumpio: true }); const context = await browser.newContext(); const page = await context.newPage(); await page.setViewportSize({ width, height }); diff --git a/test/automation/yarn.lock b/test/automation/yarn.lock index 98c63c91e0d..11785373d40 100644 --- a/test/automation/yarn.lock +++ b/test/automation/yarn.lock @@ -1634,6 +1634,11 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +tree-kill@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + tree-kill@^1.1.0: version "1.2.1" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.1.tgz#5398f374e2f292b9dcc7b2e71e30a5c3bb6c743a" From fd407adeda50c39e50ed7a7d6227abae479ce256 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 26 Feb 2020 10:40:35 +0100 Subject: [PATCH 019/235] Fixes #91051: Have Shift+Insert paste from the clipboard by default (like Ctrl+V) --- src/vs/editor/contrib/clipboard/clipboard.ts | 1 + .../electron-browser/selectionClipboard.ts | 13 +------------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/vs/editor/contrib/clipboard/clipboard.ts b/src/vs/editor/contrib/clipboard/clipboard.ts index cb106b53b82..321543523a0 100644 --- a/src/vs/editor/contrib/clipboard/clipboard.ts +++ b/src/vs/editor/contrib/clipboard/clipboard.ts @@ -161,6 +161,7 @@ class ExecCommandPasteAction extends ExecCommandAction { kbExpr: EditorContextKeys.textInputFocus, primary: KeyMod.CtrlCmd | KeyCode.KEY_V, win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, secondary: [KeyMod.Shift | KeyCode.Insert] }, + linux: { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, secondary: [KeyMod.Shift | KeyCode.Insert] }, weight: KeybindingWeight.EditorContrib }; // Do not bind paste keybindings in the browser, diff --git a/src/vs/workbench/contrib/codeEditor/electron-browser/selectionClipboard.ts b/src/vs/workbench/contrib/codeEditor/electron-browser/selectionClipboard.ts index 536d0f75c5c..592605c0759 100644 --- a/src/vs/workbench/contrib/codeEditor/electron-browser/selectionClipboard.ts +++ b/src/vs/workbench/contrib/codeEditor/electron-browser/selectionClipboard.ts @@ -20,10 +20,7 @@ import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; export class SelectionClipboard extends Disposable implements IEditorContribution { private static readonly SELECTION_LENGTH_LIMIT = 65536; @@ -119,15 +116,7 @@ class PasteSelectionClipboardAction extends EditorAction { id: 'editor.action.selectionClipboardPaste', label: nls.localize('actions.pasteSelectionClipboard', "Paste Selection Clipboard"), alias: 'Paste Selection Clipboard', - precondition: EditorContextKeys.writable, - kbOpts: { - kbExpr: ContextKeyExpr.and( - EditorContextKeys.editorTextFocus, - ContextKeyExpr.has('config.editor.selectionClipboard') - ), - primary: KeyMod.Shift | KeyCode.Insert, - weight: KeybindingWeight.EditorContrib - } + precondition: EditorContextKeys.writable }); } From b9809ceca805e44e9809e9023a4017c6d7d3ab2d Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 26 Feb 2020 11:06:26 +0100 Subject: [PATCH 020/235] fixes #90478 --- src/vs/workbench/contrib/debug/browser/debug.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index 30ae2db8bbf..d01fecdbb3c 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -267,7 +267,7 @@ configurationRegistry.registerConfiguration({ default: true }, 'debug.onTaskErrors': { - enum: ['debugAnyway', 'showErrors', 'prompt', 'cancel'], + enum: ['debugAnyway', 'showErrors', 'prompt', 'abort'], enumDescriptions: [nls.localize('debugAnyway', "Ignore task errors and start debugging."), nls.localize('showErrors', "Show the Problems view and do not start debugging."), nls.localize('prompt', "Prompt user."), nls.localize('cancel', "Cancel debugging.")], description: nls.localize('debug.onTaskErrors', "Controls what to do when errors are encountered after running a preLaunchTask."), default: 'prompt' From ebcd432491259c91013bb0ff0284610f7f84504d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 26 Feb 2020 11:39:05 +0100 Subject: [PATCH 021/235] docs for #91532 --- test/integration/browser/README.md | 1 + test/smoke/README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/test/integration/browser/README.md b/test/integration/browser/README.md index 10a55f7de17..8b36a3c172c 100644 --- a/test/integration/browser/README.md +++ b/test/integration/browser/README.md @@ -14,6 +14,7 @@ All integration tests run in an Electron instance. You can specify to run the te ## Run (inside browser) + yarn gulp mixin-server resources/server/test/test-web-integration.[sh|bat] --browser [chromium|webkit] [--debug] All integration tests run in a browser instance as specified by the command line arguments. diff --git a/test/smoke/README.md b/test/smoke/README.md index 8b41d05ed08..8836886be6b 100644 --- a/test/smoke/README.md +++ b/test/smoke/README.md @@ -13,6 +13,7 @@ yarn --cwd test/automation yarn smoketest # Dev (Web) +yarn gulp mixin-server yarn smoketest --web --browser [chromium|firefox|webkit] # Build (Electron) From f0066fe680e8c1de0c201a3da68201ce0f52af87 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 26 Feb 2020 11:55:43 +0100 Subject: [PATCH 022/235] automation: refactor web tests not to use outPath --- test/automation/src/code.ts | 116 ++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/test/automation/src/code.ts b/test/automation/src/code.ts index 3b5a667f81f..dcd75fe1e6f 100644 --- a/test/automation/src/code.ts +++ b/test/automation/src/code.ts @@ -115,9 +115,6 @@ async function createDriverHandle(): Promise { } export async function spawn(options: SpawnOptions): Promise { - const codePath = options.codePath; - const electronPath = codePath ? getBuildElectronPath(codePath) : getDevElectronPath(); - const outPath = codePath ? getBuildOutPath(codePath) : getDevOutPath(); const handle = await createDriverHandle(); let child: cp.ChildProcess | undefined; @@ -126,63 +123,66 @@ export async function spawn(options: SpawnOptions): Promise { if (options.web) { await launch(options.userDataDir, options.workspacePath, options.codePath); connectDriver = connectPlaywrightDriver.bind(connectPlaywrightDriver, options.browser); - } else { - const env = process.env; - - const args = [ - options.workspacePath, - '--skip-getting-started', - '--skip-release-notes', - '--sticky-quickopen', - '--disable-telemetry', - '--disable-updates', - '--disable-crash-reporter', - `--extensions-dir=${options.extensionsPath}`, - `--user-data-dir=${options.userDataDir}`, - '--driver', handle - ]; - - if (options.remote) { - // Replace workspace path with URI - args[0] = `--${options.workspacePath.endsWith('.code-workspace') ? 'file' : 'folder'}-uri=vscode-remote://test+test/${URI.file(options.workspacePath).path}`; - - if (codePath) { - // running against a build: copy the test resolver extension - const testResolverExtPath = path.join(options.extensionsPath, 'vscode-test-resolver'); - if (!fs.existsSync(testResolverExtPath)) { - const orig = path.join(repoPath, 'extensions', 'vscode-test-resolver'); - await new Promise((c, e) => ncp(orig, testResolverExtPath, err => err ? e(err) : c())); - } - } - args.push('--enable-proposed-api=vscode.vscode-test-resolver'); - const remoteDataDir = `${options.userDataDir}-server`; - mkdirp.sync(remoteDataDir); - env['TESTRESOLVER_DATA_FOLDER'] = remoteDataDir; - } - - if (!codePath) { - args.unshift(repoPath); - } - - if (options.verbose) { - args.push('--driver-verbose'); - } - - if (options.log) { - args.push('--log', options.log); - } - - if (options.extraArgs) { - args.push(...options.extraArgs); - } - - const spawnOptions: cp.SpawnOptions = { env }; - child = cp.spawn(electronPath, args, spawnOptions); - instances.add(child); - child.once('exit', () => instances.delete(child!)); - connectDriver = connectElectronDriver; + return connect(connectDriver, child, '', handle, options.logger); } + const env = process.env; + const codePath = options.codePath; + const outPath = codePath ? getBuildOutPath(codePath) : getDevOutPath(); + + const args = [ + options.workspacePath, + '--skip-getting-started', + '--skip-release-notes', + '--sticky-quickopen', + '--disable-telemetry', + '--disable-updates', + '--disable-crash-reporter', + `--extensions-dir=${options.extensionsPath}`, + `--user-data-dir=${options.userDataDir}`, + '--driver', handle + ]; + + if (options.remote) { + // Replace workspace path with URI + args[0] = `--${options.workspacePath.endsWith('.code-workspace') ? 'file' : 'folder'}-uri=vscode-remote://test+test/${URI.file(options.workspacePath).path}`; + + if (codePath) { + // running against a build: copy the test resolver extension + const testResolverExtPath = path.join(options.extensionsPath, 'vscode-test-resolver'); + if (!fs.existsSync(testResolverExtPath)) { + const orig = path.join(repoPath, 'extensions', 'vscode-test-resolver'); + await new Promise((c, e) => ncp(orig, testResolverExtPath, err => err ? e(err) : c())); + } + } + args.push('--enable-proposed-api=vscode.vscode-test-resolver'); + const remoteDataDir = `${options.userDataDir}-server`; + mkdirp.sync(remoteDataDir); + env['TESTRESOLVER_DATA_FOLDER'] = remoteDataDir; + } + + if (!codePath) { + args.unshift(repoPath); + } + + if (options.verbose) { + args.push('--driver-verbose'); + } + + if (options.log) { + args.push('--log', options.log); + } + + if (options.extraArgs) { + args.push(...options.extraArgs); + } + + const electronPath = codePath ? getBuildElectronPath(codePath) : getDevElectronPath(); + const spawnOptions: cp.SpawnOptions = { env }; + child = cp.spawn(electronPath, args, spawnOptions); + instances.add(child); + child.once('exit', () => instances.delete(child!)); + connectDriver = connectElectronDriver; return connect(connectDriver, child, outPath, handle, options.logger); } From 2cb430b396bc2032042449a856c44e4830ebdac7 Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Wed, 26 Feb 2020 11:54:44 +0100 Subject: [PATCH 023/235] Fixes #91433: Smoke Test: Localization Test Failure --- test/smoke/src/areas/workbench/localization.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/smoke/src/areas/workbench/localization.test.ts b/test/smoke/src/areas/workbench/localization.test.ts index 5db5fe2b74a..07e9199080e 100644 --- a/test/smoke/src/areas/workbench/localization.test.ts +++ b/test/smoke/src/areas/workbench/localization.test.ts @@ -37,10 +37,10 @@ export function setup() { await app.workbench.scm.waitForTitle(title => /quellcodeverwaltung/i.test(title)); await app.workbench.debug.openDebugViewlet(); - await app.workbench.debug.waitForTitle(title => /debug/i.test(title)); + await app.workbench.debug.waitForTitle(title => /starten/i.test(title)); - // await app.workbench.extensions.openExtensionsViewlet(); - // await app.workbench.extensions.waitForTitle(title => /erweiterungen/i.test(title)); + await app.workbench.extensions.openExtensionsViewlet(); + await app.workbench.extensions.waitForTitle(title => /extensions/i.test(title)); }); }); } From cb2acf650c15e667e911dbd99341588616e259f2 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 26 Feb 2020 11:32:19 +0100 Subject: [PATCH 024/235] Clarify StateDelta usage --- .../browser/parts/editor/editorStatus.ts | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index 18ba6d61dcb..394bb32fa84 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -170,16 +170,16 @@ class StateChange { } } -interface StateDelta { - selectionStatus?: string; - mode?: string; - encoding?: string; - EOL?: string; - indentation?: string; - tabFocusMode?: boolean; - screenReaderMode?: boolean; - metadata?: string | undefined; -} +type StateDelta = ( + { type: 'selectionStatus'; selectionStatus: string | undefined; } + | { type: 'mode'; mode: string | undefined; } + | { type: 'encoding'; encoding: string | undefined; } + | { type: 'EOL'; EOL: string | undefined; } + | { type: 'indentation'; indentation: string | undefined; } + | { type: 'tabFocusMode'; tabFocusMode: boolean; } + | { type: 'screenReaderMode'; screenReaderMode: boolean; } + | { type: 'metadata'; metadata: string | undefined; } +); class State { @@ -210,56 +210,56 @@ class State { update(update: StateDelta): StateChange { const change = new StateChange(); - if ('selectionStatus' in update) { + if (update.type === 'selectionStatus') { if (this._selectionStatus !== update.selectionStatus) { this._selectionStatus = update.selectionStatus; change.selectionStatus = true; } } - if ('indentation' in update) { + if (update.type === 'indentation') { if (this._indentation !== update.indentation) { this._indentation = update.indentation; change.indentation = true; } } - if ('mode' in update) { + if (update.type === 'mode') { if (this._mode !== update.mode) { this._mode = update.mode; change.mode = true; } } - if ('encoding' in update) { + if (update.type === 'encoding') { if (this._encoding !== update.encoding) { this._encoding = update.encoding; change.encoding = true; } } - if ('EOL' in update) { + if (update.type === 'EOL') { if (this._EOL !== update.EOL) { this._EOL = update.EOL; change.EOL = true; } } - if ('tabFocusMode' in update) { + if (update.type === 'tabFocusMode') { if (this._tabFocusMode !== update.tabFocusMode) { this._tabFocusMode = update.tabFocusMode; change.tabFocusMode = true; } } - if ('screenReaderMode' in update) { + if (update.type === 'screenReaderMode') { if (this._screenReaderMode !== update.screenReaderMode) { this._screenReaderMode = update.screenReaderMode; change.screenReaderMode = true; } } - if ('metadata' in update) { + if (update.type === 'metadata') { if (this._metadata !== update.metadata) { this._metadata = update.metadata; change.metadata = true; @@ -665,14 +665,14 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } private onModeChange(editorWidget: ICodeEditor | undefined, editorInput: IEditorInput | undefined): void { - let info: StateDelta = { mode: undefined }; + let info: StateDelta = { type: 'mode', mode: undefined }; // We only support text based editors if (editorWidget && editorInput && toEditorWithModeSupport(editorInput)) { const textModel = editorWidget.getModel(); if (textModel) { const modeId = textModel.getLanguageIdentifier().language; - info = { mode: withNullAsUndefined(this.modeService.getLanguageName(modeId)) }; + info.mode = withNullAsUndefined(this.modeService.getLanguageName(modeId)); } } @@ -680,7 +680,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } private onIndentationChange(editorWidget: ICodeEditor | undefined): void { - const update: StateDelta = { indentation: undefined }; + const update: StateDelta = { type: 'indentation', indentation: undefined }; if (editorWidget) { const model = editorWidget.getModel(); @@ -698,7 +698,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } private onMetadataChange(editor: IBaseEditor | undefined): void { - const update: StateDelta = { metadata: undefined }; + const update: StateDelta = { type: 'metadata', metadata: undefined }; if (editor instanceof BaseBinaryResourceEditor || editor instanceof BinaryResourceDiffEditor) { update.metadata = editor.getMetadata(); @@ -730,7 +730,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { this.screenReaderNotification.close(); } - this.updateState({ screenReaderMode: screenReaderMode }); + this.updateState({ type: 'screenReaderMode', screenReaderMode: screenReaderMode }); } private onSelectionChange(editorWidget: ICodeEditor | undefined): void { @@ -770,11 +770,11 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } } - this.updateState({ selectionStatus: this.getSelectionLabel(info) }); + this.updateState({ type: 'selectionStatus', selectionStatus: this.getSelectionLabel(info) }); } private onEOLChange(editorWidget: ICodeEditor | undefined): void { - const info: StateDelta = { EOL: undefined }; + const info: StateDelta = { type: 'EOL', EOL: undefined }; if (editorWidget && !editorWidget.getOption(EditorOption.readOnly)) { const codeEditorModel = editorWidget.getModel(); @@ -791,7 +791,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { return; } - const info: StateDelta = { encoding: undefined }; + const info: StateDelta = { type: 'encoding', encoding: undefined }; // We only support text based editors that have a model associated // This ensures we do not show the encoding picker while an editor @@ -825,7 +825,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } private onTabFocusModeChange(): void { - const info: StateDelta = { tabFocusMode: TabFocus.getTabFocusMode() }; + const info: StateDelta = { type: 'tabFocusMode', tabFocusMode: TabFocus.getTabFocusMode() }; this.updateState(info); } From 279b5482851fd4641bfadbf517b2511cf0965de6 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 26 Feb 2020 11:58:09 +0100 Subject: [PATCH 025/235] Fixes #91362: Render Column Selection mode in the status bar when enabled --- .../browser/parts/editor/editorStatus.ts | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index 394bb32fa84..34ae3b128ab 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -144,6 +144,7 @@ class StateChange { encoding: boolean = false; EOL: boolean = false; tabFocusMode: boolean = false; + columnSelectionMode: boolean = false; screenReaderMode: boolean = false; metadata: boolean = false; @@ -154,6 +155,7 @@ class StateChange { this.encoding = this.encoding || other.encoding; this.EOL = this.EOL || other.EOL; this.tabFocusMode = this.tabFocusMode || other.tabFocusMode; + this.columnSelectionMode = this.columnSelectionMode || other.columnSelectionMode; this.screenReaderMode = this.screenReaderMode || other.screenReaderMode; this.metadata = this.metadata || other.metadata; } @@ -165,6 +167,7 @@ class StateChange { || this.encoding || this.EOL || this.tabFocusMode + || this.columnSelectionMode || this.screenReaderMode || this.metadata; } @@ -177,6 +180,7 @@ type StateDelta = ( | { type: 'EOL'; EOL: string | undefined; } | { type: 'indentation'; indentation: string | undefined; } | { type: 'tabFocusMode'; tabFocusMode: boolean; } + | { type: 'columnSelectionMode'; columnSelectionMode: boolean; } | { type: 'screenReaderMode'; screenReaderMode: boolean; } | { type: 'metadata'; metadata: string | undefined; } ); @@ -201,6 +205,9 @@ class State { private _tabFocusMode: boolean | undefined; get tabFocusMode(): boolean | undefined { return this._tabFocusMode; } + private _columnSelectionMode: boolean | undefined; + get columnSelectionMode(): boolean | undefined { return this._columnSelectionMode; } + private _screenReaderMode: boolean | undefined; get screenReaderMode(): boolean | undefined { return this._screenReaderMode; } @@ -252,6 +259,13 @@ class State { } } + if (update.type === 'columnSelectionMode') { + if (this._columnSelectionMode !== update.columnSelectionMode) { + this._columnSelectionMode = update.columnSelectionMode; + change.columnSelectionMode = true; + } + } + if (update.type === 'screenReaderMode') { if (this._screenReaderMode !== update.screenReaderMode) { this._screenReaderMode = update.screenReaderMode; @@ -279,6 +293,7 @@ const nlsEOLCRLF = nls.localize('endOfLineCarriageReturnLineFeed', "CRLF"); export class EditorStatus extends Disposable implements IWorkbenchContribution { private readonly tabFocusModeElement = this._register(new MutableDisposable()); + private readonly columnSelectionModeElement = this._register(new MutableDisposable()); private readonly screenRedearModeElement = this._register(new MutableDisposable()); private readonly indentationElement = this._register(new MutableDisposable()); private readonly selectionElement = this._register(new MutableDisposable()); @@ -399,6 +414,22 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } } + private updateColumnSelectionModeElement(visible: boolean): void { + if (visible) { + if (!this.columnSelectionModeElement.value) { + this.columnSelectionModeElement.value = this.statusbarService.addEntry({ + text: nls.localize('columnSelectionModeEnabled', "Column Selection"), + tooltip: nls.localize('disableColumnSelectionMode', "Disable Column Selection Mode"), + command: 'editor.action.toggleColumnSelection', + backgroundColor: themeColorFromId(STATUS_BAR_PROMINENT_ITEM_BACKGROUND), + color: themeColorFromId(STATUS_BAR_PROMINENT_ITEM_FOREGROUND) + }, 'status.editor.columnSelectionMode', nls.localize('status.editor.columnSelectionMode', "Column Selection Mode"), StatusbarAlignment.RIGHT, 100.8); + } + } else { + this.columnSelectionModeElement.clear(); + } + } + private updateScreenReaderModeElement(visible: boolean): void { if (visible) { if (!this.screenRedearModeElement.value) { @@ -541,6 +572,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { private doRenderNow(changed: StateChange): void { this.updateTabFocusModeElement(!!this.state.tabFocusMode); + this.updateColumnSelectionModeElement(!!this.state.columnSelectionMode); this.updateScreenReaderModeElement(!!this.state.screenReaderMode); this.updateIndentationElement(this.state.indentation); this.updateSelectionElement(this.state.selectionStatus && !this.state.screenReaderMode ? this.state.selectionStatus : undefined); @@ -580,6 +612,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { const activeCodeEditor = activeControl ? withNullAsUndefined(getCodeEditor(activeControl.getControl())) : undefined; // Update all states + this.onColumnSelectionModeChange(activeCodeEditor); this.onScreenReaderModeChange(activeCodeEditor); this.onSelectionChange(activeCodeEditor); this.onModeChange(activeCodeEditor, activeInput); @@ -597,6 +630,9 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { // Hook Listener for Configuration changes this.activeEditorListeners.add(activeCodeEditor.onDidChangeConfiguration((event: ConfigurationChangedEvent) => { + if (event.hasChanged(EditorOption.columnSelection)) { + this.onColumnSelectionModeChange(activeCodeEditor); + } if (event.hasChanged(EditorOption.accessibilitySupport)) { this.onScreenReaderModeChange(activeCodeEditor); } @@ -707,6 +743,16 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { this.updateState(update); } + private onColumnSelectionModeChange(editorWidget: ICodeEditor | undefined): void { + const info: StateDelta = { type: 'columnSelectionMode', columnSelectionMode: false }; + + if (editorWidget && editorWidget.getOption(EditorOption.columnSelection)) { + info.columnSelectionMode = true; + } + + this.updateState(info); + } + private onScreenReaderModeChange(editorWidget: ICodeEditor | undefined): void { let screenReaderMode = false; From 29c2c6079e50de139ef5936ad66364a8e9f9f727 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 26 Feb 2020 12:03:05 +0100 Subject: [PATCH 026/235] smoke - do not restore windows --- test/automation/src/code.ts | 1 + test/smoke/src/main.ts | 35 +++++++++++++---------------------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/test/automation/src/code.ts b/test/automation/src/code.ts index dcd75fe1e6f..34bd09b739e 100644 --- a/test/automation/src/code.ts +++ b/test/automation/src/code.ts @@ -140,6 +140,7 @@ export async function spawn(options: SpawnOptions): Promise { '--disable-crash-reporter', `--extensions-dir=${options.extensionsPath}`, `--user-data-dir=${options.userDataDir}`, + `--disable-restore-windows`, '--driver', handle ]; diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index 8122d235289..a1273ba379d 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -57,8 +57,7 @@ const opts = minimist(args, { boolean: [ 'verbose', 'remote', - 'web', - 'ci' + 'web' ], default: { verbose: false @@ -299,24 +298,16 @@ describe(`VSCode Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => { }); } - // CI only tests (must be reliable) - if (opts.ci) { - // TODO@Ben figure out tests that can run continously and reliably - } - - // Non-CI execution (all tests) - else { - if (!opts.web) { setupDataMigrationTests(opts['stable-build'], testDataPath); } - if (!opts.web) { setupDataLossTests(); } - if (!opts.web) { setupDataPreferencesTests(); } - setupDataSearchTests(); - setupDataCSSTests(); - setupDataEditorTests(); - setupDataStatusbarTests(!!opts.web); - if (!opts.web) { setupDataExtensionTests(); } - setupTerminalTests(); - if (!opts.web) { setupDataMultirootTests(); } - if (!opts.web) { setupDataLocalizationTests(); } - if (!opts.web) { setupLaunchTests(); } - } + if (!opts.web) { setupDataMigrationTests(opts['stable-build'], testDataPath); } + if (!opts.web) { setupDataLossTests(); } + if (!opts.web) { setupDataPreferencesTests(); } + setupDataSearchTests(); + setupDataCSSTests(); + setupDataEditorTests(); + setupDataStatusbarTests(!!opts.web); + if (!opts.web) { setupDataExtensionTests(); } + setupTerminalTests(); + if (!opts.web) { setupDataMultirootTests(); } + if (!opts.web) { setupDataLocalizationTests(); } + if (!opts.web) { setupLaunchTests(); } }); From da48773ebda5cb575f3b3e983c7bd9a0ef97aad6 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 26 Feb 2020 12:07:26 +0100 Subject: [PATCH 027/235] notifications - change close icon to chevron (fix #91446) --- .../browser/parts/notifications/notificationsActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/notifications/notificationsActions.ts b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts index f6e1ee43461..82301a0448e 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsActions.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts @@ -63,7 +63,7 @@ export class HideNotificationsCenterAction extends Action { label: string, @ICommandService private readonly commandService: ICommandService ) { - super(id, label, 'codicon-close'); + super(id, label, 'codicon-chevron-down'); } run(notification: INotificationViewItem): Promise { From e2849363a412bdc4be2ee421512ce836e501f067 Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 26 Feb 2020 12:14:26 +0100 Subject: [PATCH 028/235] Alerts are too verbose when problems panel is open. Do not use aria-live fixes #91166 --- src/vs/workbench/contrib/markers/browser/markersView.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/markers/browser/markersView.ts b/src/vs/workbench/contrib/markers/browser/markersView.ts index 9b4453be046..bb4a5763759 100644 --- a/src/vs/workbench/contrib/markers/browser/markersView.ts +++ b/src/vs/workbench/contrib/markers/browser/markersView.ts @@ -349,7 +349,6 @@ export class MarkersView extends ViewPane implements IMarkerFilterController { private createArialLabelElement(parent: HTMLElement): void { this.ariaLabelElement = dom.append(parent, dom.$('')); this.ariaLabelElement.setAttribute('id', 'markers-panel-arialabel'); - this.ariaLabelElement.setAttribute('aria-live', 'polite'); } private createTree(parent: HTMLElement): void { From 292d56a3efac42d825c2b5dfd726ae0e511cab5e Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Wed, 26 Feb 2020 12:22:15 +0100 Subject: [PATCH 029/235] Task run options not getting configured Discovered through the instance limit testing, this was actually a problem that would hit any runOption Fixes #91438 --- .../contrib/tasks/common/taskConfiguration.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts index 8b290a74f53..14666552147 100644 --- a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts +++ b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts @@ -681,6 +681,7 @@ export namespace RunOnOptions { } export namespace RunOptions { + const properties: MetaData[] = [{ property: 'reevaluateOnRerun' }, { property: 'runOn' }, { property: 'instanceLimit' }]; export function fromConfiguration(value: RunOptionsConfig | undefined): Tasks.RunOptions { return { reevaluateOnRerun: value ? value.reevaluateOnRerun : true, @@ -688,6 +689,14 @@ export namespace RunOptions { instanceLimit: value ? value.instanceLimit : 1 }; } + + export function assignProperties(target: Tasks.RunOptions, source: Tasks.RunOptions | undefined): Tasks.RunOptions { + return _assignProperties(target, source, properties)!; + } + + export function fillProperties(target: Tasks.RunOptions, source: Tasks.RunOptions | undefined): Tasks.RunOptions { + return _fillProperties(target, source, properties)!; + } } interface ParseContext { @@ -1609,6 +1618,7 @@ namespace CustomTask { result.command.presentation = CommandConfiguration.PresentationOptions.assignProperties( result.command.presentation!, configuredProps.configurationProperties.presentation)!; result.command.options = CommandOptions.assignProperties(result.command.options, configuredProps.configurationProperties.options); + result.runOptions = RunOptions.assignProperties(result.runOptions, configuredProps.runOptions); let contributedConfigProps: Tasks.ConfigurationProperties = contributedTask.configurationProperties; fillProperty(resultConfigProps, contributedConfigProps, 'group'); @@ -1621,6 +1631,7 @@ namespace CustomTask { result.command.presentation = CommandConfiguration.PresentationOptions.fillProperties( result.command.presentation!, contributedConfigProps.presentation)!; result.command.options = CommandOptions.fillProperties(result.command.options, contributedConfigProps.options); + result.runOptions = RunOptions.fillProperties(result.runOptions, contributedTask.runOptions); if (contributedTask.hasDefinedMatchers === true) { result.hasDefinedMatchers = true; From a980d877773120a7aec99238701bad4418d3f566 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Wed, 26 Feb 2020 12:26:06 +0100 Subject: [PATCH 030/235] Polish description of task input password Fixes #91399 --- src/vs/base/parts/quickinput/common/quickInput.ts | 2 +- src/vs/vscode.d.ts | 2 +- .../configurationResolver/common/configurationResolverSchema.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/base/parts/quickinput/common/quickInput.ts b/src/vs/base/parts/quickinput/common/quickInput.ts index 8cbf10553e7..531551f95b0 100644 --- a/src/vs/base/parts/quickinput/common/quickInput.ts +++ b/src/vs/base/parts/quickinput/common/quickInput.ts @@ -113,7 +113,7 @@ export interface IInputOptions { placeHolder?: string; /** - * set to true to show a password prompt that will not show the typed value + * Controls if a password input is shown. Password input hides the typed text. */ password?: boolean; diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index ead7e54c39f..52c6a90f94e 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1806,7 +1806,7 @@ declare module 'vscode' { placeHolder?: string; /** - * Set to `true` to show a password prompt that will not show the typed value. + * Controls if a password input is shown. Password input hides the typed text. */ password?: boolean; diff --git a/src/vs/workbench/services/configurationResolver/common/configurationResolverSchema.ts b/src/vs/workbench/services/configurationResolver/common/configurationResolverSchema.ts index 6350d247915..2fceba9e4ac 100644 --- a/src/vs/workbench/services/configurationResolver/common/configurationResolverSchema.ts +++ b/src/vs/workbench/services/configurationResolver/common/configurationResolverSchema.ts @@ -46,7 +46,7 @@ export const inputsSchema: IJSONSchema = { }, password: { type: 'boolean', - description: nls.localize('JsonSchema.input.password', "Set to true to show a password prompt that will not show the typed value."), + description: nls.localize('JsonSchema.input.password', "Controls if a password input is shown. Password input hides the typed text."), }, } }, From 98d8caf7b531948d33de2b4e1e2db2157e94b23a Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 26 Feb 2020 13:54:53 +0100 Subject: [PATCH 031/235] Fixes #91361: Update selection when toggling column selection mode --- .../browser/toggleColumnSelection.ts | 57 +++++++++++++++++-- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts index 6624e94c7bd..4fcee43f63a 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts @@ -10,6 +10,13 @@ import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configur import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { Registry } from 'vs/platform/registry/common/platform'; import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; +import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { CoreNavigationCommands } from 'vs/editor/browser/controller/coreCommands'; +import { Position } from 'vs/editor/common/core/position'; +import { Selection } from 'vs/editor/common/core/selection'; +import { CursorColumns } from 'vs/editor/common/controller/cursorCommon'; export class ToggleColumnSelectionAction extends Action { public static readonly ID = 'editor.action.toggleColumnSelection'; @@ -18,14 +25,56 @@ export class ToggleColumnSelectionAction extends Action { constructor( id: string, label: string, - @IConfigurationService private readonly _configurationService: IConfigurationService + @IConfigurationService private readonly _configurationService: IConfigurationService, + @ICodeEditorService private readonly _codeEditorService: ICodeEditorService ) { super(id, label); } - public run(): Promise { - const newValue = !this._configurationService.getValue('editor.columnSelection'); - return this._configurationService.updateValue('editor.columnSelection', newValue, ConfigurationTarget.USER); + private _getCodeEditor(): ICodeEditor | null { + const codeEditor = this._codeEditorService.getFocusedCodeEditor(); + if (codeEditor) { + return codeEditor; + } + return this._codeEditorService.getActiveCodeEditor(); + } + + public async run(): Promise { + const oldValue = this._configurationService.getValue('editor.columnSelection'); + const codeEditor = this._getCodeEditor(); + await this._configurationService.updateValue('editor.columnSelection', !oldValue, ConfigurationTarget.USER); + const newValue = this._configurationService.getValue('editor.columnSelection'); + if (!codeEditor || codeEditor !== this._getCodeEditor() || oldValue === newValue || !codeEditor.hasModel()) { + return; + } + const cursors = codeEditor._getCursors(); + if (codeEditor.getOption(EditorOption.columnSelection)) { + const selection = codeEditor.getSelection(); + const modelSelectionStart = new Position(selection.selectionStartLineNumber, selection.selectionStartColumn); + const viewSelectionStart = cursors.context.convertModelPositionToViewPosition(modelSelectionStart); + const modelPosition = new Position(selection.positionLineNumber, selection.positionColumn); + const viewPosition = cursors.context.convertModelPositionToViewPosition(modelPosition); + + CoreNavigationCommands.MoveTo.runCoreEditorCommand(cursors, { + position: modelSelectionStart, + viewPosition: viewSelectionStart + }); + const visibleColumn = CursorColumns.visibleColumnFromColumn2(cursors.context.config, cursors.context.viewModel, viewPosition); + CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(cursors, { + position: modelPosition, + viewPosition: viewPosition, + doColumnSelect: true, + mouseColumn: visibleColumn + 1 + }); + } else { + const columnSelectData = cursors.getColumnSelectData(); + const fromViewColumn = CursorColumns.columnFromVisibleColumn2(cursors.context.config, cursors.context.viewModel, columnSelectData.fromViewLineNumber, columnSelectData.fromViewVisualColumn); + const fromPosition = cursors.context.convertViewPositionToModelPosition(columnSelectData.fromViewLineNumber, fromViewColumn); + const toViewColumn = CursorColumns.columnFromVisibleColumn2(cursors.context.config, cursors.context.viewModel, columnSelectData.toViewLineNumber, columnSelectData.toViewVisualColumn); + const toPosition = cursors.context.convertViewPositionToModelPosition(columnSelectData.toViewLineNumber, toViewColumn); + + codeEditor.setSelection(new Selection(fromPosition.lineNumber, fromPosition.column, toPosition.lineNumber, toPosition.column)); + } } } From e864a4d4a502c95da022a4136909c5ca6989d8e2 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 26 Feb 2020 14:02:14 +0100 Subject: [PATCH 032/235] #91545 update labels --- src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 3af86359029..c7c125df49a 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -608,7 +608,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } const result = await this.dialogService.show( Severity.Info, - localize('firs time sync', "First time Sync"), + localize('firs time sync', "Sync"), [ localize('merge', "Merge"), localize('cancel', "Cancel"), @@ -616,7 +616,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo ], { cancelId: 1, - detail: localize('first time sync detail', "Synchronizing from this device for the first time.\nWould you like to merge or replace with the data from the cloud?"), + detail: localize('first time sync detail', "It looks like this is the first time sync is set up.\nWould you like to merge or replace with the data from the cloud?"), } ); switch (result.choice) { From f85095715c403df09c8229fa3f022bb6e8cad609 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 26 Feb 2020 14:04:10 +0100 Subject: [PATCH 033/235] #91544 Change label --- src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index c7c125df49a..91cb9aa468c 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -853,7 +853,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo constructor() { super({ id: 'workbench.userData.actions.syncStatus', - title: localize('sync is on', "Sync is on"), + title: localize('sync is on', "Sync..."), menu: [ { id: MenuId.GlobalActivity, From 70b9b4b7f0988b0b99a5374726c4bc6171669f19 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 26 Feb 2020 14:21:44 +0100 Subject: [PATCH 034/235] Fixes #91369: Pass the IBulkEditOptions.label through to the IUndoRedo service --- .../services/bulkEdit/browser/bulkEditService.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts b/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts index b7f29e36862..e5b490f3187 100644 --- a/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts +++ b/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts @@ -130,6 +130,7 @@ class BulkEditModel implements IDisposable { private _tasks: ModelEditTask[] | undefined; constructor( + private readonly _label: string | undefined, private readonly _editor: ICodeEditor | undefined, private readonly _progress: IProgress, edits: WorkspaceTextEdit[], @@ -232,7 +233,7 @@ class BulkEditModel implements IDisposable { } const multiModelEditStackElement = new MultiModelEditStackElement( - localize('workspaceEdit', "Workspace Edit"), + this._label || localize('workspaceEdit', "Workspace Edit"), tasks.map(t => new EditStackElement(t.model, t.getBeforeCursorState())) ); this._undoRedoService.pushElement(multiModelEditStackElement); @@ -250,11 +251,13 @@ type Edit = WorkspaceFileEdit | WorkspaceTextEdit; class BulkEdit { + private readonly _label: string | undefined; private readonly _edits: Edit[] = []; private readonly _editor: ICodeEditor | undefined; private readonly _progress: IProgress; constructor( + label: string | undefined, editor: ICodeEditor | undefined, progress: IProgress | undefined, edits: Edit[], @@ -265,6 +268,7 @@ class BulkEdit { @IWorkingCopyFileService private readonly _workingCopyFileService: IWorkingCopyFileService, @IConfigurationService private readonly _configurationService: IConfigurationService ) { + this._label = label; this._editor = editor; this._progress = progress || Progress.None; this._edits = edits; @@ -361,7 +365,7 @@ class BulkEdit { private async _performTextEdits(edits: WorkspaceTextEdit[], progress: IProgress): Promise { this._logService.debug('_performTextEdits', JSON.stringify(edits)); - const model = this._instaService.createInstance(BulkEditModel, this._editor, progress, edits); + const model = this._instaService.createInstance(BulkEditModel, this._label, this._editor, progress, edits); await model.prepare(); @@ -439,7 +443,7 @@ export class BulkEditService implements IBulkEditService { // If the code editor is readonly still allow bulk edits to be applied #68549 codeEditor = undefined; } - const bulkEdit = this._instaService.createInstance(BulkEdit, codeEditor, options?.progress, edits); + const bulkEdit = this._instaService.createInstance(BulkEdit, options?.label, codeEditor, options?.progress, edits); return bulkEdit.perform().then(() => { return { ariaSummary: bulkEdit.ariaMessage() }; }).catch(err => { From 70d7091d75d3156578362292962bb81fc1293767 Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 26 Feb 2020 14:33:42 +0100 Subject: [PATCH 035/235] fixes #91426 --- .../contrib/debug/browser/startView.ts | 52 +++++++++---------- .../contrib/files/browser/explorerViewlet.ts | 12 ++--- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/startView.ts b/src/vs/workbench/contrib/debug/browser/startView.ts index f6b3133dc28..38ef45e83b5 100644 --- a/src/vs/workbench/contrib/debug/browser/startView.ts +++ b/src/vs/workbench/contrib/debug/browser/startView.ts @@ -75,35 +75,35 @@ export class StartView extends ViewPane { }; this._register(editorService.onDidActiveEditorChange(setContextKey)); this._register(this.debugService.getConfigurationManager().onDidRegisterDebugger(setContextKey)); - this.registerViews(); + setContextKey(); + + const debugKeybinding = this.keybindingService.lookupKeybinding(StartAction.ID); + debugKeybindingLabel = debugKeybinding ? ` (${debugKeybinding.getLabel()})` : ''; } shouldShowWelcome(): boolean { return true; } - - private registerViews(): void { - const viewsRegistry = Registry.as(Extensions.ViewsRegistry); - viewsRegistry.registerViewWelcomeContent(StartView.ID, { - content: localize('openAFileWhichCanBeDebugged', "[Open a file](command:{0}) which can be debugged or run.", isMacintosh ? OpenFileFolderAction.ID : OpenFileAction.ID), - when: CONTEXT_DEBUGGER_INTERESTED_IN_ACTIVE_EDITOR.toNegated() - }); - - const debugKeybinding = this.keybindingService.lookupKeybinding(StartAction.ID); - const debugKeybindingLabel = debugKeybinding ? ` (${debugKeybinding.getLabel()})` : ''; - viewsRegistry.registerViewWelcomeContent(StartView.ID, { - content: localize('runAndDebugAction', "[Run and Debug{0}](command:{1})", debugKeybindingLabel, StartAction.ID), - preconditions: [CONTEXT_DEBUGGER_INTERESTED_IN_ACTIVE_EDITOR] - }); - - viewsRegistry.registerViewWelcomeContent(StartView.ID, { - content: localize('customizeRunAndDebug', "To customize Run and Debug [create a launch.json file](command:{0}).", ConfigureAction.ID), - when: WorkbenchStateContext.notEqualsTo('empty') - }); - - viewsRegistry.registerViewWelcomeContent(StartView.ID, { - content: localize('customizeRunAndDebugOpenFolder', "To customize Run and Debug, [open a folder](command:{0}) and create a launch.json file.", isMacintosh ? OpenFileFolderAction.ID : OpenFolderAction.ID), - when: WorkbenchStateContext.isEqualTo('empty') - }); - } } + +const viewsRegistry = Registry.as(Extensions.ViewsRegistry); +viewsRegistry.registerViewWelcomeContent(StartView.ID, { + content: localize('openAFileWhichCanBeDebugged', "[Open a file](command:{0}) which can be debugged or run.", isMacintosh ? OpenFileFolderAction.ID : OpenFileAction.ID), + when: CONTEXT_DEBUGGER_INTERESTED_IN_ACTIVE_EDITOR.toNegated() +}); + +let debugKeybindingLabel = ''; +viewsRegistry.registerViewWelcomeContent(StartView.ID, { + content: localize('runAndDebugAction', "[Run and Debug{0}](command:{1})", debugKeybindingLabel, StartAction.ID), + preconditions: [CONTEXT_DEBUGGER_INTERESTED_IN_ACTIVE_EDITOR] +}); + +viewsRegistry.registerViewWelcomeContent(StartView.ID, { + content: localize('customizeRunAndDebug', "To customize Run and Debug [create a launch.json file](command:{0}).", ConfigureAction.ID), + when: WorkbenchStateContext.notEqualsTo('empty') +}); + +viewsRegistry.registerViewWelcomeContent(StartView.ID, { + content: localize('customizeRunAndDebugOpenFolder', "To customize Run and Debug, [open a folder](command:{0}) and create a launch.json file.", isMacintosh ? OpenFileFolderAction.ID : OpenFolderAction.ID), + when: WorkbenchStateContext.isEqualTo('empty') +}); diff --git a/src/vs/workbench/contrib/files/browser/explorerViewlet.ts b/src/vs/workbench/contrib/files/browser/explorerViewlet.ts index 720b01e66ed..ba4f2cae30f 100644 --- a/src/vs/workbench/contrib/files/browser/explorerViewlet.ts +++ b/src/vs/workbench/contrib/files/browser/explorerViewlet.ts @@ -65,21 +65,21 @@ export class ExplorerViewletViewsContribution extends Disposable implements IWor private registerViews(): void { const viewsRegistry = Registry.as(Extensions.ViewsRegistry); - viewsRegistry.registerViewWelcomeContent(EmptyView.ID, { + this._register(viewsRegistry.registerViewWelcomeContent(EmptyView.ID, { content: localize('noWorkspaceHelp', "You have not yet added a folder to the workspace.\n[Add Folder](command:{0})", AddRootFolderAction.ID), when: WorkbenchStateContext.isEqualTo('workspace') - }); + })); const commandId = isMacintosh ? OpenFileFolderAction.ID : OpenFolderAction.ID; - viewsRegistry.registerViewWelcomeContent(EmptyView.ID, { + this._register(viewsRegistry.registerViewWelcomeContent(EmptyView.ID, { content: localize('remoteNoFolderHelp', "Connected to remote.\n[Open Folder](command:{0})", commandId), when: ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), RemoteNameContext.notEqualsTo(''), IsWebContext.toNegated()) - }); + })); - viewsRegistry.registerViewWelcomeContent(EmptyView.ID, { + this._register(viewsRegistry.registerViewWelcomeContent(EmptyView.ID, { content: localize('noFolderHelp', "You have not yet opened a folder.\n[Open Folder](command:{0})", commandId), when: ContextKeyExpr.or(ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), RemoteNameContext.isEqualTo('')), ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), IsWebContext)) - }); + })); const viewDescriptors = viewsRegistry.getViews(VIEW_CONTAINER); From 46a973511b506e757e173d5a82112dbd9e1e2512 Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Wed, 26 Feb 2020 14:52:20 +0100 Subject: [PATCH 036/235] node-debug@1.43.2 --- build/builtInExtensions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index 84091196b00..b0483145e01 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -1,7 +1,7 @@ [ { "name": "ms-vscode.node-debug", - "version": "1.43.1", + "version": "1.43.2", "repo": "https://github.com/Microsoft/vscode-node-debug", "metadata": { "id": "b6ded8fb-a0a0-4c1c-acbd-ab2a3bc995a6", From ebafcb93181a8d610153734d2ab1c90dc5117d3c Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Wed, 26 Feb 2020 14:54:49 +0100 Subject: [PATCH 037/235] update DAP to final version --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 7910be5d9ae..46535c5aa3c 100644 --- a/package.json +++ b/package.json @@ -156,7 +156,7 @@ "vinyl": "^2.0.0", "vinyl-fs": "^3.0.0", "vsce": "1.48.0", - "vscode-debugprotocol": "1.39.0-pre.0", + "vscode-debugprotocol": "1.39.0", "vscode-nls-dev": "^3.3.1", "webpack": "^4.16.5", "webpack-cli": "^3.3.8", diff --git a/yarn.lock b/yarn.lock index 9050b677d92..a820c6344ac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9638,10 +9638,10 @@ vsce@1.48.0: yauzl "^2.3.1" yazl "^2.2.2" -vscode-debugprotocol@1.39.0-pre.0: - version "1.39.0-pre.0" - resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.39.0-pre.0.tgz#67843631a3c53f2d5282f75ab5996e1408c3958c" - integrity sha512-VpoD8m0gOo2Ag5dEpNT9sAI6BBxIyCxEk2dhGIBegxnlOuiB1SVxMgo1tmsvNYcRCpf9eng27kZ6d6FGoPpIAg== +vscode-debugprotocol@1.39.0: + version "1.39.0" + resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.39.0.tgz#0c639178d0d5ea7de7903b6478b53d2bc0d77461" + integrity sha512-Wkvgtuz90vjtQBcvw9Z+BYa4dA6W+sHwHMpqvJVNmwWSuT3JZdl0XDhZNLqtMXkVF4okxtAe0MmbupPSt+gnAQ== vscode-minimist@^1.2.2: version "1.2.2" From dc43bc617b16b015d05d1a9bf6e02a2b8d4eabd6 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 26 Feb 2020 15:02:55 +0100 Subject: [PATCH 038/235] Fixes #91371: Do something (the local file) even when a cross file undo/redo cannt be applied --- src/vs/platform/undoRedo/common/undoRedoService.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/platform/undoRedo/common/undoRedoService.ts b/src/vs/platform/undoRedo/common/undoRedoService.ts index 1f5191e2a74..516dd459aee 100644 --- a/src/vs/platform/undoRedo/common/undoRedoService.ts +++ b/src/vs/platform/undoRedo/common/undoRedoService.ts @@ -260,7 +260,7 @@ export class UndoRedoService implements IUndoRedoService { this._splitPastWorkspaceElement(element, element.removedResources.set); const message = nls.localize('cannotWorkspaceUndo', "Could not undo '{0}' across all files. {1}", element.label, element.removedResources.createMessage()); this._notificationService.info(message); - return; + return this.undo(resource); } // this must be the last past element in all the impacted resources! @@ -281,7 +281,7 @@ export class UndoRedoService implements IUndoRedoService { const paths = cannotUndoDueToResources.map(r => r.scheme === Schemas.file ? r.fsPath : r.path); const message = nls.localize('cannotWorkspaceUndoDueToChanges', "Could not undo '{0}' across all files because changes were made to {1}", element.label, paths.join(', ')); this._notificationService.info(message); - return; + return this.undo(resource); } return this._dialogService.show( @@ -344,7 +344,7 @@ export class UndoRedoService implements IUndoRedoService { this._splitFutureWorkspaceElement(element, element.removedResources.set); const message = nls.localize('cannotWorkspaceRedo', "Could not redo '{0}' across all files. {1}", element.label, element.removedResources.createMessage()); this._notificationService.info(message); - return; + return this.redo(resource); } // this must be the last future element in all the impacted resources! @@ -365,7 +365,7 @@ export class UndoRedoService implements IUndoRedoService { const paths = cannotRedoDueToResources.map(r => r.scheme === Schemas.file ? r.fsPath : r.path); const message = nls.localize('cannotWorkspaceRedoDueToChanges', "Could not redo '{0}' across all files because changes were made to {1}", element.label, paths.join(', ')); this._notificationService.info(message); - return; + return this.redo(resource); } for (const editStack of affectedEditStacks) { From 0c2947fda5a354eb85f7a4c3bc4fe77d53aedd1c Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 26 Feb 2020 15:35:15 +0100 Subject: [PATCH 039/235] Fixes #91557: Move settings-related menu entries to the end of the Selection menu --- .../contrib/codeEditor/browser/toggleColumnSelection.ts | 4 ++-- .../contrib/codeEditor/browser/toggleMultiCursorModifier.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts index 4fcee43f63a..fac092022e2 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts @@ -82,11 +82,11 @@ const registry = Registry.as(ActionExtensions.Workbenc registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleColumnSelectionAction, ToggleColumnSelectionAction.ID, ToggleColumnSelectionAction.LABEL), 'View: Toggle Column Selection Mode', nls.localize('view', "View")); MenuRegistry.appendMenuItem(MenuId.MenubarSelectionMenu, { - group: '3_multi', + group: '4_config', command: { id: ToggleColumnSelectionAction.ID, title: nls.localize({ key: 'miColumnSelection', comment: ['&& denotes a mnemonic'] }, "Column &&Selection Mode"), toggled: ContextKeyExpr.equals('config.editor.columnSelection', true) }, - order: 1.5 + order: 2 }); diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts index 05df06aa388..bc210c5a355 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts @@ -70,7 +70,7 @@ Registry.as(WorkbenchExtensions.Workbench).regi const registry = Registry.as(Extensions.WorkbenchActions); registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleMultiCursorModifierAction, ToggleMultiCursorModifierAction.ID, ToggleMultiCursorModifierAction.LABEL), 'Toggle Multi-Cursor Modifier'); MenuRegistry.appendMenuItem(MenuId.MenubarSelectionMenu, { - group: '3_multi', + group: '4_config', command: { id: ToggleMultiCursorModifierAction.ID, title: nls.localize('miMultiCursorAlt', "Switch to Alt+Click for Multi-Cursor") @@ -79,7 +79,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSelectionMenu, { order: 1 }); MenuRegistry.appendMenuItem(MenuId.MenubarSelectionMenu, { - group: '3_multi', + group: '4_config', command: { id: ToggleMultiCursorModifierAction.ID, title: ( From 622ddc0d6794450de81bdd4fd020dd219be1b926 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 26 Feb 2020 06:40:46 -0800 Subject: [PATCH 040/235] Fix backwards layout in terminal Fixes #91580 Fixes #91135 Fixes #91119 --- src/vs/workbench/contrib/terminal/browser/terminalView.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index c0d8a8bc8f9..12bc4fab7ff 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -114,7 +114,7 @@ export class TerminalViewPane extends ViewPane { })); // Force another layout (first is setContainers) since config has changed - this.layoutBody(this._terminalContainer.offsetWidth, this._terminalContainer.offsetHeight); + this.layoutBody(this._terminalContainer.offsetHeight, this._terminalContainer.offsetWidth); } protected layoutBody(height: number, width: number): void { @@ -321,7 +321,7 @@ export class TerminalViewPane extends ViewPane { } // TODO: Can we support ligatures? // dom.toggleClass(this._parentDomElement, 'enable-ligatures', this._terminalService.configHelper.config.fontLigatures); - this.layoutBody(this._parentDomElement.offsetWidth, this._parentDomElement.offsetHeight); + this.layoutBody(this._parentDomElement.offsetHeight, this._parentDomElement.offsetWidth); } } From fed69adea3fccae29fb04f6a0144da4acad9f8f0 Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 26 Feb 2020 15:48:37 +0100 Subject: [PATCH 041/235] debug session: use queue to make sure output messages get processed in correct order fixes #91416 --- .../contrib/debug/browser/debugSession.ts | 100 +++++++++--------- 1 file changed, 48 insertions(+), 52 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugSession.ts b/src/vs/workbench/contrib/debug/browser/debugSession.ts index 3c9ba78f0d6..214d3763448 100644 --- a/src/vs/workbench/contrib/debug/browser/debugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/debugSession.ts @@ -19,7 +19,7 @@ import { RawDebugSession } from 'vs/workbench/contrib/debug/browser/rawDebugSess import { IProductService } from 'vs/platform/product/common/productService'; import { IWorkspaceFolder, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { RunOnceScheduler } from 'vs/base/common/async'; +import { RunOnceScheduler, Queue } from 'vs/base/common/async'; import { generateUuid } from 'vs/base/common/uuid'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; @@ -807,62 +807,58 @@ export class DebugSession implements IDebugSession { this._onDidChangeState.fire(); })); - let outpuPromises: Promise[] = []; + const outputQueue = new Queue(); this.rawListeners.push(this.raw.onDidOutput(async event => { - if (!event.body || !this.raw) { - return; - } - - const outputSeverity = event.body.category === 'stderr' ? severity.Error : event.body.category === 'console' ? severity.Warning : severity.Info; - if (event.body.category === 'telemetry') { - // only log telemetry events from debug adapter if the debug extension provided the telemetry key - // and the user opted in telemetry - if (this.raw.customTelemetryService && this.telemetryService.isOptedIn) { - // __GDPR__TODO__ We're sending events in the name of the debug extension and we can not ensure that those are declared correctly. - this.raw.customTelemetryService.publicLog(event.body.output, event.body.data); - } - - return; - } - - // Make sure to append output in the correct order by properly waiting on preivous promises #33822 - const waitFor = outpuPromises.slice(); - const source = event.body.source && event.body.line ? { - lineNumber: event.body.line, - column: event.body.column ? event.body.column : 1, - source: this.getSource(event.body.source) - } : undefined; - - if (event.body.group === 'start' || event.body.group === 'startCollapsed') { - const expanded = event.body.group === 'start'; - this.repl.startGroup(event.body.output || '', expanded, source); - return; - } - if (event.body.group === 'end') { - this.repl.endGroup(); - if (!event.body.output) { - // Only return if the end event does not have additional output in it + outputQueue.queue(async () => { + if (!event.body || !this.raw) { return; } - } - if (event.body.variablesReference) { - const container = new ExpressionContainer(this, undefined, event.body.variablesReference, generateUuid()); - outpuPromises.push(container.getChildren().then(async children => { - await Promise.all(waitFor); - children.forEach(child => { - // Since we can not display multiple trees in a row, we are displaying these variables one after the other (ignoring their names) - (child).name = null; - this.appendToRepl(child, outputSeverity, source); + const outputSeverity = event.body.category === 'stderr' ? severity.Error : event.body.category === 'console' ? severity.Warning : severity.Info; + if (event.body.category === 'telemetry') { + // only log telemetry events from debug adapter if the debug extension provided the telemetry key + // and the user opted in telemetry + if (this.raw.customTelemetryService && this.telemetryService.isOptedIn) { + // __GDPR__TODO__ We're sending events in the name of the debug extension and we can not ensure that those are declared correctly. + this.raw.customTelemetryService.publicLog(event.body.output, event.body.data); + } + + return; + } + + // Make sure to append output in the correct order by properly waiting on preivous promises #33822 + const source = event.body.source && event.body.line ? { + lineNumber: event.body.line, + column: event.body.column ? event.body.column : 1, + source: this.getSource(event.body.source) + } : undefined; + + if (event.body.group === 'start' || event.body.group === 'startCollapsed') { + const expanded = event.body.group === 'start'; + this.repl.startGroup(event.body.output || '', expanded, source); + return; + } + if (event.body.group === 'end') { + this.repl.endGroup(); + if (!event.body.output) { + // Only return if the end event does not have additional output in it + return; + } + } + + if (event.body.variablesReference) { + const container = new ExpressionContainer(this, undefined, event.body.variablesReference, generateUuid()); + await container.getChildren().then(children => { + children.forEach(child => { + // Since we can not display multiple trees in a row, we are displaying these variables one after the other (ignoring their names) + (child).name = null; + this.appendToRepl(child, outputSeverity, source); + }); }); - })); - } else if (typeof event.body.output === 'string') { - await Promise.all(waitFor); - this.appendToRepl(event.body.output, outputSeverity, source); - } - - await Promise.all(outpuPromises); - outpuPromises = []; + } else if (typeof event.body.output === 'string') { + this.appendToRepl(event.body.output, outputSeverity, source); + } + }); })); this.rawListeners.push(this.raw.onDidBreakpoint(event => { From 1c270b9a692212d7ae7e3f8425226686ecf5f4b3 Mon Sep 17 00:00:00 2001 From: isidor Date: Wed, 26 Feb 2020 16:08:12 +0100 Subject: [PATCH 042/235] fixes #91322 --- .../contrib/debug/browser/debugConfigurationManager.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts b/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts index 29dcf72e752..1a4ec6cf4d7 100644 --- a/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts +++ b/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts @@ -519,18 +519,17 @@ abstract class AbstractLaunch { if (!config || (!Array.isArray(config.configurations) && !Array.isArray(config.compounds))) { return []; } else { - const names: string[] = []; + const configurations: (IConfig | ICompound)[] = []; if (config.configurations) { - names.push(...config.configurations.filter(cfg => cfg && typeof cfg.name === 'string').map(cfg => cfg.name)); + configurations.push(...config.configurations.filter(cfg => cfg && typeof cfg.name === 'string')); } if (includeCompounds && config.compounds) { if (config.compounds) { - names.push(...config.compounds.filter(compound => typeof compound.name === 'string' && compound.configurations && compound.configurations.length) - .map(compound => compound.name)); + configurations.push(...config.compounds.filter(compound => typeof compound.name === 'string' && compound.configurations && compound.configurations.length)); } } - return names; + return getVisibleAndSorted(configurations).map(c => c.name); } } From 872e4fb7014a56700b0671d6c79d4981e8fa995c Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 26 Feb 2020 14:06:57 +0100 Subject: [PATCH 043/235] Fix #91502 --- src/vs/platform/userDataSync/common/extensionsSync.ts | 2 +- src/vs/platform/userDataSync/common/globalStateSync.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/userDataSync/common/extensionsSync.ts b/src/vs/platform/userDataSync/common/extensionsSync.ts index b932d1ecd10..ccdf3c48517 100644 --- a/src/vs/platform/userDataSync/common/extensionsSync.ts +++ b/src/vs/platform/userDataSync/common/extensionsSync.ts @@ -194,7 +194,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse if (added.length || removed.length || updated.length) { // back up all disabled or market place extensions const backUpExtensions = localExtensions.filter(e => e.disabled || !!e.identifier.uuid); - await this.backupLocal(VSBuffer.fromString(JSON.stringify(backUpExtensions))); + await this.backupLocal(VSBuffer.fromString(JSON.stringify(backUpExtensions, null, '\t'))); skippedExtensions = await this.updateLocalExtensions(added, removed, updated, skippedExtensions); } diff --git a/src/vs/platform/userDataSync/common/globalStateSync.ts b/src/vs/platform/userDataSync/common/globalStateSync.ts index 9e6b1d16a43..8e00f07a9ae 100644 --- a/src/vs/platform/userDataSync/common/globalStateSync.ts +++ b/src/vs/platform/userDataSync/common/globalStateSync.ts @@ -165,7 +165,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs if (local) { // update local this.logService.trace('UI State: Updating local ui state...'); - await this.backupLocal(VSBuffer.fromString(JSON.stringify(localUserData))); + await this.backupLocal(VSBuffer.fromString(JSON.stringify(localUserData, null, '\t'))); await this.writeLocalGlobalState(local); this.logService.info('UI State: Updated local ui state'); } From d6f49e3b6a8dd3868ebc383b70f2093c94e6e89c Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 26 Feb 2020 14:32:00 +0100 Subject: [PATCH 044/235] Fix #91487 --- src/vs/platform/userDataSync/common/abstractSynchronizer.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts index a82acd2b357..7fdd78f0a10 100644 --- a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts +++ b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts @@ -202,7 +202,7 @@ export abstract class AbstractSynchroniser extends Disposable { } protected async backupLocal(content: VSBuffer): Promise { - const resource = joinPath(this.syncFolder, toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')); + const resource = joinPath(this.syncFolder, `${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}.json`); try { await this.fileService.writeFile(resource, content); } catch (e) { @@ -215,7 +215,8 @@ export abstract class AbstractSynchroniser extends Disposable { try { const stat = await this.fileService.resolve(this.syncFolder); if (stat.children) { - const all = stat.children.filter(stat => stat.isFile && /^\d{8}T\d{6}$/.test(stat.name)).sort(); + const all = stat.children.filter(stat => stat.isFile && /^\d{8}T\d{6}(\.json)?$/.test(stat.name)).sort(); + console.log(all.map(a => a.name)); const backUpMaxAge = 1000 * 60 * 60 * 24 * (this.configurationService.getValue('sync.localBackupDuration') || 30 /* Default 30 days */); let toDelete = all.filter(stat => { const ctime = stat.ctime || new Date( From 608ccd09ba374949f72414e19df0ba59e9871777 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 26 Feb 2020 16:12:41 +0100 Subject: [PATCH 045/235] Fix #91409 --- src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 91cb9aa468c..3a24fd01e20 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -99,7 +99,7 @@ const resolveKeybindingsConflictsCommand = { id: 'workbench.userData.actions.res const configureSyncCommand = { id: 'workbench.userData.actions.configureSync', title: localize('configure sync', "Sync: Configure") }; const showSyncActivityCommand = { id: 'workbench.userData.actions.showSyncActivity', title(userDataSyncService: IUserDataSyncService): string { - return getActivityTitle(localize('show sync log', "Sync: Show Activity"), userDataSyncService); + return getActivityTitle(localize('show sync log', "Sync: Show Log"), userDataSyncService); } }; const showSyncSettingsCommand = { id: 'workbench.userData.actions.syncSettings', title: localize('sync settings', "Sync: Settings"), }; From 265487690ab62171e8b28acc4ff445eff0a0a85f Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 26 Feb 2020 16:15:08 +0100 Subject: [PATCH 046/235] use CodeAction#title as bulk edit label option, #91369 --- src/vs/editor/contrib/codeAction/codeActionCommands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/codeAction/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/codeActionCommands.ts index 185ebd86867..13b92c1289d 100644 --- a/src/vs/editor/contrib/codeAction/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/codeActionCommands.ts @@ -164,7 +164,7 @@ export async function applyCodeAction( }); if (action.edit) { - await bulkEditService.apply(action.edit, { editor }); + await bulkEditService.apply(action.edit, { editor, label: action.title }); } if (action.command) { From e59cb58ccce6393ae01f1ee6302efb2bde5ff988 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 26 Feb 2020 16:18:43 +0100 Subject: [PATCH 047/235] fix #91536 --- src/vs/editor/contrib/links/getLinks.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/links/getLinks.ts b/src/vs/editor/contrib/links/getLinks.ts index a85e7f8c942..0ee40d5166e 100644 --- a/src/vs/editor/contrib/links/getLinks.ts +++ b/src/vs/editor/contrib/links/getLinks.ts @@ -77,8 +77,8 @@ export class LinksList extends Disposable { const newLinks = list.links.map(link => new Link(link, provider)); links = LinksList._union(links, newLinks); // register disposables - if (isDisposable(provider)) { - this._register(provider); + if (isDisposable(list)) { + this._register(list); } } this.links = links; From 65976ac711f25fd3c365c2d083a638825c37c9a3 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 26 Feb 2020 16:29:57 +0100 Subject: [PATCH 048/235] Revert "docs for #91532" This reverts commit ebcd432491259c91013bb0ff0284610f7f84504d. --- test/integration/browser/README.md | 1 - test/smoke/README.md | 1 - 2 files changed, 2 deletions(-) diff --git a/test/integration/browser/README.md b/test/integration/browser/README.md index 8b36a3c172c..10a55f7de17 100644 --- a/test/integration/browser/README.md +++ b/test/integration/browser/README.md @@ -14,7 +14,6 @@ All integration tests run in an Electron instance. You can specify to run the te ## Run (inside browser) - yarn gulp mixin-server resources/server/test/test-web-integration.[sh|bat] --browser [chromium|webkit] [--debug] All integration tests run in a browser instance as specified by the command line arguments. diff --git a/test/smoke/README.md b/test/smoke/README.md index 8836886be6b..8b41d05ed08 100644 --- a/test/smoke/README.md +++ b/test/smoke/README.md @@ -13,7 +13,6 @@ yarn --cwd test/automation yarn smoketest # Dev (Web) -yarn gulp mixin-server yarn smoketest --web --browser [chromium|firefox|webkit] # Build (Electron) From b59e3a6f42541d1df2c855c1a23d5a7148ae047f Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Wed, 26 Feb 2020 16:57:46 +0100 Subject: [PATCH 049/235] range returned from extension API is off by one; fix #91406 --- src/vs/workbench/contrib/debug/browser/debugHover.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/debug/browser/debugHover.ts b/src/vs/workbench/contrib/debug/browser/debugHover.ts index 5de2c78eea2..0a9b8964e1a 100644 --- a/src/vs/workbench/contrib/debug/browser/debugHover.ts +++ b/src/vs/workbench/contrib/debug/browser/debugHover.ts @@ -209,7 +209,7 @@ export class DebugHoverWidget implements IContentWidget { if (!matchingExpression) { const lineContent = model.getLineContent(pos.lineNumber); - matchingExpression = lineContent.substring(rng.startColumn - 1, rng.endColumn); + matchingExpression = lineContent.substring(rng.startColumn - 1, rng.endColumn - 1); } } From 6a883e03cca4f5688b4dc88383793608e1ada857 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 26 Feb 2020 17:11:29 +0100 Subject: [PATCH 050/235] Fixes #91388: Add a cancel option --- src/vs/platform/undoRedo/common/undoRedoService.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/vs/platform/undoRedo/common/undoRedoService.ts b/src/vs/platform/undoRedo/common/undoRedoService.ts index 516dd459aee..8bcaf9d7d16 100644 --- a/src/vs/platform/undoRedo/common/undoRedoService.ts +++ b/src/vs/platform/undoRedo/common/undoRedoService.ts @@ -289,10 +289,17 @@ export class UndoRedoService implements IUndoRedoService { nls.localize('confirmWorkspace', "Would you like to undo '{0}' across all files?", element.label), [ nls.localize('ok', "Yes, change {0} files.", affectedEditStacks.length), - nls.localize('nok', "No, change only this file.") - ] + nls.localize('nok', "No, change only this file."), + nls.localize('cancel', "Cancel"), + ], + { + cancelId: 2 + } ).then((result) => { - if (result.choice === 0) { + if (result.choice === 2) { + // cancel + return; + } else if (result.choice === 0) { for (const editStack of affectedEditStacks) { editStack.past.pop(); editStack.future.push(element); From f18717988122478a5c40ad8b6fc35834fe7643d9 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 26 Feb 2020 16:58:20 +0100 Subject: [PATCH 051/235] Fix #91575 --- .../userDataSync/browser/userDataSync.ts | 44 ++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 3a24fd01e20..15e1daa647c 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -88,12 +88,12 @@ const getActivityTitle = (label: string, userDataSyncService: IUserDataSyncServi } return label; }; -const getIdentityTitle = (label: string, account?: AuthenticationSession): string => { - return account ? `${label} (${account.accountName})` : label; +const getIdentityTitle = (label: string, authenticationProviderId: string, account: AuthenticationSession | undefined, authenticationService: IAuthenticationService): string => { + return account ? `${label} (${authenticationService.getDisplayName(authenticationProviderId)}:${account.accountName})` : label; }; const turnOnSyncCommand = { id: 'workbench.userData.actions.syncStart', title: localize('turn on sync with category', "Sync: Turn on Sync") }; const signInCommand = { id: 'workbench.userData.actions.signin', title: localize('sign in', "Sync: Sign in to sync") }; -const stopSyncCommand = { id: 'workbench.userData.actions.stopSync', title(account?: AuthenticationSession) { return getIdentityTitle(localize('stop sync', "Sync: Turn off Sync"), account); } }; +const stopSyncCommand = { id: 'workbench.userData.actions.stopSync', title(authenticationProviderId: string, account: AuthenticationSession | undefined, authenticationService: IAuthenticationService) { return getIdentityTitle(localize('stop sync', "Sync: Turn off Sync"), authenticationProviderId, account, authenticationService); } }; const resolveSettingsConflictsCommand = { id: 'workbench.userData.actions.resolveSettingsConflicts', title: localize('showConflicts', "Sync: Show Settings Conflicts") }; const resolveKeybindingsConflictsCommand = { id: 'workbench.userData.actions.resolveKeybindingsConflicts', title: localize('showKeybindingsConflicts', "Sync: Show Keybindings Conflicts") }; const configureSyncCommand = { id: 'workbench.userData.actions.configureSync', title: localize('configure sync', "Sync: Configure") }; @@ -509,7 +509,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo const disposables: DisposableStore = new DisposableStore(); const quickPick = this.quickInputService.createQuickPick(); disposables.add(quickPick); - quickPick.title = localize('turn on sync', "Turn on Sync"); + quickPick.title = localize('turn on title', "Sync: Turn On"); quickPick.ok = false; quickPick.customButton = true; if (this.authenticationState.get() === AuthStatus.SignedIn) { @@ -538,6 +538,38 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } private async doTurnOn(): Promise { + if (this.authenticationState.get() === AuthStatus.SignedIn) { + await new Promise((c, e) => { + const disposables: DisposableStore = new DisposableStore(); + const displayName = this.authenticationService.getDisplayName(this.userDataSyncStore!.authenticationProviderId); + const quickPick = this.quickInputService.createQuickPick<{ id: string, label: string, description?: string }>(); + const chooseAnotherItemId = 'chooseAnother'; + disposables.add(quickPick); + quickPick.title = localize('pick account', "Sync: Choose Account"); + quickPick.ok = false; + quickPick.placeholder = localize('choose account placeholder', "Choose account to sync"); + quickPick.ignoreFocusOut = true; + quickPick.items = [{ + id: 'existing', + label: localize('existing', "Use {0}:{1}", displayName, this.activeAccount!.accountName) + }, { + id: chooseAnotherItemId, + label: localize('choose another', "Choose another account") + }]; + disposables.add(quickPick.onDidAccept(async () => { + if (quickPick.selectedItems.length) { + if (quickPick.selectedItems[0].id === chooseAnotherItemId) { + await this.authenticationService.logout(this.userDataSyncStore!.authenticationProviderId, this.activeAccount!.id); + await this.setActiveAccount(undefined); + } + quickPick.hide(); + c(); + } + })); + disposables.add(quickPick.onDidHide(() => disposables.dispose())); + quickPick.show(); + }); + } if (this.authenticationState.get() === AuthStatus.SignedOut) { await this.signIn(); } @@ -893,7 +925,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo items.push({ id: showSyncSettingsCommand.id, label: showSyncSettingsCommand.title }); items.push({ id: showSyncActivityCommand.id, label: showSyncActivityCommand.title(that.userDataSyncService) }); items.push({ type: 'separator' }); - items.push({ id: stopSyncCommand.id, label: stopSyncCommand.title(that.activeAccount), }); + items.push({ id: stopSyncCommand.id, label: stopSyncCommand.title(that.userDataSyncStore!.authenticationProviderId, that.activeAccount, that.authenticationService) }); quickPick.items = items; const disposables = new DisposableStore(); disposables.add(quickPick.onDidAccept(() => { @@ -918,7 +950,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo constructor() { super({ id: stopSyncCommand.id, - title: stopSyncCommand.title(that.activeAccount), + title: stopSyncCommand.title(that.userDataSyncStore!.authenticationProviderId, that.activeAccount, that.authenticationService), menu: { id: MenuId.CommandPalette, when: ContextKeyExpr.and(CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), CONTEXT_SYNC_ENABLEMENT), From 15bbdbb2567233662f2941c26c1cb33abb348d18 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 26 Feb 2020 17:16:21 +0100 Subject: [PATCH 052/235] fix #91402 --- src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 15e1daa647c..2468a00f1a6 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -493,7 +493,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo localize('sync preview message', "Synchronizing your preferences is a preview feature, please read the documentation before turning it on."), [ localize('open doc', "Open Documentation"), - localize('confirm', "Continue"), + localize('turn on sync', "Turn on Sync"), localize('cancel', "Cancel"), ], { From f97a8068f81fbc4d1fc06d829c1ef98ebb53810c Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Wed, 26 Feb 2020 08:20:20 -0800 Subject: [PATCH 053/235] Use thenable instead of promise, fixes #91549 --- src/vs/editor/common/modes.ts | 2 +- src/vs/vscode.proposed.d.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index c348245a8ec..627cb4e950a 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -1373,7 +1373,7 @@ export interface RenameProvider { */ export interface AuthenticationSession { id: string; - accessToken(): Promise; + accessToken(): Thenable; accountName: string; } diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 50c03acaa3f..b603632b092 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -20,7 +20,7 @@ declare module 'vscode' { export interface AuthenticationSession { id: string; - accessToken(): Promise; + accessToken(): Thenable; accountName: string; scopes: string[] } @@ -58,13 +58,13 @@ declare module 'vscode' { /** * Returns an array of current sessions. */ - getSessions(): Promise>; + getSessions(): Thenable>; /** * Prompts a user to login. */ - login(scopes: string[]): Promise; - logout(sessionId: string): Promise; + login(scopes: string[]): Thenable; + logout(sessionId: string): Thenable; } export namespace authentication { From a98cd716582224d8c16c6ecbbc74fe59fe73f437 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 26 Feb 2020 17:20:40 +0100 Subject: [PATCH 054/235] Fix #91391 --- src/vs/platform/userDataSync/common/abstractSynchronizer.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts index 7fdd78f0a10..92590672d67 100644 --- a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts +++ b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts @@ -213,6 +213,9 @@ export abstract class AbstractSynchroniser extends Disposable { private async cleanUpBackup(): Promise { try { + if (!(await this.fileService.exists(this.syncFolder))) { + return; + } const stat = await this.fileService.resolve(this.syncFolder); if (stat.children) { const all = stat.children.filter(stat => stat.isFile && /^\d{8}T\d{6}(\.json)?$/.test(stat.name)).sort(); From 1d58311f29d9fdfdeb91fc3b1a354995768e2e67 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Wed, 26 Feb 2020 17:33:21 +0100 Subject: [PATCH 055/235] Add the "stop detecting" task quick pick changes back in Revert "Revert commits for task quick pick changes. This fixes #90474" This reverts commit d33663fac9508e12a0fd85968b902dd5d07f488d. --- .../parts/quickinput/browser/quickInput.ts | 4 + .../parts/quickinput/common/quickInput.ts | 2 + .../tasks/browser/abstractTaskService.ts | 105 +++++++++++++----- .../tasks/browser/providerProgressManager.ts | 61 ++++++++++ 4 files changed, 147 insertions(+), 25 deletions(-) create mode 100644 src/vs/workbench/contrib/tasks/browser/providerProgressManager.ts diff --git a/src/vs/base/parts/quickinput/browser/quickInput.ts b/src/vs/base/parts/quickinput/browser/quickInput.ts index afb94d70395..059eb29406d 100644 --- a/src/vs/base/parts/quickinput/browser/quickInput.ts +++ b/src/vs/base/parts/quickinput/browser/quickInput.ts @@ -575,6 +575,10 @@ class QuickPick extends QuickInput implements IQuickPi return this.visible ? this.ui.inputBox.hasFocus() : false; } + public focusOnInput() { + this.ui.inputBox.setFocus(); + } + onDidChangeSelection = this.onDidChangeSelectionEmitter.event; onDidTriggerItemButton = this.onDidTriggerItemButtonEmitter.event; diff --git a/src/vs/base/parts/quickinput/common/quickInput.ts b/src/vs/base/parts/quickinput/common/quickInput.ts index 531551f95b0..36905c59c53 100644 --- a/src/vs/base/parts/quickinput/common/quickInput.ts +++ b/src/vs/base/parts/quickinput/common/quickInput.ts @@ -209,6 +209,8 @@ export interface IQuickPick extends IQuickInput { validationMessage: string | undefined; inputHasFocus(): boolean; + + focusOnInput(): void; } export interface IInputBox extends IQuickInput { diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 728fff5fac2..e1461676966 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -63,7 +63,7 @@ import { getTemplates as getTaskTemplates } from 'vs/workbench/contrib/tasks/com import * as TaskConfig from '../common/taskConfiguration'; import { TerminalTaskSystem } from './terminalTaskSystem'; -import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput'; +import { IQuickInputService, IQuickPickItem, QuickPickInput, IQuickPick } from 'vs/platform/quickinput/common/quickInput'; import { TaskDefinitionRegistry } from 'vs/workbench/contrib/tasks/common/taskDefinitionRegistry'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -80,6 +80,7 @@ import { IPreferencesService } from 'vs/workbench/services/preferences/common/pr import { find } from 'vs/base/common/arrays'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { IViewsService } from 'vs/workbench/common/views'; +import { ProviderProgressMananger } from 'vs/workbench/contrib/tasks/browser/providerProgressManager'; const QUICKOPEN_HISTORY_LIMIT_CONFIG = 'task.quickOpen.history'; const QUICKOPEN_DETAIL_CONFIG = 'task.quickOpen.detail'; @@ -218,6 +219,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer private _providers: Map; private _providerTypes: Map; protected _taskSystemInfos: Map; + private _providerProgressManager: ProviderProgressMananger | undefined; protected _workspaceTasksPromise?: Promise>; protected _areJsonTasksSupportedPromise: Promise = Promise.resolve(false); @@ -1345,11 +1347,24 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer protected abstract getTaskSystem(): ITaskSystem; - private async provideTasksWithWarning(provider: ITaskProvider, type: string, validTypes: IStringDictionary): Promise { + private async provideTasksWithWarning(provider: ITaskProvider, type: string, validTypes: IStringDictionary): Promise { return new Promise(async (resolve, reject) => { - provider.provideTasks(validTypes).then((value) => { + let isDone = false; + let disposable: IDisposable | undefined; + const providePromise = provider.provideTasks(validTypes); + this._providerProgressManager?.addProvider(type, providePromise); + disposable = this._providerProgressManager?.canceled.token.onCancellationRequested(() => { + if (!isDone) { + resolve(); + } + }); + providePromise.then((value) => { + isDone = true; + disposable?.dispose(); resolve(value); }, (e) => { + isDone = true; + disposable?.dispose(); reject(e); }); }); @@ -1361,10 +1376,11 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer TaskDefinitionRegistry.all().forEach(definition => validTypes[definition.taskType] = true); validTypes['shell'] = true; validTypes['process'] = true; + this._providerProgressManager = new ProviderProgressMananger(); return new Promise(resolve => { let result: TaskSet[] = []; let counter: number = 0; - let done = (value: TaskSet) => { + let done = (value: TaskSet | undefined) => { if (value) { result.push(value); } @@ -2060,30 +2076,69 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } return entries; }); - return this.quickInputService.pick(pickEntries, { - placeHolder, - matchOnDescription: true, - onDidTriggerItemButton: context => { - let task = context.item.task; - this.quickInputService.cancel(); - if (ContributedTask.is(task)) { - this.customize(task, undefined, true); - } else if (CustomTask.is(task)) { - this.openConfig(task); + + const picker: IQuickPick = this.quickInputService.createQuickPick(); + picker.placeholder = placeHolder; + picker.matchOnDescription = true; + picker.ignoreFocusOut = true; + + picker.onDidTriggerItemButton(context => { + let task = context.item.task; + this.quickInputService.cancel(); + if (ContributedTask.is(task)) { + this.customize(task, undefined, true); + } else if (CustomTask.is(task)) { + this.openConfig(task); + } + }); + picker.busy = true; + const progressManager = this._providerProgressManager; + const progressTimeout = setTimeout(() => { + if (progressManager) { + progressManager.showProgress = (stillProviding, total) => { + let message = undefined; + if (stillProviding.length > 0) { + message = nls.localize('pickProgressManager.description', 'Detecting tasks ({0} of {1}): {2} in progress', total - stillProviding.length, total, stillProviding.join(', ')); + } + picker.description = message; + }; + progressManager.addOnDoneListener(() => { + picker.focusOnInput(); + picker.customButton = false; + }); + if (!progressManager.isDone) { + picker.customLabel = nls.localize('taskQuickPick.cancel', "Stop detecting"); + picker.onDidCustom(() => { + this._providerProgressManager?.cancel(); + }); + picker.customButton = true; } } - }, cancellationToken).then(async (selection) => { - if (cancellationToken.isCancellationRequested) { - // canceled when there's only one task - const task = (await pickEntries)[0]; - if ((task).task) { - selection = task; + }, 1000); + pickEntries.then(entries => { + clearTimeout(progressTimeout); + progressManager?.dispose(); + picker.busy = false; + picker.items = entries; + }); + picker.show(); + + return new Promise(resolve => { + this._register(picker.onDidAccept(async () => { + let selection = picker.selectedItems ? picker.selectedItems[0] : undefined; + if (cancellationToken.isCancellationRequested) { + // canceled when there's only one task + const task = (await pickEntries)[0]; + if ((task).task) { + selection = task; + } } - } - if (!selection) { - return; - } - return selection; + picker.dispose(); + if (!selection) { + resolve(); + } + resolve(selection); + })); }); } diff --git a/src/vs/workbench/contrib/tasks/browser/providerProgressManager.ts b/src/vs/workbench/contrib/tasks/browser/providerProgressManager.ts new file mode 100644 index 00000000000..7c48da7f73c --- /dev/null +++ b/src/vs/workbench/contrib/tasks/browser/providerProgressManager.ts @@ -0,0 +1,61 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { TaskSet } from 'vs/workbench/contrib/tasks/common/tasks'; +import { Emitter } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { CancellationTokenSource } from 'vs/base/common/cancellation'; + +export class ProviderProgressMananger extends Disposable { + private _onProviderComplete: Emitter = new Emitter(); + private _stillProviding: Set = new Set(); + private _totalProviders: number = 0; + private _onDone: Emitter = new Emitter(); + private _isDone: boolean = false; + private _showProgress: ((remaining: string[], total: number) => void) | undefined; + public canceled: CancellationTokenSource = new CancellationTokenSource(); + + constructor() { + super(); + this._register(this._onProviderComplete.event(taskType => { + this._stillProviding.delete(taskType); + if (this._stillProviding.size === 0) { + this._isDone = true; + this._onDone.fire(); + } + if (this._showProgress) { + this._showProgress(Array.from(this._stillProviding), this._totalProviders); + } + })); + } + + public addProvider(taskType: string, provider: Promise) { + this._totalProviders++; + this._stillProviding.add(taskType); + provider.then(() => this._onProviderComplete.fire(taskType)); + } + + public addOnDoneListener(onDoneListener: () => void) { + this._register(this._onDone.event(onDoneListener)); + } + + set showProgress(progressDisplayFunction: (remaining: string[], total: number) => void) { + this._showProgress = progressDisplayFunction; + this._showProgress(Array.from(this._stillProviding), this._totalProviders); + } + + get isDone(): boolean { + return this._isDone; + } + + public cancel() { + this._isDone = true; + if (this._showProgress) { + this._showProgress([], 0); + } + this._onDone.fire(); + this.canceled.cancel(); + } +} From bfc01bb9ea31d48133d6053de97dc7f8b2011b10 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Wed, 26 Feb 2020 17:36:02 +0100 Subject: [PATCH 056/235] Bandaid for task not running after detection is canceled Fixes #90474 --- .../tasks/browser/abstractTaskService.ts | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index e1461676966..27418989dde 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -562,6 +562,37 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer protected abstract versionAndEngineCompatible(filter?: TaskFilter): boolean; + private tasksAndGroupedTasks(filter?: TaskFilter): { tasks: Promise, grouped: Promise } { + if (!this.versionAndEngineCompatible(filter)) { + return { tasks: Promise.resolve([]), grouped: Promise.resolve(new TaskMap()) }; + } + const grouped = this.getGroupedTasks(filter ? filter.type : undefined); + const tasks = grouped.then((map) => { + if (!filter || !filter.type) { + return map.all(); + } + let result: Task[] = []; + map.forEach((tasks) => { + for (let task of tasks) { + if (ContributedTask.is(task) && task.defines.type === filter.type) { + result.push(task); + } else if (CustomTask.is(task)) { + if (task.type === filter.type) { + result.push(task); + } else { + let customizes = task.customizes(); + if (customizes && customizes.type === filter.type) { + result.push(task); + } + } + } + } + }); + return result; + }); + return { tasks, grouped }; + } + public tasks(filter?: TaskFilter): Promise { if (!this.versionAndEngineCompatible(filter)) { return Promise.resolve([]); @@ -705,11 +736,11 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }); } - public run(task: Task | undefined, options?: ProblemMatcherRunOptions, runSource: TaskRunSource = TaskRunSource.System): Promise { + public run(task: Task | undefined, options?: ProblemMatcherRunOptions, runSource: TaskRunSource = TaskRunSource.System, grouped?: Promise): Promise { if (!task) { throw new TaskError(Severity.Info, nls.localize('TaskServer.noTask', 'Task to execute is undefined'), TaskErrors.TaskNotFound); } - return this.getGroupedTasks().then((grouped) => { + return (grouped ?? this.getGroupedTasks()).then((grouped) => { let resolver = this.createResolver(grouped); if (options && options.attachProblemMatcher && this.shouldAttachProblemMatcher(task) && !InMemoryTask.is(task)) { return this.attachProblemMatcher(task).then((toExecute) => { @@ -2193,7 +2224,11 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer private doRunTaskCommand(tasks?: Task[]): void { this.showIgnoredFoldersMessage().then(() => { - this.showQuickPick(tasks ? tasks : this.tasks(), + let taskResult: { tasks: Promise, grouped: Promise } | undefined = undefined; + if (!tasks) { + taskResult = this.tasksAndGroupedTasks(); + } + this.showQuickPick(tasks ? tasks : taskResult!.tasks, nls.localize('TaskService.pickRunTask', 'Select the task to run'), { label: nls.localize('TaskService.noEntryToRun', 'No task to run found. Configure Tasks...'), @@ -2208,7 +2243,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer if (task === null) { this.runConfigureTasks(); } else { - this.run(task, { attachProblemMatcher: true }, TaskRunSource.User).then(undefined, reason => { + this.run(task, { attachProblemMatcher: true }, TaskRunSource.User, taskResult?.grouped).then(undefined, reason => { // eat the error, it has already been surfaced to the user and we don't care about it here }); } From 6605c1f1745e1678166679d1f18581339c4c857c Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 26 Feb 2020 17:54:10 +0100 Subject: [PATCH 057/235] #91575 updated account picker --- .../contrib/userDataSync/browser/userDataSync.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 2468a00f1a6..2c902f0708b 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -542,19 +542,20 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo await new Promise((c, e) => { const disposables: DisposableStore = new DisposableStore(); const displayName = this.authenticationService.getDisplayName(this.userDataSyncStore!.authenticationProviderId); - const quickPick = this.quickInputService.createQuickPick<{ id: string, label: string, description?: string }>(); + const quickPick = this.quickInputService.createQuickPick<{ id: string, label: string, description?: string, detail?: string }>(); const chooseAnotherItemId = 'chooseAnother'; disposables.add(quickPick); - quickPick.title = localize('pick account', "Sync: Choose Account"); + quickPick.title = localize('pick account', "{0}: Pick an account", displayName); quickPick.ok = false; - quickPick.placeholder = localize('choose account placeholder', "Choose account to sync"); + quickPick.placeholder = localize('choose account placeholder', "Pick an account for syncing"); quickPick.ignoreFocusOut = true; quickPick.items = [{ id: 'existing', - label: localize('existing', "Use {0}:{1}", displayName, this.activeAccount!.accountName) + label: localize('existing', "{0}", this.activeAccount!.accountName), + detail: localize('signed in', "Signed in"), }, { id: chooseAnotherItemId, - label: localize('choose another', "Choose another account") + label: localize('choose another', "Use another account") }]; disposables.add(quickPick.onDidAccept(async () => { if (quickPick.selectedItems.length) { From e3273a250b058522308b02030b38912bf0233e45 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 26 Feb 2020 18:03:10 +0100 Subject: [PATCH 058/235] :up: distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 46535c5aa3c..05b3a37a358 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.43.0", - "distro": "d9ed2bff7e779c71264b0c08311d08192924f473", + "distro": "efe6f8371664e7a0a280e47cb32d921d183b8aaa", "author": { "name": "Microsoft Corporation" }, From ab8b83b801e76d2270b08606ec7236d5222be49a Mon Sep 17 00:00:00 2001 From: rebornix Date: Wed, 26 Feb 2020 09:04:20 -0800 Subject: [PATCH 059/235] Update list view item height. --- src/vs/base/browser/ui/list/listView.ts | 53 +++++++++++++++++-- src/vs/base/browser/ui/list/listWidget.ts | 2 +- .../browser/ui/scrollbar/scrollableElement.ts | 4 ++ 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index 7b520501582..ade0ed5b030 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -21,6 +21,7 @@ import { equals, distinct } from 'vs/base/common/arrays'; import { DataTransfers, StaticDND, IDragAndDropData } from 'vs/base/browser/dnd'; import { disposableTimeout, Delayer } from 'vs/base/common/async'; import { isFirefox } from 'vs/base/browser/browser'; +import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; interface IItem { readonly id: string; @@ -198,6 +199,7 @@ export class ListView implements ISpliceable, IDisposable { get onDidScroll(): Event { return this.scrollableElement.onScroll; } get onWillScroll(): Event { return this.scrollableElement.onWillScroll; } + get containerDomNode(): HTMLElement { return this.rowsContainer; } constructor( container: HTMLElement, @@ -273,6 +275,28 @@ export class ListView implements ISpliceable, IDisposable { this.layout(); } + triggerScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent) { + this.scrollableElement.triggerScrollFromMouseWheelEvent(browserEvent); + } + + updateElementHeight(index: number, element: T, size: number): void { + const lastRenderRange = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight); + + let heightDiff = index < lastRenderRange.start ? size - this.items[index].size : 0; + this.rangeMap.splice(index, 1, [{ size: size }]); + + this.items[index].size = size; + + this.render(lastRenderRange, this.lastRenderTop + heightDiff, this.lastRenderHeight, undefined, undefined, true); + + if (this.supportDynamicHeights) { + this._rerender(this.lastRenderTop, this.lastRenderHeight); + } + + this.eventuallyUpdateScrollDimensions(); + return; + } + splice(start: number, deleteCount: number, elements: T[] = []): T[] { if (this.splicing) { throw new Error('Can\'t run recursive splices.'); @@ -516,14 +540,21 @@ export class ListView implements ISpliceable, IDisposable { // Render - private render(renderTop: number, renderHeight: number, renderLeft: number, scrollWidth: number): void { - const previousRenderRange = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight); + private render(previousRenderRange: IRange, renderTop: number, renderHeight: number, renderLeft: number | undefined, scrollWidth: number | undefined, updateItemsInDOM: boolean = false): void { const renderRange = this.getRenderRange(renderTop, renderHeight); const rangesToInsert = Range.relativeComplement(renderRange, previousRenderRange); const rangesToRemove = Range.relativeComplement(previousRenderRange, renderRange); const beforeElement = this.getNextToLastElement(rangesToInsert); + if (updateItemsInDOM) { + const rangesToUpdate = Range.intersect(previousRenderRange, renderRange); + + for (let i = rangesToUpdate.start; i < rangesToUpdate.end; i++) { + this.updateItemInDOM(this.items[i], i); + } + } + for (const range of rangesToInsert) { for (let i = range.start; i < range.end; i++) { this.insertItemInDOM(i, beforeElement); @@ -536,10 +567,13 @@ export class ListView implements ISpliceable, IDisposable { } } - this.rowsContainer.style.left = `-${renderLeft}px`; + if (renderLeft !== undefined) { + this.rowsContainer.style.left = `-${renderLeft}px`; + } + this.rowsContainer.style.top = `-${renderTop}px`; - if (this.horizontalScrolling) { + if (this.horizontalScrolling && scrollWidth !== undefined) { this.rowsContainer.style.width = `${Math.max(scrollWidth, this.renderWidth)}px`; } @@ -741,7 +775,8 @@ export class ListView implements ISpliceable, IDisposable { private onScroll(e: ScrollEvent): void { try { - this.render(e.scrollTop, e.height, e.scrollLeft, e.scrollWidth); + const previousRenderRange = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight); + this.render(previousRenderRange, e.scrollTop, e.height, e.scrollLeft, e.scrollWidth); if (this.supportDynamicHeights) { this._rerender(e.scrollTop, e.height); @@ -1097,6 +1132,14 @@ export class ListView implements ISpliceable, IDisposable { } const size = item.size; + + if (item.row && item.row.domNode) { + let newSize = item.row.domNode.offsetHeight; + item.size = newSize; + item.lastDynamicHeightWidth = this.renderWidth; + return newSize - size; + } + const row = this.cache.alloc(item.templateId); row.domNode!.style.height = ''; diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index aa3febf7c85..29263345a5e 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -1115,7 +1115,7 @@ export class List implements ISpliceable, IDisposable { private focus: Trait; private selection: Trait; private eventBufferer = new EventBufferer(); - private view: ListView; + protected view: ListView; private spliceable: ISpliceable; private styleController: IStyleController; private typeLabelController?: TypeLabelController; diff --git a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts index 4c34a8bafcd..309db05fe21 100644 --- a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +++ b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts @@ -303,6 +303,10 @@ export abstract class AbstractScrollableElement extends Widget { this._revealOnScroll = value; } + public triggerScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent) { + this._onMouseWheel(new StandardWheelEvent(browserEvent)); + } + // -------------------- mouse wheel scrolling -------------------- private _setListeningToMouseWheel(shouldListen: boolean): void { From 1f3d37d97ffefc64cadf9ac2efc9847f4f7f7052 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 26 Feb 2020 18:07:46 +0100 Subject: [PATCH 060/235] Fixes #91368: Improve wording for dialog --- src/vs/platform/undoRedo/common/undoRedoService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/undoRedo/common/undoRedoService.ts b/src/vs/platform/undoRedo/common/undoRedoService.ts index 8bcaf9d7d16..ccbb2c55482 100644 --- a/src/vs/platform/undoRedo/common/undoRedoService.ts +++ b/src/vs/platform/undoRedo/common/undoRedoService.ts @@ -288,8 +288,8 @@ export class UndoRedoService implements IUndoRedoService { Severity.Info, nls.localize('confirmWorkspace', "Would you like to undo '{0}' across all files?", element.label), [ - nls.localize('ok', "Yes, change {0} files.", affectedEditStacks.length), - nls.localize('nok', "No, change only this file."), + nls.localize('ok', "Undo in {0} files.", affectedEditStacks.length), + nls.localize('nok', "Undo this file."), nls.localize('cancel', "Cancel"), ], { From 29843ee1027ec53f47eb8e541d0d9508b3620275 Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Wed, 26 Feb 2020 09:11:01 -0800 Subject: [PATCH 061/235] Fix missed instance of Thenable in extHostAuthentication --- src/vs/workbench/api/common/extHostAuthentication.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/common/extHostAuthentication.ts b/src/vs/workbench/api/common/extHostAuthentication.ts index d9bcc811cbf..234de7348f3 100644 --- a/src/vs/workbench/api/common/extHostAuthentication.ts +++ b/src/vs/workbench/api/common/extHostAuthentication.ts @@ -60,7 +60,7 @@ export class AuthenticationProviderWrapper implements vscode.AuthenticationProvi return this._provider.login(scopes); } - logout(sessionId: string): Promise { + logout(sessionId: string): Thenable { return this._provider.logout(sessionId); } } From 14f9ef0f1a33c35c8396feede34775818924ce29 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 26 Feb 2020 18:11:30 +0100 Subject: [PATCH 062/235] Fixes microsoft/monaco-editor#1849: Correct documentation --- src/vs/editor/common/modes.ts | 2 +- src/vs/monaco.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 627cb4e950a..98af16d123d 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -494,7 +494,7 @@ export interface CompletionItem { preselect?: boolean; /** * A string or snippet that should be inserted in a document when selecting - * this completion. When `falsy` the [label](#CompletionItem.label) + * this completion. * is used. */ insertText: string; diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 65f7b8f4e4f..c90b75b3bc2 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -5447,7 +5447,7 @@ declare namespace monaco.languages { preselect?: boolean; /** * A string or snippet that should be inserted in a document when selecting - * this completion. When `falsy` the [label](#CompletionItem.label) + * this completion. * is used. */ insertText: string; From 5ffbdc7077e206d0ef5304b8573289a4cea27a7e Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Wed, 26 Feb 2020 09:27:36 -0800 Subject: [PATCH 063/235] Add notification on sign out, fixes #91481 --- extensions/vscode-account/package.json | 3 +++ extensions/vscode-account/src/extension.ts | 5 +++++ extensions/vscode-account/yarn.lock | 5 +++++ 3 files changed, 13 insertions(+) diff --git a/extensions/vscode-account/package.json b/extensions/vscode-account/package.json index c4df52ce732..cd579aef85a 100644 --- a/extensions/vscode-account/package.json +++ b/extensions/vscode-account/package.json @@ -39,5 +39,8 @@ "tslint": "^5.12.1", "@types/node": "^10.12.21", "@types/keytar": "^4.0.1" + }, + "dependencies": { + "vscode-nls": "^4.1.1" } } diff --git a/extensions/vscode-account/src/extension.ts b/extensions/vscode-account/src/extension.ts index 88f5f3133ed..fa94280fe3d 100644 --- a/extensions/vscode-account/src/extension.ts +++ b/extensions/vscode-account/src/extension.ts @@ -5,6 +5,9 @@ import * as vscode from 'vscode'; import { AzureActiveDirectoryService, onDidChangeSessions } from './AADHelper'; +import * as nls from 'vscode-nls'; + +const localize = nls.loadMessageBundle(); export const DEFAULT_SCOPES = 'https://management.core.windows.net/.default offline_access'; @@ -45,6 +48,7 @@ export async function activate(context: vscode.ExtensionContext) { if (sessions.length === 1) { await loginService.logout(loginService.sessions[0].id); onDidChangeSessions.fire(); + vscode.window.showInformationMessage(localize('signedOut', "Successfully signed out.")); return; } @@ -58,6 +62,7 @@ export async function activate(context: vscode.ExtensionContext) { if (selectedSession) { await loginService.logout(selectedSession.id); onDidChangeSessions.fire(); + vscode.window.showInformationMessage(localize('signedOut', "Successfully signed out.")); return; } })); diff --git a/extensions/vscode-account/yarn.lock b/extensions/vscode-account/yarn.lock index 3acdda242e9..4a86ea6a2a2 100644 --- a/extensions/vscode-account/yarn.lock +++ b/extensions/vscode-account/yarn.lock @@ -635,6 +635,11 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= +vscode-nls@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.1.tgz#f9916b64e4947b20322defb1e676a495861f133c" + integrity sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A== + which-pm-runs@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" From 3e4cb8f683720151e8224623dad918791308d984 Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Wed, 26 Feb 2020 09:30:25 -0800 Subject: [PATCH 064/235] Sign out -> Sign Out, fixes #91577 --- extensions/vscode-account/package.nls.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/vscode-account/package.nls.json b/extensions/vscode-account/package.nls.json index 8211a3f6e9c..c0bb4c4a6a0 100644 --- a/extensions/vscode-account/package.nls.json +++ b/extensions/vscode-account/package.nls.json @@ -1,6 +1,6 @@ { "displayName": "Microsoft Account", "description": "Microsoft authentication provider", - "signIn": "Sign in", - "signOut": "Sign out" + "signIn": "Sign In", + "signOut": "Sign Out" } From 02154d7ecfe6bc5788f518f0c92b122339240e18 Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Wed, 26 Feb 2020 09:47:28 -0800 Subject: [PATCH 065/235] fixes #91421 --- src/vs/workbench/browser/parts/compositeBar.ts | 8 +++++--- src/vs/workbench/common/views.ts | 1 + .../contrib/extensions/browser/extensions.contribution.ts | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index 5c19e2a5b99..f7f3e18a1b3 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -52,7 +52,7 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop { if (targetCompositeId) { if (currentLocation !== this.targetContainerLocation && this.targetContainerLocation !== ViewContainerLocation.Panel) { const destinationContainer = viewContainerRegistry.get(targetCompositeId); - if (destinationContainer) { + if (destinationContainer && !destinationContainer.rejectAddedViews) { this.viewDescriptorService.moveViewsToContainer(this.viewDescriptorService.getViewDescriptors(currentContainer)!.allViewDescriptors.filter(vd => vd.canMoveView), destinationContainer); this.openComposite(targetCompositeId, true); } @@ -73,7 +73,7 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop { if (viewDescriptor && viewDescriptor.canMoveView) { if (targetCompositeId) { const destinationContainer = viewContainerRegistry.get(targetCompositeId); - if (destinationContainer) { + if (destinationContainer && !destinationContainer.rejectAddedViews) { if (this.targetContainerLocation === ViewContainerLocation.Sidebar) { this.viewDescriptorService.moveViewsToContainer([viewDescriptor], destinationContainer); this.openComposite(targetCompositeId, true); @@ -134,6 +134,7 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop { if (this.targetContainerLocation === ViewContainerLocation.Sidebar) { const destinationContainer = viewContainerRegistry.get(targetCompositeId); return !!destinationContainer && + !destinationContainer.rejectAddedViews && this.viewDescriptorService.getViewDescriptors(currentContainer)!.allViewDescriptors.some(vd => vd.canMoveView); } // ... from sidebar to the panel @@ -155,7 +156,8 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop { } // ... into a destination - return true; + const destinationContainer = viewContainerRegistry.get(targetCompositeId); + return !!destinationContainer && !destinationContainer.rejectAddedViews; } return false; diff --git a/src/vs/workbench/common/views.ts b/src/vs/workbench/common/views.ts index 1e141807590..d1b30384874 100644 --- a/src/vs/workbench/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -53,6 +53,7 @@ export interface IViewContainerDescriptor { readonly extensionId?: ExtensionIdentifier; + readonly rejectAddedViews?: boolean; } export interface IViewContainersRegistry { diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index 8f0b1969062..cf17ac8d9c5 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -87,7 +87,8 @@ Registry.as(ViewContainerExtensions.ViewContainersRegis name: localize('extensions', "Extensions"), ctorDescriptor: new SyncDescriptor(ExtensionsViewPaneContainer), icon: 'codicon-extensions', - order: 4 + order: 4, + rejectAddedViews: true, }, ViewContainerLocation.Sidebar); From bba707d60c0f6ce8445fbf66677c324aea071a9a Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Wed, 26 Feb 2020 09:50:49 -0800 Subject: [PATCH 066/235] Use checkbox option on auth dialog, fixes #91542 --- .../api/browser/mainThreadAuthentication.ts | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadAuthentication.ts b/src/vs/workbench/api/browser/mainThreadAuthentication.ts index 311d89790db..22f91f6d2cc 100644 --- a/src/vs/workbench/api/browser/mainThreadAuthentication.ts +++ b/src/vs/workbench/api/browser/mainThreadAuthentication.ts @@ -75,48 +75,52 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu async $getSessionsPrompt(providerId: string, providerName: string, extensionId: string, extensionName: string): Promise { const alwaysAllow = this.storageService.get(`${extensionId}-${providerId}`, StorageScope.GLOBAL); if (alwaysAllow) { - return true; + return alwaysAllow === 'true'; } - const { choice } = await this.dialogService.show( + const { choice, checkboxChecked } = await this.dialogService.show( Severity.Info, nls.localize('confirmAuthenticationAccess', "The extension '{0}' is trying to access authentication information from {1}.", extensionName, providerName), - [nls.localize('cancel', "Cancel"), nls.localize('allow', "Allow"), nls.localize('alwaysAllow', "Always Allow"),], - { cancelId: 0 } + [nls.localize('cancel', "Cancel"), nls.localize('allow', "Allow")], + { + cancelId: 0, + checkbox: { + label: nls.localize('neverAgain', "Don't Show Again") + } + } ); - switch (choice) { - case 1/** Allow */: - return true; - case 2 /** Always Allow */: - this.storageService.store(`${extensionId}-${providerId}`, 'true', StorageScope.GLOBAL); - return true; - default: - return false; + const allow = choice === 1; + if (checkboxChecked) { + this.storageService.store(`${extensionId}-${providerId}`, allow ? 'true' : 'false', StorageScope.GLOBAL); } + + return allow; } async $loginPrompt(providerId: string, providerName: string, extensionId: string, extensionName: string): Promise { const alwaysAllow = this.storageService.get(`${extensionId}-${providerId}`, StorageScope.GLOBAL); if (alwaysAllow) { - return true; + return alwaysAllow === 'true'; } - const { choice } = await this.dialogService.show( + const { choice, checkboxChecked } = await this.dialogService.show( Severity.Info, nls.localize('confirmLogin', "The extension '{0}' wants to sign in using {1}.", extensionName, providerName), - [nls.localize('cancel', "Cancel"), nls.localize('continue', "Continue"), nls.localize('neverAgain', "Don't Show Again")], - { cancelId: 0 } + [nls.localize('cancel', "Cancel"), nls.localize('continue', "Continue")], + { + cancelId: 0, + checkbox: { + label: nls.localize('neverAgain', "Don't Show Again") + } + } ); - switch (choice) { - case 1/** Allow */: - return true; - case 2 /** Always Allow */: - this.storageService.store(`${extensionId}-${providerId}`, 'true', StorageScope.GLOBAL); - return true; - default: - return false; + const allow = choice === 1; + if (checkboxChecked) { + this.storageService.store(`${extensionId}-${providerId}`, allow ? 'true' : 'false', StorageScope.GLOBAL); } + + return allow; } } From 4c8c66caa062b0e52d9760a37637ea2913b20d6b Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 25 Feb 2020 12:27:47 -0800 Subject: [PATCH 067/235] Use ?. --- .../workbench/contrib/customEditor/browser/customEditors.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts index e69de1daeb0..ca4581ede56 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts @@ -333,11 +333,7 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ } const editorInfo = this._editorInfoStore.get(editor.viewType); - if (!editorInfo) { - continue; - } - - if (!editorInfo.matches(newResource)) { + if (!editorInfo?.matches(newResource)) { continue; } From 851cd9b1a5fb708e55b19c4d3fee4f11780c3b5f Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 26 Feb 2020 10:21:23 -0800 Subject: [PATCH 068/235] Use better parameter name for webview panels For #91568 --- src/vs/vscode.proposed.d.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index b603632b092..89e14e3ddc9 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1334,11 +1334,11 @@ declare module 'vscode' { * the event listeners it is interested it. The provider should also take ownership of the passed in `WebviewPanel`. * * @param document Document for resource being resolved. - * @param webview Webview being resolved. The provider should take ownership of this webview. + * @param webviewPanel Webview being resolved. The provider should take ownership of this webview. * * @return Thenable indicating that the webview editor has been resolved. */ - resolveCustomEditor(document: CustomDocument, webview: WebviewPanel): Thenable; + resolveCustomEditor(document: CustomDocument, webviewPanel: WebviewPanel): Thenable; } /** @@ -1359,11 +1359,11 @@ declare module 'vscode' { * the event listeners it is interested it. The provider should also take ownership of the passed in `WebviewPanel`. * * @param document Resource being resolved. - * @param webview Webview being resolved. The provider should take ownership of this webview. + * @param webviewPanel Webview being resolved. The provider should take ownership of this webview. * * @return Thenable indicating that the webview editor has been resolved. */ - resolveCustomTextEditor(document: TextDocument, webview: WebviewPanel): Thenable; + resolveCustomTextEditor(document: TextDocument, webviewPanel: WebviewPanel): Thenable; } namespace window { From feab34eaf048df2eb1048f66c9977a0d07a306b7 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 26 Feb 2020 19:37:44 +0100 Subject: [PATCH 069/235] extensions development - fix broken extension-development-confirm-save support --- .../services/dialogs/browser/abstractFileDialogService.ts | 4 ++++ .../services/dialogs/electron-browser/fileDialogService.ts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts b/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts index d481f2ee6ff..bdcff69df4f 100644 --- a/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts @@ -92,6 +92,10 @@ export abstract class AbstractFileDialogService implements IFileDialogService { return ConfirmResult.DONT_SAVE; // no veto when we are in extension dev mode because we cannot assume we run interactive (e.g. tests) } + return this.doShowSaveConfirm(fileNamesOrResources); + } + + protected async doShowSaveConfirm(fileNamesOrResources: (string | URI)[]): Promise { if (fileNamesOrResources.length === 0) { return ConfirmResult.DONT_SAVE; } diff --git a/src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts index 14b4f05f932..36e903296cb 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/fileDialogService.ts @@ -198,7 +198,7 @@ export class FileDialogService extends AbstractFileDialogService implements IFil } } - return super.showSaveConfirm(fileNamesOrResources); + return super.doShowSaveConfirm(fileNamesOrResources); } } From dc68e6578e9234059d9916fa97fe6dba8769328b Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 26 Feb 2020 10:29:50 -0800 Subject: [PATCH 070/235] rename custom editor activation event For #77131 Renames the activation event from `onWebviewEditor` to `onCustomEditor` to be consistent with the reset of the API --- extensions/image-preview/package.json | 2 +- extensions/markdown-language-features/package.json | 2 +- src/vs/workbench/api/browser/mainThreadWebview.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/image-preview/package.json b/extensions/image-preview/package.json index 998f3799f4d..48c7ae314a9 100644 --- a/extensions/image-preview/package.json +++ b/extensions/image-preview/package.json @@ -17,7 +17,7 @@ "Other" ], "activationEvents": [ - "onWebviewEditor:imagePreview.previewEditor", + "onCustomEditor:imagePreview.previewEditor", "onCommand:imagePreview.zoomIn", "onCommand:imagePreview.zoomOut" ], diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index f13d46a4b1c..dbc8746c913 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -26,7 +26,7 @@ "onCommand:markdown.showPreviewSecuritySelector", "onCommand:markdown.api.render", "onWebviewPanel:markdown.preview", - "onWebviewEditor:vscode.markdown.preview.editor" + "onCustomEditor:vscode.markdown.preview.editor" ], "contributes": { "commands": [ diff --git a/src/vs/workbench/api/browser/mainThreadWebview.ts b/src/vs/workbench/api/browser/mainThreadWebview.ts index 8764b50ffe8..dda6ad071d9 100644 --- a/src/vs/workbench/api/browser/mainThreadWebview.ts +++ b/src/vs/workbench/api/browser/mainThreadWebview.ts @@ -122,7 +122,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma this._register(_webviewWorkbenchService.registerResolver({ canResolve: (webview: WebviewInput) => { if (webview instanceof CustomEditorInput) { - extensionService.activateByEvent(`onWebviewEditor:${webview.viewType}`); + extensionService.activateByEvent(`onCustomEditor:${webview.viewType}`); return false; } From 9d06f1bdd1996f891cc1cf70484f03e6027abd86 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 26 Feb 2020 10:59:25 -0800 Subject: [PATCH 071/235] Better encapsulation of CustomDocument - Prefer using private fields - Explicitly mark internal hook method and prefix them with _ - Renaming --- src/vs/workbench/api/common/extHostWebview.ts | 179 ++++++++++-------- 1 file changed, 98 insertions(+), 81 deletions(-) diff --git a/src/vs/workbench/api/common/extHostWebview.ts b/src/vs/workbench/api/common/extHostWebview.ts index 121f1615990..539f31df1c2 100644 --- a/src/vs/workbench/api/common/extHostWebview.ts +++ b/src/vs/workbench/api/common/extHostWebview.ts @@ -247,143 +247,160 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa type EditType = unknown; -class WebviewEditorCustomDocument extends Disposable implements vscode.CustomDocument { - private _currentEditIndex: number = -1; - private _savePoint: number = -1; - private readonly _edits: Array = []; +class CustomDocument extends Disposable implements vscode.CustomDocument { - public userData: unknown; - - public _capabilities?: vscode.CustomEditorCapabilities = undefined; - - constructor( - private readonly _proxy: MainThreadWebviewsShape, - public readonly viewType: string, - public readonly uri: vscode.Uri, - ) { - super(); + public static create(proxy: MainThreadWebviewsShape, viewType: string, uri: vscode.Uri) { + return Object.seal(new CustomDocument(proxy, viewType, uri)); } - _setCapabilities(capabilities: vscode.CustomEditorCapabilities) { - if (this._capabilities) { - throw new Error('Capabilities already provided'); - } + // Explicitly initialize all properties as we seal the object after creation! - this._capabilities = capabilities; - capabilities.editing?.onDidEdit(edit => { - this.pushEdit(edit, this); - }); + #currentEditIndex: number = -1; + #savePoint: number = -1; + readonly #edits: Array = []; + + readonly #proxy: MainThreadWebviewsShape; + readonly #viewType: string; + readonly #uri: vscode.Uri; + + #capabilities: vscode.CustomEditorCapabilities | undefined = undefined; + + private constructor(proxy: MainThreadWebviewsShape, viewType: string, uri: vscode.Uri) { + super(); + this.#proxy = proxy; + this.#viewType = viewType; + this.#uri = uri; + } + + dispose() { + this.#onDidDispose.fire(); + super.dispose(); } //#region Public API - #_onDidDispose = this._register(new Emitter()); - public readonly onDidDispose = this.#_onDidDispose.event; + public get viewType(): string { return this.#viewType; } + + public get uri(): vscode.Uri { return this.#uri; } + + #onDidDispose = this._register(new Emitter()); + public readonly onDidDispose = this.#onDidDispose.event; + + public userData: unknown = undefined; //#endregion - dispose() { - this.#_onDidDispose.fire(); - super.dispose(); + //#region Internal + + /** @internal*/ _setCapabilities(capabilities: vscode.CustomEditorCapabilities) { + if (this.#capabilities) { + throw new Error('Capabilities already provided'); + } + + this.#capabilities = capabilities; + capabilities.editing?.onDidEdit(edit => { + this.pushEdit(edit); + }); } - private pushEdit(edit: EditType, trigger: any) { - this.spliceEdits(edit); - - this._currentEditIndex = this._edits.length - 1; - this.updateState(); - // this._onApplyEdit.fire({ edits: [edit], trigger }); - } - - private updateState() { - const dirty = this._edits.length > 0 && this._savePoint !== this._currentEditIndex; - this._proxy.$onDidChangeCustomDocumentState(this.uri, this.viewType, { dirty }); - } - - private spliceEdits(editToInsert?: EditType) { - const start = this._currentEditIndex + 1; - const toRemove = this._edits.length - this._currentEditIndex; - - editToInsert - ? this._edits.splice(start, toRemove, editToInsert) - : this._edits.splice(start, toRemove); - } - - revert() { + /** @internal*/ _revert() { const editing = this.getEditingCapability(); - if (this._currentEditIndex === this._savePoint) { + if (this.#currentEditIndex === this.#savePoint) { return true; } - if (this._currentEditIndex >= this._savePoint) { - const editsToUndo = this._edits.slice(this._savePoint, this._currentEditIndex); + if (this.#currentEditIndex >= this.#savePoint) { + const editsToUndo = this.#edits.slice(this.#savePoint, this.#currentEditIndex); editing.undoEdits(editsToUndo.reverse()); - } else if (this._currentEditIndex < this._savePoint) { - const editsToRedo = this._edits.slice(this._currentEditIndex, this._savePoint); + } else if (this.#currentEditIndex < this.#savePoint) { + const editsToRedo = this.#edits.slice(this.#currentEditIndex, this.#savePoint); editing.applyEdits(editsToRedo); } - this._currentEditIndex = this._savePoint; + this.#currentEditIndex = this.#savePoint; this.spliceEdits(); this.updateState(); return true; } - undo() { + /** @internal*/ _undo() { const editing = this.getEditingCapability(); - if (this._currentEditIndex < 0) { + if (this.#currentEditIndex < 0) { // nothing to undo return; } - const undoneEdit = this._edits[this._currentEditIndex]; - --this._currentEditIndex; + const undoneEdit = this.#edits[this.#currentEditIndex]; + --this.#currentEditIndex; editing.undoEdits([undoneEdit]); this.updateState(); } - redo() { + /** @internal*/ _redo() { const editing = this.getEditingCapability(); - if (this._currentEditIndex >= this._edits.length - 1) { + if (this.#currentEditIndex >= this.#edits.length - 1) { // nothing to redo return; } - ++this._currentEditIndex; - const redoneEdit = this._edits[this._currentEditIndex]; + ++this.#currentEditIndex; + const redoneEdit = this.#edits[this.#currentEditIndex]; editing.applyEdits([redoneEdit]); this.updateState(); } - save() { + /** @internal*/ _save() { return this.getEditingCapability().save(); } - saveAs(target: vscode.Uri) { + /** @internal*/ _saveAs(target: vscode.Uri) { return this.getEditingCapability().saveAs(target); } - backup(cancellation: CancellationToken) { + /** @internal*/ _backup(cancellation: CancellationToken) { return this.getEditingCapability().backup(cancellation); } + //#endregion + + private pushEdit(edit: EditType) { + this.spliceEdits(edit); + + this.#currentEditIndex = this.#edits.length - 1; + this.updateState(); + } + + private updateState() { + const dirty = this.#edits.length > 0 && this.#savePoint !== this.#currentEditIndex; + this.#proxy.$onDidChangeCustomDocumentState(this.uri, this.viewType, { dirty }); + } + + private spliceEdits(editToInsert?: EditType) { + const start = this.#currentEditIndex + 1; + const toRemove = this.#edits.length - this.#currentEditIndex; + + editToInsert + ? this.#edits.splice(start, toRemove, editToInsert) + : this.#edits.splice(start, toRemove); + } + private getEditingCapability(): vscode.CustomEditorEditingCapability { - if (!this._capabilities?.editing) { + if (!this.#capabilities?.editing) { throw new Error('Document is not editable'); } - return this._capabilities.editing; + return this.#capabilities.editing; } } class WebviewDocumentStore { - private readonly _documents = new Map(); + private readonly _documents = new Map(); - public get(viewType: string, resource: vscode.Uri): WebviewEditorCustomDocument | undefined { + public get(viewType: string, resource: vscode.Uri): CustomDocument | undefined { return this._documents.get(this.key(viewType, resource)); } - public add(document: WebviewEditorCustomDocument) { + public add(document: CustomDocument) { const key = this.key(document.viewType, document.uri); if (this._documents.has(key)) { throw new Error(`Document already exists for viewType:${document.viewType} resource:${document.uri}`); @@ -391,7 +408,7 @@ class WebviewDocumentStore { this._documents.set(key, document); } - public delete(document: WebviewEditorCustomDocument) { + public delete(document: CustomDocument) { const key = this.key(document.viewType, document.uri); this._documents.delete(key); } @@ -622,7 +639,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { } const revivedResource = URI.revive(resource); - const document = Object.seal(new WebviewEditorCustomDocument(this._proxy, viewType, revivedResource)); + const document = CustomDocument.create(this._proxy, viewType, revivedResource); const capabilities = await entry.provider.resolveCustomDocument(document); document._setCapabilities(capabilities); this._documents.add(document); @@ -687,39 +704,39 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { async $undo(resourceComponents: UriComponents, viewType: string): Promise { const document = this.getDocument(viewType, resourceComponents); - document.undo(); + document._undo(); } async $redo(resourceComponents: UriComponents, viewType: string): Promise { const document = this.getDocument(viewType, resourceComponents); - document.redo(); + document._redo(); } async $revert(resourceComponents: UriComponents, viewType: string): Promise { const document = this.getDocument(viewType, resourceComponents); - document.revert(); + document._revert(); } async $onSave(resourceComponents: UriComponents, viewType: string): Promise { const document = this.getDocument(viewType, resourceComponents); - document.save(); + document._save(); } async $onSaveAs(resourceComponents: UriComponents, viewType: string, targetResource: UriComponents): Promise { const document = this.getDocument(viewType, resourceComponents); - return document.saveAs(URI.revive(targetResource)); + return document._saveAs(URI.revive(targetResource)); } async $backup(resourceComponents: UriComponents, viewType: string, cancellation: CancellationToken): Promise { const document = this.getDocument(viewType, resourceComponents); - return document.backup(cancellation); + return document._backup(cancellation); } private getWebviewPanel(handle: WebviewPanelHandle): ExtHostWebviewEditor | undefined { return this._webviewPanels.get(handle); } - private getDocument(viewType: string, resource: UriComponents): WebviewEditorCustomDocument { + private getDocument(viewType: string, resource: UriComponents): CustomDocument { const document = this._documents.get(viewType, URI.revive(resource)); if (!document) { throw new Error('No webview editor custom document found'); From 835c77b8a5919d1908164f238f736a1758f4826e Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Wed, 26 Feb 2020 11:16:51 -0800 Subject: [PATCH 072/235] improve view moving command flow fixes #91422 --- .../browser/actions/layoutActions.ts | 76 ++++++++++--------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index 50906972e6c..f03e93dd95f 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -25,9 +25,10 @@ import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/commo import { SideBarVisibleContext } from 'vs/workbench/common/viewlet'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IViewDescriptorService, IViewContainersRegistry, Extensions as ViewContainerExtensions, IViewsService, FocusedViewContext, ViewContainerLocation } from 'vs/workbench/common/views'; -import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; +import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; +import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService'; const registry = Registry.as(WorkbenchExtensions.WorkbenchActions); const viewCategory = nls.localize('view', "View"); @@ -534,6 +535,7 @@ export class MoveFocusedViewAction extends Action { @IQuickInputService private quickInputService: IQuickInputService, @IContextKeyService private contextKeyService: IContextKeyService, @INotificationService private notificationService: INotificationService, + @IActivityBarService private activityBarService: IActivityBarService, @IViewletService private viewletService: IViewletService ) { super(id, label); @@ -542,58 +544,64 @@ export class MoveFocusedViewAction extends Action { run(): Promise { const viewContainerRegistry = Registry.as(ViewContainerExtensions.ViewContainersRegistry); - const focusedView = FocusedViewContext.getValue(this.contextKeyService); + const focusedViewId = FocusedViewContext.getValue(this.contextKeyService); - if (focusedView === undefined || focusedView.trim() === '') { + if (focusedViewId === undefined || focusedViewId.trim() === '') { this.notificationService.error(nls.localize('moveFocusedView.error.noFocusedView', "There is no view currently focused.")); return Promise.resolve(); } - const viewDescriptor = this.viewDescriptorService.getViewDescriptor(focusedView); + const viewDescriptor = this.viewDescriptorService.getViewDescriptor(focusedViewId); if (!viewDescriptor || !viewDescriptor.canMoveView) { - this.notificationService.error(nls.localize('moveFocusedView.error.nonMovableView', "The currently focused view is not movable {0}.", focusedView)); + this.notificationService.error(nls.localize('moveFocusedView.error.nonMovableView', "The currently focused view is not movable {0}.", focusedViewId)); return Promise.resolve(); } const quickPick = this.quickInputService.createQuickPick(); - quickPick.placeholder = nls.localize('moveFocusedView.selectDestination', "Select a destination area for the view..."); - quickPick.autoFocusOnList = true; + quickPick.placeholder = nls.localize('moveFocusedView.selectDestination', "Select a Destination for the View"); - quickPick.items = [ - { - id: 'sidebar', - label: nls.localize('sidebar', "Sidebar") - }, - { - id: 'panel', + const pinnedViewlets = this.activityBarService.getPinnedViewletIds(); + const items: Array = this.viewletService.getViewlets() + .filter(viewlet => { + if (viewlet.id === this.viewDescriptorService.getViewContainer(focusedViewId)!.id) { + return false; + } + + return !viewContainerRegistry.get(viewlet.id)!.rejectAddedViews && pinnedViewlets.indexOf(viewlet.id) !== -1; + }) + .map(viewlet => { + return { + id: viewlet.id, + label: viewlet.name, + }; + }); + + if (this.viewDescriptorService.getViewLocation(focusedViewId) !== ViewContainerLocation.Panel) { + items.unshift({ + type: 'separator', + label: nls.localize('sidebar', "Side Bar") + }); + items.push({ + type: 'separator', label: nls.localize('panel', "Panel") - } - ]; + }); + items.push({ + id: '_.panel.newcontainer', + label: nls.localize('moveFocusedView.newContainerInPanel', "New Container in Panel"), + }); + } + + quickPick.items = items; quickPick.onDidAccept(() => { const destination = quickPick.selectedItems[0]; - if (destination.id === 'panel') { - quickPick.hide(); + if (destination.id === '_.panel.newcontainer') { this.viewDescriptorService.moveViewToLocation(viewDescriptor!, ViewContainerLocation.Panel); - this.viewsService.openView(focusedView, true); - - return; - } else if (destination.id === 'sidebar') { - quickPick.placeholder = nls.localize('moveFocusedView.selectDestinationContainer', "Select a destination view group..."); - quickPick.items = this.viewletService.getViewlets().map(viewlet => { - return { - id: viewlet.id, - label: viewlet.name - }; - }); - - return; + this.viewsService.openView(focusedViewId, true); } else if (destination.id) { - quickPick.hide(); this.viewDescriptorService.moveViewsToContainer([viewDescriptor], viewContainerRegistry.get(destination.id)!); - this.viewsService.openView(focusedView, true); - return; + this.viewsService.openView(focusedViewId, true); } quickPick.hide(); From 4cdce8d4e8b9673f1f9bbb4ceb4cc6a64bdaadc3 Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Wed, 26 Feb 2020 11:27:04 -0800 Subject: [PATCH 073/235] fixes #91423 --- src/vs/workbench/browser/parts/views/viewPaneContainer.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts index 90554ca9351..bf954530159 100644 --- a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts +++ b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts @@ -255,7 +255,10 @@ export abstract class ViewPane extends Pane implements IView { this._onDidFocus.fire(); })); this._register(focusTracker.onDidBlur(() => { - this.focusedViewContextKey.reset(); + if (this.focusedViewContextKey.get() === this.id) { + this.focusedViewContextKey.reset(); + } + this._onDidBlur.fire(); })); } From 611231f0c02a3f79bcee47fa58ade692851202b6 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Wed, 26 Feb 2020 11:32:54 -0800 Subject: [PATCH 074/235] debug: update js-debug-nightly to "2020.2.2517" @ 2020-02-26T01:05:44.117Z --- build/builtInExtensions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index b0483145e01..ddc65ea119f 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -46,7 +46,7 @@ }, { "name": "ms-vscode.js-debug-nightly", - "version": "2020.2.2507", + "version": "2020.2.2517", "forQualities": [ "insider" ], From 38aa49e5dc248d1e23673d8c601b978f5de4ce6e Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Wed, 26 Feb 2020 11:36:50 -0800 Subject: [PATCH 075/235] fixes #91483 --- src/vs/workbench/browser/parts/compositeBarActions.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/browser/parts/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositeBarActions.ts index b025bf17474..c4eb0fbc8ed 100644 --- a/src/vs/workbench/browser/parts/compositeBarActions.ts +++ b/src/vs/workbench/browser/parts/compositeBarActions.ts @@ -616,6 +616,8 @@ export class CompositeActionViewItem extends ActivityActionViewItem { const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype); if (Array.isArray(data)) { const draggedViewId = data[0].id; + this.updateFromDragging(container, false); + this.compositeTransfer.clearData(DraggedViewIdentifier.prototype); this.dndHandler.drop(new CompositeDragAndDropData('view', draggedViewId), this.activity.id, e); } From 428c0d091c831675a27fccbbd7e096b41027cf04 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 26 Feb 2020 21:10:09 +0100 Subject: [PATCH 076/235] Fix #91584 --- .../userDataSync/browser/userDataSync.ts | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 2c902f0708b..e1f7ad007a6 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -409,9 +409,9 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo const sourceArea = getSyncAreaLabel(error.source); this.notificationService.notify({ severity: Severity.Error, - message: localize('too large', "Disabled syncing {0} because size of the {1} file to sync is larger than {2}. Please open the file and reduce the size and enable sync", sourceArea, sourceArea, '100kb'), + message: localize('too large', "Disabled syncing {0} because size of the {1} file to sync is larger than {2}. Please open the file and reduce the size and enable sync", sourceArea.toLowerCase(), sourceArea.toLowerCase(), '100kb'), actions: { - primary: [new Action('open sync file', localize('open file', "Open {0} file", sourceArea), undefined, true, + primary: [new Action('open sync file', localize('open file', "Open {0} File", sourceArea), undefined, true, () => error.source === SyncSource.Settings ? this.preferencesService.openGlobalSettings(true) : this.preferencesService.openGlobalKeybindingSettings(true))] } }); @@ -450,22 +450,31 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } private handleInvalidContentError(source: SyncSource): void { - if (!this.invalidContentErrorDisposables.has(source)) { - const errorArea = getSyncAreaLabel(source); - const handle = this.notificationService.notify({ - severity: Severity.Error, - message: localize('errorInvalidConfiguration', "Unable to sync {0} because there are some errors/warnings in the file. Please open the file to correct errors/warnings in it.", errorArea), - actions: { - primary: [new Action('open sync file', localize('open file', "Open {0} file", errorArea), undefined, true, - () => source === SyncSource.Settings ? this.preferencesService.openGlobalSettings(true) : this.preferencesService.openGlobalKeybindingSettings(true))] - } - }); - this.invalidContentErrorDisposables.set(source, toDisposable(() => { - // close the error warning notification - handle.close(); - this.invalidContentErrorDisposables.delete(source); - })); + if (this.invalidContentErrorDisposables.has(source)) { + return; } + if (source !== SyncSource.Settings && source !== SyncSource.Keybindings) { + return; + } + const resource = source === SyncSource.Settings ? this.workbenchEnvironmentService.settingsResource : this.workbenchEnvironmentService.keybindingsResource; + if (isEqual(resource, this.editorService.activeEditor?.resource)) { + // Do not show notification if the file in error is active + return; + } + const errorArea = getSyncAreaLabel(source); + const handle = this.notificationService.notify({ + severity: Severity.Error, + message: localize('errorInvalidConfiguration', "Unable to sync {0} because there are some errors/warnings in the file. Please open the file to correct errors/warnings in it.", errorArea.toLowerCase()), + actions: { + primary: [new Action('open sync file', localize('open file', "Open {0} File", errorArea), undefined, true, + () => source === SyncSource.Settings ? this.preferencesService.openGlobalSettings(true) : this.preferencesService.openGlobalKeybindingSettings(true))] + } + }); + this.invalidContentErrorDisposables.set(source, toDisposable(() => { + // close the error warning notification + handle.close(); + this.invalidContentErrorDisposables.delete(source); + })); } private async updateBadge(): Promise { From 3b6b125d6e70d727746c93c8189f72d38a35ef6d Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 26 Feb 2020 21:10:54 +0100 Subject: [PATCH 077/235] #91544 revert label change --- src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index e1f7ad007a6..9ce3ae4a81e 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -895,7 +895,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo constructor() { super({ id: 'workbench.userData.actions.syncStatus', - title: localize('sync is on', "Sync..."), + title: localize('sync is on', "Sync is on"), menu: [ { id: MenuId.GlobalActivity, From 9db2563ee5c43204bf22574c758958fcfd4f14dc Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 26 Feb 2020 21:13:03 +0100 Subject: [PATCH 078/235] #91584 convert to lower case --- .../workbench/contrib/userDataSync/browser/userDataSync.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 9ce3ae4a81e..0a54cd4b5b4 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -290,7 +290,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo const conflictsEditorInput = this.getConflictsEditorInput(conflictsSource); if (!conflictsEditorInput && !this.conflictsDisposables.has(conflictsSource)) { const conflictsArea = getSyncAreaLabel(conflictsSource); - const handle = this.notificationService.prompt(Severity.Warning, localize('conflicts detected', "Unable to sync due to conflicts in {0}. Please resolve them to continue.", conflictsArea), + const handle = this.notificationService.prompt(Severity.Warning, localize('conflicts detected', "Unable to sync due to conflicts in {0}. Please resolve them to continue.", conflictsArea.toLowerCase()), [ { label: localize('accept remote', "Accept Remote"), @@ -1133,8 +1133,8 @@ class AcceptChangesContribution extends Disposable implements IEditorContributio ? localize('Sync accept remote', "Sync: {0}", acceptRemoteLabel) : localize('Sync accept local', "Sync: {0}", acceptLocalLabel), message: isRemote - ? localize('confirm replace and overwrite local', "Would you like to accept Remote {0} and replace Local {1}?", syncAreaLabel, syncAreaLabel) - : localize('confirm replace and overwrite remote', "Would you like to accept Local {0} and replace Remote {1}?", syncAreaLabel, syncAreaLabel), + ? localize('confirm replace and overwrite local', "Would you like to accept Remote {0} and replace Local {1}?", syncAreaLabel.toLowerCase(), syncAreaLabel.toLowerCase()) + : localize('confirm replace and overwrite remote', "Would you like to accept Local {0} and replace Remote {1}?", syncAreaLabel.toLowerCase(), syncAreaLabel.toLowerCase()), primaryButton: isRemote ? acceptRemoteLabel : acceptLocalLabel }); if (result.confirmed) { From 57f7d837ac32a01842607a00ca823dba86261efa Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 26 Feb 2020 22:06:32 +0100 Subject: [PATCH 079/235] [folding] add setting to allow clicking in empty space to unfold. Fixes #88522 --- src/vs/editor/common/config/editorOptions.ts | 10 +++++----- .../editor/common/standalone/standaloneEnums.ts | 2 +- src/vs/editor/contrib/folding/folding.ts | 16 +++++++--------- src/vs/monaco.d.ts | 6 +++--- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index de910398d63..270e0018dff 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -510,7 +510,7 @@ export interface IEditorOptions { * Controls whether clicking on the empty content after a folded line will unfold the line. * Defaults to false. */ - unfoldOnClickInEmptyContent?: boolean; + unfoldOnClickAfterEndOfLine?: boolean; /** * Enable highlighting of matching brackets. * Defaults to 'always'. @@ -3325,7 +3325,7 @@ export const enum EditorOption { folding, foldingStrategy, foldingHighlight, - unfoldOnClickInEmptyContent, + unfoldOnClickAfterEndOfLine, fontFamily, fontInfo, fontLigatures, @@ -3625,9 +3625,9 @@ export const EditorOptions = { EditorOption.foldingHighlight, 'foldingHighlight', true, { description: nls.localize('foldingHighlight', "Controls whether the editor should highlight folded ranges.") } )), - unfoldOnClickInEmptyContent: register(new EditorBooleanOption( - EditorOption.unfoldOnClickInEmptyContent, 'unfoldOnClickInEmptyContent', false, - { description: nls.localize('unfoldOnClickInEmptyContent', "Controls whether clicking on the empty content after a folded line will unfold the line.") } + unfoldOnClickAfterEndOfLine: register(new EditorBooleanOption( + EditorOption.unfoldOnClickAfterEndOfLine, 'unfoldOnClickAfterEndOfLine', false, + { description: nls.localize('unfoldOnClickAfterEndOfLine', "Controls whether clicking on the empty content after a folded line will unfold the line.") } )), fontFamily: register(new EditorStringOption( EditorOption.fontFamily, 'fontFamily', EDITOR_FONT_DEFAULTS.fontFamily, diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index 458faca8bf2..418fe492a04 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -199,7 +199,7 @@ export enum EditorOption { folding = 31, foldingStrategy = 32, foldingHighlight = 33, - unfoldOnClickInEmptyContent = 34, + unfoldOnClickAfterEndOfLine = 34, fontFamily = 35, fontInfo = 36, fontLigatures = 37, diff --git a/src/vs/editor/contrib/folding/folding.ts b/src/vs/editor/contrib/folding/folding.ts index c2d01a5ce0e..e80d1f68e5f 100644 --- a/src/vs/editor/contrib/folding/folding.ts +++ b/src/vs/editor/contrib/folding/folding.ts @@ -62,7 +62,7 @@ export class FoldingController extends Disposable implements IEditorContribution private readonly editor: ICodeEditor; private _isEnabled: boolean; private _useFoldingProviders: boolean; - private _unfoldOnClickInEmptyContent: boolean; + private _unfoldOnClickAfterEndOfLine: boolean; private readonly foldingDecorationProvider: FoldingDecorationProvider; @@ -92,7 +92,7 @@ export class FoldingController extends Disposable implements IEditorContribution const options = this.editor.getOptions(); this._isEnabled = options.get(EditorOption.folding); this._useFoldingProviders = options.get(EditorOption.foldingStrategy) !== 'indentation'; - this._unfoldOnClickInEmptyContent = options.get(EditorOption.unfoldOnClickInEmptyContent); + this._unfoldOnClickAfterEndOfLine = options.get(EditorOption.unfoldOnClickAfterEndOfLine); this.foldingModel = null; this.hiddenRangeModel = null; @@ -114,8 +114,7 @@ export class FoldingController extends Disposable implements IEditorContribution this._register(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { if (e.hasChanged(EditorOption.folding)) { - const options = this.editor.getOptions(); - this._isEnabled = options.get(EditorOption.folding); + this._isEnabled = this.editor.getOptions().get(EditorOption.folding); this.foldingEnabled.set(this._isEnabled); this.onModelChanged(); } @@ -126,12 +125,11 @@ export class FoldingController extends Disposable implements IEditorContribution this.onModelContentChanged(); } if (e.hasChanged(EditorOption.foldingStrategy)) { - const options = this.editor.getOptions(); - this._useFoldingProviders = options.get(EditorOption.foldingStrategy) !== 'indentation'; + this._useFoldingProviders = this.editor.getOptions().get(EditorOption.foldingStrategy) !== 'indentation'; this.onFoldingStrategyChanged(); } - if (e.hasChanged(EditorOption.unfoldOnClickInEmptyContent)) { - this._unfoldOnClickInEmptyContent = options.get(EditorOption.unfoldOnClickInEmptyContent); + if (e.hasChanged(EditorOption.unfoldOnClickAfterEndOfLine)) { + this._unfoldOnClickAfterEndOfLine = this.editor.getOptions().get(EditorOption.unfoldOnClickAfterEndOfLine); } })); this.onModelChanged(); @@ -370,7 +368,7 @@ export class FoldingController extends Disposable implements IEditorContribution iconClicked = true; break; case MouseTargetType.CONTENT_EMPTY: { - if (this._unfoldOnClickInEmptyContent && this.hiddenRangeModel.hasRanges()) { + if (this._unfoldOnClickAfterEndOfLine && this.hiddenRangeModel.hasRanges()) { const data = e.target.detail as IEmptyContentData; if (!data.isAfterLines) { break; diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index c90b75b3bc2..fd704b03bd3 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -3035,7 +3035,7 @@ declare namespace monaco.editor { * Controls whether clicking on the empty content after a folded line will unfold the line. * Defaults to false. */ - unfoldOnClickInEmptyContent?: boolean; + unfoldOnClickAfterEndOfLine?: boolean; /** * Enable highlighting of matching brackets. * Defaults to 'always'. @@ -3825,7 +3825,7 @@ declare namespace monaco.editor { folding = 31, foldingStrategy = 32, foldingHighlight = 33, - unfoldOnClickInEmptyContent = 34, + unfoldOnClickAfterEndOfLine = 34, fontFamily = 35, fontInfo = 36, fontLigatures = 37, @@ -3941,7 +3941,7 @@ declare namespace monaco.editor { folding: IEditorOption; foldingStrategy: IEditorOption; foldingHighlight: IEditorOption; - unfoldOnClickInEmptyContent: IEditorOption; + unfoldOnClickAfterEndOfLine: IEditorOption; fontFamily: IEditorOption; fontInfo: IEditorOption; fontLigatures2: IEditorOption; From eb1f88b5dc57ea7e6cb5f17ea9cdfb3f5892dc90 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 26 Feb 2020 22:25:18 +0100 Subject: [PATCH 080/235] #91556 Add telemetry to auto sync trigger sources --- .../common/userDataAutoSyncService.ts | 11 +++++- .../userDataSync/common/userDataSync.ts | 4 +- .../userDataSync/common/userDataSyncIpc.ts | 2 +- .../common/userDataSyncService.ts | 4 +- .../userDataAutoSyncService.ts | 13 ++++--- .../browser/userDataAutoSyncService.ts | 13 ++++--- .../userDataSync/browser/userDataSync.ts | 2 +- .../browser/userDataSyncTrigger.ts | 39 +++++++++++-------- .../userDataAutoSyncService.ts | 4 +- .../electron-browser/userDataSyncService.ts | 2 +- 10 files changed, 55 insertions(+), 39 deletions(-) diff --git a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts index b64192c62d6..b623b9754a0 100644 --- a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts @@ -8,6 +8,11 @@ import { Event, Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { IUserDataSyncLogService, IUserDataSyncService, SyncStatus, IUserDataAutoSyncService, UserDataSyncError, UserDataSyncErrorCode, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; import { IAuthenticationTokenService } from 'vs/platform/authentication/common/authentication'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; + +type AutoSyncTriggerClassification = { + source: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; +}; export class UserDataAutoSyncService extends Disposable implements IUserDataAutoSyncService { @@ -25,6 +30,7 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto @IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService, @IUserDataSyncLogService private readonly logService: IUserDataSyncLogService, @IAuthenticationTokenService private readonly authTokenService: IAuthenticationTokenService, + @ITelemetryService private readonly telemetryService: ITelemetryService, ) { super(); this.updateEnablement(false, true); @@ -32,7 +38,7 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto this._register(Event.any(authTokenService.onDidChangeToken)(() => this.updateEnablement(true, true))); this._register(Event.any(userDataSyncService.onDidChangeStatus)(() => this.updateEnablement(true, true))); this._register(this.userDataSyncEnablementService.onDidChangeEnablement(() => this.updateEnablement(true, false))); - this._register(this.userDataSyncEnablementService.onDidChangeResourceEnablement(() => this.triggerAutoSync())); + this._register(this.userDataSyncEnablementService.onDidChangeResourceEnablement(() => this.triggerAutoSync(['resourceEnablement']))); } private async updateEnablement(stopIfDisabled: boolean, auto: boolean): Promise { @@ -99,7 +105,8 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto this.successiveFailures = 0; } - async triggerAutoSync(): Promise { + async triggerAutoSync(sources: string[]): Promise { + sources.forEach(source => this.telemetryService.publicLog2<{ source: string }, AutoSyncTriggerClassification>('sync/triggerAutoSync', { source })); if (this.enabled) { return this.syncDelayer.trigger(() => { this.logService.info('Auto Sync: Triggered.'); diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index 23bd81b6526..79589c43e4f 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -278,7 +278,7 @@ export interface IUserDataSyncService { readonly conflictsSources: SyncSource[]; readonly onDidChangeConflicts: Event; - readonly onDidChangeLocal: Event; + readonly onDidChangeLocal: Event; readonly onSyncErrors: Event<[SyncSource, UserDataSyncError][]>; readonly lastSyncTime: number | undefined; @@ -299,7 +299,7 @@ export const IUserDataAutoSyncService = createDecorator; - triggerAutoSync(): Promise; + triggerAutoSync(sources: string[]): Promise; } export const IUserDataSyncUtilService = createDecorator('IUserDataSyncUtilService'); diff --git a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts index 04c8649a703..a2b8c25e64d 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts @@ -86,7 +86,7 @@ export class UserDataAutoSyncChannel implements IServerChannel { call(context: any, command: string, args?: any): Promise { switch (command) { - case 'triggerAutoSync': return this.service.triggerAutoSync(); + case 'triggerAutoSync': return this.service.triggerAutoSync(args[0]); } throw new Error('Invalid call'); } diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts index 07203267160..4d0a2619afe 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -34,7 +34,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ private _onDidChangeStatus: Emitter = this._register(new Emitter()); readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; - readonly onDidChangeLocal: Event; + readonly onDidChangeLocal: Event; private _conflictsSources: SyncSource[] = []; get conflictsSources(): SyncSource[] { return this._conflictsSources; } @@ -74,7 +74,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ } this._lastSyncTime = this.storageService.getNumber(LAST_SYNC_TIME_KEY, StorageScope.GLOBAL, undefined); - this.onDidChangeLocal = Event.any(...this.synchronisers.map(s => s.onDidChangeLocal)); + this.onDidChangeLocal = Event.any(...this.synchronisers.map(s => Event.map(s.onDidChangeLocal, () => s.source))); } async pull(): Promise { diff --git a/src/vs/platform/userDataSync/electron-browser/userDataAutoSyncService.ts b/src/vs/platform/userDataSync/electron-browser/userDataAutoSyncService.ts index 770865e5e26..6fa694e1d27 100644 --- a/src/vs/platform/userDataSync/electron-browser/userDataAutoSyncService.ts +++ b/src/vs/platform/userDataSync/electron-browser/userDataAutoSyncService.ts @@ -8,6 +8,7 @@ import { Event } from 'vs/base/common/event'; import { IElectronService } from 'vs/platform/electron/node/electron'; import { UserDataAutoSyncService as BaseUserDataAutoSyncService } from 'vs/platform/userDataSync/common/userDataAutoSyncService'; import { IAuthenticationTokenService } from 'vs/platform/authentication/common/authentication'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; export class UserDataAutoSyncService extends BaseUserDataAutoSyncService { @@ -17,15 +18,15 @@ export class UserDataAutoSyncService extends BaseUserDataAutoSyncService { @IElectronService electronService: IElectronService, @IUserDataSyncLogService logService: IUserDataSyncLogService, @IAuthenticationTokenService authTokenService: IAuthenticationTokenService, + @ITelemetryService telemetryService: ITelemetryService, ) { - super(userDataSyncEnablementService, userDataSyncService, logService, authTokenService); + super(userDataSyncEnablementService, userDataSyncService, logService, authTokenService, telemetryService); - // Sync immediately if there is a local change. - this._register(Event.debounce(Event.any( - electronService.onWindowFocus, - electronService.onWindowOpen, + this._register(Event.debounce(Event.any( + Event.map(electronService.onWindowFocus, () => 'windowFocus'), + Event.map(electronService.onWindowOpen, () => 'windowOpen'), userDataSyncService.onDidChangeLocal, - ), () => undefined, 500)(() => this.triggerAutoSync())); + ), (last, source) => last ? [...last, source] : [source], 1000)(sources => this.triggerAutoSync(sources))); } } diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataAutoSyncService.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataAutoSyncService.ts index 3caeb60f404..7e035fddbce 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataAutoSyncService.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataAutoSyncService.ts @@ -10,6 +10,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { UserDataSyncTrigger } from 'vs/workbench/contrib/userDataSync/browser/userDataSyncTrigger'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IAuthenticationTokenService } from 'vs/platform/authentication/common/authentication'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; export class UserDataAutoSyncService extends BaseUserDataAutoSyncService { @@ -20,15 +21,15 @@ export class UserDataAutoSyncService extends BaseUserDataAutoSyncService { @IAuthenticationTokenService authTokenService: IAuthenticationTokenService, @IInstantiationService instantiationService: IInstantiationService, @IHostService hostService: IHostService, + @ITelemetryService telemetryService: ITelemetryService, ) { - super(userDataSyncEnablementService, userDataSyncService, logService, authTokenService); + super(userDataSyncEnablementService, userDataSyncService, logService, authTokenService, telemetryService); - // Sync immediately if there is a local change. - this._register(Event.debounce(Event.any( - userDataSyncService.onDidChangeLocal, + this._register(Event.debounce(Event.any( + Event.map(hostService.onDidChangeFocus, () => 'windowFocus'), instantiationService.createInstance(UserDataSyncTrigger).onDidTriggerSync, - hostService.onDidChangeFocus - ), () => undefined, 500)(() => this.triggerAutoSync())); + userDataSyncService.onDidChangeLocal, + ), (last, source) => last ? [...last, source] : [source], 1000)(sources => this.triggerAutoSync(sources))); } } diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 0a54cd4b5b4..8bf9147ddcb 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -163,7 +163,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo this.registerActions(); this.initializeActiveAccount().then(_ => { if (!isWeb) { - this._register(instantiationService.createInstance(UserDataSyncTrigger).onDidTriggerSync(() => userDataAutoSyncService.triggerAutoSync())); + this._register(instantiationService.createInstance(UserDataSyncTrigger).onDidTriggerSync(source => userDataAutoSyncService.triggerAutoSync([source]))); } }); diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSyncTrigger.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSyncTrigger.ts index 43b93c20ab2..1642cd210a4 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSyncTrigger.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSyncTrigger.ts @@ -16,8 +16,8 @@ import { IViewlet } from 'vs/workbench/common/viewlet'; export class UserDataSyncTrigger extends Disposable { - private readonly _onDidTriggerSync: Emitter = this._register(new Emitter()); - readonly onDidTriggerSync: Event = this._onDidTriggerSync.event; + private readonly _onDidTriggerSync: Emitter = this._register(new Emitter()); + readonly onDidTriggerSync: Event = this._onDidTriggerSync.event; constructor( @IEditorService editorService: IEditorService, @@ -25,37 +25,44 @@ export class UserDataSyncTrigger extends Disposable { @IViewletService viewletService: IViewletService, ) { super(); - this._register(Event.debounce(Event.any( - Event.filter(editorService.onDidActiveEditorChange, () => this.isUserDataEditorInput(editorService.activeEditor)), - Event.filter(viewletService.onDidViewletOpen, viewlet => this.isUserDataViewlet(viewlet)) - ), () => undefined, 500)(() => this._onDidTriggerSync.fire())); + this._register(Event.any( + Event.map(editorService.onDidActiveEditorChange, () => this.getUserDataEditorInputSource(editorService.activeEditor)), + Event.map(viewletService.onDidViewletOpen, viewlet => this.getUserDataViewletSource(viewlet)) + )(source => { + if (source) { + this._onDidTriggerSync.fire(source); + } + })); } - private isUserDataViewlet(viewlet: IViewlet): boolean { - return viewlet.getId() === VIEWLET_ID; + private getUserDataViewletSource(viewlet: IViewlet): string | undefined { + if (viewlet.getId() === VIEWLET_ID) { + return 'extensionsViewlet'; + } + return undefined; } - private isUserDataEditorInput(editorInput: IEditorInput | undefined): boolean { + private getUserDataEditorInputSource(editorInput: IEditorInput | undefined): string | undefined { if (!editorInput) { - return false; + return undefined; } if (editorInput instanceof SettingsEditor2Input) { - return true; + return 'settingsEditor'; } if (editorInput instanceof PreferencesEditorInput) { - return true; + return 'settingsEditor'; } if (editorInput instanceof KeybindingsEditorInput) { - return true; + return 'keybindingsEditor'; } const resource = editorInput.resource; if (isEqual(resource, this.workbenchEnvironmentService.settingsResource)) { - return true; + return 'settingsEditor'; } if (isEqual(resource, this.workbenchEnvironmentService.keybindingsResource)) { - return true; + return 'keybindingsEditor'; } - return false; + return undefined; } } diff --git a/src/vs/workbench/services/userDataSync/electron-browser/userDataAutoSyncService.ts b/src/vs/workbench/services/userDataSync/electron-browser/userDataAutoSyncService.ts index 4dc5de8bc46..88ee0dcb78f 100644 --- a/src/vs/workbench/services/userDataSync/electron-browser/userDataAutoSyncService.ts +++ b/src/vs/workbench/services/userDataSync/electron-browser/userDataAutoSyncService.ts @@ -24,8 +24,8 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto this.channel = sharedProcessService.getChannel('userDataAutoSync'); } - triggerAutoSync(): Promise { - return this.channel.call('triggerAutoSync'); + triggerAutoSync(sources: string[]): Promise { + return this.channel.call('triggerAutoSync', [sources]); } } diff --git a/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts b/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts index 2b495a43dc9..b3ec8ffeb95 100644 --- a/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts +++ b/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts @@ -22,7 +22,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ private _onDidChangeStatus: Emitter = this._register(new Emitter()); readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; - get onDidChangeLocal(): Event { return this.channel.listen('onDidChangeLocal'); } + get onDidChangeLocal(): Event { return this.channel.listen('onDidChangeLocal'); } private _conflictsSources: SyncSource[] = []; get conflictsSources(): SyncSource[] { return this._conflictsSources; } From 2e16c59fde65096c9ac2b3334f6b8b1fcbf87606 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 26 Feb 2020 14:06:56 -0800 Subject: [PATCH 081/235] Update distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 05b3a37a358..09843bf7d28 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.43.0", - "distro": "efe6f8371664e7a0a280e47cb32d921d183b8aaa", + "distro": "e16fca95fbe6abb7e846db3fd372c95da67a41ad", "author": { "name": "Microsoft Corporation" }, From 7a13028b705142564dc582eafaf5b3e0e5dfddf7 Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Wed, 26 Feb 2020 15:06:53 -0800 Subject: [PATCH 082/235] Lowercase auth provider ids, fixes #91538 --- extensions/github-authentication/src/extension.ts | 2 +- extensions/vscode-account/src/extension.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/github-authentication/src/extension.ts b/extensions/github-authentication/src/extension.ts index 943db6f20b5..c377e020939 100644 --- a/extensions/github-authentication/src/extension.ts +++ b/extensions/github-authentication/src/extension.ts @@ -16,7 +16,7 @@ export async function activate(context: vscode.ExtensionContext) { await loginService.initialize(); vscode.authentication.registerAuthenticationProvider({ - id: 'GitHub', + id: 'github', displayName: 'GitHub', onDidChangeSessions: onDidChangeSessions.event, getSessions: () => Promise.resolve(loginService.sessions), diff --git a/extensions/vscode-account/src/extension.ts b/extensions/vscode-account/src/extension.ts index fa94280fe3d..e70fbe59cb0 100644 --- a/extensions/vscode-account/src/extension.ts +++ b/extensions/vscode-account/src/extension.ts @@ -18,7 +18,7 @@ export async function activate(context: vscode.ExtensionContext) { await loginService.initialize(); context.subscriptions.push(vscode.authentication.registerAuthenticationProvider({ - id: 'MSA', + id: 'microsoft', displayName: 'Microsoft', onDidChangeSessions: onDidChangeSessions.event, getSessions: () => Promise.resolve(loginService.sessions), From 438b39e016a6852f9ebb224b98fbf81ac8033aac Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Wed, 26 Feb 2020 15:13:21 -0800 Subject: [PATCH 083/235] fixes #91622 --- src/vs/workbench/browser/actions/layoutActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index f03e93dd95f..0ece351afc3 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -553,7 +553,7 @@ export class MoveFocusedViewAction extends Action { const viewDescriptor = this.viewDescriptorService.getViewDescriptor(focusedViewId); if (!viewDescriptor || !viewDescriptor.canMoveView) { - this.notificationService.error(nls.localize('moveFocusedView.error.nonMovableView', "The currently focused view is not movable {0}.", focusedViewId)); + this.notificationService.error(nls.localize('moveFocusedView.error.nonMovableView', "The currently focused view is not movable.")); return Promise.resolve(); } From 8d19b6982eefc742dd9e4102f29157735b9fbdd8 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Wed, 26 Feb 2020 15:19:39 -0800 Subject: [PATCH 084/235] Fix #91559 --- src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts index 8f26a359018..a32b0f8fc23 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts @@ -194,6 +194,7 @@ export class SearchEditor extends BaseTextEditor { const runAgainLink = DOM.append(this.messageBox, DOM.$('a.pointer.prominent.message', {}, localize('runSearch', "Run Search"))); this.messageDisposables.push(DOM.addDisposableListener(runAgainLink, DOM.EventType.CLICK, async () => { await this.triggerSearch(); + this.searchResultEditor.focus(); this.toggleRunAgainMessage(false); })); } From eee9122c870f32eccac1084d5dd10a2d7b153de5 Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Wed, 26 Feb 2020 15:24:47 -0800 Subject: [PATCH 085/235] accessToken -> getAccessToken, fixes #91570 --- extensions/github-authentication/src/github.ts | 6 +++--- extensions/vscode-account/src/AADHelper.ts | 2 +- src/vs/editor/common/modes.ts | 2 +- src/vs/vscode.proposed.d.ts | 2 +- src/vs/workbench/api/browser/mainThreadAuthentication.ts | 4 ++-- src/vs/workbench/api/common/extHostAuthentication.ts | 6 +++--- .../workbench/contrib/userDataSync/browser/userDataSync.ts | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/extensions/github-authentication/src/github.ts b/extensions/github-authentication/src/github.ts index 0f46d20d81b..52c7c4e333a 100644 --- a/extensions/github-authentication/src/github.ts +++ b/extensions/github-authentication/src/github.ts @@ -71,7 +71,7 @@ export class GitHubAuthenticationProvider { id: session.id, accountName: session.accountName, scopes: session.scopes, - accessToken: () => Promise.resolve(session.accessToken) + getAccessToken: () => Promise.resolve(session.accessToken) }; }); } catch (e) { @@ -84,7 +84,7 @@ export class GitHubAuthenticationProvider { private async storeSessions(): Promise { const sessionData: SessionData[] = await Promise.all(this._sessions.map(async session => { - const resolvedAccessToken = await session.accessToken(); + const resolvedAccessToken = await session.getAccessToken(); return { id: session.id, accountName: session.accountName, @@ -111,7 +111,7 @@ export class GitHubAuthenticationProvider { const userInfo = await this._githubServer.getUserInfo(token); return { id: userInfo.id, - accessToken: () => Promise.resolve(token), + getAccessToken: () => Promise.resolve(token), accountName: userInfo.accountName, scopes: scopes }; diff --git a/extensions/vscode-account/src/AADHelper.ts b/extensions/vscode-account/src/AADHelper.ts index 5f193828141..b1aee3e6bdf 100644 --- a/extensions/vscode-account/src/AADHelper.ts +++ b/extensions/vscode-account/src/AADHelper.ts @@ -184,7 +184,7 @@ export class AzureActiveDirectoryService { private convertToSession(token: IToken): vscode.AuthenticationSession { return { id: token.sessionId, - accessToken: () => this.resolveAccessToken(token), + getAccessToken: () => this.resolveAccessToken(token), accountName: token.accountName, scopes: token.scope.split(' ') }; diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 98af16d123d..b93301c609d 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -1373,7 +1373,7 @@ export interface RenameProvider { */ export interface AuthenticationSession { id: string; - accessToken(): Thenable; + getAccessToken(): Thenable; accountName: string; } diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 89e14e3ddc9..86cb76837b3 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -20,7 +20,7 @@ declare module 'vscode' { export interface AuthenticationSession { id: string; - accessToken(): Thenable; + getAccessToken(): Thenable; accountName: string; scopes: string[] } diff --git a/src/vs/workbench/api/browser/mainThreadAuthentication.ts b/src/vs/workbench/api/browser/mainThreadAuthentication.ts index 22f91f6d2cc..15af9ba8bc6 100644 --- a/src/vs/workbench/api/browser/mainThreadAuthentication.ts +++ b/src/vs/workbench/api/browser/mainThreadAuthentication.ts @@ -25,7 +25,7 @@ export class MainThreadAuthenticationProvider { return { id: session.id, accountName: session.accountName, - accessToken: () => this._proxy.$getSessionAccessToken(this.id, session.id) + getAccessToken: () => this._proxy.$getSessionAccessToken(this.id, session.id) }; }); } @@ -35,7 +35,7 @@ export class MainThreadAuthenticationProvider { return { id: session.id, accountName: session.accountName, - accessToken: () => this._proxy.$getSessionAccessToken(this.id, session.id) + getAccessToken: () => this._proxy.$getSessionAccessToken(this.id, session.id) }; }); } diff --git a/src/vs/workbench/api/common/extHostAuthentication.ts b/src/vs/workbench/api/common/extHostAuthentication.ts index 234de7348f3..b3b2d4d0f4a 100644 --- a/src/vs/workbench/api/common/extHostAuthentication.ts +++ b/src/vs/workbench/api/common/extHostAuthentication.ts @@ -34,7 +34,7 @@ export class AuthenticationProviderWrapper implements vscode.AuthenticationProvi id: session.id, accountName: session.accountName, scopes: session.scopes, - accessToken: async () => { + getAccessToken: async () => { const isAllowed = await this._proxy.$getSessionsPrompt( this._provider.id, this.displayName, @@ -45,7 +45,7 @@ export class AuthenticationProviderWrapper implements vscode.AuthenticationProvi throw new Error('User did not consent to token access.'); } - return session.accessToken(); + return session.getAccessToken(); } }; }); @@ -137,7 +137,7 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape { const sessions = await authProvider.getSessions(); const session = sessions.find(session => session.id === sessionId); if (session) { - return session.accessToken(); + return session.getAccessToken(); } throw new Error(`Unable to find session with id: ${sessionId}`); diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 8bf9147ddcb..3399c0adb64 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -226,7 +226,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo if (account) { try { - const token = await account.accessToken(); + const token = await account.getAccessToken(); this.authTokenService.setToken(token); this.authenticationState.set(AuthStatus.SignedIn); } catch (e) { From 75d8eee5648abe963b451e5452fc4a521f16cce1 Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Wed, 26 Feb 2020 15:28:40 -0800 Subject: [PATCH 086/235] fixes #91620 --- .../workbench/contrib/files/browser/media/explorerviewlet.css | 4 ++-- .../workbench/contrib/files/browser/views/openEditorsView.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css b/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css index e7e32d6ff20..04e0bf24825 100644 --- a/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css +++ b/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css @@ -55,11 +55,11 @@ align-items: center; } -.explorer-viewlet .pane-header .monaco-count-badge.hidden { +.pane-header .dirty-count.monaco-count-badge.hidden { display: none; } -.explorer-viewlet .monaco-count-badge { +.dirty-count.monaco-count-badge { padding: 1px 6px 2px; margin-left: 6px; min-height: auto; diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index c388727aba4..9c5162d1999 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -185,7 +185,7 @@ export class OpenEditorsView extends ViewPane { super.renderHeaderTitle(container, this.title); const count = dom.append(container, $('.count')); - this.dirtyCountElement = dom.append(count, $('.monaco-count-badge')); + this.dirtyCountElement = dom.append(count, $('.dirty-count.monaco-count-badge')); this._register((attachStylerCallback(this.themeService, { badgeBackground, badgeForeground, contrastBorder }, colors => { const background = colors.badgeBackground ? colors.badgeBackground.toString() : ''; From c5944491c0a4d2ac3b2a21d10201512587976438 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 26 Feb 2020 15:52:03 -0800 Subject: [PATCH 087/235] Improving documentation for custom editors --- src/vs/vscode.proposed.d.ts | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 86cb76837b3..b3bea7c0a5a 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1279,8 +1279,8 @@ declare module 'vscode' { /** * Represents a custom document for a custom webview editor. * - * Custom documents are only used within a given `WebviewCustomEditorProvider`. The lifecycle of a - * `WebviewEditorCustomDocument` is managed by VS Code. When more more references remain to a given `WebviewEditorCustomDocument` + * Custom documents are only used within a given `CustomEditorProvider`. The lifecycle of a + * `CustomDocument` is managed by VS Code. When more more references remain to a given `CustomDocument` * then it is disposed of. * * @param UserDataType Type of custom object that extensions can store on the document. @@ -1297,7 +1297,7 @@ declare module 'vscode' { readonly uri: Uri; /** - * Event fired when there are no more references to the `WebviewEditorCustomDocument`. + * Event fired when there are no more references to the `CustomDocument`. */ readonly onDidDispose: Event; @@ -1313,7 +1313,7 @@ declare module 'vscode' { /** * Provider for webview editors that use a custom data model. * - * Custom webview editors use [`WebviewEditorCustomDocument`](#WebviewEditorCustomDocument) as their data model. + * Custom webview editors use [`CustomDocument`](#CustomDocument) as their data model. * This gives extensions full control over actions such as edit, save, and backup. * * You should use custom text based editors when dealing with binary files or more complex scenarios. For simple text @@ -1321,20 +1321,22 @@ declare module 'vscode' { */ export interface CustomEditorProvider { /** - * Create the model for a given + * Resolve the model for a given resource. * - * @param document Resource being resolved. + * @param document Document to resolve. + * + * @return The capabilities of the resolved document. */ resolveCustomDocument(document: CustomDocument): Thenable; /** * Resolve a webview editor for a given resource. * - * To resolve a webview editor, a provider must fill in its initial html content and hook up all + * To resolve a webview editor, the provider must fill in its initial html content and hook up all * the event listeners it is interested it. The provider should also take ownership of the passed in `WebviewPanel`. * - * @param document Document for resource being resolved. - * @param webviewPanel Webview being resolved. The provider should take ownership of this webview. + * @param document Document for the resource being resolved. + * @param webviewPanel Webview to resolve. The provider should take ownership of this webview. * * @return Thenable indicating that the webview editor has been resolved. */ @@ -1349,7 +1351,7 @@ declare module 'vscode' { * undo and backup. The provider is responsible for synchronizing text changes between the webview and the `TextDocument`. * * You should use text based webview editors when dealing with text based file formats, such as `xml` or `json`. - * For binary files or more specialized use cases, see [WebviewCustomEditorProvider](#WebviewCustomEditorProvider). + * For binary files or more specialized use cases, see [CustomEditorProvider](#CustomEditorProvider). */ export interface CustomTextEditorProvider { /** @@ -1359,7 +1361,7 @@ declare module 'vscode' { * the event listeners it is interested it. The provider should also take ownership of the passed in `WebviewPanel`. * * @param document Resource being resolved. - * @param webviewPanel Webview being resolved. The provider should take ownership of this webview. + * @param webviewPanel Webview to resolve. The provider should take ownership of this webview. * * @return Thenable indicating that the webview editor has been resolved. */ From 027da88563a9551046782b599a7b67788b3d43d9 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 26 Feb 2020 16:03:10 -0800 Subject: [PATCH 088/235] Use constant --- .../src/features/fileConfigurationManager.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/extensions/typescript-language-features/src/features/fileConfigurationManager.ts b/extensions/typescript-language-features/src/features/fileConfigurationManager.ts index cad4e5196b9..825a3049cba 100644 --- a/extensions/typescript-language-features/src/features/fileConfigurationManager.ts +++ b/extensions/typescript-language-features/src/features/fileConfigurationManager.ts @@ -7,9 +7,10 @@ import * as vscode from 'vscode'; import type * as Proto from '../protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; import API from '../utils/api'; +import { Disposable } from '../utils/dispose'; +import * as fileSchemes from '../utils/fileSchemes'; import { isTypeScriptDocument } from '../utils/languageModeIds'; import { ResourceMap } from '../utils/resourceMap'; -import { Disposable } from '../utils/dispose'; function objsAreEqual(a: T, b: T): boolean { @@ -185,7 +186,7 @@ export default class FileConfigurationManager extends Disposable { return { quotePreference: this.getQuoteStylePreference(config), importModuleSpecifierPreference: getImportModuleSpecifierPreference(config), - allowTextChangesInNewFiles: document.uri.scheme === 'file', + allowTextChangesInNewFiles: document.uri.scheme === fileSchemes.file, providePrefixAndSuffixTextForRename: config.get('renameShorthandProperties', true), allowRenameOfImportPath: true, }; From e4beca6b31a6d991322069896294d448637b57bb Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 26 Feb 2020 16:03:40 -0800 Subject: [PATCH 089/235] Remove TS 3.7 protocol workaround --- .../src/features/fileConfigurationManager.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/extensions/typescript-language-features/src/features/fileConfigurationManager.ts b/extensions/typescript-language-features/src/features/fileConfigurationManager.ts index 825a3049cba..4a625231458 100644 --- a/extensions/typescript-language-features/src/features/fileConfigurationManager.ts +++ b/extensions/typescript-language-features/src/features/fileConfigurationManager.ts @@ -145,9 +145,7 @@ export default class FileConfigurationManager extends Disposable { isTypeScriptDocument(document) ? 'typescript.format' : 'javascript.format', document.uri); - // `semicolons` added to `Proto.FormatCodeSettings` in TypeScript 3.7: - // remove intersection type after upgrading TypeScript. - const settings: Proto.FormatCodeSettings & { semicolons?: string } = { + return { tabSize: options.tabSize, indentSize: options.tabSize, convertTabsToSpaces: options.insertSpaces, @@ -170,8 +168,6 @@ export default class FileConfigurationManager extends Disposable { placeOpenBraceOnNewLineForControlBlocks: config.get('placeOpenBraceOnNewLineForControlBlocks'), semicolons: config.get('semicolons'), }; - - return settings; } private getPreferences(document: vscode.TextDocument): Proto.UserPreferences { From 24aeb687f73773be5c539e93f2e21d0f56d00edb Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Wed, 26 Feb 2020 16:10:13 -0800 Subject: [PATCH 090/235] Add rerun action and icon. Close #91508. --- .../contrib/searchEditor/browser/constants.ts | 2 ++ .../browser/searchEditor.contribution.ts | 30 +++++++++++-------- .../searchEditor/browser/searchEditor.ts | 4 +-- .../browser/searchEditorActions.ts | 18 +++++++++++ 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/contrib/searchEditor/browser/constants.ts b/src/vs/workbench/contrib/searchEditor/browser/constants.ts index 3de68eda5a0..7de8978e745 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/constants.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/constants.ts @@ -22,3 +22,5 @@ export const SearchEditorScheme = 'search-editor'; export const SearchEditorBodyScheme = 'search-editor-body'; export const SearchEditorFindMatchClass = 'seaarchEditorFindMatch'; + +export const SearchEditorID = 'workbench.editor.searchEditor'; diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts index 57b857a860d..eb2646630b4 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts @@ -9,7 +9,7 @@ import { endsWith } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { ToggleCaseSensitiveKeybinding, ToggleRegexKeybinding, ToggleWholeWordKeybinding } from 'vs/editor/contrib/find/findModel'; import { localize } from 'vs/nls'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -20,11 +20,11 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { EditorDescriptor, Extensions as EditorExtensions, IEditorRegistry } from 'vs/workbench/browser/editor'; import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; -import { Extensions as EditorInputExtensions, IEditorInputFactory, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor'; +import { Extensions as EditorInputExtensions, IEditorInputFactory, IEditorInputFactoryRegistry, ActiveEditorContext } from 'vs/workbench/common/editor'; import * as SearchConstants from 'vs/workbench/contrib/search/common/constants'; import * as SearchEditorConstants from 'vs/workbench/contrib/searchEditor/browser/constants'; import { SearchEditor } from 'vs/workbench/contrib/searchEditor/browser/searchEditor'; -import { OpenResultsInEditorAction, OpenSearchEditorAction, toggleSearchEditorCaseSensitiveCommand, toggleSearchEditorContextLinesCommand, toggleSearchEditorRegexCommand, toggleSearchEditorWholeWordCommand, selectAllSearchEditorMatchesCommand } from 'vs/workbench/contrib/searchEditor/browser/searchEditorActions'; +import { OpenResultsInEditorAction, OpenSearchEditorAction, toggleSearchEditorCaseSensitiveCommand, toggleSearchEditorContextLinesCommand, toggleSearchEditorRegexCommand, toggleSearchEditorWholeWordCommand, selectAllSearchEditorMatchesCommand, RerunSearchEditorSearchAction } from 'vs/workbench/contrib/searchEditor/browser/searchEditorActions'; import { getOrMakeSearchEditorInput, SearchEditorInput } from 'vs/workbench/contrib/searchEditor/browser/searchEditorInput'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; @@ -159,15 +159,6 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ handler: selectAllSearchEditorMatchesCommand }); -CommandsRegistry.registerCommand( - SearchEditorConstants.RerunSearchEditorSearchCommandId, - (accessor: ServicesAccessor) => { - const activeControl = accessor.get(IEditorService).activeControl; - if (activeControl instanceof SearchEditor) { - activeControl.triggerSearch({ resetCursor: false }); - } - }); - CommandsRegistry.registerCommand( SearchEditorConstants.CleanSearchEditorStateCommandId, (accessor: ServicesAccessor) => { @@ -191,4 +182,19 @@ registry.registerWorkbenchAction( registry.registerWorkbenchAction( SyncActionDescriptor.create(OpenSearchEditorAction, OpenSearchEditorAction.ID, OpenSearchEditorAction.LABEL), 'Search Editor: Open New Search Editor', category); + +registry.registerWorkbenchAction(SyncActionDescriptor.create(RerunSearchEditorSearchAction, RerunSearchEditorSearchAction.ID, RerunSearchEditorSearchAction.LABEL, + { mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_R } }, ContextKeyExpr.and(SearchEditorConstants.InSearchEditor)), + 'Search Editor: Rerun', category); //#endregion + + +MenuRegistry.appendMenuItem(MenuId.EditorTitle, { + command: { + id: RerunSearchEditorSearchAction.ID, + title: RerunSearchEditorSearchAction.LABEL, + icon: { id: 'codicon/refresh' }, + }, + group: 'navigation', + when: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(SearchEditorConstants.SearchEditorID)) +}); diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts index a32b0f8fc23..523e97cdac5 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.ts @@ -35,7 +35,7 @@ import { InputBoxFocusedKey } from 'vs/workbench/contrib/search/common/constants import { ITextQueryBuilderOptions, QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder'; import { getOutOfWorkspaceEditorResources } from 'vs/workbench/contrib/search/common/search'; import { SearchModel } from 'vs/workbench/contrib/search/common/searchModel'; -import { InSearchEditor, SearchEditorFindMatchClass } from 'vs/workbench/contrib/searchEditor/browser/constants'; +import { InSearchEditor, SearchEditorFindMatchClass, SearchEditorID } from 'vs/workbench/contrib/searchEditor/browser/constants'; import type { SearchConfiguration, SearchEditorInput } from 'vs/workbench/contrib/searchEditor/browser/searchEditorInput'; import { extractSearchQuery, serializeSearchConfiguration, serializeSearchResultForEditor } from 'vs/workbench/contrib/searchEditor/browser/searchEditorSerialization'; import { IPatternInfo, ISearchConfigurationProperties, ITextQuery } from 'vs/workbench/services/search/common/search'; @@ -56,7 +56,7 @@ const FILE_LINE_REGEX = /^(\S.*):$/; type SearchEditorViewState = ICodeEditorViewState & { focused: 'input' | 'editor' }; export class SearchEditor extends BaseTextEditor { - static readonly ID: string = 'workbench.editor.searchEditor'; + static readonly ID: string = SearchEditorID; static readonly SEARCH_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'searchEditorViewState'; diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditorActions.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditorActions.ts index 094acf25fd3..464d2bb6e51 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditorActions.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditorActions.ts @@ -116,6 +116,24 @@ export class OpenResultsInEditorAction extends Action { } } +export class RerunSearchEditorSearchAction extends Action { + static readonly ID: string = Constants.RerunSearchEditorSearchCommandId; + static readonly LABEL = localize('search.rerunSearchInEditor', "Search Again"); + + constructor(id: string, label: string, + @IEditorService private readonly editorService: IEditorService, + ) { + super(id, label, 'codicon-refresh'); + } + + async run() { + const input = this.editorService.activeEditor; + if (input instanceof SearchEditorInput) { + (this.editorService.activeControl as SearchEditor).triggerSearch({ resetCursor: false }); + } + } +} + const openNewSearchEditor = async (accessor: ServicesAccessor) => { const editorService = accessor.get(IEditorService); From 20c071dd266f2526db347819191979186c12ac17 Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Wed, 26 Feb 2020 16:17:46 -0800 Subject: [PATCH 091/235] fixes #91630 --- src/vs/workbench/browser/parts/compositeBar.ts | 15 ++++++++++++--- src/vs/workbench/browser/parts/panel/panelPart.ts | 3 ++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index f7f3e18a1b3..ab90e89569c 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -24,6 +24,7 @@ import { DraggedViewIdentifier } from 'vs/workbench/browser/parts/views/viewPane import { Registry } from 'vs/platform/registry/common/platform'; import { IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainerLocation, IViewDescriptorService } from 'vs/workbench/common/views'; import { ICompositeDragAndDrop, CompositeDragAndDropData } from 'vs/base/parts/composite/browser/compositeDnd'; +import { IPaneComposite } from 'vs/workbench/common/panecomposite'; export interface ICompositeBarItem { id: string; @@ -38,7 +39,7 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop { constructor( private viewDescriptorService: IViewDescriptorService, private targetContainerLocation: ViewContainerLocation, - private openComposite: (id: string, focus?: boolean) => void, + private openComposite: (id: string, focus?: boolean) => Promise, private moveComposite: (from: string, to: string) => void, private getVisibleCompositeIds: () => string[] ) { } @@ -76,7 +77,11 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop { if (destinationContainer && !destinationContainer.rejectAddedViews) { if (this.targetContainerLocation === ViewContainerLocation.Sidebar) { this.viewDescriptorService.moveViewsToContainer([viewDescriptor], destinationContainer); - this.openComposite(targetCompositeId, true); + this.openComposite(targetCompositeId, true).then(composite => { + if (composite) { + composite.openView(viewDescriptor.id, true); + } + }); } else { this.viewDescriptorService.moveViewToLocation(viewDescriptor, this.targetContainerLocation); this.moveComposite(this.viewDescriptorService.getViewContainer(viewDescriptor.id)!.id, targetCompositeId); @@ -91,7 +96,11 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop { this.moveComposite(newCompositeId, targetId); } - this.openComposite(newCompositeId, true); + this.openComposite(newCompositeId, true).then(composite => { + if (composite) { + composite.openView(viewDescriptor.id, true); + } + }); } } } diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index e8126ec13e1..a73f42b53f0 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -36,6 +36,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { ViewContainer, IViewContainersRegistry, Extensions as ViewContainerExtensions, IViewDescriptorService, IViewDescriptorCollection, ViewContainerLocation } from 'vs/workbench/common/views'; import { MenuId } from 'vs/platform/actions/common/actions'; import { ViewMenuActions } from 'vs/workbench/browser/parts/views/viewMenuActions'; +import { IPaneComposite } from 'vs/workbench/common/panecomposite'; interface ICachedPanel { id: string; @@ -143,7 +144,7 @@ export class PanelPart extends CompositePart implements IPanelService { getDefaultCompositeId: () => this.panelRegistry.getDefaultPanelId(), hidePart: () => this.layoutService.setPanelHidden(true), dndHandler: new CompositeDragAndDrop(this.viewDescriptorService, ViewContainerLocation.Panel, - (id: string, focus?: boolean) => this.openPanel(id, focus), + (id: string, focus?: boolean) => this.openPanel(id, focus) as Promise, (from: string, to: string) => this.compositeBar.move(from, to), () => this.getPinnedPanels().map(p => p.id) ), From e63119f785ae89239ee85ad40d40bfc0a166e36a Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 26 Feb 2020 16:24:15 -0800 Subject: [PATCH 092/235] Fix #90538 --- test/smoke/src/areas/css/css.test.ts | 43 ---------------------------- test/smoke/src/main.ts | 1 - 2 files changed, 44 deletions(-) delete mode 100644 test/smoke/src/areas/css/css.test.ts diff --git a/test/smoke/src/areas/css/css.test.ts b/test/smoke/src/areas/css/css.test.ts deleted file mode 100644 index aa6ccb9590b..00000000000 --- a/test/smoke/src/areas/css/css.test.ts +++ /dev/null @@ -1,43 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Application, ProblemSeverity, Problems } from '../../../../automation'; - -export function setup() { - describe('CSS', () => { - it('verifies quick outline', async function () { - const app = this.app as Application; - await app.workbench.quickopen.openFile('style.css'); - - await app.workbench.quickopen.openQuickOutline(); - await app.workbench.quickopen.waitForQuickOpenElements(names => names.length === 2); - }); - - it('verifies warnings for the empty rule', async function () { - const app = this.app as Application; - await app.workbench.quickopen.openFile('style.css'); - await app.workbench.editor.waitForTypeInEditor('style.css', '.foo{}'); - - await app.code.waitForElement(Problems.getSelectorInEditor(ProblemSeverity.WARNING)); - - await app.workbench.problems.showProblemsView(); - await app.code.waitForElement(Problems.getSelectorInProblemsView(ProblemSeverity.WARNING)); - await app.workbench.problems.hideProblemsView(); - }); - - it('verifies that warning becomes an error once setting changed', async function () { - const app = this.app as Application; - await app.workbench.settingsEditor.addUserSetting('css.lint.emptyRules', '"error"'); - await app.workbench.quickopen.openFile('style.css'); - - await app.code.waitForElement(Problems.getSelectorInEditor(ProblemSeverity.ERROR)); - - const problems = new Problems(app.code); - await problems.showProblemsView(); - await app.code.waitForElement(Problems.getSelectorInProblemsView(ProblemSeverity.ERROR)); - await problems.hideProblemsView(); - }); - }); -} diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index a1273ba379d..a7eec01dacc 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -25,7 +25,6 @@ import { setup as setupDataMigrationTests } from './areas/workbench/data-migrati import { setup as setupDataLossTests } from './areas/workbench/data-loss.test'; import { setup as setupDataPreferencesTests } from './areas/preferences/preferences.test'; import { setup as setupDataSearchTests } from './areas/search/search.test'; -import { setup as setupDataCSSTests } from './areas/css/css.test'; import { setup as setupDataEditorTests } from './areas/editor/editor.test'; import { setup as setupDataStatusbarTests } from './areas/statusbar/statusbar.test'; import { setup as setupDataExtensionTests } from './areas/extensions/extensions.test'; From 8510f53b59582cccc267c335150b518ae2a97a63 Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Wed, 26 Feb 2020 16:24:51 -0800 Subject: [PATCH 093/235] refs #91630 --- src/vs/workbench/browser/parts/compositeBar.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index ab90e89569c..9598c3c1c32 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -54,8 +54,13 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop { if (currentLocation !== this.targetContainerLocation && this.targetContainerLocation !== ViewContainerLocation.Panel) { const destinationContainer = viewContainerRegistry.get(targetCompositeId); if (destinationContainer && !destinationContainer.rejectAddedViews) { - this.viewDescriptorService.moveViewsToContainer(this.viewDescriptorService.getViewDescriptors(currentContainer)!.allViewDescriptors.filter(vd => vd.canMoveView), destinationContainer); - this.openComposite(targetCompositeId, true); + const viewsToMove = this.viewDescriptorService.getViewDescriptors(currentContainer)!.allViewDescriptors.filter(vd => vd.canMoveView); + this.viewDescriptorService.moveViewsToContainer(viewsToMove, destinationContainer); + this.openComposite(targetCompositeId, true).then(composite => { + if (composite && viewsToMove.length === 1) { + composite.openView(viewsToMove[0].id, true); + } + }); } } else { this.moveComposite(dragData.id, targetCompositeId); From 7f1f3981cef74c2fd41b864ddecdb506579723be Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Wed, 26 Feb 2020 16:32:24 -0800 Subject: [PATCH 094/235] Flip result/file counts. --- .../contrib/searchEditor/browser/searchEditorSerialization.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditorSerialization.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditorSerialization.ts index 389faee3931..038519308e4 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditorSerialization.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditorSerialization.ts @@ -216,7 +216,7 @@ export const serializeSearchResultForEditor = const info = [ searchResult.count() - ? `${filecount} - ${resultcount}` + ? `${resultcount} - ${filecount}` : localize('noResults', "No Results"), '']; From b8de1ad5264ef1f7b8e0f56caa026becac39bbd5 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 26 Feb 2020 16:44:48 -0800 Subject: [PATCH 095/235] Fix #91300 --- src/vs/editor/contrib/suggest/media/suggest.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index 821cb7d2623..875769452fa 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -392,6 +392,10 @@ word-wrap: break-word; } +.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .docs.markdown-docs .codicon { + vertical-align: sub; +} + .monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > p:empty { display: none; } From 3c1e64220f137f9f4710841022b9d58e654e9f01 Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Wed, 26 Feb 2020 17:13:11 -0800 Subject: [PATCH 096/235] Fixes #91384 --- .../electron-browser/processExplorer/processExplorerMain.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vs/code/electron-browser/processExplorer/processExplorerMain.ts b/src/vs/code/electron-browser/processExplorer/processExplorerMain.ts index 09ccca9b823..9684cbd4c20 100644 --- a/src/vs/code/electron-browser/processExplorer/processExplorerMain.ts +++ b/src/vs/code/electron-browser/processExplorer/processExplorerMain.ts @@ -75,7 +75,11 @@ function getProcessItem(processes: FormattedProcessItem[], item: ProcessItem, in // Recurse into children if any if (Array.isArray(item.children)) { - item.children.forEach(child => getProcessItem(processes, child, indent + 1, isLocal)); + item.children.forEach(child => { + if (child) { + getProcessItem(processes, child, indent + 1, isLocal); + } + }); } } From db380eaad006fec0c7a205ed33a0fc50ada6a723 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 26 Feb 2020 17:29:55 -0800 Subject: [PATCH 097/235] Fix build --- test/smoke/src/main.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index a7eec01dacc..fc1f4e5569f 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -301,7 +301,6 @@ describe(`VSCode Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => { if (!opts.web) { setupDataLossTests(); } if (!opts.web) { setupDataPreferencesTests(); } setupDataSearchTests(); - setupDataCSSTests(); setupDataEditorTests(); setupDataStatusbarTests(!!opts.web); if (!opts.web) { setupDataExtensionTests(); } From 61538b5e3e2674e449a28e328210fb5030435fc3 Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Wed, 26 Feb 2020 17:34:34 -0800 Subject: [PATCH 098/235] only set drop target background for valid tgt --- src/vs/base/parts/composite/browser/compositeDnd.ts | 1 + src/vs/workbench/browser/parts/compositeBar.ts | 10 ++++++++-- src/vs/workbench/browser/parts/compositeBarActions.ts | 6 ++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/vs/base/parts/composite/browser/compositeDnd.ts b/src/vs/base/parts/composite/browser/compositeDnd.ts index ca8b52d491a..6091c8a10d3 100644 --- a/src/vs/base/parts/composite/browser/compositeDnd.ts +++ b/src/vs/base/parts/composite/browser/compositeDnd.ts @@ -21,4 +21,5 @@ export class CompositeDragAndDropData implements IDragAndDropData { export interface ICompositeDragAndDrop { drop(data: IDragAndDropData, target: string | undefined, originalEvent: DragEvent): void; onDragOver(data: IDragAndDropData, target: string | undefined, originalEvent: DragEvent): boolean; + onDragEnter(data: IDragAndDropData, target: string | undefined, originalEvent: DragEvent): boolean; } diff --git a/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index 9598c3c1c32..a77472da253 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -111,7 +111,15 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop { } } + onDragEnter(data: CompositeDragAndDropData, targetCompositeId: string | undefined, originalEvent: DragEvent): boolean { + return this.canDrop(data, targetCompositeId); + } + onDragOver(data: CompositeDragAndDropData, targetCompositeId: string | undefined, originalEvent: DragEvent): boolean { + return this.canDrop(data, targetCompositeId); + } + + private canDrop(data: CompositeDragAndDropData, targetCompositeId: string | undefined): boolean { const dragData = data.getData(); const viewContainerRegistry = Registry.as(ViewContainerExtensions.ViewContainersRegistry); @@ -173,8 +181,6 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop { const destinationContainer = viewContainerRegistry.get(targetCompositeId); return !!destinationContainer && !destinationContainer.rejectAddedViews; } - - return false; } } diff --git a/src/vs/workbench/browser/parts/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositeBarActions.ts index c4eb0fbc8ed..399b868395a 100644 --- a/src/vs/workbench/browser/parts/compositeBarActions.ts +++ b/src/vs/workbench/browser/parts/compositeBarActions.ts @@ -544,14 +544,16 @@ export class CompositeActionViewItem extends ActivityActionViewItem { if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) { const data = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype); if (Array.isArray(data) && data[0].id !== this.activity.id) { - this.updateFromDragging(container, true); + const validDropTarget = this.dndHandler.onDragOver(new CompositeDragAndDropData('composite', data[0].id), this.activity.id, e); + this.updateFromDragging(container, validDropTarget); } } if (this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) { const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype); if (Array.isArray(data) && data[0].id !== this.activity.id) { - this.updateFromDragging(container, true); + const validDropTarget = this.dndHandler.onDragOver(new CompositeDragAndDropData('view', data[0].id), this.activity.id, e); + this.updateFromDragging(container, validDropTarget); } } }, From 6f15da251fffbc5a45fafa3971d9aa06d7ff7773 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 26 Feb 2020 17:36:35 -0800 Subject: [PATCH 099/235] Only add new separator when SyncSettingAction is present --- .../workbench/contrib/preferences/browser/settingsTree.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts index dedf95bbe56..bae1aee1cd5 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts @@ -1205,7 +1205,6 @@ export class SettingTreeRenderers { new Separator(), this._instantiationService.createInstance(CopySettingIdAction), this._instantiationService.createInstance(CopySettingAsJSONAction), - new Separator(), ]; const actionFactory = (setting: ISetting) => this.getActionsForSetting(setting); @@ -1239,7 +1238,10 @@ export class SettingTreeRenderers { private getActionsForSetting(setting: ISetting): IAction[] { const enableSync = this._userDataSyncEnablementService.isEnabled(); return enableSync && !setting.disallowSyncIgnore ? - [this._instantiationService.createInstance(SyncSettingAction, setting)] : + [ + new Separator(), + this._instantiationService.createInstance(SyncSettingAction, setting) + ] : []; } From 8c168ae86df8f1d1578a0ca9aa720219e0661cca Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 26 Feb 2020 17:47:06 -0800 Subject: [PATCH 100/235] Fix #89933 --- src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts index abd5d1d00fe..fd2523ba4d9 100644 --- a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts +++ b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts @@ -856,6 +856,7 @@ export class ResourceDragAndDrop implements ITreeDragAndDrop { registerThemingParticipant((theme, collector) => { const linkFg = theme.getColor(textLinkForeground); if (linkFg) { - collector.addRule(`.markers-panel .markers-panel-container .tree-container .monaco-tl-contents .details-container a.code-link span:hover { color: ${linkFg}; }`); + collector.addRule(`.markers-panel .markers-panel-container .tree-container .monaco-tl-contents .details-container a.code-link .marker-code > span:hover { color: ${linkFg}; }`); + collector.addRule(`.markers-panel .markers-panel-container .tree-container .monaco-list:focus .monaco-tl-contents .details-container a.code-link .marker-code > span:hover { color: ${linkFg.lighten(.4)}; }`); } }); From 0eebaf9ad23748baca2afc0da425650922bc23de Mon Sep 17 00:00:00 2001 From: Miguel Solorio Date: Wed, 26 Feb 2020 19:55:11 -0800 Subject: [PATCH 101/235] Update Codicons: add bell-progress (ref #91469) --- .../ui/codiconLabel/codicon/codicon.css | 7 ++++--- .../ui/codiconLabel/codicon/codicon.ttf | Bin 57012 -> 57380 bytes 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css index 41efce5c63d..b71ef2dafa5 100644 --- a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css +++ b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css @@ -5,7 +5,7 @@ @font-face { font-family: "codicon"; - src: url("./codicon.ttf?279add2ec8b3d516ca20a123230cbf9f") format("truetype"); + src: url("./codicon.ttf?b5dd8f5aa953889dc1f4c9fa9b44d3dd") format("truetype"); } .codicon[class*='codicon-'] { @@ -415,5 +415,6 @@ .codicon-group-by-ref-type:before { content: "\eb97" } .codicon-ungroup-by-ref-type:before { content: "\eb98" } .codicon-bell-dot:before { content: "\f101" } -.codicon-debug-alt-2:before { content: "\f102" } -.codicon-debug-alt:before { content: "\f103" } +.codicon-bell-progress:before { content: "\f102" } +.codicon-debug-alt-2:before { content: "\f103" } +.codicon-debug-alt:before { content: "\f104" } diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf index df86f7d4d9a21847df1652c1782ecf6f8aa0eddb..845205f5b3a4132caa8bdf4b586532cfb8a1cd19 100644 GIT binary patch delta 5308 zcmYM%33$}ixd!m}WI{HwlYN~mBq1aOLYP1d5JG?uAjBX6sUkZO6G1>kLD#{Fx49sA3^1Djw9W0Dy~Le7a~cSH9Y|ciu;cCp9}Spx6v*5KbeFZypFJ-vEaw1U z%hw>#&L_hE*ejj)_fcVc=kk@i{k#Wr76?7wv3Tz6&fF*Y{poc;NJr=Fl}kce@D{(G z#uxc-pWQh>@1=}U_W|#n;0vObEMB(!!Do}IfcN)_o?q=K8`?$_bmVMd(4oo9P_FP-F?)Y4ShT$w5unq&yWk( zej-B7!*}go8EX{ayMWLT?{mcSzYnk*>?Zq;Yj&I6wu_-%Ux!r(e~7=}Bp$#KlZ0R4 zGIrw&RGD%(T*PNsgd)6++1P>~qulgC8)8fumSZmdh+p7!ykWBNDDK5~5ilW`ZxZnp zo-z^m+C-TI6K%rqkTE8f@5zTy^g3 z6=}#s7P66pT=ir?O2Q@xC2YE40mD$?!rpkja9e@ ztFZ<_tmSL&!#doL2eBR-un`Yq6CS~4Jch^7g(t8T-^VsQiKp;CcpCqUAK)20i|zOk zUc^h-iCy>!UdB)H3cAsQpJ5MPtHECUoJ;LZ{1W?d0KdjT{D#Zv5Z=MN_$?0OJ-m;j zIELTh_c)F}-~*h%pYUg#>iQ%iJ!tU>KE(z66PNHWe2y#lH~xb!@eRJkRRiNQp{AD! zH<6~di7{~|*`%0MlV;LQhRHP9CdcF&zsWQCrqJ{?MW)!4n0}_z^fv=cg&AlDnMyO* zRN*;1j~B25qfn2Dn1p7GG4Ys?gBFZOIx_Go7UDL1&lDgQakvh(T&ZEtKO4y<0bXkU zi{0kk^65a=D^aOjc(8MXOAvOha52Kp6D~{G`GO;?3xrD*cA;?5!nO;SFYK+tg$%n$ zxTIlk6L2Tm4j|~=aGk?;3RgVr?ZUMWyI8mjV3!E@1MD5bodLU4xJO`@33m(Za^b## zy;Hb@U{?srxt{D@d_de*uq%Zd4EAn84C^Z4rh~mlxcy*P3pXO{y}~UCyGFPN~p18AN9~1;w*9&($toJp7cZoKLce(9GVK0Dv zShy!(HwpU#?9JXUBz(=fSqxj2eN0RO>*HdgS-XTS1=jns5*}iGLX2VEDkiqeAMb_D8~g1pA_}Gr_(j>`|~gh209)yQsvz1-nbw!C-&l ztuWrOnZdp+Y-_MT6*f57SA?w&_ElligY6c!KiJ*EMhM#@Y>BWx6E;WKJpw=LYr=-f z73N)eV(*0Yt~{}e!tNFJQ`nyiJ1guyVULAcOAV}pkMwXjvg9uzih*xv}-H|$%&Mh^S7u%*Ku5;k|(cZ6*o_OP(w!@ehM{jf)b zLx9Wweclk~0qjxXWPm*;oDs0U6HW`*-wWpk>~Y})f&GJUmcV`>oGP&1ek0Bo*b~A@ z1N$cla_GRG6pkO*KMMyD>?z?$g8hqdIKh4>98<7=6%H)e)56gO`#0ebgFPdd#rk*Q zV1qsDUH`Luck}q*AA$v}=Y(Sq_9Ni{ggq}Dg|HtB2Og{yjz?H09F(x12uCLDr^4Y0 zdqJ?2*WdnAI8k9g6V6uHi^3@jdr3HNVgDtZys(#rGZ^-B;WUQ5BAm;x{}xVY*e`^$ z8umXF_XH%J)u;3|co4{oq9{=roVgCN`xVI+hL2*V*jfXOj`r~Sjc3^tP=(2StkiTW(_v;hG1D+glQS> zdSPycYZWGFxGBOc4R?buRl`jc=4-e%VbX@1Cd}M$(}n39?nVhRh{MegMsm3C2*Wwt zO~RNCceCIs>r63x-|iMMKGs=cLRn{v>BTxnOgQUYF_El1+ITlGUc;C#CWdu^m^jvj zVvD@Sp~_S$JfFdt7*UgXM}(oe;aq z(({5ReO0~%z5~9qp(UXQLeKV^+3Q5uj_|eN=fl5^m>4l9Vr9f55!)l)iZ~TvBV!|L zBNs*XL{&z$M;+)L(mSj7y58rbW25V%S4HoQJ`*!5W^GJ&%>LNs*nM&NaoggK#$Abz zkI#>x{D|JWe>9nG>jcF&+8`ED*KbKLLu{Sd+ zb7tm_ti-J5taVx2vn#XPvR7q4oqZ{1K+e3J4|6x=p7xje_vAI_eVIQZ|4PBW!sf!Q zg*yu`_s!}%r*H6ZQEX9N(IZ8di%W~w6@OS#S+cgIr(blxBc-9GD@xDyZ|J|Fe|MR` zthVf?^62uC@|N-q<(CKSsEDW-QL(6EbH(0@3j^m2Ts?5tz)ORM4q7#+XOOMTs%))% zs`A~z(+9s&)l>D^kXb_x1`tRJGzGQ!}@BJH7Vw@XF!4Mr4dwGUD(^jI15Gy)L$HWnFjOsZm*@7LD36>TrEj{qp+P zN0*G=G5S)&s)l_H-;P-{X3yBb*coG2kJ~iv-Erp{6B`4K9gTa&cZ}aU{zQ|%sj+Ew z)Apt_6JDHfZerHN_K9026;7HnY4XYDu;zy5LzBZMw@ltP*|sFL%xl@&(tUl>^~+mJ zTRU3Uv~F&FuC-@M&XfgHelg|J4UIP(oti&&`qZbVo^PvZo7MI}+rhRkrmdRx^z`M^ z58arudt2tMp~+!fc<}A??c}Mhktu!#b8u%@eD3(d)Ie2ncuG=uadlBxcxs?BwO3Vj zYFJWgc+rs5@RZ8x;;{VUuDQ9R^VVnh{Z+}y2?-TTD++Qa=3YfEA6EJ2|M!Wm?%eu< zjQ>7*JHv0h7qkz%_UeL)Ve2w-y(iG^f8k{_WcQ9E?I9r{fv(tNKaP!=Gryywe96+q Q3zyDcwruws$G(dGKW`nJnE(I) delta 5119 zcmYM%4Sde!9tQC1-ZR_meY1_d7_%8>#%3F4W|+Ls`%8K=FKfwLXd(3=m9%PENu7?< zk)%=yITDhjbV^G?l2nrJTSBG6;aq>$`Fswa@ALaVvw5Cp|NH*^u6y-P-=^)p+H`+C zU}^x2nlQCu#-UwtF9JcEfY>>=PMKTTYf#M!Aeq)5ubNabvGK22oB6%Rsj!M)2tL%H z39q+NM%C2Wb6)SvE0_~NVEvTo6Dqp+!}+s`*+9VLsTFf(1PsO={=4@x&8JmNos{-c zQjdke$8-1%p);n>n*Dg*=)J(c#Xxks$G4?-&xi5;L%_bYJN1^R;@=VGJLSE`ky$hU z_WOq@olU(Cj#rX1T`u+eeJ(Pz)AS7U1hU|0>0A- z4A{yaisoM*Uu=o3v3p&)t92{R`IZHD@~^~Ee2M$;iD`tL_!S%Q2RfQ;Se(T#xD74& zxyGRmFC*K;Vk9C=Tg<|E9K?3~3tLPw9>sh-fC6JM(Zt{)o;Ja_WEz@i6J{DVxC`nP`R9XoD=Y zMLXo6Jvty4dB{g0I-xVVpf|2VAM`^xhF~a$VK_!$6h>nVuE$v1fE#fWZpJOBzywUf zt*FB7n1ZR8hUu7rJ1`ToaVM&A7v^9t=HYJKgL~oU_bk9dKNevz?#F|82utxW9>HU% z#p76pC-5Ye<0-7b(|87d!?XB1{(8n0~@gkZ(=jv!dAS^ zb+rTU;9cy(d)STl@c}->UVMaq<74c@r>Mtg*pJU~0AXL?5Dw!AzQWgaXF?MF4yW-m z&fpx*<2U?{3-}X%;WGY%E4XR`jL!s`AQNIjO}L3PaVFj*n8v1wNi<0&#WXdkrkQDO z(oDL^FfC1{X=PfQHYUroGdZTc>0okAp6Q5xVii{71(c!(24Eltq0B^~KL#hDFPb0` z>rsixs4*=Ni6V5}_*}yX|iGd7a;6J;ZlU1B>052 zQn)-}Zxt?7*ecjH+yk(8 z2zLYQO!4-+oh95Mu(P>j_yBGe*gJ*W2DVz@z3^Satpv;7;Nhl%ohyi7ohRIAuy+f$ z9PE7I=7YUQxD8?N6>RtO;(xd|VHXItur3ttSJ*|uoeS&zx`}%jmd(k--3)ubz`K>+ zbK(w%eNf=tt|h`<54)87d|(5BeOS0LV7VqdYznZC2`;hLifPFDxR_|xWn#iuz279U zjle!3@Lu#u;roGIE^IQWYaQ{3KZ?(v7xp~Z)xtgl`+~6Jz^)PY9@rO!T?lrquphBC z3p*36cPEKG3icIYw}M?K>|3y}0)Fp-Ee!TGVKak$UD(!O*9#jQ>>Gk4)(ryh4s8^q zuySU3(3JH}K`QHJK{HnGZWEe&YtXyhgf!N-1T9!O2Ruk;eOr*hx=oPDx?R|FVRs0- zFYG(QJ`B54*pXr174~M>T^_DKwrSY+gbf>Zx3G1?zAtRzuzQ5<9QFfYV~71v*y3UL z3Y$Ib$HKM``-yM>!0r={0+1@@3|%D^5L&KuY-#m~_Ldqg;dV80TMBiN(D!36uYa74i#6AmlbZ-iqD_PB6> z!G0?oWw74~hZ^kn!tn-s!n^+`_~|F`$q&Mr2YXUD{a}9-&Oz8y!ifm`lW^|ATH%z0 zb;5ZGds;X-VSg6RP}nnqJ9z)?FT%kJdsaANVb2MNE$n&W*oFO7IDlb)6OLlo--SaN z_JVLc!~P*0)UbaFM>gzVF9i0IT>E5~c}-Zr`X9kU)+@qs4|`QO_`wf< z4I==Y5rzS{0AVbE^9ch2{4S7Bh*<%yfiN||1qt&5T(B@nz=a4i1zba6x_}E6<_x$n zVd8)b7iJH*2w@6=i@b&(cLgt^#OuH=S{PE`VuW!8E>;*^;2H@d3|yQr%)rG9o?}fA z1{}D?!l(n+L>PMD68ZWrk)M7oYmzVt!6geb5nPHe9lve)}S^EgSW9=*Wp0%Ig1Z#i653B-@!;KauZ@4kS3=Vg_ z_!-CH#tMTu+zrBr4tJw4ti#A|`-!oERT#g_uCr@nV8lCx{7Qo#@^F ziA+qPd@@N)IBTVtNY-1$#IaV1iD$h{OakjmpW zF-=)#h)HF=LrgQ)nPQr=&JvTxI$KOS>z!gUSgXafWW7sFChHtAtyt%hpAV)rFXoA9 z!+N)vEY|sAynTC*m>kx7#dzD+`w(QjZM#5BF6%-ud8~_sXC=7%gr_F%|HXVlJV3$S zFFZ=YJs><(!96G_WnCgXXu&-sJaWM;6&}9e9u^+M;A#YAtd9tfW^j*Q!?)d^7mo=B zv(^d^Zg9(lM>x1T;b9K$3E{C0?n&VR4{o{es0a6yzrfS?T9-OpAtVLeop+__`?Z73Du3!xTx`h#wVKOHCdGykXV}d zOj2CZ#H20BNS>0sHu-4sm6V#4^(hBZE;Jq3bV<`4shv|#HY;kjxOsH*wP_>LR$|q$ZRfRJ-ga|#W%i=%m$ScXSDu5M@i{AUcIVjkaqauI-`4(MhoBAvJ1pyPAU86% zEVnv$UG8sr8F?EzhUQ1+_s`#2kXkUdU|PZIf-{9Vh5ZZX6|U^mqElt3i=8Vw*ZaGa zby?hHT~T;ZPEm2!$gWGfZYVA)uIU!kZFaYhN-|5vmMky1(!Hwt{?hQ$!qV!}-KA%G zWcHZYV_(nMo{M^+*T7x}$`Z=Plv-MhB;rrrmyJJ~0rPidbieQNvc=^Nd5Pv5is z^7_r|x2oU4epmVz4+t1gI-q*Mt^sET-aByHp!`9D#|>Ip-lBY5`OD?!2bT?=Hh9P2 zvqQp%OdGOq=;EP!h8`Yjhh82QIc(0box__9A2@u~h^!IwM{F2zVPwydPmJ6;^4O@< vQNu Date: Thu, 27 Feb 2020 08:05:36 +0100 Subject: [PATCH 102/235] Fix #91576 --- src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 3399c0adb64..3769fabc22a 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -522,7 +522,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo quickPick.ok = false; quickPick.customButton = true; if (this.authenticationState.get() === AuthStatus.SignedIn) { - quickPick.customLabel = localize('turn on', "Turn on"); + quickPick.customLabel = localize('turn on', "Turn On"); } else { const displayName = this.authenticationService.getDisplayName(this.userDataSyncStore!.authenticationProviderId); quickPick.description = localize('sign in and turn on sync detail', "Sign in with your {0} account to synchronize your data across devices.", displayName); @@ -680,7 +680,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo type: 'info', message: localize('turn off sync confirmation', "Turn off Sync"), detail: localize('turn off sync detail', "Your settings, keybindings, extensions and UI State will no longer be synced."), - primaryButton: localize('turn off', "Turn off"), + primaryButton: localize('turn off', "Turn Off"), checkbox: { label: localize('turn off sync everywhere', "Turn off sync on all your devices and clear the data from the cloud.") } From b8f6178bea672f076decaef65b7b1a5739d3576a Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Wed, 26 Feb 2020 23:11:29 -0800 Subject: [PATCH 103/235] improve feedback for composite excess area --- .../activitybar/media/activitybarpart.css | 4 + .../workbench/browser/parts/compositeBar.ts | 140 ++++++++++++------ .../browser/parts/compositeBarActions.ts | 4 +- .../browser/parts/panel/media/panelpart.css | 4 + 4 files changed, 105 insertions(+), 47 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css index cbc3d14705b..6e3ff5bf0f4 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css @@ -27,6 +27,10 @@ margin-bottom: auto; } +.monaco-workbench .activitybar > .content > .composite-bar-excess { + height: 100%; +} + .monaco-workbench .activitybar .menubar { width: 100%; height: 35px; diff --git a/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index a77472da253..93102067fa2 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -17,8 +17,8 @@ import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { Widget } from 'vs/base/browser/ui/widget'; import { isUndefinedOrNull } from 'vs/base/common/types'; -import { LocalSelectionTransfer } from 'vs/workbench/browser/dnd'; -import { ITheme } from 'vs/platform/theme/common/themeService'; +import { LocalSelectionTransfer, DragAndDropObserver } from 'vs/workbench/browser/dnd'; +import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService'; import { Emitter } from 'vs/base/common/event'; import { DraggedViewIdentifier } from 'vs/workbench/browser/parts/views/viewPaneContainer'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -222,6 +222,7 @@ export class CompositeBar extends Widget implements ICompositeBar { constructor( items: ICompositeBarItem[], private options: ICompositeBarOptions, + @IThemeService private readonly themeService: IThemeService, @IInstantiationService private readonly instantiationService: IInstantiationService, @IContextMenuService private readonly contextMenuService: IContextMenuService ) { @@ -250,6 +251,7 @@ export class CompositeBar extends Widget implements ICompositeBar { create(parent: HTMLElement): HTMLElement { const actionBarDiv = parent.appendChild($('.composite-bar')); + const excessDiv = parent.appendChild($('.composite-bar-excess')); this.compositeSwitcherBar = this._register(new ActionBar(actionBarDiv, { actionViewItemProvider: (action: IAction) => { @@ -276,58 +278,99 @@ export class CompositeBar extends Widget implements ICompositeBar { this._register(addDisposableListener(parent, EventType.CONTEXT_MENU, e => this.showContextMenu(e))); // Allow to drop at the end to move composites to the end - this._register(addDisposableListener(parent, EventType.DROP, (e: DragEvent) => { - if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) { - EventHelper.stop(e, true); + this._register(new DragAndDropObserver(excessDiv, { + onDragOver: (e: DragEvent) => { + if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) { + EventHelper.stop(e, true); - const data = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype); - if (Array.isArray(data)) { - const draggedCompositeId = data[0].id; - this.compositeTransfer.clearData(DraggedCompositeIdentifier.prototype); + const data = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype); + if (Array.isArray(data)) { + const draggedCompositeId = data[0].id; - this.options.dndHandler.drop(new CompositeDragAndDropData('composite', draggedCompositeId), undefined, e); - } - } - - if (this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) { - const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype); - if (Array.isArray(data)) { - const draggedViewId = data[0].id; - this.compositeTransfer.clearData(DraggedViewIdentifier.prototype); - - this.options.dndHandler.drop(new CompositeDragAndDropData('view', draggedViewId), undefined, e); - } - } - })); - - this._register(addDisposableListener(parent, EventType.DRAG_OVER, (e: DragEvent) => { - if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) { - EventHelper.stop(e, true); - - const data = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype); - if (Array.isArray(data)) { - const draggedCompositeId = data[0].id; - - // Check if drop is allowed - if (e.dataTransfer && !this.options.dndHandler.onDragOver(new CompositeDragAndDropData('composite', draggedCompositeId), undefined, e)) { - e.dataTransfer.dropEffect = 'none'; + // Check if drop is allowed + if (e.dataTransfer && !this.options.dndHandler.onDragOver(new CompositeDragAndDropData('composite', draggedCompositeId), undefined, e)) { + e.dataTransfer.dropEffect = 'none'; + } } } - } - if (this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) { - EventHelper.stop(e, true); + if (this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) { + EventHelper.stop(e, true); - const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype); - if (Array.isArray(data)) { - const draggedViewId = data[0].id; + const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype); + if (Array.isArray(data)) { + const draggedViewId = data[0].id; - // Check if drop is allowed - if (e.dataTransfer && !this.options.dndHandler.onDragOver(new CompositeDragAndDropData('view', draggedViewId), undefined, e)) { - e.dataTransfer.dropEffect = 'none'; + // Check if drop is allowed + if (e.dataTransfer && !this.options.dndHandler.onDragOver(new CompositeDragAndDropData('view', draggedViewId), undefined, e)) { + e.dataTransfer.dropEffect = 'none'; + } } } - } + }, + + onDragEnter: (e: DragEvent) => { + if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) { + EventHelper.stop(e, true); + + const data = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype); + if (Array.isArray(data)) { + const draggedCompositeId = data[0].id; + + // Check if drop is allowed + const validDropTarget = this.options.dndHandler.onDragEnter(new CompositeDragAndDropData('composite', draggedCompositeId), undefined, e); + this.updateFromDragging(excessDiv, validDropTarget); + } + } + + if (this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) { + EventHelper.stop(e, true); + + const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype); + if (Array.isArray(data)) { + const draggedViewId = data[0].id; + + // Check if drop is allowed + const validDropTarget = this.options.dndHandler.onDragEnter(new CompositeDragAndDropData('view', draggedViewId), undefined, e); + this.updateFromDragging(excessDiv, validDropTarget); + } + } + }, + + onDragLeave: (e: DragEvent) => { + if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype) || + this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) { + this.updateFromDragging(excessDiv, false); + } + }, + onDragEnd: (e: DragEvent) => { + // no-op, will not be called + }, + onDrop: (e: DragEvent) => { + if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) { + EventHelper.stop(e, true); + + const data = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype); + if (Array.isArray(data)) { + const draggedCompositeId = data[0].id; + this.compositeTransfer.clearData(DraggedCompositeIdentifier.prototype); + + this.options.dndHandler.drop(new CompositeDragAndDropData('composite', draggedCompositeId), undefined, e); + this.updateFromDragging(excessDiv, false); + } + } + + if (this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) { + const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype); + if (Array.isArray(data)) { + const draggedViewId = data[0].id; + this.compositeTransfer.clearData(DraggedViewIdentifier.prototype); + + this.options.dndHandler.drop(new CompositeDragAndDropData('view', draggedViewId), undefined, e); + this.updateFromDragging(excessDiv, false); + } + } + }, })); return actionBarDiv; @@ -432,6 +475,13 @@ export class CompositeBar extends Widget implements ICompositeBar { } } + private updateFromDragging(element: HTMLElement, isDragging: boolean): void { + const theme = this.themeService.getTheme(); + const dragBackground = this.options.colors(theme).dragAndDropBackground; + + element.style.backgroundColor = isDragging && dragBackground ? dragBackground.toString() : ''; + } + private resetActiveComposite(compositeId: string) { const defaultCompositeId = this.options.getDefaultCompositeId(); diff --git a/src/vs/workbench/browser/parts/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositeBarActions.ts index 399b868395a..f4d2bf15876 100644 --- a/src/vs/workbench/browser/parts/compositeBarActions.ts +++ b/src/vs/workbench/browser/parts/compositeBarActions.ts @@ -544,7 +544,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem { if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) { const data = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype); if (Array.isArray(data) && data[0].id !== this.activity.id) { - const validDropTarget = this.dndHandler.onDragOver(new CompositeDragAndDropData('composite', data[0].id), this.activity.id, e); + const validDropTarget = this.dndHandler.onDragEnter(new CompositeDragAndDropData('composite', data[0].id), this.activity.id, e); this.updateFromDragging(container, validDropTarget); } } @@ -552,7 +552,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem { if (this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) { const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype); if (Array.isArray(data) && data[0].id !== this.activity.id) { - const validDropTarget = this.dndHandler.onDragOver(new CompositeDragAndDropData('view', data[0].id), this.activity.id, e); + const validDropTarget = this.dndHandler.onDragEnter(new CompositeDragAndDropData('view', data[0].id), this.activity.id, e); this.updateFromDragging(container, validDropTarget); } } diff --git a/src/vs/workbench/browser/parts/panel/media/panelpart.css b/src/vs/workbench/browser/parts/panel/media/panelpart.css index abca35a41a7..5ac0818950c 100644 --- a/src/vs/workbench/browser/parts/panel/media/panelpart.css +++ b/src/vs/workbench/browser/parts/panel/media/panelpart.css @@ -62,6 +62,10 @@ } +.monaco-workbench .part.panel > .composite.title > .composite-bar-excess { + width: 100%; +} + .monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar { line-height: 27px; /* matches panel titles in settings */ height: 35px; From 72f07ea1ae71cec5c1444e1a4b37325c6352d36c Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 27 Feb 2020 08:13:27 +0100 Subject: [PATCH 104/235] FIx #89786 --- .../workbench/contrib/extensions/browser/extensionsActions.ts | 2 +- .../extensionManagement/common/extensionManagementService.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index dec8ffa2385..e032e135584 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -2669,7 +2669,7 @@ export class SystemDisabledWarningAction extends ExtensionAction { if (server) { this.tooltip = localize('Install in other server to enable', "Install the extension on '{0}' to enable.", server.label); } else { - this.tooltip = localize('disabled because of extension kind', "This extension cannot be enabled in the remote server."); + this.tooltip = localize('disabled because of extension kind', "This extension has defined that it cannot run on the remote server"); } return; } diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts index 4a07843244d..9f8c6ac6f5e 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts @@ -209,7 +209,7 @@ export class ExtensionManagementService extends Disposable implements IExtension return Promise.reject(localize('Manifest is not found', "Installing Extension {0} failed: Manifest is not found.", gallery.displayName || gallery.name)); } if (!isLanguagePackExtension(manifest) && !canExecuteOnWorkspace(manifest, this.productService, this.configurationService)) { - const error = new Error(localize('cannot be installed', "Cannot install '{0}' extension since it cannot be enabled in the remote server.", gallery.displayName || gallery.name)); + const error = new Error(localize('cannot be installed', "Cannot install '{0}' because this extension has defined that it cannot run on the remote server.", gallery.displayName || gallery.name)); error.name = INSTALL_ERROR_NOT_SUPPORTED; return Promise.reject(error); } From 93aa21cd8ae90b85a08525939ec01b8fae7d6851 Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Wed, 26 Feb 2020 23:19:19 -0800 Subject: [PATCH 105/235] fixes #91367 --- src/vs/workbench/browser/parts/views/viewPaneContainer.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts index bf954530159..21e312a5084 100644 --- a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts +++ b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts @@ -1009,7 +1009,8 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { } if (!this.areExtensionsReady) { if (this.visibleViewsCountFromCache === undefined) { - return true; + // TODO @sbatten fix hack for #91367 + return this.viewDescriptorService.getViewContainerLocation(this.viewContainer) === ViewContainerLocation.Panel; } // Check in cache so that view do not jump. See #29609 return this.visibleViewsCountFromCache === 1; From e9b2ec522862cc2f21e78be05352e9f9debf7e9f Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 27 Feb 2020 08:29:21 +0100 Subject: [PATCH 106/235] fixes #91062 --- src/vs/workbench/contrib/scm/browser/scmViewlet.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts index b78b35610e7..1d3fdd35ad5 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts @@ -44,7 +44,7 @@ export interface ISpliceEvent { export class EmptyPane extends ViewPane { static readonly ID = 'workbench.scm'; - static readonly TITLE = localize('scm providers', "Source Control Providers"); + static readonly TITLE = localize('scm', "Source Control"); constructor( options: IViewPaneOptions, From 50ec1b1b33f81e4f6ba9313407d2f34846991187 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 27 Feb 2020 08:31:09 +0100 Subject: [PATCH 107/235] fixes #91070 --- extensions/git/package.nls.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index 6328edd99bf..e163ffad48d 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -150,11 +150,11 @@ "colors.ignored": "Color for ignored resources.", "colors.conflict": "Color for resources with conflicts.", "colors.submodule": "Color for submodule resources.", - "view.workbench.scm.missing": "A valid git installation was not detected, more details can be found in the [git output](command:git.showOutput).\nPlease [install git](https://git-scm.com/), or learn more about how to use Git and source control in VS Code in [our docs](https://aka.ms/vscode-scm).\nIf you're using a different version control system, you can [search the Marketplace](command:workbench.extensions.search?%22%40category%3A%5C%22scm%20providers%5C%22%22) for additional extensions.", - "view.workbench.scm.disabled": "If you would like to use git features, please enable git in your [settings](command:workbench.action.openSettings?%5B%22git.enabled%22%5D).\nTo learn more about how to use Git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).", - "view.workbench.scm.empty": "In order to use git features, you can open a folder containing a git repository or clone from a URL.\n[Open Folder](command:vscode.openFolder)\n[Clone Repository](command:git.clone)\nTo learn more about how to use Git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).", - "view.workbench.scm.folder": "The folder currently open doesn't have a git repository.\n[Initialize Repository](command:git.init?%5Btrue%5D)\nTo learn more about how to use Git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).", - "view.workbench.scm.workspace": "The workspace currently open doesn't have any folders containing git repositories.\n[Initialize Repository](command:git.init)\nTo learn more about how to use Git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).", - "view.workbench.scm.emptyWorkspace": "The workspace currently open doesn't have any folders containing git repositories.\n[Add Folder to Workspace](command:workbench.action.addRootFolder)\nTo learn more about how to use Git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).", - "view.workbench.cloneRepository": "You can also clone a repository from a URL. To learn more about how to use Git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).\n[Clone Repository](command:git.clone)" + "view.workbench.scm.missing": "A valid git installation was not detected, more details can be found in the [git output](command:git.showOutput).\nPlease [install git](https://git-scm.com/), or learn more about how to use git and source control in VS Code in [our docs](https://aka.ms/vscode-scm).\nIf you're using a different version control system, you can [search the Marketplace](command:workbench.extensions.search?%22%40category%3A%5C%22scm%20providers%5C%22%22) for additional extensions.", + "view.workbench.scm.disabled": "If you would like to use git features, please enable git in your [settings](command:workbench.action.openSettings?%5B%22git.enabled%22%5D).\nTo learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).", + "view.workbench.scm.empty": "In order to use git features, you can open a folder containing a git repository or clone from a URL.\n[Open Folder](command:vscode.openFolder)\n[Clone Repository](command:git.clone)\nTo learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).", + "view.workbench.scm.folder": "The folder currently open doesn't have a git repository.\n[Initialize Repository](command:git.init?%5Btrue%5D)\nTo learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).", + "view.workbench.scm.workspace": "The workspace currently open doesn't have any folders containing git repositories.\n[Initialize Repository](command:git.init)\nTo learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).", + "view.workbench.scm.emptyWorkspace": "The workspace currently open doesn't have any folders containing git repositories.\n[Add Folder to Workspace](command:workbench.action.addRootFolder)\nTo learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).", + "view.workbench.cloneRepository": "You can also clone a repository from a URL. To learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).\n[Clone Repository](command:git.clone)" } From 666989131e271fe7c17f620d74b37b50ec84641d Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 27 Feb 2020 08:37:26 +0100 Subject: [PATCH 108/235] fixes #91462, fixes #91465 --- .../contrib/welcome/common/viewsWelcomeExtensionPoint.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/welcome/common/viewsWelcomeExtensionPoint.ts b/src/vs/workbench/contrib/welcome/common/viewsWelcomeExtensionPoint.ts index 28a5bc02dfa..8171b85762b 100644 --- a/src/vs/workbench/contrib/welcome/common/viewsWelcomeExtensionPoint.ts +++ b/src/vs/workbench/contrib/welcome/common/viewsWelcomeExtensionPoint.ts @@ -22,7 +22,7 @@ export type ViewsWelcomeExtensionPoint = ViewWelcome[]; const viewsWelcomeExtensionPointSchema = Object.freeze({ type: 'array', - description: nls.localize('contributes.viewsWelcome', "Contributed views welcome content."), + description: nls.localize('contributes.viewsWelcome', "Contributed views welcome content. Welcome content will be rendered in views whenever they have no meaningful content to display, ie. the File Explorer when no folder is open. Such content is useful as in-product documentation to drive users to use certain features before they are available. A good example would be a `Clone Repository` button in the File Explorer welcome view."), items: { type: 'object', description: nls.localize('contributes.viewsWelcome.view', "Contributed welcome content for a specific view."), @@ -33,15 +33,15 @@ const viewsWelcomeExtensionPointSchema = Object.freeze Date: Thu, 27 Feb 2020 08:56:42 +0100 Subject: [PATCH 109/235] fix global storage change events for deletes ( #91582) --- src/vs/base/parts/storage/common/storage.ts | 10 ++++--- .../parts/storage/test/node/storage.test.ts | 19 ++++++------ .../storage/browser/storageService.ts | 29 ++++++++++++++++++- src/vs/platform/storage/node/storageIpc.ts | 23 ++++++++++----- .../platform/storage/node/storageService.ts | 10 +++---- 5 files changed, 63 insertions(+), 28 deletions(-) diff --git a/src/vs/base/parts/storage/common/storage.ts b/src/vs/base/parts/storage/common/storage.ts index 03dedeca57f..2c2c909a9d1 100644 --- a/src/vs/base/parts/storage/common/storage.ts +++ b/src/vs/base/parts/storage/common/storage.ts @@ -27,7 +27,8 @@ export interface IUpdateRequest { } export interface IStorageItemsChangeEvent { - items: Map; + changed?: Map; + deleted?: Set; } export interface IStorageDatabase { @@ -104,10 +105,11 @@ export class Storage extends Disposable implements IStorage { // items that change external require us to update our // caches with the values. we just accept the value and // emit an event if there is a change. - e.items.forEach((value, key) => this.accept(key, value)); + e.changed?.forEach((value, key) => this.accept(key, value)); + e.deleted?.forEach(key => this.accept(key, undefined)); } - private accept(key: string, value: string): void { + private accept(key: string, value: string | undefined): void { if (this.state === StorageState.Closed) { return; // Return early if we are already closed } @@ -315,4 +317,4 @@ export class InMemoryStorageDatabase implements IStorageDatabase { close(): Promise { return Promise.resolve(); } -} \ No newline at end of file +} diff --git a/src/vs/base/parts/storage/test/node/storage.test.ts b/src/vs/base/parts/storage/test/node/storage.test.ts index 9c966c0868b..5c25b92dffc 100644 --- a/src/vs/base/parts/storage/test/node/storage.test.ts +++ b/src/vs/base/parts/storage/test/node/storage.test.ts @@ -124,28 +124,27 @@ suite('Storage Library', () => { changes.clear(); // Nothing happens if changing to same value - const change = new Map(); - change.set('foo', 'bar'); - database.fireDidChangeItemsExternal({ items: change }); + const changed = new Map(); + changed.set('foo', 'bar'); + database.fireDidChangeItemsExternal({ changed }); equal(changes.size, 0); // Change is accepted if valid - change.set('foo', 'bar1'); - database.fireDidChangeItemsExternal({ items: change }); + changed.set('foo', 'bar1'); + database.fireDidChangeItemsExternal({ changed }); ok(changes.has('foo')); equal(storage.get('foo'), 'bar1'); changes.clear(); // Delete is accepted - change.set('foo', undefined!); - database.fireDidChangeItemsExternal({ items: change }); + const deleted = new Set(['foo']); + database.fireDidChangeItemsExternal({ deleted }); ok(changes.has('foo')); - equal(storage.get('foo', null!), null); + equal(storage.get('foo', undefined), undefined); changes.clear(); // Nothing happens if changing to same value - change.set('foo', undefined!); - database.fireDidChangeItemsExternal({ items: change }); + database.fireDidChangeItemsExternal({ deleted }); equal(changes.size, 0); await storage.close(); diff --git a/src/vs/platform/storage/browser/storageService.ts b/src/vs/platform/storage/browser/storageService.ts index 839f2c94ff9..1c8174147b0 100644 --- a/src/vs/platform/storage/browser/storageService.ts +++ b/src/vs/platform/storage/browser/storageService.ts @@ -240,9 +240,36 @@ export class FileStorageDatabase extends Disposable implements IStorageDatabase private async onDidStorageChangeExternal(): Promise { const items = await this.doGetItemsFromFile(); + // pervious cache, diff for changes + let changed = new Map(); + let deleted = new Set(); + if (this.cache) { + items.forEach((value, key) => { + const existingValue = this.cache?.get(key); + if (existingValue !== value) { + changed.set(key, value); + } + }); + + this.cache.forEach((_, key) => { + if (!items.has(key)) { + deleted.add(key); + } + }); + } + + // no previous cache, consider all as changed + else { + changed = items; + } + + // Update cache this.cache = items; - this._onDidChangeItemsExternal.fire({ items }); + // Emit as event as needed + if (changed.size > 0 || deleted.size > 0) { + this._onDidChangeItemsExternal.fire({ changed, deleted }); + } } async getItems(): Promise> { diff --git a/src/vs/platform/storage/node/storageIpc.ts b/src/vs/platform/storage/node/storageIpc.ts index e2bbca21641..a6f2367f355 100644 --- a/src/vs/platform/storage/node/storageIpc.ts +++ b/src/vs/platform/storage/node/storageIpc.ts @@ -24,15 +24,16 @@ interface ISerializableUpdateRequest { } interface ISerializableItemsChangeEvent { - items: Item[]; + changed?: Item[]; + deleted?: Key[]; } export class GlobalStorageDatabaseChannel extends Disposable implements IServerChannel { private static readonly STORAGE_CHANGE_DEBOUNCE_TIME = 100; - private readonly _onDidChangeItems: Emitter = this._register(new Emitter()); - readonly onDidChangeItems: Event = this._onDidChangeItems.event; + private readonly _onDidChangeItems = this._register(new Emitter()); + readonly onDidChangeItems = this._onDidChangeItems.event; private whenReady: Promise; @@ -99,15 +100,18 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC } private serializeEvents(events: IStorageChangeEvent[]): ISerializableItemsChangeEvent { - const items = new Map(); + const changed = new Map(); + const deleted = new Set(); events.forEach(event => { const existing = this.storageMainService.get(event.key); if (typeof existing === 'string') { - items.set(event.key, existing); + changed.set(event.key, existing); + } else { + deleted.add(event.key); } }); - return { items: mapToSerializable(items) }; + return { changed: mapToSerializable(changed), deleted: values(deleted) }; } listen(_: unknown, event: string): Event { @@ -170,8 +174,11 @@ export class GlobalStorageDatabaseChannelClient extends Disposable implements IS } private onDidChangeItemsOnMain(e: ISerializableItemsChangeEvent): void { - if (Array.isArray(e.items)) { - this._onDidChangeItemsExternal.fire({ items: serializableToMap(e.items) }); + if (Array.isArray(e.changed) || Array.isArray(e.deleted)) { + this._onDidChangeItemsExternal.fire({ + changed: e.changed ? serializableToMap(e.changed) : undefined, + deleted: e.deleted ? new Set(e.deleted) : undefined + }); } } diff --git a/src/vs/platform/storage/node/storageService.ts b/src/vs/platform/storage/node/storageService.ts index 1aed6216d8f..cf68e7b5aac 100644 --- a/src/vs/platform/storage/node/storageService.ts +++ b/src/vs/platform/storage/node/storageService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { Event, Emitter } from 'vs/base/common/event'; +import { Emitter } from 'vs/base/common/event'; import { ILogService, LogLevel } from 'vs/platform/log/common/log'; import { IWorkspaceStorageChangeEvent, IStorageService, StorageScope, IWillSaveStateEvent, WillSaveStateReason, logStorage } from 'vs/platform/storage/common/storage'; import { SQLiteStorageDatabase, ISQLiteStorageDatabaseLoggingOptions } from 'vs/base/parts/storage/node/storage'; @@ -25,11 +25,11 @@ export class NativeStorageService extends Disposable implements IStorageService private static readonly WORKSPACE_STORAGE_NAME = 'state.vscdb'; private static readonly WORKSPACE_META_NAME = 'workspace.json'; - private readonly _onDidChangeStorage: Emitter = this._register(new Emitter()); - readonly onDidChangeStorage: Event = this._onDidChangeStorage.event; + private readonly _onDidChangeStorage = this._register(new Emitter()); + readonly onDidChangeStorage = this._onDidChangeStorage.event; - private readonly _onWillSaveState: Emitter = this._register(new Emitter()); - readonly onWillSaveState: Event = this._onWillSaveState.event; + private readonly _onWillSaveState = this._register(new Emitter()); + readonly onWillSaveState = this._onWillSaveState.event; private globalStorage: IStorage; From 3cc41d42718c3a124aa5900604a3336cd6f471fb Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 27 Feb 2020 09:05:51 +0100 Subject: [PATCH 110/235] update docs for #91242 --- src/vs/vscode.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 52c6a90f94e..207183cb8d8 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1500,7 +1500,7 @@ declare module 'vscode' { /** * A file system watcher notifies about changes to files and folders - * on disk. + * on disk or from other [FileSystemProviders](#FileSystemProvider). * * To get an instance of a `FileSystemWatcher` use * [createFileSystemWatcher](#workspace.createFileSystemWatcher). From d5661c98ddee18be82ad2fdfbacf640590ece30a Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 27 Feb 2020 09:06:18 +0100 Subject: [PATCH 111/235] fixes #91471 --- src/vs/workbench/common/views.ts | 18 ++++++++++++++++-- .../welcome/common/viewsWelcomeContribution.ts | 5 +++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/common/views.ts b/src/vs/workbench/common/views.ts index d1b30384874..6b29b27222e 100644 --- a/src/vs/workbench/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -17,7 +17,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IAction, IActionViewItem } from 'vs/base/common/actions'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; -import { flatten } from 'vs/base/common/arrays'; +import { flatten, mergeSort } from 'vs/base/common/arrays'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { SetMap } from 'vs/base/common/collections'; @@ -212,9 +212,16 @@ export interface IViewDescriptorCollection extends IDisposable { readonly allViewDescriptors: IViewDescriptor[]; } +export enum ViewContentPriority { + Normal = 0, + Low = 1, + Lowest = 2 +} + export interface IViewContentDescriptor { readonly content: string; readonly when?: ContextKeyExpr | 'default'; + readonly priority?: ViewContentPriority; /** * ordered preconditions for each button in the content @@ -248,6 +255,13 @@ export interface IViewsRegistry { } function compareViewContentDescriptors(a: IViewContentDescriptor, b: IViewContentDescriptor): number { + const aPriority = a.priority ?? ViewContentPriority.Normal; + const bPriority = b.priority ?? ViewContentPriority.Normal; + + if (aPriority !== bPriority) { + return aPriority - bPriority; + } + return a.content < b.content ? -1 : 1; } @@ -329,8 +343,8 @@ class ViewsRegistry extends Disposable implements IViewsRegistry { getViewWelcomeContent(id: string): IViewContentDescriptor[] { const result: IViewContentDescriptor[] = []; - result.sort(compareViewContentDescriptors); this._viewWelcomeContents.forEach(id, descriptor => result.push(descriptor)); + mergeSort(result, compareViewContentDescriptors); return result; } diff --git a/src/vs/workbench/contrib/welcome/common/viewsWelcomeContribution.ts b/src/vs/workbench/contrib/welcome/common/viewsWelcomeContribution.ts index 51fb3194e95..8506ff7eb34 100644 --- a/src/vs/workbench/contrib/welcome/common/viewsWelcomeContribution.ts +++ b/src/vs/workbench/contrib/welcome/common/viewsWelcomeContribution.ts @@ -9,7 +9,7 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { ViewsWelcomeExtensionPoint, ViewWelcome, viewsWelcomeExtensionPointDescriptor } from './viewsWelcomeExtensionPoint'; import { Registry } from 'vs/platform/registry/common/platform'; -import { Extensions as ViewContainerExtensions, IViewsRegistry } from 'vs/workbench/common/views'; +import { Extensions as ViewContainerExtensions, IViewsRegistry, ViewContentPriority } from 'vs/workbench/common/views'; import { localize } from 'vs/nls'; const viewsRegistry = Registry.as(ViewContainerExtensions.ViewsRegistry); @@ -47,7 +47,8 @@ export class ViewsWelcomeContribution extends Disposable implements IWorkbenchCo for (const welcome of contribution.value) { const disposable = viewsRegistry.registerViewWelcomeContent(welcome.view, { content: welcome.contents, - when: ContextKeyExpr.deserialize(welcome.when) + when: ContextKeyExpr.deserialize(welcome.when), + priority: contribution.description.isBuiltin ? ViewContentPriority.Low : ViewContentPriority.Lowest }); this.viewWelcomeContents.set(welcome, disposable); From 52901c545b4a098748d5f08c2e994c309738453c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 27 Feb 2020 09:07:33 +0100 Subject: [PATCH 112/235] Two icons for representing notification progress are confusing (fix #91469) --- .../browser/parts/notifications/notificationsStatus.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts b/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts index 1bdde771ccb..cf45117e80c 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts @@ -69,8 +69,9 @@ export class NotificationsStatus extends Disposable { } } + // Show the bell with a dot if there are unread or in-progress notifications const statusProperties: IStatusbarEntry = { - text: `${this.newNotificationsCount === 0 ? '$(bell)' : '$(bell-dot)'}${notificationsInProgress > 0 ? ' $(sync~spin)' : ''}`, + text: `${notificationsInProgress > 0 || this.newNotificationsCount > 0 ? '$(bell-dot)' : '$(bell)'}`, command: this.isNotificationsCenterVisible ? HIDE_NOTIFICATIONS_CENTER : SHOW_NOTIFICATIONS_CENTER, tooltip: this.getTooltip(notificationsInProgress), showBeak: this.isNotificationsCenterVisible From 04c9b01affe9201c3c96533aba56639e810e940f Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 27 Feb 2020 09:24:38 +0100 Subject: [PATCH 113/235] fixes #91466 --- extensions/git/package.json | 14 +++++++------- .../welcome/common/viewsWelcomeContribution.ts | 5 +++-- .../welcome/common/viewsWelcomeExtensionPoint.ts | 7 +++++++ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/extensions/git/package.json b/extensions/git/package.json index 1eaf39ad44b..5246020c6c2 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -1825,37 +1825,37 @@ }, "viewsWelcome": [ { - "view": "workbench.scm", + "view": "scm", "contents": "%view.workbench.scm.disabled%", "when": "!config.git.enabled" }, { - "view": "workbench.scm", + "view": "scm", "contents": "%view.workbench.scm.missing%", "when": "config.git.enabled && git.missing" }, { - "view": "workbench.scm", + "view": "scm", "contents": "%view.workbench.scm.empty%", "when": "config.git.enabled && !git.missing && workbenchState == empty" }, { - "view": "workbench.scm", + "view": "scm", "contents": "%view.workbench.scm.folder%", "when": "config.git.enabled && !git.missing && workbenchState == folder" }, { - "view": "workbench.scm", + "view": "scm", "contents": "%view.workbench.scm.workspace%", "when": "config.git.enabled && !git.missing && workbenchState == workspace && workspaceFolderCount != 0" }, { - "view": "workbench.scm", + "view": "scm", "contents": "%view.workbench.scm.emptyWorkspace%", "when": "config.git.enabled && !git.missing && workbenchState == workspace && workspaceFolderCount == 0" }, { - "view": "workbench.explorer.emptyView", + "view": "explorer", "contents": "%view.workbench.cloneRepository%" } ] diff --git a/src/vs/workbench/contrib/welcome/common/viewsWelcomeContribution.ts b/src/vs/workbench/contrib/welcome/common/viewsWelcomeContribution.ts index 8506ff7eb34..e7e50346aa5 100644 --- a/src/vs/workbench/contrib/welcome/common/viewsWelcomeContribution.ts +++ b/src/vs/workbench/contrib/welcome/common/viewsWelcomeContribution.ts @@ -7,7 +7,7 @@ import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { ViewsWelcomeExtensionPoint, ViewWelcome, viewsWelcomeExtensionPointDescriptor } from './viewsWelcomeExtensionPoint'; +import { ViewsWelcomeExtensionPoint, ViewWelcome, viewsWelcomeExtensionPointDescriptor, ViewIdentifierMap } from './viewsWelcomeExtensionPoint'; import { Registry } from 'vs/platform/registry/common/platform'; import { Extensions as ViewContainerExtensions, IViewsRegistry, ViewContentPriority } from 'vs/workbench/common/views'; import { localize } from 'vs/nls'; @@ -45,7 +45,8 @@ export class ViewsWelcomeContribution extends Disposable implements IWorkbenchCo } for (const welcome of contribution.value) { - const disposable = viewsRegistry.registerViewWelcomeContent(welcome.view, { + const id = ViewIdentifierMap[welcome.view] ?? welcome.view; + const disposable = viewsRegistry.registerViewWelcomeContent(id, { content: welcome.contents, when: ContextKeyExpr.deserialize(welcome.when), priority: contribution.description.isBuiltin ? ViewContentPriority.Low : ViewContentPriority.Lowest diff --git a/src/vs/workbench/contrib/welcome/common/viewsWelcomeExtensionPoint.ts b/src/vs/workbench/contrib/welcome/common/viewsWelcomeExtensionPoint.ts index 8171b85762b..9a1fdbe078e 100644 --- a/src/vs/workbench/contrib/welcome/common/viewsWelcomeExtensionPoint.ts +++ b/src/vs/workbench/contrib/welcome/common/viewsWelcomeExtensionPoint.ts @@ -20,6 +20,12 @@ export interface ViewWelcome { export type ViewsWelcomeExtensionPoint = ViewWelcome[]; +export const ViewIdentifierMap: { [key: string]: string } = { + 'explorer': 'workbench.explorer.emptyView', + 'debug': 'workbench.debug.startView', + 'scm': 'workbench.scm', +}; + const viewsWelcomeExtensionPointSchema = Object.freeze({ type: 'array', description: nls.localize('contributes.viewsWelcome', "Contributed views welcome content. Welcome content will be rendered in views whenever they have no meaningful content to display, ie. the File Explorer when no folder is open. Such content is useful as in-product documentation to drive users to use certain features before they are available. A good example would be a `Clone Repository` button in the File Explorer welcome view."), @@ -34,6 +40,7 @@ const viewsWelcomeExtensionPointSchema = Object.freeze Date: Thu, 27 Feb 2020 09:35:12 +0100 Subject: [PATCH 114/235] dispose quick pick --- .../workbench/contrib/userDataSync/browser/userDataSync.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 3769fabc22a..aeb8ef22ab9 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -552,8 +552,8 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo const disposables: DisposableStore = new DisposableStore(); const displayName = this.authenticationService.getDisplayName(this.userDataSyncStore!.authenticationProviderId); const quickPick = this.quickInputService.createQuickPick<{ id: string, label: string, description?: string, detail?: string }>(); - const chooseAnotherItemId = 'chooseAnother'; disposables.add(quickPick); + const chooseAnotherItemId = 'chooseAnother'; quickPick.title = localize('pick account', "{0}: Pick an account", displayName); quickPick.ok = false; quickPick.placeholder = localize('choose account placeholder', "Pick an account for syncing"); @@ -916,7 +916,9 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo return new Promise((c, e) => { const quickInputService = accessor.get(IQuickInputService); const commandService = accessor.get(ICommandService); + const disposables = new DisposableStore(); const quickPick = quickInputService.createQuickPick(); + disposables.add(quickPick); const items: Array = []; if (that.userDataSyncService.conflictsSources.length) { for (const source of that.userDataSyncService.conflictsSources) { @@ -937,7 +939,6 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo items.push({ type: 'separator' }); items.push({ id: stopSyncCommand.id, label: stopSyncCommand.title(that.userDataSyncStore!.authenticationProviderId, that.activeAccount, that.authenticationService) }); quickPick.items = items; - const disposables = new DisposableStore(); disposables.add(quickPick.onDidAccept(() => { if (quickPick.selectedItems[0] && quickPick.selectedItems[0].id) { commandService.executeCommand(quickPick.selectedItems[0].id); From 9ee247f352d7fe1ba3a9bc6217c5661694bd49d9 Mon Sep 17 00:00:00 2001 From: Gustavo Cassel Date: Thu, 27 Feb 2020 05:47:16 -0300 Subject: [PATCH 115/235] Improved documentation of 'title' property on OpenDialogOptions and SaveDialogOptions (#91633) --- src/vs/vscode.proposed.d.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index b3bea7c0a5a..6c28f957862 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1705,7 +1705,10 @@ declare module 'vscode' { */ export interface OpenDialogOptions { /** - * Dialog title + * Dialog title. + * + * Depending on the underlying operating system this parameter might be ignored, since some + * systems do not present title on open dialogs. */ title?: string; } @@ -1715,7 +1718,10 @@ declare module 'vscode' { */ export interface SaveDialogOptions { /** - * Dialog title + * Dialog title. + * + * Depending on the underlying operating system this parameter might be ignored, since some + * systems do not present title on save dialogs. */ title?: string; } From 4fa435b69b32b7f7ee4740f1787497edb54ef1de Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Thu, 27 Feb 2020 09:47:28 +0100 Subject: [PATCH 116/235] Show OK by default for multi-select (fixes #90365) --- src/vs/base/parts/quickinput/browser/quickInput.ts | 7 ++++--- src/vs/base/parts/quickinput/common/quickInput.ts | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vs/base/parts/quickinput/browser/quickInput.ts b/src/vs/base/parts/quickinput/browser/quickInput.ts index 059eb29406d..d3d94acb6ad 100644 --- a/src/vs/base/parts/quickinput/browser/quickInput.ts +++ b/src/vs/base/parts/quickinput/browser/quickInput.ts @@ -397,7 +397,7 @@ class QuickPick extends QuickInput implements IQuickPi private _valueSelection: Readonly<[number, number]> | undefined; private valueSelectionUpdated = true; private _validationMessage: string | undefined; - private _ok = false; + private _ok: boolean | 'default' = 'default'; private _customButton = false; private _customButtonLabel: string | undefined; private _customButtonHover: string | undefined; @@ -566,7 +566,7 @@ class QuickPick extends QuickInput implements IQuickPi return this._ok; } - set ok(showOkButton: boolean) { + set ok(showOkButton: boolean | 'default') { this._ok = showOkButton; this.update(); } @@ -757,7 +757,8 @@ class QuickPick extends QuickInput implements IQuickPi if (!this.visible) { return; } - this.ui.setVisibilities(this.canSelectMany ? { title: !!this.title || !!this.step, description: !!this.description, checkAll: true, inputBox: true, visibleCount: true, count: true, ok: this.ok, list: true, message: !!this.validationMessage, customButton: this.customButton } : { title: !!this.title || !!this.step, description: !!this.description, inputBox: true, visibleCount: true, list: true, message: !!this.validationMessage, customButton: this.customButton, ok: this.ok }); + const ok = this.ok === 'default' ? this.canSelectMany : this.ok; + this.ui.setVisibilities(this.canSelectMany ? { title: !!this.title || !!this.step, description: !!this.description, checkAll: true, inputBox: true, visibleCount: true, count: true, ok, list: true, message: !!this.validationMessage, customButton: this.customButton } : { title: !!this.title || !!this.step, description: !!this.description, inputBox: true, visibleCount: true, list: true, message: !!this.validationMessage, customButton: this.customButton, ok }); super.update(); if (this.ui.inputBox.value !== this.value) { this.ui.inputBox.value = this.value; diff --git a/src/vs/base/parts/quickinput/common/quickInput.ts b/src/vs/base/parts/quickinput/common/quickInput.ts index 36905c59c53..10c8255a444 100644 --- a/src/vs/base/parts/quickinput/common/quickInput.ts +++ b/src/vs/base/parts/quickinput/common/quickInput.ts @@ -162,7 +162,7 @@ export interface IQuickPick extends IQuickInput { readonly onDidAccept: Event; - ok: boolean; + ok: boolean | 'default'; readonly onDidCustom: Event; From 96dfec43ee7ecc124ca6d9d4a4e41aac5ea56ab3 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 27 Feb 2020 09:58:01 +0100 Subject: [PATCH 117/235] fixes #90934 --- extensions/git/src/commands.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index ad4d47485e7..10d2cfc2d5b 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -1397,12 +1397,16 @@ export class CommandCenter { opts.signoff = true; } + const smartCommitChanges = config.get<'all' | 'tracked'>('smartCommitChanges'); + if ( ( // no changes (noStagedChanges && noUnstagedChanges) // or no staged changes and not `all` || (!opts.all && noStagedChanges) + // no staged changes and no tracked unstaged changes + || (noStagedChanges && smartCommitChanges === 'tracked' && repository.workingTreeGroup.resourceStates.every(r => r.type === Status.UNTRACKED)) ) && !opts.empty ) { @@ -1416,7 +1420,7 @@ export class CommandCenter { return false; } - if (opts.all && config.get<'all' | 'tracked'>('smartCommitChanges') === 'tracked') { + if (opts.all && smartCommitChanges === 'tracked') { opts.all = 'tracked'; } From 1c0ac37b1e189eecaa9c380a442534cb79c053be Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 27 Feb 2020 10:41:36 +0100 Subject: [PATCH 118/235] fix #91665 --- .../editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.ts b/src/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.ts index a2ac8275f37..68c3275a7a4 100644 --- a/src/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.ts +++ b/src/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.ts @@ -338,9 +338,8 @@ export class GotoDefinitionAtPositionEditorContribution implements IEditorContri private gotoDefinition(position: Position, openToSide: boolean): Promise { this.editor.setPosition(position); - const definitionLinkOpensInPeek = this.editor.getOption(EditorOption.definitionLinkOpensInPeek); return this.editor.invokeWithinContext((accessor) => { - const canPeek = definitionLinkOpensInPeek && !this.isInPeekEditor(accessor); + const canPeek = !openToSide && this.editor.getOption(EditorOption.definitionLinkOpensInPeek) && !this.isInPeekEditor(accessor); const action = new DefinitionAction({ openToSide, openInPeek: canPeek, muteMessage: true }, { alias: '', label: '', id: '', precondition: undefined }); return action.run(accessor, this.editor); }); From 05549445001dad9c611237d2e7f8b927fa76037a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 27 Feb 2020 10:57:00 +0100 Subject: [PATCH 119/235] refine wording for settings doc, #62571 --- src/vs/editor/common/config/editorOptions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 270e0018dff..f2873a887f8 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -3769,7 +3769,7 @@ export const EditorOptions = { )), definitionLinkOpensInPeek: register(new EditorBooleanOption( EditorOption.definitionLinkOpensInPeek, 'definitionLinkOpensInPeek', false, - { description: nls.localize('definitionLinkOpensInPeek', "Controls whether the definition link opens element in the peek widget.") } + { description: nls.localize('definitionLinkOpensInPeek', "Controls whether the Go to Definition mouse gesture always opens the peek widget.") } )), quickSuggestions: register(new EditorQuickSuggestions()), quickSuggestionsDelay: register(new EditorIntOption( From 9ff4a28982b2ced53660c77e0b281133328ac1ec Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 27 Feb 2020 11:04:14 +0100 Subject: [PATCH 120/235] text files - trace dispose() calls --- .../workbench/services/textfile/common/textFileEditorModel.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 67332750e50..949e69d12ef 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -919,6 +919,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } dispose(): void { + this.logService.trace('[text file model] dispose()', this.resource.toString(true)); + this.disposed = true; this.inConflictMode = false; this.inOrphanMode = false; From 864f21ad6144b72cbb21b8752ae226d8d06f940f Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 27 Feb 2020 11:19:59 +0100 Subject: [PATCH 121/235] tests - exit CLI process when renderer crashes or is unresponsive instead of bringing up a dialog --- src/vs/code/electron-main/window.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 1f1c08a58f1..55600018311 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -32,6 +32,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; +import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; const RUN_TEXTMATE_IN_WORKER = false; @@ -100,7 +101,8 @@ export class CodeWindow extends Disposable implements ICodeWindow { @IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService, @IBackupMainService private readonly backupMainService: IBackupMainService, @ITelemetryService private readonly telemetryService: ITelemetryService, - @IDialogMainService private readonly dialogMainService: IDialogMainService + @IDialogMainService private readonly dialogMainService: IDialogMainService, + @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService ) { super(); @@ -244,6 +246,8 @@ export class CodeWindow extends Disposable implements ICodeWindow { get isExtensionTestHost(): boolean { return !!(this.config && this.config.extensionTestsPath); } + get isExtensionDevelopmentTestFromCli(): boolean { return this.isExtensionDevelopmentHost && this.isExtensionTestHost && !this.config?.debugId; } + setRepresentedFilename(filename: string): void { if (isMacintosh) { this.win.setRepresentedFilename(filename); @@ -447,6 +451,15 @@ export class CodeWindow extends Disposable implements ICodeWindow { private onWindowError(error: WindowError): void { this.logService.error(error === WindowError.CRASHED ? '[VS Code]: render process crashed!' : '[VS Code]: detected unresponsive'); + // If we run extension tests from CLI, showing a dialog is not + // very helpful in this case. Rather, we bring down the test run + // to signal back a failing run. + if (this.isExtensionDevelopmentTestFromCli) { + this.lifecycleMainService.kill(1); + return; + } + + // Telemetry type WindowErrorClassification = { type: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; }; From 24307c0e1b012c493a1763024371a2f805c97da9 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 27 Feb 2020 11:25:58 +0100 Subject: [PATCH 122/235] Support Link Titles with single quotes in Welcome Views (fix #91442) --- src/vs/base/common/linkedText.ts | 2 +- src/vs/base/test/common/linkedText.test.ts | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vs/base/common/linkedText.ts b/src/vs/base/common/linkedText.ts index ee268d9fdcd..65e48078110 100644 --- a/src/vs/base/common/linkedText.ts +++ b/src/vs/base/common/linkedText.ts @@ -23,7 +23,7 @@ export class LinkedText { } } -const LINK_REGEX = /\[([^\]]+)\]\(((?:https?:\/\/|command:)[^\)\s]+)(?: "([^"]+)")?\)/gi; +const LINK_REGEX = /\[([^\]]+)\]\(((?:https?:\/\/|command:)[^\)\s]+)(?: (?:"|')([^"]+)(?:"|'))?\)/gi; export function parseLinkedText(text: string): LinkedText { const result: LinkedTextNode[] = []; diff --git a/src/vs/base/test/common/linkedText.test.ts b/src/vs/base/test/common/linkedText.test.ts index 8e1cb887485..15185ef44ae 100644 --- a/src/vs/base/test/common/linkedText.test.ts +++ b/src/vs/base/test/common/linkedText.test.ts @@ -21,6 +21,11 @@ suite('LinkedText', () => { { label: 'link text', href: 'http://link.href', title: 'and a title' }, '.' ]); + assert.deepEqual(parseLinkedText('Some message with [link text](http://link.href \'and a title\').').nodes, [ + 'Some message with ', + { label: 'link text', href: 'http://link.href', title: 'and a title' }, + '.' + ]); assert.deepEqual(parseLinkedText('Some message with [link text](random stuff).').nodes, [ 'Some message with [link text](random stuff).' ]); From 15bdd26e460fb16ca3cca2202875de4d31863f4c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 27 Feb 2020 11:41:09 +0100 Subject: [PATCH 123/235] fix #91672 --- .../contrib/bulkEdit/browser/bulkEdit.contribution.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/bulkEdit/browser/bulkEdit.contribution.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkEdit.contribution.ts index 66624cf7bb6..faf9b538534 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/bulkEdit.contribution.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkEdit.contribution.ts @@ -111,6 +111,7 @@ class BulkEditPreviewContribution { private async _previewEdit(edit: WorkspaceEdit) { this._ctxEnabled.set(true); + const uxState = this._activeSession?.uxState ?? new UXState(this._panelService, this._editorGroupsService); const view = await getBulkEditPane(this._viewsService); if (!view) { this._ctxEnabled.set(false); @@ -136,9 +137,9 @@ class BulkEditPreviewContribution { let session: PreviewSession; if (this._activeSession) { this._activeSession.cts.dispose(true); - session = new PreviewSession(this._activeSession.uxState); + session = new PreviewSession(uxState); } else { - session = new PreviewSession(new UXState(this._panelService, this._editorGroupsService)); + session = new PreviewSession(uxState); } this._activeSession = session; From 8758dc9dddf95f358eb93c969353e5cf245ed1e4 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 27 Feb 2020 11:50:18 +0100 Subject: [PATCH 124/235] Fixes #91405: Improve minimap settings --- .../browser/viewParts/minimap/minimap.ts | 6 ++--- src/vs/editor/common/config/editorOptions.ts | 26 +++++++++---------- .../viewLayout/editorLayoutProvider.test.ts | 12 ++++----- src/vs/monaco.d.ts | 2 +- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index d5aa95d0611..4e2808594db 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -46,7 +46,7 @@ class MinimapOptions { public readonly renderMinimap: RenderMinimap; - public readonly mode: 'actual' | 'cover' | 'contain'; + public readonly size: 'proportional' | 'fill' | 'fit'; public readonly minimapHeightIsEditorHeight: boolean; @@ -108,7 +108,7 @@ class MinimapOptions { const minimapOpts = options.get(EditorOption.minimap); this.renderMinimap = layoutInfo.renderMinimap | 0; - this.mode = minimapOpts.mode; + this.size = minimapOpts.size; this.minimapHeightIsEditorHeight = layoutInfo.minimapHeightIsEditorHeight; this.scrollBeyondLastLine = options.get(EditorOption.scrollBeyondLastLine); this.showSlider = minimapOpts.showSlider; @@ -144,7 +144,7 @@ class MinimapOptions { public equals(other: MinimapOptions): boolean { return (this.renderMinimap === other.renderMinimap - && this.mode === other.mode + && this.size === other.size && this.minimapHeightIsEditorHeight === other.minimapHeightIsEditorHeight && this.scrollBeyondLastLine === other.scrollBeyondLastLine && this.showSlider === other.showSlider diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index f2873a887f8..e149ea0793c 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -1802,7 +1802,7 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption= 2 ? Math.round(minimap.scale * 2) : minimap.scale); const minimapMaxColumn = minimap.maxColumn | 0; - const minimapMode = minimap.mode; + const minimapSize = minimap.size; const scrollbar = options.get(EditorOption.scrollbar); const verticalScrollbarWidth = scrollbar.verticalScrollbarSize | 0; @@ -1866,7 +1866,7 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption minimapCanvasInnerHeight) { + if (minimapSize === 'fill' || effectiveMinimapHeight > minimapCanvasInnerHeight) { minimapHeightIsEditorHeight = true; const configuredFontScale = minimapScale; minimapLineHeight = Math.min(lineHeight * pixelRatio, Math.max(1, Math.floor(1 / desiredRatio))); @@ -2074,7 +2074,7 @@ export interface IEditorMinimapOptions { * Control the minimap rendering mode. * Defaults to 'actual'. */ - mode?: 'actual' | 'cover' | 'contain'; + size?: 'proportional' | 'fill' | 'fit'; /** * Control the rendering of the minimap slider. * Defaults to 'mouseover'. @@ -2103,7 +2103,7 @@ class EditorMinimap extends BaseEditorOption(input.mode, this.defaultValue.mode, ['actual', 'cover', 'contain']), + size: EditorStringEnumOption.stringSet<'proportional' | 'fill' | 'fit'>(input.size, this.defaultValue.size, ['proportional', 'fill', 'fit']), side: EditorStringEnumOption.stringSet<'right' | 'left'>(input.side, this.defaultValue.side, ['right', 'left']), showSlider: EditorStringEnumOption.stringSet<'always' | 'mouseover'>(input.showSlider, this.defaultValue.showSlider, ['always', 'mouseover']), renderCharacters: EditorBooleanOption.boolean(input.renderCharacters, this.defaultValue.renderCharacters), diff --git a/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts b/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts index ff7e6ef7fbc..f9e64360021 100644 --- a/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts +++ b/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts @@ -33,7 +33,7 @@ interface IEditorLayoutProviderOpts { readonly minimapSide: 'left' | 'right'; readonly minimapRenderCharacters: boolean; readonly minimapMaxColumn: number; - minimapMode?: 'actual' | 'cover' | 'contain'; + minimapSize?: 'proportional' | 'fill' | 'fit'; readonly pixelRatio: number; } @@ -47,7 +47,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { options._write(EditorOption.folding, false); const minimapOptions: EditorMinimapOptions = { enabled: input.minimap, - mode: input.minimapMode || 'actual', + size: input.minimapSize || 'proportional', side: input.minimapSide, renderCharacters: input.minimapRenderCharacters, maxColumn: input.minimapMaxColumn, @@ -978,7 +978,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, - minimapMode: 'cover', + minimapSize: 'fill', pixelRatio: 2, }, { width: 1000, @@ -1042,7 +1042,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, - minimapMode: 'cover', + minimapSize: 'fill', pixelRatio: 2, }, { width: 1000, @@ -1106,7 +1106,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, - minimapMode: 'contain', + minimapSize: 'fit', pixelRatio: 2, }, { width: 1000, @@ -1170,7 +1170,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => { minimapSide: 'right', minimapRenderCharacters: true, minimapMaxColumn: 150, - minimapMode: 'contain', + minimapSize: 'fit', pixelRatio: 2, }, { width: 1000, diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index fd704b03bd3..ecb0e10c7ca 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -3444,7 +3444,7 @@ declare namespace monaco.editor { * Control the minimap rendering mode. * Defaults to 'actual'. */ - mode?: 'actual' | 'cover' | 'contain'; + size?: 'proportional' | 'fill' | 'fit'; /** * Control the rendering of the minimap slider. * Defaults to 'mouseover'. From fdfed71af4e0f1e963bf0b70e04b77580aebda91 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 27 Feb 2020 12:11:51 +0100 Subject: [PATCH 125/235] Fixes #91363 --- .../contrib/codeEditor/browser/toggleColumnSelection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts index fac092022e2..011918eb9b8 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts @@ -79,7 +79,7 @@ export class ToggleColumnSelectionAction extends Action { } const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleColumnSelectionAction, ToggleColumnSelectionAction.ID, ToggleColumnSelectionAction.LABEL), 'View: Toggle Column Selection Mode', nls.localize('view', "View")); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleColumnSelectionAction, ToggleColumnSelectionAction.ID, ToggleColumnSelectionAction.LABEL), 'Toggle Column Selection Mode'); MenuRegistry.appendMenuItem(MenuId.MenubarSelectionMenu, { group: '4_config', From b8dc2402a1a2c2eea53ef9820971f76df2ea07bb Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 27 Feb 2020 12:16:04 +0100 Subject: [PATCH 126/235] Fixes #91386: Improve JSON schema for minimap.scale --- src/vs/editor/common/config/editorOptions.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index e149ea0793c..941502e43d3 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -2146,7 +2146,8 @@ class EditorMinimap extends BaseEditorOption Date: Thu, 27 Feb 2020 12:45:19 +0100 Subject: [PATCH 127/235] consolidate debug test instructions --- test/unit/README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/unit/README.md b/test/unit/README.md index 4172285834f..f471ebb7d8e 100644 --- a/test/unit/README.md +++ b/test/unit/README.md @@ -9,6 +9,8 @@ All unit tests are run inside a electron-browser environment which access to DOM - use the `--debug` to see an electron window with dev tools which allows for debugging - to run only a subset of tests use the `--run` or `--glob` options +For instance, `./scripts/test.sh --debug --glob **/extHost*.test.js` runs all tests from `extHost`-files and enables you to debug them. + ## Run (inside browser) yarn test-browser --browser webkit --browser chromium @@ -24,11 +26,6 @@ Unit tests from layers `common` and `browser` are run inside `chromium`, `webkit yarn run mocha --run src/vs/editor/test/browser/controller/cursor.test.ts -## Debug - -To debug tests use `--debug` when running the test script. Also, the set of tests can be reduced with the `--run` and `--runGlob` flags. Both require a file path/pattern. Like so: - - ./scripts/test.sh --debug --runGrep **/extHost*.test.js ## Coverage From d9b345b155648314dac8b666fdede94e2dbde662 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 27 Feb 2020 12:45:08 +0100 Subject: [PATCH 128/235] Avoid having quotes inside quotes (for #91368) --- src/vs/editor/browser/services/bulkEditService.ts | 1 + src/vs/editor/contrib/rename/rename.ts | 3 ++- src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/browser/services/bulkEditService.ts b/src/vs/editor/browser/services/bulkEditService.ts index 3d18020da6f..f6fdac9c874 100644 --- a/src/vs/editor/browser/services/bulkEditService.ts +++ b/src/vs/editor/browser/services/bulkEditService.ts @@ -16,6 +16,7 @@ export interface IBulkEditOptions { progress?: IProgress; showPreview?: boolean; label?: string; + quotableLabel?: string; } export interface IBulkEditResult { diff --git a/src/vs/editor/contrib/rename/rename.ts b/src/vs/editor/contrib/rename/rename.ts index 28aba650e6a..360986dd666 100644 --- a/src/vs/editor/contrib/rename/rename.ts +++ b/src/vs/editor/contrib/rename/rename.ts @@ -206,7 +206,8 @@ class RenameController implements IEditorContribution { this._bulkEditService.apply(renameResult, { editor: this.editor, showPreview: inputFieldResult.wantsPreview, - label: nls.localize('label', "Renaming '{0}'", loc?.text) + label: nls.localize('label', "Renaming '{0}'", loc?.text), + quotableLabel: nls.localize('quotableLabel', "Renaming {0}", loc?.text), }).then(result => { if (result.ariaSummary) { alert(nls.localize('aria', "Successfully renamed '{0}' to '{1}'. Summary: {2}", loc!.text, inputFieldResult.newName, result.ariaSummary)); diff --git a/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts b/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts index e5b490f3187..dcb5a2c3346 100644 --- a/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts +++ b/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts @@ -443,7 +443,7 @@ export class BulkEditService implements IBulkEditService { // If the code editor is readonly still allow bulk edits to be applied #68549 codeEditor = undefined; } - const bulkEdit = this._instaService.createInstance(BulkEdit, options?.label, codeEditor, options?.progress, edits); + const bulkEdit = this._instaService.createInstance(BulkEdit, options?.quotableLabel || options?.label, codeEditor, options?.progress, edits); return bulkEdit.perform().then(() => { return { ariaSummary: bulkEdit.ariaMessage() }; }).catch(err => { From bde129b1deb57fd02230f79dda33d098c85946a2 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 27 Feb 2020 12:46:51 +0100 Subject: [PATCH 129/235] More tweaks to options (fixes #91368) --- src/vs/platform/undoRedo/common/undoRedoService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/undoRedo/common/undoRedoService.ts b/src/vs/platform/undoRedo/common/undoRedoService.ts index ccbb2c55482..8568767aa3d 100644 --- a/src/vs/platform/undoRedo/common/undoRedoService.ts +++ b/src/vs/platform/undoRedo/common/undoRedoService.ts @@ -288,8 +288,8 @@ export class UndoRedoService implements IUndoRedoService { Severity.Info, nls.localize('confirmWorkspace', "Would you like to undo '{0}' across all files?", element.label), [ - nls.localize('ok', "Undo in {0} files.", affectedEditStacks.length), - nls.localize('nok', "Undo this file."), + nls.localize('ok', "Undo In {0} Files", affectedEditStacks.length), + nls.localize('nok', "Undo This File"), nls.localize('cancel', "Cancel"), ], { From abf3b9d0ca38033c38273506a88113959d601cec Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 27 Feb 2020 12:46:10 +0100 Subject: [PATCH 130/235] continuation of #91442 --- src/vs/base/common/linkedText.ts | 4 ++-- src/vs/base/test/common/linkedText.test.ts | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/vs/base/common/linkedText.ts b/src/vs/base/common/linkedText.ts index 65e48078110..5f6c6a05dcf 100644 --- a/src/vs/base/common/linkedText.ts +++ b/src/vs/base/common/linkedText.ts @@ -23,7 +23,7 @@ export class LinkedText { } } -const LINK_REGEX = /\[([^\]]+)\]\(((?:https?:\/\/|command:)[^\)\s]+)(?: (?:"|')([^"]+)(?:"|'))?\)/gi; +const LINK_REGEX = /\[([^\]]+)\]\(((?:https?:\/\/|command:)[^\)\s]+)(?: ("|')([^\3]+)(\3))?\)/gi; export function parseLinkedText(text: string): LinkedText { const result: LinkedTextNode[] = []; @@ -36,7 +36,7 @@ export function parseLinkedText(text: string): LinkedText { result.push(text.substring(index, match.index)); } - const [, label, href, title] = match; + const [, label, href, , title] = match; if (title) { result.push({ label, href, title }); diff --git a/src/vs/base/test/common/linkedText.test.ts b/src/vs/base/test/common/linkedText.test.ts index 15185ef44ae..a7b61a558c2 100644 --- a/src/vs/base/test/common/linkedText.test.ts +++ b/src/vs/base/test/common/linkedText.test.ts @@ -26,6 +26,16 @@ suite('LinkedText', () => { { label: 'link text', href: 'http://link.href', title: 'and a title' }, '.' ]); + assert.deepEqual(parseLinkedText('Some message with [link text](http://link.href "and a \'title\'").').nodes, [ + 'Some message with ', + { label: 'link text', href: 'http://link.href', title: 'and a \'title\'' }, + '.' + ]); + assert.deepEqual(parseLinkedText('Some message with [link text](http://link.href \'and a "title"\').').nodes, [ + 'Some message with ', + { label: 'link text', href: 'http://link.href', title: 'and a "title"' }, + '.' + ]); assert.deepEqual(parseLinkedText('Some message with [link text](random stuff).').nodes, [ 'Some message with [link text](random stuff).' ]); From 1b352f2f259856c0d82d02f0890a531b8840a8af Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 27 Feb 2020 13:01:01 +0100 Subject: [PATCH 131/235] Fixes #64459: Allow a mouse down to result in dragging the slider (when not using proportional rendering) --- src/vs/editor/browser/viewParts/minimap/minimap.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index 4e2808594db..ed05d886991 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -1111,7 +1111,7 @@ class InnerMinimap extends Disposable { if (!this._lastRenderData) { return; } - if (this._model.options.minimapHeightIsEditorHeight) { + if (this._model.options.size !== 'proportional') { if (e.leftButton && this._lastRenderData) { // pretend the click occured in the center of the slider const position = dom.getDomNodePagePosition(this._slider.domNode); From 2f8ddbe3c20f8b5152d54147895c1e559317798b Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 27 Feb 2020 12:59:49 +0100 Subject: [PATCH 132/235] notifications - revised progress indication for hidden notifications (fix #91469) --- .../notification/common/notification.ts | 7 +++ .../notifications/notificationsActions.ts | 20 ++----- .../notifications/notificationsCenter.ts | 20 +++++-- .../notifications/notificationsCommands.ts | 2 + .../notifications/notificationsToasts.ts | 39 +++++++------ src/vs/workbench/common/notifications.ts | 23 ++++++++ .../progress/browser/progressService.ts | 56 +++++++++++++++++-- .../test/common/notifications.test.ts | 11 ++++ 8 files changed, 135 insertions(+), 43 deletions(-) diff --git a/src/vs/platform/notification/common/notification.ts b/src/vs/platform/notification/common/notification.ts index a81672c8311..f7f2b5a3d9e 100644 --- a/src/vs/platform/notification/common/notification.ts +++ b/src/vs/platform/notification/common/notification.ts @@ -173,6 +173,13 @@ export interface INotificationHandle { */ readonly onDidClose: Event; + /** + * Will be fired whenever the visibility of the notification changes. + * A notification can either be visible as toast or inside the notification + * center if it is visible. + */ + readonly onDidChangeVisibility: Event; + /** * Allows to indicate progress on the notification even after the * notification is already visible. diff --git a/src/vs/workbench/browser/parts/notifications/notificationsActions.ts b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts index 82301a0448e..ae63e201e24 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsActions.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts @@ -26,10 +26,8 @@ export class ClearNotificationAction extends Action { super(id, label, 'codicon-close'); } - run(notification: INotificationViewItem): Promise { + async run(notification: INotificationViewItem): Promise { this.commandService.executeCommand(CLEAR_NOTIFICATION, notification); - - return Promise.resolve(); } } @@ -46,10 +44,8 @@ export class ClearAllNotificationsAction extends Action { super(id, label, 'codicon-clear-all'); } - run(notification: INotificationViewItem): Promise { + async run(notification: INotificationViewItem): Promise { this.commandService.executeCommand(CLEAR_ALL_NOTIFICATIONS); - - return Promise.resolve(); } } @@ -66,10 +62,8 @@ export class HideNotificationsCenterAction extends Action { super(id, label, 'codicon-chevron-down'); } - run(notification: INotificationViewItem): Promise { + async run(notification: INotificationViewItem): Promise { this.commandService.executeCommand(HIDE_NOTIFICATIONS_CENTER); - - return Promise.resolve(); } } @@ -86,10 +80,8 @@ export class ExpandNotificationAction extends Action { super(id, label, 'codicon-chevron-up'); } - run(notification: INotificationViewItem): Promise { + async run(notification: INotificationViewItem): Promise { this.commandService.executeCommand(EXPAND_NOTIFICATION, notification); - - return Promise.resolve(); } } @@ -106,10 +98,8 @@ export class CollapseNotificationAction extends Action { super(id, label, 'codicon-chevron-down'); } - run(notification: INotificationViewItem): Promise { + async run(notification: INotificationViewItem): Promise { this.commandService.executeCommand(COLLAPSE_NOTIFICATION, notification); - - return Promise.resolve(); } } diff --git a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts index 094c9e1567f..c37af327a36 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts @@ -100,6 +100,9 @@ export class NotificationsCenter extends Themable implements INotificationsCente // Theming this.updateStyles(); + // Mark as visible + this.model.notifications.forEach(notification => notification.updateVisibility(true)); + // Context Key this.notificationsCenterVisibleContextKey.set(true); @@ -115,7 +118,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente clearAllAction.enabled = false; } else { notificationsCenterTitle.textContent = localize('notifications', "Notifications"); - clearAllAction.enabled = true; + clearAllAction.enabled = this.model.notifications.some(notification => !notification.hasProgress); } } @@ -172,20 +175,22 @@ export class NotificationsCenter extends Themable implements INotificationsCente return; // only if visible } - let focusGroup = false; + let focusEditor = false; // Update notifications list based on event const [notificationsList, notificationsCenterContainer] = assertAllDefined(this.notificationsList, this.notificationsCenterContainer); switch (e.kind) { case NotificationChangeType.ADD: notificationsList.updateNotificationsList(e.index, 0, [e.item]); + e.item.updateVisibility(true); break; case NotificationChangeType.CHANGE: notificationsList.updateNotificationsList(e.index, 1, [e.item]); break; case NotificationChangeType.REMOVE: - focusGroup = isAncestor(document.activeElement, notificationsCenterContainer); + focusEditor = isAncestor(document.activeElement, notificationsCenterContainer); notificationsList.updateNotificationsList(e.index, 1); + e.item.updateVisibility(false); break; } @@ -197,7 +202,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente this.hide(); // Restore focus to editor group if we had focus - if (focusGroup) { + if (focusEditor) { this.editorGroupService.activeGroup.focus(); } } @@ -208,13 +213,16 @@ export class NotificationsCenter extends Themable implements INotificationsCente return; // already hidden } - const focusGroup = isAncestor(document.activeElement, this.notificationsCenterContainer); + const focusEditor = isAncestor(document.activeElement, this.notificationsCenterContainer); // Hide this._isVisible = false; removeClass(this.notificationsCenterContainer, 'visible'); this.notificationsList.hide(); + // Mark as hidden + this.model.notifications.forEach(notification => notification.updateVisibility(false)); + // Context Key this.notificationsCenterVisibleContextKey.set(false); @@ -222,7 +230,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente this._onDidChangeVisibility.fire(); // Restore focus to editor group if we had focus - if (focusGroup) { + if (focusEditor) { this.editorGroupService.activeGroup.focus(); } } diff --git a/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts b/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts index 413e700668d..b2797f261f3 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts @@ -75,6 +75,7 @@ export function registerNotificationCommands(center: INotificationsCenterControl // Show Notifications Cneter CommandsRegistry.registerCommand(SHOW_NOTIFICATIONS_CENTER, () => { + toasts.hide(); center.show(); }); @@ -92,6 +93,7 @@ export function registerNotificationCommands(center: INotificationsCenterControl if (center.isVisible) { center.hide(); } else { + toasts.hide(); center.show(); } }); diff --git a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts index 95e287fbd49..ecee706fcb9 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts @@ -179,11 +179,8 @@ export class NotificationsToasts extends Themable implements INotificationsToast const toast: INotificationToast = { item, list: notificationList, container: notificationToastContainer, toast: notificationToast, toDispose: itemDisposables }; this.mapNotificationToToast.set(item, toast); - itemDisposables.add(toDisposable(() => { - if (this.isToastVisible(toast) && notificationsToastsContainer) { - notificationsToastsContainer.removeChild(toast.container); - } - })); + // When disposed, remove as visible + itemDisposables.add(toDisposable(() => this.updateToastVisibility(toast, false))); // Make visible notificationList.show(); @@ -236,6 +233,9 @@ export class NotificationsToasts extends Themable implements INotificationsToast addClass(notificationToast, 'notification-fade-in-done'); })); + // Mark as visible + item.updateVisibility(true); + // Events if (!this._isVisible) { this._isVisible = true; @@ -292,12 +292,13 @@ export class NotificationsToasts extends Themable implements INotificationsToast } private removeToast(item: INotificationViewItem): void { + let focusEditor = false; + const notificationToast = this.mapNotificationToToast.get(item); - let focusGroup = false; if (notificationToast) { const toastHasDOMFocus = isAncestor(document.activeElement, notificationToast.container); if (toastHasDOMFocus) { - focusGroup = !(this.focusNext() || this.focusPrevious()); // focus next if any, otherwise focus editor + focusEditor = !(this.focusNext() || this.focusPrevious()); // focus next if any, otherwise focus editor } // Listeners @@ -317,7 +318,7 @@ export class NotificationsToasts extends Themable implements INotificationsToast this.doHide(); // Move focus back to editor group as needed - if (focusGroup) { + if (focusEditor) { this.editorGroupService.activeGroup.focus(); } } @@ -346,11 +347,11 @@ export class NotificationsToasts extends Themable implements INotificationsToast } hide(): void { - const focusGroup = this.notificationsToastsContainer ? isAncestor(document.activeElement, this.notificationsToastsContainer) : false; + const focusEditor = this.notificationsToastsContainer ? isAncestor(document.activeElement, this.notificationsToastsContainer) : false; this.removeToasts(); - if (focusGroup) { + if (focusEditor) { this.editorGroupService.activeGroup.focus(); } } @@ -459,12 +460,12 @@ export class NotificationsToasts extends Themable implements INotificationsToast notificationToasts.push(toast); break; case ToastVisibility.HIDDEN: - if (!this.isToastVisible(toast)) { + if (!this.isToastInDOM(toast)) { notificationToasts.push(toast); } break; case ToastVisibility.VISIBLE: - if (this.isToastVisible(toast)) { + if (this.isToastInDOM(toast)) { notificationToasts.push(toast); } break; @@ -530,7 +531,7 @@ export class NotificationsToasts extends Themable implements INotificationsToast // In order to measure the client height, the element cannot have display: none toast.container.style.opacity = '0'; - this.setVisibility(toast, true); + this.updateToastVisibility(toast, true); heightToGive -= toast.container.offsetHeight; @@ -542,7 +543,7 @@ export class NotificationsToasts extends Themable implements INotificationsToast } // Hide or show toast based on context - this.setVisibility(toast, makeVisible); + this.updateToastVisibility(toast, makeVisible); toast.container.style.opacity = ''; if (makeVisible) { @@ -551,20 +552,24 @@ export class NotificationsToasts extends Themable implements INotificationsToast }); } - private setVisibility(toast: INotificationToast, visible: boolean): void { - if (this.isToastVisible(toast) === visible) { + private updateToastVisibility(toast: INotificationToast, visible: boolean): void { + if (this.isToastInDOM(toast) === visible) { return; } + // Update visibility in DOM const notificationsToastsContainer = assertIsDefined(this.notificationsToastsContainer); if (visible) { notificationsToastsContainer.appendChild(toast.container); } else { notificationsToastsContainer.removeChild(toast.container); } + + // Update visibility in model + toast.item.updateVisibility(visible); } - private isToastVisible(toast: INotificationToast): boolean { + private isToastInDOM(toast: INotificationToast): boolean { return !!toast.container.parentElement; } } diff --git a/src/vs/workbench/common/notifications.ts b/src/vs/workbench/common/notifications.ts index 73f0ef74053..809037bf68e 100644 --- a/src/vs/workbench/common/notifications.ts +++ b/src/vs/workbench/common/notifications.ts @@ -92,6 +92,9 @@ export class NotificationHandle extends Disposable implements INotificationHandl private readonly _onDidClose = this._register(new Emitter()); readonly onDidClose = this._onDidClose.event; + private readonly _onDidChangeVisibility = this._register(new Emitter()); + readonly onDidChangeVisibility = this._onDidChangeVisibility.event; + constructor(private readonly item: INotificationViewItem, private readonly onClose: (item: INotificationViewItem) => void) { super(); @@ -99,6 +102,11 @@ export class NotificationHandle extends Disposable implements INotificationHandl } private registerListeners(): void { + + // Visibility + this._register(this.item.onDidChangeVisibility(visible => this._onDidChangeVisibility.fire(visible))); + + // Closing Event.once(this.item.onDidClose)(() => { this._onDidClose.fire(); @@ -265,6 +273,7 @@ export interface INotificationViewItem { readonly onDidChangeExpansion: Event; readonly onDidClose: Event; + readonly onDidChangeVisibility: Event; readonly onDidChangeLabel: Event; expand(): void; @@ -275,6 +284,8 @@ export interface INotificationViewItem { updateMessage(message: NotificationMessage): void; updateActions(actions?: INotificationActions): void; + updateVisibility(visible: boolean): void; + close(): void; equals(item: INotificationViewItem): boolean; @@ -398,6 +409,7 @@ export class NotificationViewItem extends Disposable implements INotificationVie private static readonly MAX_MESSAGE_LENGTH = 1000; private _expanded: boolean | undefined; + private _visible: boolean = false; private _actions: INotificationActions | undefined; private _progress: NotificationViewItemProgress | undefined; @@ -411,6 +423,9 @@ export class NotificationViewItem extends Disposable implements INotificationVie private readonly _onDidChangeLabel = this._register(new Emitter()); readonly onDidChangeLabel = this._onDidChangeLabel.event; + private readonly _onDidChangeVisibility = this._register(new Emitter()); + readonly onDidChangeVisibility = this._onDidChangeVisibility.event; + static create(notification: INotification, filter: NotificationsFilter = NotificationsFilter.OFF): INotificationViewItem | undefined { if (!notification || !notification.message || isPromiseCanceledError(notification.message)) { return undefined; // we need a message to show @@ -600,6 +615,14 @@ export class NotificationViewItem extends Disposable implements INotificationVie this._onDidChangeLabel.fire({ kind: NotificationViewItemLabelKind.ACTIONS }); } + updateVisibility(visible: boolean): void { + if (this._visible !== visible) { + this._visible = visible; + + this._onDidChangeVisibility.fire(visible); + } + } + expand(): void { if (this._expanded || !this.canCollapse) { return; diff --git a/src/vs/workbench/services/progress/browser/progressService.ts b/src/vs/workbench/services/progress/browser/progressService.ts index 6d4723b34e3..e0b2980aad4 100644 --- a/src/vs/workbench/services/progress/browser/progressService.ts +++ b/src/vs/workbench/services/progress/browser/progressService.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/progressService'; import { localize } from 'vs/nls'; -import { IDisposable, dispose, DisposableStore, MutableDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, DisposableStore, MutableDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { IProgressService, IProgressOptions, IProgressStep, ProgressLocation, IProgress, Progress, IProgressCompositeOptions, IProgressNotificationOptions, IProgressRunner, IProgressIndicator, IProgressWindowOptions } from 'vs/platform/progress/common/progress'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { StatusbarAlignment, IStatusbarService } from 'vs/workbench/services/statusbar/common/statusbar'; @@ -191,6 +191,38 @@ export class ProgressService extends Disposable implements IProgressService { } }; + const createWindowProgress = () => { + + // Create a promise that we can resolve as needed + // when the outside calls dispose on us + let promiseResolve: () => void; + const promise = new Promise(resolve => promiseResolve = resolve); + + this.withWindowProgress({ + location: ProgressLocation.Window, + title: options.title, + command: 'notifications.showList' + }, progress => { + + // Apply any progress that was made already + if (progressStateModel.step) { + progress.report(progressStateModel.step); + } + + // Continue to report progress as it happens + const onDidReportListener = progressStateModel.onDidReport(step => progress.report(step)); + promise.finally(() => onDidReportListener.dispose()); + + // When the progress model gets disposed, we are done as well + Event.once(progressStateModel.onDispose)(() => promiseResolve()); + + return promise; + }); + + // Dispose means completing our promise + return toDisposable(() => promiseResolve()); + }; + const createNotification = (message: string, increment?: number): INotificationHandle => { const notificationDisposables = new DisposableStore(); @@ -229,7 +261,7 @@ export class ProgressService extends Disposable implements IProgressService { primaryActions.push(cancelAction); } - const handle = this.notificationService.notify({ + const notification = this.notificationService.notify({ severity: Severity.Info, message, source: options.source, @@ -237,12 +269,26 @@ export class ProgressService extends Disposable implements IProgressService { progress: typeof increment === 'number' && increment >= 0 ? { total: 100, worked: increment } : { infinite: true } }); - updateProgress(handle, increment); + // Switch to window based progress once the notification + // changes visibility to hidden and is still ongoing. + // Remove that window based progress once the notification + // shows again. + let windowProgressDisposable: IDisposable | undefined = undefined; + notificationDisposables.add(notification.onDidChangeVisibility(visible => { + + // Clear any previous running window progress + dispose(windowProgressDisposable); + + // Create new window progress if notification got hidden + if (!visible && !progressStateModel.done) { + windowProgressDisposable = createWindowProgress(); + } + })); // Clear upon dispose - Event.once(handle.onDidClose)(() => notificationDisposables.dispose()); + Event.once(notification.onDidClose)(() => notificationDisposables.dispose()); - return handle; + return notification; }; const updateProgress = (notification: INotificationHandle, increment?: number): void => { diff --git a/src/vs/workbench/test/common/notifications.test.ts b/src/vs/workbench/test/common/notifications.test.ts index 7eefd25cb8e..a050bc29422 100644 --- a/src/vs/workbench/test/common/notifications.test.ts +++ b/src/vs/workbench/test/common/notifications.test.ts @@ -98,6 +98,17 @@ suite('Notifications', () => { assert.equal(called, 1); + called = 0; + item1.onDidChangeVisibility(e => { + called++; + }); + + item1.updateVisibility(true); + item1.updateVisibility(false); + item1.updateVisibility(false); + + assert.equal(called, 2); + called = 0; item1.onDidClose(() => { called++; From f9b397429954f2bdae755a0eea2b3bc1b40c3f9e Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 27 Feb 2020 13:13:33 +0100 Subject: [PATCH 133/235] notifications - handle markdown links in status bar --- .../services/progress/browser/progressService.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/services/progress/browser/progressService.ts b/src/vs/workbench/services/progress/browser/progressService.ts index e0b2980aad4..2f464fb7405 100644 --- a/src/vs/workbench/services/progress/browser/progressService.ts +++ b/src/vs/workbench/services/progress/browser/progressService.ts @@ -24,6 +24,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { EventHelper } from 'vs/base/browser/dom'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; +import { parseLinkedText } from 'vs/base/common/linkedText'; export class ProgressService extends Disposable implements IProgressService { @@ -200,17 +201,25 @@ export class ProgressService extends Disposable implements IProgressService { this.withWindowProgress({ location: ProgressLocation.Window, - title: options.title, + title: options.title ? parseLinkedText(options.title).toString() : undefined, // convert markdown links => string command: 'notifications.showList' }, progress => { + function reportProgress(step: IProgressStep) { + if (step.message) { + progress.report({ + message: parseLinkedText(step.message).toString() // convert markdown links => string + }); + } + } + // Apply any progress that was made already if (progressStateModel.step) { - progress.report(progressStateModel.step); + reportProgress(progressStateModel.step); } // Continue to report progress as it happens - const onDidReportListener = progressStateModel.onDidReport(step => progress.report(step)); + const onDidReportListener = progressStateModel.onDidReport(step => reportProgress(step)); promise.finally(() => onDidReportListener.dispose()); // When the progress model gets disposed, we are done as well From 4f232ba78f3d7dc673fc2f5bbd041cf990987b67 Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Thu, 27 Feb 2020 13:15:30 +0100 Subject: [PATCH 134/235] improve documentation for debug hover API; fxes #91404 --- src/vs/vscode.d.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 207183cb8d8..cbf69745888 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2495,16 +2495,18 @@ declare module 'vscode' { /** * The evaluatable expression provider interface defines the contract between extensions and - * the debug hover. + * the debug hover. In this contract the provider returns an evaluatable expression for a given position + * in a document and VS Code evaluates this expression in the active debug session and shows the result in a debug hover. */ export interface EvaluatableExpressionProvider { /** * Provide an evaluatable expression for the given document and position. + * VS Code will evaluate this expression in the active debug session and will show the result in the debug hover. * The expression can be implicitly specified by the range in the underlying document or by explicitly returning an expression. * - * @param document The document in which the debug hover is opened. - * @param position The position in the document where the debug hover is opened. + * @param document The document for which the debug hover is about to appear. + * @param position The line and character position in the document where the debug hover is about to appear. * @param token A cancellation token. * @return An EvaluatableExpression or a thenable that resolves to such. The lack of a result can be * signaled by returning `undefined` or `null`. @@ -9174,6 +9176,7 @@ declare module 'vscode' { /** * Register a provider that locates evaluatable expressions in text documents. + * VS Code will evaluate the expression in the active debug session and will show the result in the debug hover. * * If multiple providers are registered for a language an arbitrary provider will be used. * From 0bab257fe5d087a7064b4ffeeb30827e4ce8a67a Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 27 Feb 2020 14:22:23 +0100 Subject: [PATCH 135/235] smoke - remove firefox from docs --- test/smoke/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/smoke/README.md b/test/smoke/README.md index 8b41d05ed08..7bec799f89d 100644 --- a/test/smoke/README.md +++ b/test/smoke/README.md @@ -13,13 +13,13 @@ yarn --cwd test/automation yarn smoketest # Dev (Web) -yarn smoketest --web --browser [chromium|firefox|webkit] +yarn smoketest --web --browser [chromium|webkit] # Build (Electron) yarn smoketest --build --stable-build # Build (Web - read instructions below) -yarn smoketest --build --web --browser [chromium|firefox|webkit] +yarn smoketest --build --web --browser [chromium|webkit] # Remote (Electron) yarn smoketest --build --remote From fbb020867f97d7f08cf00e9e9156c10a3bebe817 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Thu, 27 Feb 2020 14:53:37 +0100 Subject: [PATCH 136/235] File schema check was deleted from simple file dialog Paritally reverts commit 5dfa261ceddacf93eefc9612e48b170f3ee8bbf0 Fixes #91687 --- .../services/dialogs/browser/simpleFileDialog.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts b/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts index e9e8c8fff36..58c9355d126 100644 --- a/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts +++ b/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts @@ -156,7 +156,7 @@ export class SimpleFileDialog { public async showOpenDialog(options: IOpenDialogOptions = {}): Promise { this.scheme = this.getScheme(options.availableFileSystems, options.defaultUri); - this.userHome = await this.remotePathService.userHome; + this.userHome = await this.getUserHome(); const newOptions = this.getOptions(options); if (!newOptions) { return Promise.resolve(undefined); @@ -167,7 +167,7 @@ export class SimpleFileDialog { public async showSaveDialog(options: ISaveDialogOptions): Promise { this.scheme = this.getScheme(options.availableFileSystems, options.defaultUri); - this.userHome = await this.remotePathService.userHome; + this.userHome = await this.getUserHome(); this.requiresTrailing = true; const newOptions = this.getOptions(options, true); if (!newOptions) { @@ -231,6 +231,13 @@ export class SimpleFileDialog { return this.remoteAgentEnvironment; } + private async getUserHome(): Promise { + if (this.scheme !== Schemas.file) { + return this.remotePathService.userHome; + } + return URI.from({ scheme: this.scheme, path: this.environmentService.userHome }); + } + private async pickResource(isSave: boolean = false): Promise { this.allowFolderSelection = !!this.options.canSelectFolders; this.allowFileSelection = !!this.options.canSelectFiles; From 6a0b43c06222efa199cb1854f957608736647708 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 27 Feb 2020 15:10:18 +0100 Subject: [PATCH 137/235] Fixes #91644 --- src/vs/editor/browser/widget/diffReview.ts | 23 ++++++++++++++----- .../browser/widget/media/diffReview.css | 9 ++++---- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/vs/editor/browser/widget/diffReview.ts b/src/vs/editor/browser/widget/diffReview.ts index cfa24de682f..2da217bb864 100644 --- a/src/vs/editor/browser/widget/diffReview.ts +++ b/src/vs/editor/browser/widget/diffReview.ts @@ -617,10 +617,11 @@ export class DiffReview extends Disposable { header.setAttribute('role', 'listitem'); container.appendChild(header); + const lineHeight = modifiedOptions.get(EditorOption.lineHeight); let modLine = minModifiedLine; for (let i = 0, len = diffs.length; i < len; i++) { const diffEntry = diffs[i]; - DiffReview._renderSection(container, diffEntry, modLine, this._width, originalOptions, originalModel, originalModelOpts, modifiedOptions, modifiedModel, modifiedModelOpts); + DiffReview._renderSection(container, diffEntry, modLine, lineHeight, this._width, originalOptions, originalModel, originalModelOpts, modifiedOptions, modifiedModel, modifiedModelOpts); if (diffEntry.modifiedLineStart !== 0) { modLine = diffEntry.modifiedLineEnd; } @@ -632,7 +633,7 @@ export class DiffReview extends Disposable { } private static _renderSection( - dest: HTMLElement, diffEntry: DiffEntry, modLine: number, width: number, + dest: HTMLElement, diffEntry: DiffEntry, modLine: number, lineHeight: number, width: number, originalOptions: IComputedEditorOptions, originalModel: ITextModel, originalModelOpts: TextModelResolvedOptions, modifiedOptions: IComputedEditorOptions, modifiedModel: ITextModel, modifiedModelOpts: TextModelResolvedOptions ): void { @@ -641,17 +642,18 @@ export class DiffReview extends Disposable { let rowClassName: string = 'diff-review-row'; let lineNumbersExtraClassName: string = ''; - let spacerClassName: string = 'diff-review-spacer'; + const spacerClassName: string = 'diff-review-spacer'; + let spacerCodiconName: string | null = null; switch (type) { case DiffEntryType.Insert: rowClassName = 'diff-review-row line-insert'; lineNumbersExtraClassName = ' char-insert'; - spacerClassName = 'diff-review-spacer insert-sign'; + spacerCodiconName = 'codicon codicon-add'; break; case DiffEntryType.Delete: rowClassName = 'diff-review-row line-delete'; lineNumbersExtraClassName = ' char-delete'; - spacerClassName = 'diff-review-spacer delete-sign'; + spacerCodiconName = 'codicon codicon-remove'; break; } @@ -686,6 +688,7 @@ export class DiffReview extends Disposable { let cell = document.createElement('div'); cell.className = 'diff-review-cell'; + cell.style.height = `${lineHeight}px`; row.appendChild(cell); const originalLineNumber = document.createElement('span'); @@ -713,7 +716,15 @@ export class DiffReview extends Disposable { const spacer = document.createElement('span'); spacer.className = spacerClassName; - spacer.innerHTML = '  '; + + if (spacerCodiconName) { + const spacerCodicon = document.createElement('span'); + spacerCodicon.className = spacerCodiconName; + spacerCodicon.innerHTML = '  '; + spacer.appendChild(spacerCodicon); + } else { + spacer.innerHTML = '  '; + } cell.appendChild(spacer); let lineContent: string; diff --git a/src/vs/editor/browser/widget/media/diffReview.css b/src/vs/editor/browser/widget/media/diffReview.css index b2b17028489..56c6f15cbf6 100644 --- a/src/vs/editor/browser/widget/media/diffReview.css +++ b/src/vs/editor/browser/widget/media/diffReview.css @@ -37,13 +37,14 @@ width: 100%; } -.monaco-diff-editor .diff-review-cell { - display: table-cell; -} - .monaco-diff-editor .diff-review-spacer { display: inline-block; width: 10px; + vertical-align: middle; +} + +.monaco-diff-editor .diff-review-spacer > .codicon { + font-size: 9px !important; } .monaco-diff-editor .diff-review-actions { From 9e8d88b23277a1bd255327caba881e6358159a89 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 27 Feb 2020 16:06:41 +0100 Subject: [PATCH 138/235] Fixes #91460 --- src/vs/editor/common/controller/cursor.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/common/controller/cursor.ts b/src/vs/editor/common/controller/cursor.ts index 883abf19c6d..d1dc46b0a16 100644 --- a/src/vs/editor/common/controller/cursor.ts +++ b/src/vs/editor/common/controller/cursor.ts @@ -430,15 +430,14 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { return this._columnSelectData; } const primaryCursor = this._cursors.getPrimaryCursor(); - const primaryPos = primaryCursor.viewState.selectionStart.getStartPosition(); - const viewLineNumber = primaryPos.lineNumber; - const viewVisualColumn = CursorColumns.visibleColumnFromColumn2(this.context.config, this.context.viewModel, primaryPos); + const viewSelectionStart = primaryCursor.viewState.selectionStart.getStartPosition(); + const viewPosition = primaryCursor.viewState.position; return { isReal: false, - fromViewLineNumber: viewLineNumber, - fromViewVisualColumn: viewVisualColumn, - toViewLineNumber: viewLineNumber, - toViewVisualColumn: viewVisualColumn, + fromViewLineNumber: viewSelectionStart.lineNumber, + fromViewVisualColumn: CursorColumns.visibleColumnFromColumn2(this.context.config, this.context.viewModel, viewSelectionStart), + toViewLineNumber: viewPosition.lineNumber, + toViewVisualColumn: CursorColumns.visibleColumnFromColumn2(this.context.config, this.context.viewModel, viewPosition), }; } From 684e2399e04a3af0b40ab4b753fbb837452253eb Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Thu, 27 Feb 2020 08:00:01 -0800 Subject: [PATCH 139/235] remove from cmd palette fixes #91423 --- src/vs/workbench/browser/actions/layoutActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index 0ece351afc3..5cde8dd380a 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -613,7 +613,7 @@ export class MoveFocusedViewAction extends Action { } } -registry.registerWorkbenchAction(SyncActionDescriptor.create(MoveFocusedViewAction, MoveFocusedViewAction.ID, MoveFocusedViewAction.LABEL), 'View: Move Focused View', viewCategory); +registry.registerWorkbenchAction(SyncActionDescriptor.create(MoveFocusedViewAction, MoveFocusedViewAction.ID, MoveFocusedViewAction.LABEL), 'View: Move Focused View', viewCategory, FocusedViewContext.notEqualsTo('')); // --- Resize View From d983fe60149c8c82782313c3a3e85a215c8fecda Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 25 Feb 2020 11:40:13 -0500 Subject: [PATCH 140/235] Fixes bad encoding in title - ref #91377 --- extensions/git/src/commands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 10d2cfc2d5b..a27fa783fc0 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -2357,7 +2357,7 @@ export class CommandCenter { else if (item.previousRef === 'HEAD' && item.ref === '~') { title = localize('git.title.index', '{0} (Index)', basename); } else { - title = localize('git.title.diffRefs', '{0} ({1}) \u27f7 {0} ({2})', basename, item.shortPreviousRef, item.shortRef); + title = localize('git.title.diffRefs', '{0} ({1}) ⟷ {0} ({2})', basename, item.shortPreviousRef, item.shortRef); } return commands.executeCommand('vscode.diff', toGitUri(uri, item.previousRef), item.ref === '' ? uri : toGitUri(uri, item.ref), title); From 5acdde478f2911d6f375b56ad00e267cc8beaf4f Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Thu, 27 Feb 2020 11:23:23 -0500 Subject: [PATCH 141/235] Fixes #91677 --- .../contrib/timeline/browser/timelinePane.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/timeline/browser/timelinePane.ts b/src/vs/workbench/contrib/timeline/browser/timelinePane.ts index d438a1b739c..29dceaaca3d 100644 --- a/src/vs/workbench/contrib/timeline/browser/timelinePane.ts +++ b/src/vs/workbench/contrib/timeline/browser/timelinePane.ts @@ -251,7 +251,7 @@ export class TimelinePane extends ViewPane { } this._tree.setChildren(null, undefined); - this.message = localize('timeline.loading', 'Loading timeline for ${0}...', basename(uri.fsPath)); + this.message = localize('timeline.loading', 'Loading timeline for {0}...', basename(uri.fsPath)); }, 500, this._uri); } } @@ -291,7 +291,7 @@ export class TimelinePane extends ViewPane { if (!reset) { // TODO: Handle pending request - if (cursors?.more === false) { + if (cursors?.more !== true) { continue; } @@ -306,6 +306,10 @@ export class TimelinePane extends ViewPane { request?.tokenSource ?? new CancellationTokenSource(), { cacheResults: true } )!; + if (request === undefined) { + continue; + } + this._pendingRequests.set(source, request); if (!reusingToken) { request.tokenSource.token.onCancellationRequested(() => this._pendingRequests.delete(source)); @@ -322,6 +326,10 @@ export class TimelinePane extends ViewPane { new CancellationTokenSource(), { cacheResults: true } )!; + if (request === undefined) { + continue; + } + this._pendingRequests.set(source, request); request.tokenSource.token.onCancellationRequested(() => this._pendingRequests.delete(source)); } From 2f0714be6286cb0392db1e111748b912a749412b Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Thu, 27 Feb 2020 08:30:33 -0800 Subject: [PATCH 142/235] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: João Moreno --- src/vs/base/browser/ui/list/listView.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index ade0ed5b030..1138d7f4a14 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -279,21 +279,24 @@ export class ListView implements ISpliceable, IDisposable { this.scrollableElement.triggerScrollFromMouseWheelEvent(browserEvent); } - updateElementHeight(index: number, element: T, size: number): void { + updateElementHeight(index: number, size: number): void { + if (this.items[index].size === size) { + return; + } + const lastRenderRange = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight); - let heightDiff = index < lastRenderRange.start ? size - this.items[index].size : 0; + const heightDiff = index < lastRenderRange.start ? size - this.items[index].size : 0; this.rangeMap.splice(index, 1, [{ size: size }]); - this.items[index].size = size; this.render(lastRenderRange, this.lastRenderTop + heightDiff, this.lastRenderHeight, undefined, undefined, true); + this.eventuallyUpdateScrollDimensions(); + if (this.supportDynamicHeights) { this._rerender(this.lastRenderTop, this.lastRenderHeight); } - - this.eventuallyUpdateScrollDimensions(); return; } From bddc5ef7019edf0a1c2d8be9ba2cba832cd614cb Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 27 Feb 2020 17:54:17 +0100 Subject: [PATCH 143/235] Fix #91486 --- src/vs/platform/environment/node/environmentService.ts | 2 +- src/vs/platform/userDataSync/common/abstractSynchronizer.ts | 2 +- .../services/environment/browser/environmentService.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index 0428e1e888a..15b5c20cbbf 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -112,7 +112,7 @@ export class EnvironmentService implements IEnvironmentService { get settingsResource(): URI { return resources.joinPath(this.userRoamingDataHome, 'settings.json'); } @memoize - get userDataSyncHome(): URI { return resources.joinPath(this.userRoamingDataHome, '.sync'); } + get userDataSyncHome(): URI { return resources.joinPath(this.userRoamingDataHome, 'sync'); } @memoize get settingsSyncPreviewResource(): URI { return resources.joinPath(this.userDataSyncHome, 'settings.json'); } diff --git a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts index 92590672d67..0dcf03eebde 100644 --- a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts +++ b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts @@ -68,7 +68,7 @@ export abstract class AbstractSynchroniser extends Disposable { ) { super(); this.syncFolder = joinPath(environmentService.userDataSyncHome, source); - this.lastSyncResource = joinPath(this.syncFolder, `.lastSync${source}.json`); + this.lastSyncResource = joinPath(this.syncFolder, `lastSync${source}.json`); this.cleanUpDelayer = new ThrottledDelayer(50); this.cleanUpBackup(); } diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index b7ee69dc594..c94ee4e88cf 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -137,7 +137,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment get argvResource(): URI { return joinPath(this.userRoamingDataHome, 'argv.json'); } @memoize - get userDataSyncHome(): URI { return joinPath(this.userRoamingDataHome, '.sync'); } + get userDataSyncHome(): URI { return joinPath(this.userRoamingDataHome, 'sync'); } @memoize get settingsSyncPreviewResource(): URI { return joinPath(this.userDataSyncHome, 'settings.json'); } From b77929959cb3e0b13d669fb7f711bca77ac7ff02 Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Thu, 27 Feb 2020 10:12:12 -0800 Subject: [PATCH 144/235] Log additional information when getting auth token --- extensions/vscode-account/src/AADHelper.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extensions/vscode-account/src/AADHelper.ts b/extensions/vscode-account/src/AADHelper.ts index b1aee3e6bdf..16e7990be0b 100644 --- a/extensions/vscode-account/src/AADHelper.ts +++ b/extensions/vscode-account/src/AADHelper.ts @@ -192,7 +192,9 @@ export class AzureActiveDirectoryService { private async resolveAccessToken(token: IToken): Promise { if (token.accessToken && (!token.expiresAt || token.expiresAt > Date.now())) { - Logger.info('Token available from cache'); + token.expiresAt + ? Logger.info(`Token available from cache, expires in ${token.expiresAt - Date.now()} milliseconds`) + : Logger.info('Token available from cache'); return Promise.resolve(token.accessToken); } From d7a42153287b9c7f3da8a8fcbe01925c7d783565 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 27 Feb 2020 10:47:40 -0800 Subject: [PATCH 145/235] Fix #90552 --- src/vs/editor/contrib/suggest/media/suggest.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index 875769452fa..af01d6da5c5 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -234,7 +234,7 @@ flex-shrink: 0; } .monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label) > .contents > .main > .left > .monaco-icon-label { - max-width: 80%; + max-width: 100%; } .monaco-editor .suggest-widget .monaco-list .monaco-list-row.string-label > .contents > .main > .left > .monaco-icon-label { flex-shrink: 1; From 9c70b061384794c1755a959d0cace6191ee4f300 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 27 Feb 2020 10:51:15 -0800 Subject: [PATCH 146/235] Revert "Fix #90552" This reverts commit d7a42153287b9c7f3da8a8fcbe01925c7d783565. --- src/vs/editor/contrib/suggest/media/suggest.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index af01d6da5c5..875769452fa 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -234,7 +234,7 @@ flex-shrink: 0; } .monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label) > .contents > .main > .left > .monaco-icon-label { - max-width: 100%; + max-width: 80%; } .monaco-editor .suggest-widget .monaco-list .monaco-list-row.string-label > .contents > .main > .left > .monaco-icon-label { flex-shrink: 1; From d87d03311db5abe1e301f038ebd83e02add658ea Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 27 Feb 2020 10:51:39 -0800 Subject: [PATCH 147/235] Fix #90865 --- src/vs/editor/contrib/suggest/media/suggest.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index 875769452fa..af01d6da5c5 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -234,7 +234,7 @@ flex-shrink: 0; } .monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.string-label) > .contents > .main > .left > .monaco-icon-label { - max-width: 80%; + max-width: 100%; } .monaco-editor .suggest-widget .monaco-list .monaco-list-row.string-label > .contents > .main > .left > .monaco-icon-label { flex-shrink: 1; From a35a8a2acf6f067de9fca2a2526659f4e50b1b01 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 27 Feb 2020 11:03:48 -0800 Subject: [PATCH 148/235] Fix #89772 --- src/vs/editor/common/config/editorOptions.ts | 23 +++++++++++++------ .../editor/contrib/suggest/suggestWidget.ts | 2 +- src/vs/monaco.d.ts | 9 ++++++-- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 941502e43d3..284c6f904bb 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -2835,9 +2835,14 @@ export interface ISuggestOptions { */ showSnippets?: boolean; /** - * Controls the visibility of the status bar at the bottom of the suggest widget. + * Status bar related settings. */ - hideStatusBar?: boolean; + statusBar?: { + /** + * Controls the visibility of the status bar at the bottom of the suggest widget. + */ + visible?: boolean; + } } export type InternalSuggestOptions = Readonly>; @@ -2879,7 +2884,9 @@ class EditorSuggest extends BaseEditorOption toggleClass(this.element, 'with-status-bar', !this.editor.getOption(EditorOption.suggest).hideStatusBar); + const applyStatusBarStyle = () => toggleClass(this.element, 'with-status-bar', this.editor.getOption(EditorOption.suggest).statusBar.visible); applyStatusBarStyle(); this.statusBarElement = append(this.element, $('.suggest-status-bar')); diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index ecb0e10c7ca..543ac0ca086 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -3754,9 +3754,14 @@ declare namespace monaco.editor { */ showSnippets?: boolean; /** - * Controls the visibility of the status bar at the bottom of the suggest widget. + * Status bar related settings. */ - hideStatusBar?: boolean; + statusBar?: { + /** + * Controls the visibility of the status bar at the bottom of the suggest widget. + */ + visible?: boolean; + }; } export type InternalSuggestOptions = Readonly>; From 06529506b21c87ac276272041bc1cf586c25dcde Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Thu, 27 Feb 2020 11:04:51 -0800 Subject: [PATCH 149/235] debug: update js-debug-nightly to "2020.2.2617" @ 2020-02-27T01:06:21.78Z --- build/builtInExtensions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index ddc65ea119f..bd9188f8ee1 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -46,7 +46,7 @@ }, { "name": "ms-vscode.js-debug-nightly", - "version": "2020.2.2517", + "version": "2020.2.2617", "forQualities": [ "insider" ], From 8ef18acdaf4502e3b81efc498036b432e925df04 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 27 Feb 2020 11:55:33 -0800 Subject: [PATCH 150/235] Don't require return value backup Fixes #91703 All custom editors should implement backup or throw an exception if they cannot for some reason. --- src/vs/vscode.proposed.d.ts | 2 +- src/vs/workbench/api/common/extHost.protocol.ts | 2 +- src/vs/workbench/api/common/extHostWebview.ts | 2 +- .../contrib/customEditor/common/customEditor.ts | 2 +- .../contrib/customEditor/common/customEditorModel.ts | 12 ++++++++---- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 6c28f957862..15474e3339a 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1273,7 +1273,7 @@ declare module 'vscode' { * in an operation that takes time to complete, your extension may decide to finish the ongoing backup rather * than cancelling it to ensure that VS Code has some valid backup. */ - backup(cancellation: CancellationToken): Thenable; + backup(cancellation: CancellationToken): Thenable; } /** diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index a54b3d0766a..10f51d23548 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -620,7 +620,7 @@ export interface ExtHostWebviewsShape { $onSave(resource: UriComponents, viewType: string): Promise; $onSaveAs(resource: UriComponents, viewType: string, targetResource: UriComponents): Promise; - $backup(resource: UriComponents, viewType: string, cancellation: CancellationToken): Promise; + $backup(resource: UriComponents, viewType: string, cancellation: CancellationToken): Promise; } export interface MainThreadUrlsShape extends IDisposable { diff --git a/src/vs/workbench/api/common/extHostWebview.ts b/src/vs/workbench/api/common/extHostWebview.ts index 539f31df1c2..cfac95a00b3 100644 --- a/src/vs/workbench/api/common/extHostWebview.ts +++ b/src/vs/workbench/api/common/extHostWebview.ts @@ -727,7 +727,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { return document._saveAs(URI.revive(targetResource)); } - async $backup(resourceComponents: UriComponents, viewType: string, cancellation: CancellationToken): Promise { + async $backup(resourceComponents: UriComponents, viewType: string, cancellation: CancellationToken): Promise { const document = this.getDocument(viewType, resourceComponents); return document._backup(cancellation); } diff --git a/src/vs/workbench/contrib/customEditor/common/customEditor.ts b/src/vs/workbench/contrib/customEditor/common/customEditor.ts index a0e84261e3a..f14ffcf0a81 100644 --- a/src/vs/workbench/contrib/customEditor/common/customEditor.ts +++ b/src/vs/workbench/contrib/customEditor/common/customEditor.ts @@ -74,7 +74,7 @@ export interface ICustomEditorModel extends IWorkingCopy { readonly onWillSave: Event; readonly onWillSaveAs: Event; - onBackup(f: () => CancelablePromise): void; + onBackup(f: () => CancelablePromise): void; setDirty(dirty: boolean): void; undo(): void; diff --git a/src/vs/workbench/contrib/customEditor/common/customEditorModel.ts b/src/vs/workbench/contrib/customEditor/common/customEditorModel.ts index 6adac4c6199..43f887a82a0 100644 --- a/src/vs/workbench/contrib/customEditor/common/customEditorModel.ts +++ b/src/vs/workbench/contrib/customEditor/common/customEditorModel.ts @@ -29,7 +29,7 @@ namespace HotExitState { readonly type = Type.Pending; constructor( - public readonly operation: CancelablePromise, + public readonly operation: CancelablePromise, ) { } } @@ -90,9 +90,9 @@ export class CustomEditorModel extends Disposable implements ICustomEditorModel private readonly _onWillSaveAs = this._register(new Emitter()); public readonly onWillSaveAs = this._onWillSaveAs.event; - private _onBackup: undefined | (() => CancelablePromise); + private _onBackup: undefined | (() => CancelablePromise); - public onBackup(f: () => CancelablePromise) { + public onBackup(f: () => CancelablePromise) { if (this._onBackup) { throw new Error('Backup already implemented'); } @@ -182,7 +182,11 @@ export class CustomEditorModel extends Disposable implements ICustomEditorModel this._hotExitState = pendingState; try { - this._hotExitState = await pendingState.operation ? HotExitState.Allowed : HotExitState.NotAllowed; + await pendingState.operation; + // Make sure state has not changed in the meantime + if (this._hotExitState === pendingState) { + this._hotExitState = HotExitState.Allowed; + } } catch (e) { // Make sure state has not changed in the meantime if (this._hotExitState === pendingState) { From fac3bb4bf64afa342d15887ac4fcd1c3d526a270 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 27 Feb 2020 14:09:46 -0800 Subject: [PATCH 151/235] Clairify documentation docs Fixes #91514 --- src/vs/vscode.proposed.d.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 15474e3339a..d1ccd81b83f 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1682,9 +1682,10 @@ declare module 'vscode' { * * The documentation is shown in the code actions menu if either: * - * - Code actions of `kind` are requested by VS Code. Note that in this case, we always pick the most specific - * documentation. For example, if documentation for both `Refactor` and `RefactorExtract` is provided, and we - * request code actions for `RefactorExtract`, we prefer the more specific documentation for `RefactorExtract`. + * - Code actions of `kind` are requested by VS Code. In this case, VS Code will show the documentation that + * most closely matches the requested code action kind. For example, if a provider has documentation for + * both `Refactor` and `RefactorExtract`, when the user requests code actions for `RefactorExtract`, + * VS Code will use the documentation for `RefactorExtract` intead of the documentation for `Refactor`. * * - Any code actions of `kind` are returned by the provider. */ From 1bbce1ce03d60c81d1247edfdf502d1aefe456db Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 27 Feb 2020 14:23:56 -0800 Subject: [PATCH 152/235] Improve docs for `CodeAction.disabled` For #85160 --- src/vs/vscode.d.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index cbf69745888..9e852eca701 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2020,7 +2020,7 @@ declare module 'vscode' { * Base kind for source actions: `source` * * Source code actions apply to the entire file. They must be explicitly requested and will not show in the - * normal [light bulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) menu. Source actions + * normal [lightbulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) menu. Source actions * can be run on save using `editor.codeActionsOnSave` and are also shown in the `source` context menu. */ static readonly Source: CodeActionKind; @@ -2086,7 +2086,7 @@ declare module 'vscode' { /** * Requested kind of actions to return. * - * Actions not of this kind are filtered out before being shown by the lightbulb. + * Actions not of this kind are filtered out before being shown by the [lightbulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action). */ readonly only?: CodeActionKind; } @@ -2138,7 +2138,15 @@ declare module 'vscode' { /** * Marks that the code action cannot currently be applied. * - * Disabled code actions will be surfaced in the refactor UI but cannot be applied. + * - Disabled code actions are not shown in automatic [lightbulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) + * code action menu. + * + * - Disabled actions are shown as faded out in the code action menu when the user request a more specific type + * of code action, such as refactorings. + * + * - If the user has a [keybinding](https://code.visualstudio.com/docs/editor/refactoring#_keybindings-for-code-actions) + * that auto applies a code action and only a disabled code actions are returned, VS Code will show the user a + * message with `reason` in the editor. */ disabled?: { /** @@ -2163,7 +2171,7 @@ declare module 'vscode' { /** * The code action interface defines the contract between extensions and - * the [light bulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) feature. + * the [lightbulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) feature. * * A code action can be any command that is [known](#commands.getCommands) to the system. */ From e5834d3280fcd04898efeac32b9cf1b893f9b127 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Thu, 27 Feb 2020 17:31:32 -0500 Subject: [PATCH 153/235] Fixes #91378 --- src/vs/workbench/api/common/extHostTimeline.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/api/common/extHostTimeline.ts b/src/vs/workbench/api/common/extHostTimeline.ts index 87fefc82cfc..9db000d04f7 100644 --- a/src/vs/workbench/api/common/extHostTimeline.ts +++ b/src/vs/workbench/api/common/extHostTimeline.ts @@ -71,11 +71,17 @@ export class ExtHostTimeline implements IExtHostTimeline { scheme: scheme, onDidChange: undefined, async provideTimeline(uri: URI, options: TimelineOptions, token: CancellationToken, internalOptions?: { cacheResults?: boolean }) { - timelineDisposables.clear(); - // For now, only allow the caching of a single Uri - if (internalOptions?.cacheResults && !itemsBySourceByUriMap.has(getUriKey(uri))) { - itemsBySourceByUriMap.clear(); + if (internalOptions?.cacheResults) { + if (options.cursor === undefined) { + timelineDisposables.clear(); + } + + if (!itemsBySourceByUriMap.has(getUriKey(uri))) { + itemsBySourceByUriMap.clear(); + } + } else { + timelineDisposables.clear(); } const result = await provider.provideTimeline(uri, options, token); From 8c8c6cdf8f9935aa2b7a97a4d3acecb8c1d18068 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 28 Feb 2020 09:27:13 +0100 Subject: [PATCH 154/235] Fix #91725 --- src/vs/platform/userDataSync/common/abstractSynchronizer.ts | 1 - src/vs/platform/userDataSync/common/userDataSync.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts index 0dcf03eebde..58ea47ff8bc 100644 --- a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts +++ b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts @@ -219,7 +219,6 @@ export abstract class AbstractSynchroniser extends Disposable { const stat = await this.fileService.resolve(this.syncFolder); if (stat.children) { const all = stat.children.filter(stat => stat.isFile && /^\d{8}T\d{6}(\.json)?$/.test(stat.name)).sort(); - console.log(all.map(a => a.name)); const backUpMaxAge = 1000 * 60 * 60 * 24 * (this.configurationService.getValue('sync.localBackupDuration') || 30 /* Default 30 days */); let toDelete = all.filter(stat => { const ctime = stat.ctime || new Date( diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index 79589c43e4f..b2911d2a364 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -96,7 +96,6 @@ export function registerConfiguration(): IDisposable { const defaultIgnoredSettings = getDefaultIgnoredSettings().filter(s => s !== CONFIGURATION_SYNC_STORE_KEY); const settings = Object.keys(allSettings.properties).filter(setting => defaultIgnoredSettings.indexOf(setting) === -1); const ignoredSettings = defaultIgnoredSettings.filter(setting => disallowedIgnoredSettings.indexOf(setting) === -1); - console.log(ignoredSettings); const ignoredSettingsSchema: IJSONSchema = { items: { type: 'string', From 1cc28745dd55009a32df0789ff8890d7ae1fa278 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 28 Feb 2020 10:36:40 +0100 Subject: [PATCH 155/235] Regression: Quickly closing a git commit message in VS code skips autosave, causing a (fix #91709) (#91732) --- src/vs/workbench/electron-browser/window.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index d4c3246d98d..e1c129c76f1 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -613,6 +613,8 @@ export class ElectronWindow extends Disposable { } private trackClosedWaitFiles(waitMarkerFile: URI, resourcesToWaitFor: URI[]): IDisposable { + let remainingResourcesToWaitFor = resourcesToWaitFor.slice(0); + // In wait mode, listen to changes to the editors and wait until the files // are closed that the user wants to wait for. When this happens we delete // the wait marker file to signal to the outside that editing is done. @@ -622,7 +624,7 @@ export class ElectronWindow extends Disposable { // Remove from resources to wait for based on the // resources from editors that got closed - resourcesToWaitFor = resourcesToWaitFor.filter(resourceToWaitFor => { + remainingResourcesToWaitFor = remainingResourcesToWaitFor.filter(resourceToWaitFor => { if (isEqual(resourceToWaitFor, masterResource) || isEqual(resourceToWaitFor, detailsResource)) { return false; // remove - the closing editor matches this resource } @@ -630,7 +632,7 @@ export class ElectronWindow extends Disposable { return true; // keep - not yet closed }); - if (resourcesToWaitFor.length === 0) { + if (remainingResourcesToWaitFor.length === 0) { // If auto save is configured with the default delay (1s) it is possible // to close the editor while the save still continues in the background. As such // we have to also check if the files to wait for are dirty and if so wait From 3608ffb2b3942240200a4686a529616730644d3b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 28 Feb 2020 10:43:53 +0100 Subject: [PATCH 156/235] Fix #91661 --- src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index aeb8ef22ab9..174055d3a88 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -49,6 +49,7 @@ import { fromNow } from 'vs/base/common/date'; import { IProductService } from 'vs/platform/product/common/productService'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { timeout } from 'vs/base/common/async'; const enum AuthStatus { Initializing = 'Initializing', @@ -941,7 +942,8 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo quickPick.items = items; disposables.add(quickPick.onDidAccept(() => { if (quickPick.selectedItems[0] && quickPick.selectedItems[0].id) { - commandService.executeCommand(quickPick.selectedItems[0].id); + // Introduce timeout as workaround - #91661 #91740 + timeout(0).then(() => commandService.executeCommand(quickPick.selectedItems[0].id!)); } quickPick.hide(); })); From b575a51ebcfd33f599e7fd695102f551a8166b2a Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 28 Feb 2020 11:02:46 +0100 Subject: [PATCH 157/235] Fix #91737 --- src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index aeb8ef22ab9..96b55d61fa6 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -510,7 +510,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } ); switch (result.choice) { - case 0: this.openerService.open(URI.parse('https://go.microsoft.com/fwlink/?LinkId=827846')); return; + case 0: this.openerService.open(URI.parse('https://aka.ms/vscode-settings-sync-help')); return; case 2: return; } } From a949694b25eb9e01998b4033103e0420ab18674c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 28 Feb 2020 11:33:55 +0100 Subject: [PATCH 158/235] debt - reduce usage of explicit any --- .eslintrc.json | 3 +- src/vs/base/browser/fastDomNode.ts | 4 +- src/vs/base/browser/iframe.ts | 2 +- src/vs/base/browser/touch.ts | 2 +- src/vs/base/browser/ui/actionbar/actionbar.ts | 10 +- src/vs/base/browser/ui/toolbar/toolbar.ts | 6 +- src/vs/base/common/assert.ts | 4 +- src/vs/base/common/stream.ts | 4 +- src/vs/base/common/strings.ts | 6 +- src/vs/base/node/crypto.ts | 10 +- src/vs/code/node/cli.ts | 2 +- .../electron-main/electronMainService.ts | 2 +- src/vs/platform/environment/node/stdin.ts | 24 ++--- src/vs/platform/progress/common/progress.ts | 6 +- src/vs/platform/workspace/common/workspace.ts | 4 +- .../platform/workspaces/common/workspaces.ts | 6 +- .../electron-main/workspacesService.ts | 2 +- .../browser/actions/layoutActions.ts | 48 +++------- .../browser/actions/navigationActions.ts | 12 +-- .../browser/actions/workspaceActions.ts | 23 ++--- src/vs/workbench/browser/panel.ts | 2 +- .../parts/activitybar/activitybarActions.ts | 23 ++--- .../workbench/browser/parts/compositeBar.ts | 3 +- .../browser/parts/compositeBarActions.ts | 10 +- .../parts/editor/editor.contribution.ts | 4 +- .../browser/parts/editor/editorActions.ts | 91 ++++++++++--------- .../browser/parts/editor/editorCommands.ts | 2 +- .../browser/parts/editor/editorStatus.ts | 26 ++++-- .../notifications/notificationsActions.ts | 14 +-- .../notifications/notificationsCommands.ts | 6 +- .../browser/parts/panel/panelActions.ts | 26 ++---- .../browser/parts/quickopen/quickopen.ts | 4 +- .../browser/parts/sidebar/sidebarPart.ts | 7 +- .../browser/parts/statusbar/statusbarPart.ts | 8 +- .../browser/parts/views/customView.ts | 2 +- src/vs/workbench/browser/parts/views/views.ts | 4 +- src/vs/workbench/browser/viewlet.ts | 9 +- src/vs/workbench/common/actions.ts | 4 +- src/vs/workbench/common/memento.ts | 2 +- .../editors/textFileSaveErrorHandler.ts | 18 ++-- .../contrib/files/browser/fileActions.ts | 50 +++++----- .../files/browser/views/openEditorsView.ts | 4 +- .../services/activity/common/activity.ts | 38 ++++---- .../editor/test/browser/editorService.test.ts | 2 +- .../environment/browser/environmentService.ts | 2 +- .../progress/browser/progressIndicator.ts | 8 +- .../progress/browser/progressService.ts | 4 +- .../services/statusbar/common/statusbar.ts | 2 +- src/vs/workbench/workbench.web.api.ts | 2 +- 49 files changed, 258 insertions(+), 299 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 5414b07f942..57c99ae5a66 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -35,7 +35,8 @@ "external", "status", "origin", - "orientation" + "orientation", + "context" ], // non-complete list of globals that are easy to access unintentionally "no-var": "warn", "jsdoc/no-types": "warn", diff --git a/src/vs/base/browser/fastDomNode.ts b/src/vs/base/browser/fastDomNode.ts index 28ce15064f9..a5f9c18b2d6 100644 --- a/src/vs/base/browser/fastDomNode.ts +++ b/src/vs/base/browser/fastDomNode.ts @@ -244,11 +244,11 @@ export class FastDomNode { this.domNode.removeAttribute(name); } - public appendChild(child: FastDomNode): void { + public appendChild(child: FastDomNode): void { this.domNode.appendChild(child.domNode); } - public removeChild(child: FastDomNode): void { + public removeChild(child: FastDomNode): void { this.domNode.removeChild(child.domNode); } } diff --git a/src/vs/base/browser/iframe.ts b/src/vs/base/browser/iframe.ts index 7868cafbba2..2ba88fac42d 100644 --- a/src/vs/base/browser/iframe.ts +++ b/src/vs/base/browser/iframe.ts @@ -98,7 +98,7 @@ export class IframeUtils { /** * Returns the position of `childWindow` relative to `ancestorWindow` */ - public static getPositionOfChildWindowRelativeToAncestorWindow(childWindow: Window, ancestorWindow: any) { + public static getPositionOfChildWindowRelativeToAncestorWindow(childWindow: Window, ancestorWindow: Window) { if (!ancestorWindow || childWindow === ancestorWindow) { return { diff --git a/src/vs/base/browser/touch.ts b/src/vs/base/browser/touch.ts index f8b32d9cb76..8eb1262df1f 100644 --- a/src/vs/base/browser/touch.ts +++ b/src/vs/base/browser/touch.ts @@ -131,7 +131,7 @@ export class Gesture extends Disposable { @memoize private static isTouchDevice(): boolean { - return 'ontouchstart' in window as any || navigator.maxTouchPoints > 0 || window.navigator.msMaxTouchPoints > 0; + return 'ontouchstart' in window || navigator.maxTouchPoints > 0 || window.navigator.msMaxTouchPoints > 0; } public dispose(): void { diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 28e9c4b55ed..523a242daaa 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -104,7 +104,7 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { return this._action.enabled; } - setActionContext(newContext: any): void { + setActionContext(newContext: unknown): void { this._context = newContext; } @@ -248,7 +248,7 @@ export class ActionViewItem extends BaseActionViewItem { private cssClass?: string; - constructor(context: any, action: IAction, options: IActionViewItemOptions = {}) { + constructor(context: unknown, action: IAction, options: IActionViewItemOptions = {}) { super(context, action, options); this.options = options; @@ -423,7 +423,7 @@ export class ActionBar extends Disposable implements IActionRunner { options: IActionBarOptions; private _actionRunner: IActionRunner; - private _context: any; + private _context: unknown; // View Items viewItems: IActionViewItem[]; @@ -821,7 +821,7 @@ export class ActionBar extends Disposable implements IActionRunner { this._onDidCancel.fire(); } - run(action: IAction, context?: any): Promise { + run(action: IAction, context?: unknown): Promise { return this._actionRunner.run(action, context); } @@ -838,7 +838,7 @@ export class ActionBar extends Disposable implements IActionRunner { export class SelectActionViewItem extends BaseActionViewItem { protected selectBox: SelectBox; - constructor(ctx: any, action: IAction, options: ISelectOptionItem[], selected: number, contextViewProvider: IContextViewProvider, selectBoxOptions?: ISelectBoxOptions) { + constructor(ctx: unknown, action: IAction, options: ISelectOptionItem[], selected: number, contextViewProvider: IContextViewProvider, selectBoxOptions?: ISelectBoxOptions) { super(ctx, action); this.selectBox = new SelectBox(options, selected, contextViewProvider, undefined, selectBoxOptions); diff --git a/src/vs/base/browser/ui/toolbar/toolbar.ts b/src/vs/base/browser/ui/toolbar/toolbar.ts index 846e156dfa3..8a7a9705228 100644 --- a/src/vs/base/browser/ui/toolbar/toolbar.ts +++ b/src/vs/base/browser/ui/toolbar/toolbar.ts @@ -86,7 +86,7 @@ export class ToolBar extends Disposable { return this.actionBar.actionRunner; } - set context(context: any) { + set context(context: unknown) { this.actionBar.context = context; if (this.toggleMenuActionViewItem.value) { this.toggleMenuActionViewItem.value.setActionContext(context); @@ -166,10 +166,8 @@ class ToggleMenuAction extends Action { this.toggleDropdownMenu = toggleDropdownMenu; } - run(): Promise { + async run(): Promise { this.toggleDropdownMenu(); - - return Promise.resolve(true); } get menuActions(): ReadonlyArray { diff --git a/src/vs/base/common/assert.ts b/src/vs/base/common/assert.ts index 1e227df640e..9e2510b4d0b 100644 --- a/src/vs/base/common/assert.ts +++ b/src/vs/base/common/assert.ts @@ -6,8 +6,8 @@ /** * Throws an error with the provided message if the provided value does not evaluate to a true Javascript value. */ -export function ok(value?: any, message?: string) { +export function ok(value?: unknown, message?: string) { if (!value) { - throw new Error(message ? 'Assertion failed (' + message + ')' : 'Assertion Failed'); + throw new Error(message ? `Assertion failed (${message})` : 'Assertion Failed'); } } diff --git a/src/vs/base/common/stream.ts b/src/vs/base/common/stream.ts index 1172496a897..8234770bd19 100644 --- a/src/vs/base/common/stream.ts +++ b/src/vs/base/common/stream.ts @@ -95,8 +95,8 @@ export interface WriteableStream extends ReadableStream { end(result?: T | Error): void; } -export function isReadableStream(obj: any): obj is ReadableStream { - const candidate: ReadableStream = obj; +export function isReadableStream(obj: unknown): obj is ReadableStream { + const candidate = obj as ReadableStream; return candidate && [candidate.on, candidate.pause, candidate.resume, candidate.destroy].every(fn => typeof fn === 'function'); } diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index 8d67e493772..157057415e5 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -240,7 +240,7 @@ export function regExpFlags(regexp: RegExp): string { return (regexp.global ? 'g' : '') + (regexp.ignoreCase ? 'i' : '') + (regexp.multiline ? 'm' : '') - + ((regexp as any).unicode ? 'u' : ''); + + (regexp.unicode ? 'u' : ''); } /** @@ -853,7 +853,7 @@ export function removeAnsiEscapeCodes(str: string): string { } export const removeAccents: (str: string) => string = (function () { - if (typeof (String.prototype as any).normalize !== 'function') { + if (typeof String.prototype.normalize !== 'function') { // ☹️ no ES6 features... return function (str: string) { return str; }; } else { @@ -861,7 +861,7 @@ export const removeAccents: (str: string) => string = (function () { // see: https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript/37511463#37511463 const regex = /[\u0300-\u036f]/g; return function (str: string) { - return (str as any).normalize('NFD').replace(regex, ''); + return str.normalize('NFD').replace(regex, ''); }; } })(); diff --git a/src/vs/base/node/crypto.ts b/src/vs/base/node/crypto.ts index f18503ab882..7323a92770a 100644 --- a/src/vs/base/node/crypto.ts +++ b/src/vs/base/node/crypto.ts @@ -5,19 +5,17 @@ import * as fs from 'fs'; import * as crypto from 'crypto'; -import * as stream from 'stream'; import { once } from 'vs/base/common/functional'; export function checksum(path: string, sha1hash: string | undefined): Promise { const promise = new Promise((c, e) => { const input = fs.createReadStream(path); const hash = crypto.createHash('sha1'); - const hashStream = hash as any as stream.PassThrough; - input.pipe(hashStream); + input.pipe(hash); const done = once((err?: Error, result?: string) => { input.removeAllListeners(); - hashStream.removeAllListeners(); + hash.removeAllListeners(); if (err) { e(err); @@ -28,8 +26,8 @@ export function checksum(path: string, sha1hash: string | undefined): Promise done(undefined, data.toString('hex'))); + hash.once('error', done); + hash.once('data', (data: Buffer) => done(undefined, data.toString('hex'))); }); return promise.then(hash => { diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index 609395b535a..f1fe93e5f0c 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -128,7 +128,7 @@ export async function main(argv: string[]): Promise { delete env['ELECTRON_RUN_AS_NODE']; - const processCallbacks: ((child: ChildProcess) => Promise)[] = []; + const processCallbacks: ((child: ChildProcess) => Promise)[] = []; const verbose = args.verbose || args.status; if (verbose) { diff --git a/src/vs/platform/electron/electron-main/electronMainService.ts b/src/vs/platform/electron/electron-main/electronMainService.ts index 6a7310f2dc7..27ef89f17e2 100644 --- a/src/vs/platform/electron/electron-main/electronMainService.ts +++ b/src/vs/platform/electron/electron-main/electronMainService.ts @@ -21,7 +21,7 @@ import { URI } from 'vs/base/common/uri'; import { ITelemetryData, ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -export interface IElectronMainService extends AddFirstParameterToFunctions /* only methods, not events */, number | undefined /* window ID */> { } +export interface IElectronMainService extends AddFirstParameterToFunctions /* only methods, not events */, number | undefined /* window ID */> { } export const IElectronMainService = createDecorator('electronMainService'); diff --git a/src/vs/platform/environment/node/stdin.ts b/src/vs/platform/environment/node/stdin.ts index 2cd928e2507..e870ac6e704 100644 --- a/src/vs/platform/environment/node/stdin.ts +++ b/src/vs/platform/environment/node/stdin.ts @@ -39,18 +39,20 @@ export function getStdinFilePath(): string { return paths.join(os.tmpdir(), `code-stdin-${Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 3)}.txt`); } -export function readFromStdin(targetPath: string, verbose: boolean): Promise { +export async function readFromStdin(targetPath: string, verbose: boolean): Promise { + // open tmp file for writing const stdinFileStream = fs.createWriteStream(targetPath); - // Pipe into tmp file using terminals encoding - return resolveTerminalEncoding(verbose).then(async encoding => { - const iconv = await import('iconv-lite'); - if (!iconv.encodingExists(encoding)) { - console.log(`Unsupported terminal encoding: ${encoding}, falling back to UTF-8.`); - encoding = 'utf8'; - } - const converterStream = iconv.decodeStream(encoding); - process.stdin.pipe(converterStream).pipe(stdinFileStream); - }); + let encoding = await resolveTerminalEncoding(verbose); + + const iconv = await import('iconv-lite'); + if (!iconv.encodingExists(encoding)) { + console.log(`Unsupported terminal encoding: ${encoding}, falling back to UTF-8.`); + encoding = 'utf8'; + } + + // Pipe into tmp file using terminals encoding + const converterStream = iconv.decodeStream(encoding); + process.stdin.pipe(converterStream).pipe(stdinFileStream); } diff --git a/src/vs/platform/progress/common/progress.ts b/src/vs/platform/progress/common/progress.ts index a0cea0a3659..b6ff5e5057b 100644 --- a/src/vs/platform/progress/common/progress.ts +++ b/src/vs/platform/progress/common/progress.ts @@ -17,7 +17,7 @@ export interface IProgressService { _serviceBrand: undefined; - withProgress( + withProgress( options: IProgressOptions | IProgressNotificationOptions | IProgressWindowOptions | IProgressCompositeOptions, task: (progress: IProgress) => Promise, onDidCancel?: (choice?: number) => void @@ -36,7 +36,7 @@ export interface IProgressIndicator { * Indicate progress for the duration of the provided promise. Progress will stop in * any case of promise completion, error or cancellation. */ - showWhile(promise: Promise, delay?: number): Promise; + showWhile(promise: Promise, delay?: number): Promise; } export const enum ProgressLocation { @@ -98,7 +98,7 @@ export interface IProgress { export class Progress implements IProgress { - static readonly None: IProgress = Object.freeze({ report() { } }); + static readonly None: IProgress = Object.freeze({ report() { } }); private _value?: T; get value(): T | undefined { return this._value; } diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index 7e31738058d..d52bbb4199d 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -81,7 +81,7 @@ export interface IWorkspaceFoldersChangeEvent { } export namespace IWorkspace { - export function isIWorkspace(thing: any): thing is IWorkspace { + export function isIWorkspace(thing: unknown): thing is IWorkspace { return thing && typeof thing === 'object' && typeof (thing as IWorkspace).id === 'string' && Array.isArray((thing as IWorkspace).folders); @@ -126,7 +126,7 @@ export interface IWorkspaceFolderData { } export namespace IWorkspaceFolder { - export function isIWorkspaceFolder(thing: any): thing is IWorkspaceFolder { + export function isIWorkspaceFolder(thing: unknown): thing is IWorkspaceFolder { return thing && typeof thing === 'object' && URI.isUri((thing as IWorkspaceFolder).uri) && typeof (thing as IWorkspaceFolder).name === 'string' diff --git a/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts index efef7f31107..b904c106efa 100644 --- a/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -93,7 +93,7 @@ export function reviveWorkspaceIdentifier(workspace: { id: string, configPath: U return { id: workspace.id, configPath: URI.revive(workspace.configPath) }; } -export function isStoredWorkspaceFolder(thing: any): thing is IStoredWorkspaceFolder { +export function isStoredWorkspaceFolder(thing: unknown): thing is IStoredWorkspaceFolder { return isRawFileWorkspaceFolder(thing) || isRawUriWorkspaceFolder(thing); } @@ -148,11 +148,11 @@ export interface IEnterWorkspaceResult { backupPath?: string; } -export function isSingleFolderWorkspaceIdentifier(obj: any): obj is ISingleFolderWorkspaceIdentifier { +export function isSingleFolderWorkspaceIdentifier(obj: unknown): obj is ISingleFolderWorkspaceIdentifier { return obj instanceof URI; } -export function isWorkspaceIdentifier(obj: any): obj is IWorkspaceIdentifier { +export function isWorkspaceIdentifier(obj: unknown): obj is IWorkspaceIdentifier { const workspaceIdentifier = obj as IWorkspaceIdentifier; return workspaceIdentifier && typeof workspaceIdentifier.id === 'string' && workspaceIdentifier.configPath instanceof URI; diff --git a/src/vs/platform/workspaces/electron-main/workspacesService.ts b/src/vs/platform/workspaces/electron-main/workspacesService.ts index 70f2bd9bb79..3084a7ea969 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesService.ts @@ -10,7 +10,7 @@ import { IWorkspacesMainService } from 'vs/platform/workspaces/electron-main/wor import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows'; import { IWorkspacesHistoryMainService } from 'vs/platform/workspaces/electron-main/workspacesHistoryMainService'; -export class WorkspacesService implements AddFirstParameterToFunctions /* only methods, not events */, number /* window ID */> { +export class WorkspacesService implements AddFirstParameterToFunctions /* only methods, not events */, number /* window ID */> { _serviceBrand: undefined; diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index 5cde8dd380a..d8e36e8297f 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -50,10 +50,8 @@ export class CloseSidebarAction extends Action { this.enabled = !!this.layoutService; } - run(): Promise { + async run(): Promise { this.layoutService.setSideBarHidden(true); - - return Promise.resolve(); } } @@ -79,7 +77,7 @@ export class ToggleActivityBarVisibilityAction extends Action { this.enabled = !!this.layoutService; } - run(): Promise { + run(): Promise { const visibility = this.layoutService.isVisible(Parts.ACTIVITYBAR_PART); const newVisibilityValue = !visibility; @@ -115,10 +113,8 @@ class ToggleCenteredLayout extends Action { this.enabled = !!this.layoutService; } - run(): Promise { + async run(): Promise { this.layoutService.centerEditorLayout(!this.layoutService.isEditorLayoutCentered()); - - return Promise.resolve(); } } @@ -165,11 +161,9 @@ export class ToggleEditorLayoutAction extends Action { this.enabled = this.editorGroupService.count > 1; } - run(): Promise { + async run(): Promise { const newOrientation = (this.editorGroupService.orientation === GroupOrientation.VERTICAL) ? GroupOrientation.HORIZONTAL : GroupOrientation.VERTICAL; this.editorGroupService.setGroupOrientation(newOrientation); - - return Promise.resolve(); } } @@ -205,7 +199,7 @@ export class ToggleSidebarPositionAction extends Action { this.enabled = !!this.layoutService && !!this.configurationService; } - run(): Promise { + run(): Promise { const position = this.layoutService.getSideBarPosition(); const newPositionValue = (position === Position.LEFT) ? 'right' : 'left'; @@ -255,10 +249,8 @@ export class ToggleEditorVisibilityAction extends Action { this.enabled = !!this.layoutService; } - run(): Promise { + async run(): Promise { this.layoutService.toggleMaximizedPanel(); - - return Promise.resolve(); } } @@ -289,11 +281,9 @@ export class ToggleSidebarVisibilityAction extends Action { this.enabled = !!this.layoutService; } - run(): Promise { + async run(): Promise { const hideSidebar = this.layoutService.isVisible(Parts.SIDEBAR_PART); this.layoutService.setSideBarHidden(hideSidebar); - - return Promise.resolve(); } } @@ -336,7 +326,7 @@ export class ToggleStatusbarVisibilityAction extends Action { this.enabled = !!this.layoutService; } - run(): Promise { + run(): Promise { const visibility = this.layoutService.isVisible(Parts.STATUSBAR_PART); const newVisibilityValue = !visibility; @@ -373,7 +363,7 @@ class ToggleTabsVisibilityAction extends Action { super(id, label); } - run(): Promise { + run(): Promise { const visibility = this.configurationService.getValue(ToggleTabsVisibilityAction.tabsVisibleKey); const newVisibilityValue = !visibility; @@ -403,10 +393,8 @@ class ToggleZenMode extends Action { this.enabled = !!this.layoutService; } - run(): Promise { + async run(): Promise { this.layoutService.toggleZenMode(); - - return Promise.resolve(); } } @@ -466,9 +454,7 @@ export class ToggleMenuBarAction extends Action { newVisibilityValue = (isWeb && currentVisibilityValue === 'hidden') ? 'compact' : 'default'; } - this.configurationService.updateValue(ToggleMenuBarAction.menuBarVisibilityKey, newVisibilityValue, ConfigurationTarget.USER); - - return Promise.resolve(); + return this.configurationService.updateValue(ToggleMenuBarAction.menuBarVisibilityKey, newVisibilityValue, ConfigurationTarget.USER); } } @@ -501,7 +487,7 @@ export class ResetViewLocationsAction extends Action { super(id, label); } - run(): Promise { + async run(): Promise { const viewContainerRegistry = Registry.as(ViewContainerExtensions.ViewContainersRegistry); viewContainerRegistry.all.forEach(viewContainer => { const viewDescriptors = this.viewDescriptorService.getViewDescriptors(viewContainer); @@ -515,8 +501,6 @@ export class ResetViewLocationsAction extends Action { } }); }); - - return Promise.resolve(); } } @@ -541,20 +525,20 @@ export class MoveFocusedViewAction extends Action { super(id, label); } - run(): Promise { + async run(): Promise { const viewContainerRegistry = Registry.as(ViewContainerExtensions.ViewContainersRegistry); const focusedViewId = FocusedViewContext.getValue(this.contextKeyService); if (focusedViewId === undefined || focusedViewId.trim() === '') { this.notificationService.error(nls.localize('moveFocusedView.error.noFocusedView', "There is no view currently focused.")); - return Promise.resolve(); + return; } const viewDescriptor = this.viewDescriptorService.getViewDescriptor(focusedViewId); if (!viewDescriptor || !viewDescriptor.canMoveView) { this.notificationService.error(nls.localize('moveFocusedView.error.nonMovableView', "The currently focused view is not movable.")); - return Promise.resolve(); + return; } const quickPick = this.quickInputService.createQuickPick(); @@ -608,8 +592,6 @@ export class MoveFocusedViewAction extends Action { }); quickPick.show(); - - return Promise.resolve(); } } diff --git a/src/vs/workbench/browser/actions/navigationActions.ts b/src/vs/workbench/browser/actions/navigationActions.ts index a3669a60af3..e9dc403f254 100644 --- a/src/vs/workbench/browser/actions/navigationActions.ts +++ b/src/vs/workbench/browser/actions/navigationActions.ts @@ -30,7 +30,7 @@ abstract class BaseNavigationAction extends Action { super(id, label); } - run(): Promise { + async run(): Promise { const isEditorFocus = this.layoutService.hasFocus(Parts.EDITOR_PART); const isPanelFocus = this.layoutService.hasFocus(Parts.PANEL_PART); const isSidebarFocus = this.layoutService.hasFocus(Parts.SIDEBAR_PART); @@ -39,7 +39,7 @@ abstract class BaseNavigationAction extends Action { if (isEditorFocus) { const didNavigate = this.navigateAcrossEditorGroup(this.toGroupDirection(this.direction)); if (didNavigate) { - return Promise.resolve(true); + return true; } neighborPart = this.layoutService.getVisibleNeighborPart(Parts.EDITOR_PART, this.direction); @@ -54,7 +54,7 @@ abstract class BaseNavigationAction extends Action { } if (neighborPart === Parts.EDITOR_PART) { - return Promise.resolve(this.navigateToEditorGroup(this.direction === Direction.Right ? GroupLocation.FIRST : GroupLocation.LAST)); + return this.navigateToEditorGroup(this.direction === Direction.Right ? GroupLocation.FIRST : GroupLocation.LAST); } if (neighborPart === Parts.SIDEBAR_PART) { @@ -65,7 +65,7 @@ abstract class BaseNavigationAction extends Action { return this.navigateToPanel(); } - return Promise.resolve(false); + return false; } private async navigateToPanel(): Promise { @@ -90,12 +90,12 @@ abstract class BaseNavigationAction extends Action { private async navigateToSidebar(): Promise { if (!this.layoutService.isVisible(Parts.SIDEBAR_PART)) { - return Promise.resolve(false); + return false; } const activeViewlet = this.viewletService.getActiveViewlet(); if (!activeViewlet) { - return Promise.resolve(false); + return false; } const activeViewletId = activeViewlet.getId(); diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index c8941a826a1..6607abc7716 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -37,7 +37,7 @@ export class OpenFileAction extends Action { super(id, label); } - run(event?: any, data?: ITelemetryData): Promise { + run(event?: unknown, data?: ITelemetryData): Promise { return this.dialogService.pickFileAndOpen({ forceNewWindow: false, telemetryExtraData: data }); } } @@ -55,7 +55,7 @@ export class OpenFolderAction extends Action { super(id, label); } - run(event?: any, data?: ITelemetryData): Promise { + run(event?: unknown, data?: ITelemetryData): Promise { return this.dialogService.pickFolderAndOpen({ forceNewWindow: false, telemetryExtraData: data }); } } @@ -73,7 +73,7 @@ export class OpenFileFolderAction extends Action { super(id, label); } - run(event?: any, data?: ITelemetryData): Promise { + run(event?: unknown, data?: ITelemetryData): Promise { return this.dialogService.pickFileFolderAndOpen({ forceNewWindow: false, telemetryExtraData: data }); } } @@ -91,7 +91,7 @@ export class OpenWorkspaceAction extends Action { super(id, label); } - run(event?: any, data?: ITelemetryData): Promise { + run(event?: unknown, data?: ITelemetryData): Promise { return this.dialogService.pickWorkspaceAndOpen({ telemetryExtraData: data }); } } @@ -139,12 +139,11 @@ export class OpenWorkspaceConfigFileAction extends Action { this.enabled = !!this.workspaceContextService.getWorkspace().configuration; } - run(): Promise { + async run(): Promise { const configuration = this.workspaceContextService.getWorkspace().configuration; if (configuration) { - return this.editorService.openEditor({ resource: configuration }); + await this.editorService.openEditor({ resource: configuration }); } - return Promise.resolve(); } } @@ -161,7 +160,7 @@ export class AddRootFolderAction extends Action { super(id, label); } - run(): Promise { + run(): Promise { return this.commandService.executeCommand(ADD_ROOT_FOLDER_COMMAND_ID); } } @@ -181,7 +180,7 @@ export class GlobalRemoveRootFolderAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { const state = this.contextService.getWorkbenchState(); // Workspace / Folder @@ -191,8 +190,6 @@ export class GlobalRemoveRootFolderAction extends Action { await this.workspaceEditingService.removeFolders([folder.uri]); } } - - return true; } } @@ -211,7 +208,7 @@ export class SaveWorkspaceAsAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { const configPathUri = await this.workspaceEditingService.pickNewWorkspacePath(); if (configPathUri && hasWorkspaceFileExtension(configPathUri)) { switch (this.contextService.getWorkbenchState()) { @@ -243,7 +240,7 @@ export class DuplicateWorkspaceInNewWindowAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { const folders = this.workspaceContextService.getWorkspace().folders; const remoteAuthority = this.environmentService.configuration.remoteAuthority; diff --git a/src/vs/workbench/browser/panel.ts b/src/vs/workbench/browser/panel.ts index f9ff5312187..89830e45418 100644 --- a/src/vs/workbench/browser/panel.ts +++ b/src/vs/workbench/browser/panel.ts @@ -101,7 +101,7 @@ export abstract class TogglePanelAction extends Action { super(id, label, cssClass); } - async run(): Promise { + async run(): Promise { if (this.isPanelFocused()) { this.layoutService.setPanelHidden(true); } else { diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 45da3780a68..eb88e507397 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -74,15 +74,15 @@ export class ViewletActivityAction extends ActivityAction { this.activity = activity; } - async run(event: any): Promise { + async run(event: unknown): Promise { if (event instanceof MouseEvent && event.button === 2) { - return false; // do not run on right click + return; // do not run on right click } // prevent accident trigger on a doubleclick (to help nervous people) const now = Date.now(); if (now > this.lastRun /* https://github.com/Microsoft/vscode/issues/25830 */ && now - this.lastRun < ViewletActivityAction.preventDoubleClickDelay) { - return true; + return; } this.lastRun = now; @@ -93,7 +93,7 @@ export class ViewletActivityAction extends ActivityAction { if (sideBarVisible && activeViewlet?.getId() === this.activity.id) { this.logAction('hide'); this.layoutService.setSideBarHidden(true); - return true; + return; } this.logAction('show'); @@ -120,17 +120,17 @@ export class ToggleViewletAction extends Action { super(_viewlet.id, _viewlet.name); } - run(): Promise { + async run(): Promise { const sideBarVisible = this.layoutService.isVisible(Parts.SIDEBAR_PART); const activeViewlet = this.viewletService.getActiveViewlet(); // Hide sidebar if selected viewlet already visible if (sideBarVisible && activeViewlet?.getId() === this._viewlet.id) { this.layoutService.setSideBarHidden(true); - return Promise.resolve(); + return; } - return this.viewletService.openViewlet(this._viewlet.id, true); + await this.viewletService.openViewlet(this._viewlet.id, true); } } @@ -226,7 +226,7 @@ class SwitchSideBarViewAction extends Action { super(id, name); } - run(offset: number): Promise { + async run(offset: number): Promise { const pinnedViewletIds = this.activityBarService.getPinnedViewletIds(); const activeViewlet = this.viewletService.getActiveViewlet(); @@ -240,7 +240,8 @@ class SwitchSideBarViewAction extends Action { break; } } - return this.viewletService.openViewlet(targetViewletId, true); + + await this.viewletService.openViewlet(targetViewletId, true); } } @@ -258,7 +259,7 @@ export class PreviousSideBarViewAction extends SwitchSideBarViewAction { super(id, name, viewletService, activityBarService); } - run(): Promise { + run(): Promise { return super.run(-1); } } @@ -277,7 +278,7 @@ export class NextSideBarViewAction extends SwitchSideBarViewAction { super(id, name, viewletService, activityBarService); } - run(): Promise { + run(): Promise { return super.run(1); } } diff --git a/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index 93102067fa2..8ff7cfd6917 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -25,6 +25,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainerLocation, IViewDescriptorService } from 'vs/workbench/common/views'; import { ICompositeDragAndDrop, CompositeDragAndDropData } from 'vs/base/parts/composite/browser/compositeDnd'; import { IPaneComposite } from 'vs/workbench/common/panecomposite'; +import { IComposite } from 'vs/workbench/common/composite'; export interface ICompositeBarItem { id: string; @@ -197,7 +198,7 @@ export interface ICompositeBarOptions { getOnCompositeClickAction: (compositeId: string) => Action; getContextMenuActions: () => Action[]; getContextMenuActionsForComposite: (compositeId: string) => Action[]; - openComposite: (compositeId: string) => Promise; + openComposite: (compositeId: string) => Promise; getDefaultCompositeId: () => string; hidePart: () => void; } diff --git a/src/vs/workbench/browser/parts/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositeBarActions.ts index f4d2bf15876..af39c3cfdf6 100644 --- a/src/vs/workbench/browser/parts/compositeBarActions.ts +++ b/src/vs/workbench/browser/parts/compositeBarActions.ts @@ -364,10 +364,8 @@ export class CompositeOverflowActivityAction extends ActivityAction { }); } - run(event: any): Promise { + async run(): Promise { this.showMenu(); - - return Promise.resolve(true); } } @@ -442,7 +440,7 @@ class ManageExtensionAction extends Action { super('activitybar.manage.extension', nls.localize('manageExtension', "Manage Extension")); } - run(id: string): Promise { + run(id: string): Promise { return this.commandService.executeCommand('_extensions.manage', id); } } @@ -733,7 +731,7 @@ export class ToggleCompositePinnedAction extends Action { this.checked = !!this.activity && this.compositeBar.isPinned(this.activity.id); } - run(context: string): Promise { + async run(context: string): Promise { const id = this.activity ? this.activity.id : context; if (this.compositeBar.isPinned(id)) { @@ -741,7 +739,5 @@ export class ToggleCompositePinnedAction extends Action { } else { this.compositeBar.pin(id); } - - return Promise.resolve(true); } } diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index a5d1e5f4f4b..0786123fff8 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -273,13 +273,13 @@ export class QuickOpenActionContributor extends ActionBarContributor { super(); } - hasActions(context: any): boolean { + hasActions(context: unknown): boolean { const entry = this.getEntry(context); return !!entry; } - getActions(context: any): ReadonlyArray { + getActions(context: unknown): ReadonlyArray { const actions: Action[] = []; const entry = this.getEntry(context); diff --git a/src/vs/workbench/browser/parts/editor/editorActions.ts b/src/vs/workbench/browser/parts/editor/editorActions.ts index 4d1f372052f..c145f1ca68d 100644 --- a/src/vs/workbench/browser/parts/editor/editorActions.ts +++ b/src/vs/workbench/browser/parts/editor/editorActions.ts @@ -37,7 +37,7 @@ export class ExecuteCommandAction extends Action { super(id, label); } - run(): Promise { + run(): Promise { return this.commandService.executeCommand(this.commandId, this.commandArgs); } } @@ -71,7 +71,7 @@ export class BaseSplitEditorAction extends Action { })); } - async run(context?: IEditorIdentifier): Promise { + async run(context?: IEditorIdentifier): Promise { splitEditor(this.editorGroupService, this.direction, context); } } @@ -181,7 +181,7 @@ export class JoinTwoGroupsAction extends Action { super(id, label); } - async run(context?: IEditorIdentifier): Promise { + async run(context?: IEditorIdentifier): Promise { let sourceGroup: IEditorGroup | undefined; if (context && typeof context.groupId === 'number') { sourceGroup = this.editorGroupService.getGroup(context.groupId); @@ -216,7 +216,7 @@ export class JoinAllGroupsAction extends Action { super(id, label); } - async run(context?: IEditorIdentifier): Promise { + async run(): Promise { mergeAllGroups(this.editorGroupService); } } @@ -234,7 +234,7 @@ export class NavigateBetweenGroupsAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { const nextGroup = this.editorGroupService.findGroup({ location: GroupLocation.NEXT }, this.editorGroupService.activeGroup, true); nextGroup.focus(); } @@ -253,7 +253,7 @@ export class FocusActiveGroupAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { this.editorGroupService.activeGroup.focus(); } } @@ -269,7 +269,7 @@ export abstract class BaseFocusGroupAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { const group = this.editorGroupService.findGroup(this.scope, this.editorGroupService.activeGroup, true); if (group) { group.focus(); @@ -409,25 +409,26 @@ export class OpenToSideFromQuickOpenAction extends Action { this.class = (preferredDirection === GroupDirection.RIGHT) ? 'codicon-split-horizontal' : 'codicon-split-vertical'; } - async run(context: any): Promise { + async run(context: unknown): Promise { const entry = toEditorQuickOpenEntry(context); if (entry) { const input = entry.getInput(); if (input) { if (input instanceof EditorInput) { - return this.editorService.openEditor(input, entry.getOptions(), SIDE_GROUP); + await this.editorService.openEditor(input, entry.getOptions(), SIDE_GROUP); + return; } const resourceInput = input as IResourceInput; resourceInput.options = mixin(resourceInput.options, entry.getOptions()); - return this.editorService.openEditor(resourceInput, SIDE_GROUP); + await this.editorService.openEditor(resourceInput, SIDE_GROUP); } } } } -export function toEditorQuickOpenEntry(element: any): IEditorQuickOpenEntry | null { +export function toEditorQuickOpenEntry(element: unknown): IEditorQuickOpenEntry | null { // QuickOpenEntryGroup if (element instanceof QuickOpenEntryGroup) { @@ -458,7 +459,7 @@ export class CloseEditorAction extends Action { super(id, label, 'codicon-close'); } - run(context?: IEditorCommandsContext): Promise { + run(context?: IEditorCommandsContext): Promise { return this.commandService.executeCommand(CLOSE_EDITOR_COMMAND_ID, undefined, context); } } @@ -476,7 +477,7 @@ export class CloseOneEditorAction extends Action { super(id, label, 'codicon-close'); } - async run(context?: IEditorCommandsContext): Promise { + async run(context?: IEditorCommandsContext): Promise { let group: IEditorGroup | undefined; let editorIndex: number | undefined; if (context) { @@ -519,7 +520,7 @@ export class RevertAndCloseEditorAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { const activeControl = this.editorService.activeControl; if (activeControl) { const editor = activeControl.input; @@ -555,7 +556,7 @@ export class CloseLeftEditorsInGroupAction extends Action { super(id, label); } - async run(context?: IEditorIdentifier): Promise { + async run(context?: IEditorIdentifier): Promise { const { group, editor } = getTarget(this.editorService, this.editorGroupService, context); if (group && editor) { return group.closeEditors({ direction: CloseDirection.LEFT, except: editor }); @@ -600,7 +601,7 @@ export abstract class BaseCloseAllAction extends Action { return groupsToClose; } - async run(): Promise { + async run(): Promise { // Just close all if there are no dirty editors if (!this.workingCopyService.hasDirty) { @@ -653,7 +654,7 @@ export abstract class BaseCloseAllAction extends Action { } } - protected abstract doCloseAll(): Promise; + protected abstract doCloseAll(): Promise; } export class CloseAllEditorsAction extends BaseCloseAllAction { @@ -672,8 +673,8 @@ export class CloseAllEditorsAction extends BaseCloseAllAction { super(id, label, 'codicon-close-all', workingCopyService, fileDialogService, editorGroupService, editorService); } - protected doCloseAll(): Promise { - return Promise.all(this.groupsToClose.map(g => g.closeAllEditors())); + protected async doCloseAll(): Promise { + await Promise.all(this.groupsToClose.map(g => g.closeAllEditors())); } } @@ -693,7 +694,7 @@ export class CloseAllEditorGroupsAction extends BaseCloseAllAction { super(id, label, undefined, workingCopyService, fileDialogService, editorGroupService, editorService); } - protected async doCloseAll(): Promise { + protected async doCloseAll(): Promise { await Promise.all(this.groupsToClose.map(group => group.closeAllEditors())); this.groupsToClose.forEach(group => this.editorGroupService.removeGroup(group)); @@ -713,9 +714,9 @@ export class CloseEditorsInOtherGroupsAction extends Action { super(id, label); } - run(context?: IEditorIdentifier): Promise { + async run(context?: IEditorIdentifier): Promise { const groupToSkip = context ? this.editorGroupService.getGroup(context.groupId) : this.editorGroupService.activeGroup; - return Promise.all(this.editorGroupService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE).map(async g => { + await Promise.all(this.editorGroupService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE).map(async g => { if (groupToSkip && g.id === groupToSkip.id) { return; } @@ -739,10 +740,10 @@ export class CloseEditorInAllGroupsAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { const activeEditor = this.editorService.activeEditor; if (activeEditor) { - return Promise.all(this.editorGroupService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE).map(g => g.closeEditor(activeEditor))); + await Promise.all(this.editorGroupService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE).map(g => g.closeEditor(activeEditor))); } } } @@ -758,7 +759,7 @@ export class BaseMoveGroupAction extends Action { super(id, label); } - async run(context?: IEditorIdentifier): Promise { + async run(context?: IEditorIdentifier): Promise { let sourceGroup: IEditorGroup | undefined; if (context && typeof context.groupId === 'number') { sourceGroup = this.editorGroupService.getGroup(context.groupId); @@ -867,7 +868,7 @@ export class MinimizeOtherGroupsAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { this.editorGroupService.arrangeGroups(GroupsArrangement.MINIMIZE_OTHERS); } } @@ -881,7 +882,7 @@ export class ResetGroupSizesAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { this.editorGroupService.arrangeGroups(GroupsArrangement.EVEN); } } @@ -895,7 +896,7 @@ export class ToggleGroupSizesAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { this.editorGroupService.arrangeGroups(GroupsArrangement.TOGGLE); } } @@ -915,7 +916,7 @@ export class MaximizeGroupAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { if (this.editorService.activeEditor) { this.editorGroupService.arrangeGroups(GroupsArrangement.MINIMIZE_OTHERS); this.layoutService.setSideBarHidden(true); @@ -934,7 +935,7 @@ export abstract class BaseNavigateEditorAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { const result = this.navigate(); if (!result) { return; @@ -947,7 +948,7 @@ export abstract class BaseNavigateEditorAction extends Action { const group = this.editorGroupService.getGroup(groupId); if (group) { - return group.openEditor(editor); + await group.openEditor(editor); } } @@ -1123,7 +1124,7 @@ export class NavigateForwardAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { this.historyService.forward(); } } @@ -1137,7 +1138,7 @@ export class NavigateBackwardsAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { this.historyService.back(); } } @@ -1151,7 +1152,7 @@ export class NavigateToLastEditLocationAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { this.historyService.openLastEditLocation(); } } @@ -1165,7 +1166,7 @@ export class NavigateLastAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { this.historyService.last(); } } @@ -1183,7 +1184,7 @@ export class ReopenClosedEditorAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { this.historyService.reopenLastClosedEditor(); } } @@ -1202,7 +1203,7 @@ export class ClearRecentFilesAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { // Clear global recently opened this.workspacesService.clearRecentlyOpened(); @@ -1266,7 +1267,7 @@ export class BaseQuickOpenEditorAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { const keybindings = this.keybindingService.lookupKeybindings(this.id); this.quickOpenService.show(this.prefix, { quickNavigateConfiguration: { keybindings } }); @@ -1347,7 +1348,7 @@ export class QuickOpenPreviousEditorFromHistoryAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { const keybindings = this.keybindingService.lookupKeybindings(this.id); this.quickOpenService.show(undefined, { quickNavigateConfiguration: { keybindings } }); @@ -1367,7 +1368,7 @@ export class OpenNextRecentlyUsedEditorAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { this.historyService.openNextRecentlyUsedEditor(); } } @@ -1385,7 +1386,7 @@ export class OpenPreviousRecentlyUsedEditorAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { this.historyService.openPreviouslyUsedEditor(); } } @@ -1404,7 +1405,7 @@ export class OpenNextRecentlyUsedEditorInGroupAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { this.historyService.openNextRecentlyUsedEditor(this.editorGroupsService.activeGroup.id); } } @@ -1423,7 +1424,7 @@ export class OpenPreviousRecentlyUsedEditorInGroupAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { this.historyService.openPreviouslyUsedEditor(this.editorGroupsService.activeGroup.id); } } @@ -1441,7 +1442,7 @@ export class ClearEditorHistoryAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { // Editor history this.historyService.clear(); @@ -1711,7 +1712,7 @@ export class BaseCreateEditorGroupAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { this.editorGroupService.addGroup(this.editorGroupService.activeGroup, this.direction, { activate: true }); } } diff --git a/src/vs/workbench/browser/parts/editor/editorCommands.ts b/src/vs/workbench/browser/parts/editor/editorCommands.ts index eeb80e7449b..a6c94bdaa38 100644 --- a/src/vs/workbench/browser/parts/editor/editorCommands.ts +++ b/src/vs/workbench/browser/parts/editor/editorCommands.ts @@ -84,7 +84,7 @@ function registerActiveEditorMoveCommand(): void { weight: KeybindingWeight.WorkbenchContrib, when: EditorContextKeys.editorTextFocus, primary: 0, - handler: (accessor, args: any) => moveActiveEditor(args, accessor), + handler: (accessor, args) => moveActiveEditor(args, accessor), description: { description: nls.localize('editorCommand.activeEditorMove.description', "Move the active editor by tabs or groups"), args: [ diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index 34ae3b128ab..aaf1ae0f35a 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -1046,10 +1046,11 @@ export class ChangeModeAction extends Action { super(actionId, actionLabel); } - async run(): Promise { + async run(): Promise { const activeTextEditorWidget = getCodeEditor(this.editorService.activeTextEditorWidget); if (!activeTextEditorWidget) { - return this.quickInputService.pick([{ label: nls.localize('noEditor', "No text editor active at this time") }]); + await this.quickInputService.pick([{ label: nls.localize('noEditor', "No text editor active at this time") }]); + return; } const textModel = activeTextEditorWidget.getModel(); @@ -1246,14 +1247,16 @@ export class ChangeEOLAction extends Action { super(actionId, actionLabel); } - async run(): Promise { + async run(): Promise { const activeTextEditorWidget = getCodeEditor(this.editorService.activeTextEditorWidget); if (!activeTextEditorWidget) { - return this.quickInputService.pick([{ label: nls.localize('noEditor', "No text editor active at this time") }]); + await this.quickInputService.pick([{ label: nls.localize('noEditor', "No text editor active at this time") }]); + return; } if (this.editorService.activeEditor?.isReadonly()) { - return this.quickInputService.pick([{ label: nls.localize('noWritableCodeEditor', "The active code editor is read-only.") }]); + await this.quickInputService.pick([{ label: nls.localize('noWritableCodeEditor', "The active code editor is read-only.") }]); + return; } let textModel = activeTextEditorWidget.getModel(); @@ -1295,19 +1298,22 @@ export class ChangeEncodingAction extends Action { super(actionId, actionLabel); } - async run(): Promise { + async run(): Promise { if (!getCodeEditor(this.editorService.activeTextEditorWidget)) { - return this.quickInputService.pick([{ label: nls.localize('noEditor', "No text editor active at this time") }]); + await this.quickInputService.pick([{ label: nls.localize('noEditor', "No text editor active at this time") }]); + return; } const activeControl = this.editorService.activeControl; if (!activeControl) { - return this.quickInputService.pick([{ label: nls.localize('noEditor', "No text editor active at this time") }]); + await this.quickInputService.pick([{ label: nls.localize('noEditor', "No text editor active at this time") }]); + return; } const encodingSupport: IEncodingSupport | null = toEditorWithEncodingSupport(activeControl.input); if (!encodingSupport) { - return this.quickInputService.pick([{ label: nls.localize('noFileEditor', "No file active at this time") }]); + await this.quickInputService.pick([{ label: nls.localize('noFileEditor', "No file active at this time") }]); + return; } const saveWithEncodingPick: IQuickPickItem = { label: nls.localize('saveWithEncoding', "Save with Encoding") }; @@ -1342,7 +1348,7 @@ export class ChangeEncodingAction extends Action { const resource = toResource(activeControl.input, { supportSideBySide: SideBySideEditor.MASTER }); if (!resource || (!this.fileService.canHandleResource(resource) && resource.scheme !== Schemas.untitled)) { - return null; // encoding detection only possible for resources the file service can handle or that are untitled + return; // encoding detection only possible for resources the file service can handle or that are untitled } let guessedEncoding: string | undefined = undefined; diff --git a/src/vs/workbench/browser/parts/notifications/notificationsActions.ts b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts index ae63e201e24..5318fd1ace0 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsActions.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts @@ -26,7 +26,7 @@ export class ClearNotificationAction extends Action { super(id, label, 'codicon-close'); } - async run(notification: INotificationViewItem): Promise { + async run(notification: INotificationViewItem): Promise { this.commandService.executeCommand(CLEAR_NOTIFICATION, notification); } } @@ -44,7 +44,7 @@ export class ClearAllNotificationsAction extends Action { super(id, label, 'codicon-clear-all'); } - async run(notification: INotificationViewItem): Promise { + async run(): Promise { this.commandService.executeCommand(CLEAR_ALL_NOTIFICATIONS); } } @@ -62,7 +62,7 @@ export class HideNotificationsCenterAction extends Action { super(id, label, 'codicon-chevron-down'); } - async run(notification: INotificationViewItem): Promise { + async run(): Promise { this.commandService.executeCommand(HIDE_NOTIFICATIONS_CENTER); } } @@ -80,7 +80,7 @@ export class ExpandNotificationAction extends Action { super(id, label, 'codicon-chevron-up'); } - async run(notification: INotificationViewItem): Promise { + async run(notification: INotificationViewItem): Promise { this.commandService.executeCommand(EXPAND_NOTIFICATION, notification); } } @@ -98,7 +98,7 @@ export class CollapseNotificationAction extends Action { super(id, label, 'codicon-chevron-down'); } - async run(notification: INotificationViewItem): Promise { + async run(notification: INotificationViewItem): Promise { this.commandService.executeCommand(COLLAPSE_NOTIFICATION, notification); } } @@ -130,7 +130,7 @@ export class CopyNotificationMessageAction extends Action { super(id, label); } - run(notification: INotificationViewItem): Promise { + run(notification: INotificationViewItem): Promise { return this.clipboardService.writeText(notification.message.raw); } } @@ -144,7 +144,7 @@ export class NotificationActionRunner extends ActionRunner { super(); } - protected async runAction(action: IAction, context: INotificationViewItem): Promise { + protected async runAction(action: IAction, context: INotificationViewItem): Promise { this.telemetryService.publicLog2('workbenchActionExecuted', { id: action.id, from: 'message' }); // Run and make sure to notify on any error again diff --git a/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts b/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts index b2797f261f3..e41c8692e57 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts @@ -107,7 +107,7 @@ export function registerNotificationCommands(center: INotificationsCenterControl mac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace }, - handler: (accessor, args?: any) => { + handler: (accessor, args?) => { const notification = getNotificationFromContext(accessor.get(IListService), args); if (notification && !notification.hasProgress) { notification.close(); @@ -121,7 +121,7 @@ export function registerNotificationCommands(center: INotificationsCenterControl weight: KeybindingWeight.WorkbenchContrib, when: NotificationFocusedContext, primary: KeyCode.RightArrow, - handler: (accessor, args?: any) => { + handler: (accessor, args?) => { const notification = getNotificationFromContext(accessor.get(IListService), args); if (notification) { notification.expand(); @@ -135,7 +135,7 @@ export function registerNotificationCommands(center: INotificationsCenterControl weight: KeybindingWeight.WorkbenchContrib, when: NotificationFocusedContext, primary: KeyCode.LeftArrow, - handler: (accessor, args?: any) => { + handler: (accessor, args?) => { const notification = getNotificationFromContext(accessor.get(IListService), args); if (notification) { notification.collapse(); diff --git a/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts index 8c3117a0b12..3e7f1a53bd4 100644 --- a/src/vs/workbench/browser/parts/panel/panelActions.ts +++ b/src/vs/workbench/browser/parts/panel/panelActions.ts @@ -32,9 +32,8 @@ export class ClosePanelAction extends Action { super(id, name, 'codicon-close'); } - run(): Promise { + async run(): Promise { this.layoutService.setPanelHidden(true); - return Promise.resolve(); } } @@ -51,9 +50,8 @@ export class TogglePanelAction extends Action { super(id, name, layoutService.isVisible(Parts.PANEL_PART) ? 'panel expanded' : 'panel'); } - run(): Promise { + async run(): Promise { this.layoutService.setPanelHidden(this.layoutService.isVisible(Parts.PANEL_PART)); - return Promise.resolve(); } } @@ -71,12 +69,12 @@ class FocusPanelAction extends Action { super(id, label); } - run(): Promise { + async run(): Promise { // Show panel if (!this.layoutService.isVisible(Parts.PANEL_PART)) { this.layoutService.setPanelHidden(false); - return Promise.resolve(); + return; } // Focus into active panel @@ -84,8 +82,6 @@ class FocusPanelAction extends Action { if (panel) { panel.focus(); } - - return Promise.resolve(); } } @@ -115,13 +111,12 @@ export class ToggleMaximizedPanelAction extends Action { })); } - run(): Promise { + async run(): Promise { if (!this.layoutService.isVisible(Parts.PANEL_PART)) { this.layoutService.setPanelHidden(false); } this.layoutService.toggleMaximizedPanel(); - return Promise.resolve(); } } @@ -166,10 +161,9 @@ export class SetPanelPositionAction extends Action { super(id, label); } - run(): Promise { + async run(): Promise { const position = positionByActionId.get(this.id); this.layoutService.setPanelPosition(position === undefined ? Position.BOTTOM : position); - return Promise.resolve(); } } @@ -182,7 +176,7 @@ export class PanelActivityAction extends ActivityAction { super(activity); } - async run(event: any): Promise { + async run(): Promise { await this.panelService.openPanel(this.activity.id, true); this.activate(); } @@ -224,7 +218,7 @@ export class SwitchPanelViewAction extends Action { super(id, name); } - async run(offset: number): Promise { + async run(offset: number): Promise { const pinnedPanels = this.panelService.getPinnedPanels(); const activePanel = this.panelService.getActivePanel(); if (!activePanel) { @@ -256,7 +250,7 @@ export class PreviousPanelViewAction extends SwitchPanelViewAction { super(id, name, panelService); } - run(): Promise { + run(): Promise { return super.run(-1); } } @@ -274,7 +268,7 @@ export class NextPanelViewAction extends SwitchPanelViewAction { super(id, name, panelService); } - run(): Promise { + run(): Promise { return super.run(1); } } diff --git a/src/vs/workbench/browser/parts/quickopen/quickopen.ts b/src/vs/workbench/browser/parts/quickopen/quickopen.ts index a1e64954456..2e79e602673 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickopen.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickopen.ts @@ -60,14 +60,12 @@ export class BaseQuickOpenNavigateAction extends Action { super(id, label); } - run(event?: any): Promise { + async run(): Promise { const keys = this.keybindingService.lookupKeybindings(this.id); const quickNavigate = this.quickNavigate ? { keybindings: keys } : undefined; this.quickOpenService.navigate(this.next, quickNavigate); this.quickInputService.navigate(this.next, quickNavigate); - - return Promise.resolve(true); } } diff --git a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts index 02a5769f116..76e0dcce519 100644 --- a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts +++ b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts @@ -328,11 +328,12 @@ class FocusSideBarAction extends Action { super(id, label); } - run(): Promise { + async run(): Promise { // Show side bar if (!this.layoutService.isVisible(Parts.SIDEBAR_PART)) { - return Promise.resolve(this.layoutService.setSideBarHidden(false)); + this.layoutService.setSideBarHidden(false); + return; } // Focus into active viewlet @@ -340,8 +341,6 @@ class FocusSideBarAction extends Action { if (viewlet) { viewlet.focus(); } - - return Promise.resolve(true); } } diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index 9ec20f5c9c0..688534ce6fe 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -303,14 +303,12 @@ class ToggleStatusbarEntryVisibilityAction extends Action { this.checked = !model.isHidden(id); } - run(): Promise { + async run(): Promise { if (this.model.isHidden(this.id)) { this.model.show(this.id); } else { this.model.hide(this.id); } - - return Promise.resolve(true); } } @@ -320,10 +318,8 @@ class HideStatusbarEntryAction extends Action { super(id, nls.localize('hide', "Hide '{0}'", name), undefined, true); } - run(): Promise { + async run(): Promise { this.model.hide(this.id); - - return Promise.resolve(true); } } diff --git a/src/vs/workbench/browser/parts/views/customView.ts b/src/vs/workbench/browser/parts/views/customView.ts index e4cfff2a63c..666a9e25f3f 100644 --- a/src/vs/workbench/browser/parts/views/customView.ts +++ b/src/vs/workbench/browser/parts/views/customView.ts @@ -881,7 +881,7 @@ class MultipleSelectionActionRunner extends ActionRunner { })); } - runAction(action: IAction, context: TreeViewItemHandleArg): Promise { + runAction(action: IAction, context: TreeViewItemHandleArg): Promise { const selection = this.getSelectedResources(); let selectionHandleArgs: TreeViewItemHandleArg[] | undefined = undefined; let actionInSelected: boolean = false; diff --git a/src/vs/workbench/browser/parts/views/views.ts b/src/vs/workbench/browser/parts/views/views.ts index 232a343d488..5480d538e6a 100644 --- a/src/vs/workbench/browser/parts/views/views.ts +++ b/src/vs/workbench/browser/parts/views/views.ts @@ -559,7 +559,7 @@ export class ViewsService extends Disposable implements IViewsService { } }); } - run(accessor: ServicesAccessor): any { + run(accessor: ServicesAccessor): void { accessor.get(IViewsService).openView(viewDescriptor.id, true); } })); @@ -589,7 +589,7 @@ export class ViewsService extends Disposable implements IViewsService { }], }); } - run(accessor: ServicesAccessor): any { + run(accessor: ServicesAccessor): void { accessor.get(IViewDescriptorService).moveViewToLocation(viewDescriptor, newLocation); accessor.get(IViewsService).openView(viewDescriptor.id, true); } diff --git a/src/vs/workbench/browser/viewlet.ts b/src/vs/workbench/browser/viewlet.ts index ddcb76a0a95..d75f30812fa 100644 --- a/src/vs/workbench/browser/viewlet.ts +++ b/src/vs/workbench/browser/viewlet.ts @@ -165,17 +165,16 @@ export class ShowViewletAction extends Action { this.enabled = !!this.viewletService && !!this.editorGroupService; } - run(): Promise { + async run(): Promise { // Pass focus to viewlet if not open or focused if (this.otherViewletShowing() || !this.sidebarHasFocus()) { - return this.viewletService.openViewlet(this.viewletId, true); + await this.viewletService.openViewlet(this.viewletId, true); + return; } // Otherwise pass focus to editor group this.editorGroupService.activeGroup.focus(); - - return Promise.resolve(true); } private otherViewletShowing(): boolean { @@ -194,7 +193,7 @@ export class ShowViewletAction extends Action { } export class CollapseAction extends Action { - constructor(tree: AsyncDataTree | AbstractTree, enabled: boolean, clazz?: string) { + constructor(tree: AsyncDataTree | AbstractTree, enabled: boolean, clazz?: string) { super('workbench.action.collapse', nls.localize('collapse', "Collapse All"), clazz, enabled, () => { tree.collapseAll(); diff --git a/src/vs/workbench/common/actions.ts b/src/vs/workbench/common/actions.ts index 7f5a5cbdd14..e8f331cda34 100644 --- a/src/vs/workbench/common/actions.ts +++ b/src/vs/workbench/common/actions.ts @@ -98,7 +98,7 @@ Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionR }; } - private async triggerAndDisposeAction(instantiationService: IInstantiationService, lifecycleService: ILifecycleService, descriptor: SyncActionDescriptor, args: any): Promise { + private async triggerAndDisposeAction(instantiationService: IInstantiationService, lifecycleService: ILifecycleService, descriptor: SyncActionDescriptor, args: unknown): Promise { // run action when workbench is created await lifecycleService.when(LifecyclePhase.Ready); @@ -115,7 +115,7 @@ Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionR // otherwise run and dispose try { - const from = args?.from || 'keybinding'; + const from = (args as any)?.from || 'keybinding'; await actionInstance.run(undefined, { from }); } finally { actionInstance.dispose(); diff --git a/src/vs/workbench/common/memento.ts b/src/vs/workbench/common/memento.ts index 795b6ac8d90..6102751b8f5 100644 --- a/src/vs/workbench/common/memento.ts +++ b/src/vs/workbench/common/memento.ts @@ -87,4 +87,4 @@ class ScopedMemento { this.storageService.remove(this.id, this.scope); } } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts b/src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts index 2170391364a..c622bf0d5dd 100644 --- a/src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts +++ b/src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts @@ -100,7 +100,7 @@ export class TextFileSaveErrorHandler extends Disposable implements ISaveErrorHa } } - onSaveError(error: any, model: ITextFileEditorModel): void { + onSaveError(error: unknown, model: ITextFileEditorModel): void { const fileOperationError = error as FileOperationError; const resource = model.resource; @@ -208,8 +208,8 @@ class ResolveConflictLearnMoreAction extends Action { super('workbench.files.action.resolveConflictLearnMore', nls.localize('learnMore', "Learn More")); } - run(): Promise { - return this.openerService.open(URI.parse('https://go.microsoft.com/fwlink/?linkid=868264')); + async run(): Promise { + await this.openerService.open(URI.parse('https://go.microsoft.com/fwlink/?linkid=868264')); } } @@ -221,7 +221,7 @@ class DoNotShowResolveConflictLearnMoreAction extends Action { super('workbench.files.action.resolveConflictLearnMoreDoNotShowAgain', nls.localize('dontShowAgain', "Don't Show Again")); } - async run(notification: IDisposable): Promise { + async run(notification: IDisposable): Promise { this.storageService.store(LEARN_MORE_DIRTY_WRITE_IGNORE_KEY, true, StorageScope.GLOBAL); // Hide notification @@ -241,7 +241,7 @@ class ResolveSaveConflictAction extends Action { super('workbench.files.action.resolveConflict', nls.localize('compareChanges', "Compare")); } - async run(): Promise { + async run(): Promise { if (!this.model.isDisposed()) { const resource = this.model.resource; const name = basename(resource); @@ -272,7 +272,7 @@ class SaveElevatedAction extends Action { super('workbench.files.action.saveElevated', triedToMakeWriteable ? isWindows ? nls.localize('overwriteElevated', "Overwrite as Admin...") : nls.localize('overwriteElevatedSudo', "Overwrite as Sudo...") : isWindows ? nls.localize('saveElevated', "Retry as Admin...") : nls.localize('saveElevatedSudo', "Retry as Sudo...")); } - async run(): Promise { + async run(): Promise { if (!this.model.isDisposed()) { this.model.save({ writeElevated: true, @@ -291,7 +291,7 @@ class OverwriteReadonlyAction extends Action { super('workbench.files.action.overwrite', nls.localize('overwrite', "Overwrite")); } - async run(): Promise { + async run(): Promise { if (!this.model.isDisposed()) { this.model.save({ overwriteReadonly: true, reason: SaveReason.EXPLICIT }); } @@ -306,7 +306,7 @@ class SaveIgnoreModifiedSinceAction extends Action { super('workbench.files.action.saveIgnoreModifiedSince', nls.localize('overwrite', "Overwrite")); } - async run(): Promise { + async run(): Promise { if (!this.model.isDisposed()) { this.model.save({ ignoreModifiedSince: true, reason: SaveReason.EXPLICIT }); } @@ -321,7 +321,7 @@ class ConfigureSaveConflictAction extends Action { super('workbench.files.action.configureSaveConflict', nls.localize('configure', "Configure")); } - async run(): Promise { + async run(): Promise { this.preferencesService.openSettings(undefined, 'files.saveConflictResolution'); } } diff --git a/src/vs/workbench/contrib/files/browser/fileActions.ts b/src/vs/workbench/contrib/files/browser/fileActions.ts index 5c8be8905a0..2bc6d031192 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.ts @@ -100,7 +100,7 @@ export class NewFileAction extends Action { })); } - run(): Promise { + run(): Promise { return this.commandService.executeCommand(NEW_FILE_COMMAND_ID); } } @@ -122,7 +122,7 @@ export class NewFolderAction extends Action { })); } - run(): Promise { + run(): Promise { return this.commandService.executeCommand(NEW_FOLDER_COMMAND_ID); } } @@ -140,8 +140,8 @@ export class GlobalNewUntitledFileAction extends Action { super(id, label); } - run(): Promise { - return this.editorService.openEditor({ options: { pinned: true } }); // untitled are always pinned + async run(): Promise { + await this.editorService.openEditor({ options: { pinned: true } }); // untitled are always pinned } } @@ -436,7 +436,7 @@ export function incrementFileName(name: string, isFolder: boolean, incrementalNa // folder.1=>folder.2 if (isFolder && name.match(/(\d+)$/)) { - return name.replace(/(\d+)$/, (match: string, ...groups: any[]) => { + return name.replace(/(\d+)$/, (match, ...groups) => { let number = parseInt(groups[0]); return number < maxNumber ? strings.pad(number + 1, groups[0].length) @@ -446,7 +446,7 @@ export function incrementFileName(name: string, isFolder: boolean, incrementalNa // 1.folder=>2.folder if (isFolder && name.match(/^(\d+)/)) { - return name.replace(/^(\d+)(.*)$/, (match: string, ...groups: any[]) => { + return name.replace(/^(\d+)(.*)$/, (match, ...groups) => { let number = parseInt(groups[0]); return number < maxNumber ? strings.pad(number + 1, groups[0].length) + groups[1] @@ -474,7 +474,7 @@ export class GlobalCompareResourcesAction extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { const activeInput = this.editorService.activeEditor; const activeResource = activeInput ? activeInput.resource : undefined; if (activeResource) { @@ -520,7 +520,7 @@ export class ToggleAutoSaveAction extends Action { super(id, label); } - run(): Promise { + run(): Promise { return this.filesConfigurationService.toggleAutoSave(); } } @@ -543,7 +543,7 @@ export abstract class BaseSaveAllAction extends Action { this.registerListeners(); } - protected abstract doRun(context: any): Promise; + protected abstract doRun(context: unknown): Promise; private registerListeners(): void { @@ -559,7 +559,7 @@ export abstract class BaseSaveAllAction extends Action { } } - async run(context?: any): Promise { + async run(context?: unknown): Promise { try { await this.doRun(context); } catch (error) { @@ -577,7 +577,7 @@ export class SaveAllAction extends BaseSaveAllAction { return 'explorer-action codicon-save-all'; } - protected doRun(context: any): Promise { + protected doRun(): Promise { return this.commandService.executeCommand(SAVE_ALL_COMMAND_ID); } } @@ -591,7 +591,7 @@ export class SaveAllInGroupAction extends BaseSaveAllAction { return 'explorer-action codicon-save-all'; } - protected doRun(context: any): Promise { + protected doRun(context: unknown): Promise { return this.commandService.executeCommand(SAVE_ALL_IN_GROUP_COMMAND_ID, {}, context); } } @@ -605,7 +605,7 @@ export class CloseGroupAction extends Action { super(id, label, 'codicon-close-all'); } - run(context?: any): Promise { + run(context?: unknown): Promise { return this.commandService.executeCommand(CLOSE_EDITORS_AND_GROUP_COMMAND_ID, {}, context); } } @@ -623,8 +623,8 @@ export class FocusFilesExplorer extends Action { super(id, label); } - run(): Promise { - return this.viewletService.openViewlet(VIEWLET_ID, true); + async run(): Promise { + await this.viewletService.openViewlet(VIEWLET_ID, true); } } @@ -643,15 +643,13 @@ export class ShowActiveFileInExplorer extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { const resource = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }); if (resource) { this.commandService.executeCommand(REVEAL_IN_EXPLORER_COMMAND_ID, resource); } else { this.notificationService.info(nls.localize('openFileToShow', "Open a file first to show it in the explorer")); } - - return true; } } @@ -672,7 +670,7 @@ export class CollapseExplorerView extends Action { })); } - async run(): Promise { + async run(): Promise { const explorerViewlet = (await this.viewletService.openViewlet(VIEWLET_ID))?.getViewPaneContainer() as ExplorerViewPaneContainer; const explorerView = explorerViewlet.getExplorerView(); if (explorerView) { @@ -699,7 +697,7 @@ export class RefreshExplorerView extends Action { })); } - async run(): Promise { + async run(): Promise { await this.viewletService.openViewlet(VIEWLET_ID); this.explorerService.refresh(); } @@ -721,7 +719,7 @@ export class ShowOpenedFileInNewWindow extends Action { super(id, label); } - async run(): Promise { + async run(): Promise { const fileResource = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }); if (fileResource) { if (this.fileService.canHandleResource(fileResource)) { @@ -732,8 +730,6 @@ export class ShowOpenedFileInNewWindow extends Action { } else { this.notificationService.info(nls.localize('openFileToShowInNewWindow.nofile', "Open a file first to open in new window")); } - - return true; } } @@ -817,7 +813,7 @@ export class CompareWithClipboardAction extends Action { this.enabled = true; } - async run(): Promise { + async run(): Promise { const resource = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }); if (resource && (this.fileService.canHandleResource(resource) || resource.scheme === Schemas.untitled)) { if (!this.registrationDisposal) { @@ -828,13 +824,11 @@ export class CompareWithClipboardAction extends Action { const name = resources.basename(resource); const editorLabel = nls.localize('clipboardComparisonLabel', "Clipboard ↔ {0}", name); - return this.editorService.openEditor({ leftResource: resource.with({ scheme: CompareWithClipboardAction.SCHEME }), rightResource: resource, label: editorLabel }).finally(() => { + await this.editorService.openEditor({ leftResource: resource.with({ scheme: CompareWithClipboardAction.SCHEME }), rightResource: resource, label: editorLabel }).finally(() => { dispose(this.registrationDisposal); this.registrationDisposal = undefined; }); } - - return true; } dispose(): void { @@ -859,7 +853,7 @@ class ClipboardContentProvider implements ITextModelContentProvider { } } -function onErrorWithRetry(notificationService: INotificationService, error: any, retry: () => Promise): void { +function onErrorWithRetry(notificationService: INotificationService, error: unknown, retry: () => Promise): void { notificationService.prompt(Severity.Error, toErrorMessage(error, false), [{ label: nls.localize('retry', "Retry"), diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index 9c5162d1999..339367815bb 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -491,9 +491,9 @@ interface IEditorGroupTemplateData { class OpenEditorActionRunner extends ActionRunner { public editor: OpenEditor | undefined; - run(action: IAction, context?: any): Promise { + async run(action: IAction): Promise { if (!this.editor) { - return Promise.resolve(); + return; } return super.run(action, { groupId: this.editor.groupId, editorIndex: this.editor.editorIndex }); diff --git a/src/vs/workbench/services/activity/common/activity.ts b/src/vs/workbench/services/activity/common/activity.ts index 628590befc4..d8bdaca851b 100644 --- a/src/vs/workbench/services/activity/common/activity.ts +++ b/src/vs/workbench/services/activity/common/activity.ts @@ -6,14 +6,25 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +export const IActivityService = createDecorator('activityService'); + +export interface IActivityService { + + _serviceBrand: undefined; + + /** + * Show activity in the panel for the given panel or in the activitybar for the given viewlet or global action. + */ + showActivity(compositeOrActionId: string, badge: IBadge, clazz?: string, priority?: number): IDisposable; +} + export interface IBadge { getDescription(): string; } -export class BaseBadge implements IBadge { - descriptorFn: (args: any) => string; +class BaseBadge implements IBadge { - constructor(descriptorFn: (args: any) => string) { + constructor(public readonly descriptorFn: (arg: any) => string) { this.descriptorFn = descriptorFn; } @@ -23,9 +34,8 @@ export class BaseBadge implements IBadge { } export class NumberBadge extends BaseBadge { - number: number; - constructor(number: number, descriptorFn: (args: any) => string) { + constructor(public readonly number: number, descriptorFn: (num: number) => string) { super(descriptorFn); this.number = number; @@ -37,31 +47,17 @@ export class NumberBadge extends BaseBadge { } export class TextBadge extends BaseBadge { - text: string; - constructor(text: string, descriptorFn: (args: any) => string) { + constructor(public readonly text: string, descriptorFn: () => string) { super(descriptorFn); - - this.text = text; } } export class IconBadge extends BaseBadge { - constructor(descriptorFn: (args: any) => string) { + constructor(descriptorFn: () => string) { super(descriptorFn); } } export class ProgressBadge extends BaseBadge { } - -export const IActivityService = createDecorator('activityService'); - -export interface IActivityService { - _serviceBrand: undefined; - - /** - * Show activity in the panel for the given panel or in the activitybar for the given viewlet or global action. - */ - showActivity(compositeOrActionId: string, badge: IBadge, clazz?: string, priority?: number): IDisposable; -} diff --git a/src/vs/workbench/services/editor/test/browser/editorService.test.ts b/src/vs/workbench/services/editor/test/browser/editorService.test.ts index a57f108b8fb..51024bda79e 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -306,7 +306,7 @@ suite('EditorService', () => { layout(): void { } - createEditor(): any { } + createEditor(): void { } } const ed = instantiationService.createInstance(MyEditor, 'my.editor'); diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index c94ee4e88cf..80873b34704 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -62,7 +62,7 @@ export class BrowserWindowConfiguration implements IWindowConfiguration { //#region TODO MOVE TO NODE LAYER - _!: any[]; + _!: string[]; windowId!: number; mainPid!: number; diff --git a/src/vs/workbench/services/progress/browser/progressIndicator.ts b/src/vs/workbench/services/progress/browser/progressIndicator.ts index ff1da4bab76..dc0b538df55 100644 --- a/src/vs/workbench/services/progress/browser/progressIndicator.ts +++ b/src/vs/workbench/services/progress/browser/progressIndicator.ts @@ -45,7 +45,7 @@ export class ProgressBarIndicator extends Disposable implements IProgressIndicat }; } - async showWhile(promise: Promise, delay?: number): Promise { + async showWhile(promise: Promise, delay?: number): Promise { try { this.progressbar.infinite().show(delay); @@ -92,7 +92,7 @@ export class EditorProgressIndicator extends ProgressBarIndicator { return super.show(infiniteOrTotal, delay); } - async showWhile(promise: Promise, delay?: number): Promise { + async showWhile(promise: Promise, delay?: number): Promise { // No editor open: ignore any progress reporting if (this.group.isEmpty) { @@ -125,7 +125,7 @@ namespace ProgressIndicatorState { readonly type = Type.While; constructor( - readonly whilePromise: Promise, + readonly whilePromise: Promise, readonly whileStart: number, readonly whileDelay: number, ) { } @@ -311,7 +311,7 @@ export class CompositeProgressIndicator extends CompositeScope implements IProgr }; } - async showWhile(promise: Promise, delay?: number): Promise { + async showWhile(promise: Promise, delay?: number): Promise { // Join with existing running promise to ensure progress is accurate if (this.progressState.type === ProgressIndicatorState.Type.While) { diff --git a/src/vs/workbench/services/progress/browser/progressService.ts b/src/vs/workbench/services/progress/browser/progressService.ts index 2f464fb7405..3cdea6762a5 100644 --- a/src/vs/workbench/services/progress/browser/progressService.ts +++ b/src/vs/workbench/services/progress/browser/progressService.ts @@ -245,7 +245,7 @@ export class ProgressService extends Disposable implements IProgressService { super(`progress.button.${button}`, button, undefined, true); } - async run(): Promise { + async run(): Promise { progressStateModel.cancel(index); } }; @@ -261,7 +261,7 @@ export class ProgressService extends Disposable implements IProgressService { super('progress.cancel', localize('cancel', "Cancel"), undefined, true); } - async run(): Promise { + async run(): Promise { progressStateModel.cancel(); } }; diff --git a/src/vs/workbench/services/statusbar/common/statusbar.ts b/src/vs/workbench/services/statusbar/common/statusbar.ts index 91519f20cbd..31f46524c9c 100644 --- a/src/vs/workbench/services/statusbar/common/statusbar.ts +++ b/src/vs/workbench/services/statusbar/common/statusbar.ts @@ -50,7 +50,7 @@ export interface IStatusbarEntry { /** * Optional arguments for the command. */ - readonly arguments?: any[]; + readonly arguments?: unknown[]; /** * Whether to show a beak above the status bar entry. diff --git a/src/vs/workbench/workbench.web.api.ts b/src/vs/workbench/workbench.web.api.ts index 140711b300e..9f18e7bf59d 100644 --- a/src/vs/workbench/workbench.web.api.ts +++ b/src/vs/workbench/workbench.web.api.ts @@ -238,7 +238,7 @@ async function create(domElement: HTMLElement, options: IWorkbenchConstructionOp // Register commands if any if (Array.isArray(options.commands)) { for (const command of options.commands) { - CommandsRegistry.registerCommand(command.id, (accessor, ...args: any[]) => { + CommandsRegistry.registerCommand(command.id, (accessor, ...args) => { // we currently only pass on the arguments but not the accessor // to the command to reduce our exposure of internal API. command.handler(...args); From 40cd953770733307e17b946e47ab9904ba487993 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 28 Feb 2020 11:47:10 +0100 Subject: [PATCH 159/235] Turn off JSON item resolving. Fixes #91747 --- .../json-language-features/server/src/jsonServerMain.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/extensions/json-language-features/server/src/jsonServerMain.ts b/extensions/json-language-features/server/src/jsonServerMain.ts index 4f40bd5a3fd..182eef7e9ee 100644 --- a/extensions/json-language-features/server/src/jsonServerMain.ts +++ b/extensions/json-language-features/server/src/jsonServerMain.ts @@ -160,7 +160,10 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { formatterMaxNumberOfEdits = params.initializationOptions?.customCapabilities?.rangeFormatting?.editLimit || Number.MAX_VALUE; const capabilities: ServerCapabilities = { textDocumentSync: TextDocumentSyncKind.Incremental, - completionProvider: clientSnippetSupport ? { resolveProvider: true, triggerCharacters: ['"', ':'] } : undefined, + completionProvider: clientSnippetSupport ? { + resolveProvider: false, // turn off resolving as the current language service doesn't do anything on resolve. Also fixes #91747 + triggerCharacters: ['"', ':'] + } : undefined, hoverProvider: true, documentSymbolProvider: true, documentRangeFormattingProvider: params.initializationOptions.provideFormatter === true, From 33287fbd13e31863bf997a4b60862e8161454426 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Fri, 28 Feb 2020 11:50:51 +0100 Subject: [PATCH 160/235] Make sure that C: is C:\ in simple file picker (#91746) Fixes https://github.com/microsoft/vscode-remote-release/issues/1596 --- src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts b/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts index 58c9355d126..a3f45c88cdb 100644 --- a/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts +++ b/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts @@ -297,6 +297,8 @@ export class SimpleFileDialog { function doResolve(dialog: SimpleFileDialog, uri: URI | undefined) { if (uri) { + uri = resources.addTrailingPathSeparator(uri, dialog.separator); // Ensures that c: is c:/ since this comes from user input and can be incorrect. + // To be consistent, we should never have a trailing path separator on directories (or anything else). Will not remove from c:/. uri = resources.removeTrailingPathSeparator(uri); } resolve(uri); From 7298bf4bd1c1cd2d0d39d06cccf4ef18d48b8c95 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 28 Feb 2020 11:51:14 +0100 Subject: [PATCH 161/235] make sure unnotarized build is published even if notarization fails --- build/azure-pipelines/darwin/product-build-darwin.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 795bc78556e..cbfcbfc50ea 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -179,6 +179,13 @@ steps: zip -d $(agent.builddirectory)/VSCode-darwin.zip "*.pkg" displayName: Clean Archive +- script: | + set -e + AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ + AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ + node build/azure-pipelines/common/createAsset.js darwin-unnotarized archive "VSCode-darwin-$VSCODE_QUALITY.zip" $(agent.builddirectory)/VSCode-darwin.zip + displayName: Publish Unnotarized Build + - script: | APP_ROOT=$(agent.builddirectory)/VSCode-darwin APP_NAME="`ls $APP_ROOT | head -n 1`" From a808018f29cb6496642bddedc74dcc51bf5c8499 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 28 Feb 2020 12:10:59 +0100 Subject: [PATCH 162/235] fix compile errors --- src/vs/base/browser/iframe.ts | 2 +- src/vs/workbench/browser/viewlet.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/base/browser/iframe.ts b/src/vs/base/browser/iframe.ts index 2ba88fac42d..ade89e96ccc 100644 --- a/src/vs/base/browser/iframe.ts +++ b/src/vs/base/browser/iframe.ts @@ -98,7 +98,7 @@ export class IframeUtils { /** * Returns the position of `childWindow` relative to `ancestorWindow` */ - public static getPositionOfChildWindowRelativeToAncestorWindow(childWindow: Window, ancestorWindow: Window) { + public static getPositionOfChildWindowRelativeToAncestorWindow(childWindow: Window, ancestorWindow: Window | null) { if (!ancestorWindow || childWindow === ancestorWindow) { return { diff --git a/src/vs/workbench/browser/viewlet.ts b/src/vs/workbench/browser/viewlet.ts index d75f30812fa..096974a38ae 100644 --- a/src/vs/workbench/browser/viewlet.ts +++ b/src/vs/workbench/browser/viewlet.ts @@ -193,7 +193,7 @@ export class ShowViewletAction extends Action { } export class CollapseAction extends Action { - constructor(tree: AsyncDataTree | AbstractTree, enabled: boolean, clazz?: string) { + constructor(tree: AsyncDataTree | AbstractTree, enabled: boolean, clazz?: string) { super('workbench.action.collapse', nls.localize('collapse', "Collapse All"), clazz, enabled, () => { tree.collapseAll(); From 0c29fa309f4887bc7774fc3efeefc904d70353a6 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 28 Feb 2020 13:52:13 +0100 Subject: [PATCH 163/235] Distinguish context key factory from type --- src/vs/editor/browser/editorExtensions.ts | 12 +- src/vs/editor/common/editorAction.ts | 6 +- src/vs/editor/common/editorContextKeys.ts | 10 +- src/vs/editor/contrib/find/findModel.ts | 4 +- src/vs/editor/contrib/peekView/peekView.ts | 4 +- .../standalone/browser/simpleServices.ts | 4 +- src/vs/platform/actions/common/actions.ts | 18 +-- .../contextkey/browser/contextKeyService.ts | 4 +- .../platform/contextkey/common/contextkey.ts | 131 +++++++++--------- .../platform/contextkey/common/contextkeys.ts | 4 +- .../keybinding/common/keybindingResolver.ts | 8 +- .../keybinding/common/keybindingsRegistry.ts | 10 +- .../common/resolvedKeybindingItem.ts | 6 +- .../common/abstractKeybindingService.test.ts | 4 +- .../test/common/keybindingResolver.test.ts | 6 +- .../test/common/mockKeybindingService.ts | 4 +- .../parts/editor/editor.contribution.ts | 4 +- .../browser/parts/panel/panelActions.ts | 4 +- src/vs/workbench/common/actions.ts | 6 +- src/vs/workbench/common/editor.ts | 4 +- src/vs/workbench/common/views.ts | 8 +- .../common/documentationContribution.ts | 4 +- .../debug/browser/debug.contribution.ts | 10 +- .../files/browser/fileActions.contribution.ts | 6 +- .../contrib/terminal/common/terminal.ts | 10 +- .../userDataSync/browser/userDataSync.ts | 6 +- .../webview/browser/webviewCommands.ts | 12 +- .../electron-browser/webviewCommands.ts | 12 +- .../keybinding/browser/keybindingService.ts | 4 +- .../keybinding/common/keybindingIO.ts | 4 +- 30 files changed, 167 insertions(+), 162 deletions(-) diff --git a/src/vs/editor/browser/editorExtensions.ts b/src/vs/editor/browser/editorExtensions.ts index f6d836aac53..149d562a3d4 100644 --- a/src/vs/editor/browser/editorExtensions.ts +++ b/src/vs/editor/browser/editorExtensions.ts @@ -15,7 +15,7 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; -import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { IConstructorSignature1, ServicesAccessor as InstantiationServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindings, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -39,26 +39,26 @@ export interface IDiffEditorContributionDescription { //#region Command export interface ICommandKeybindingsOptions extends IKeybindings { - kbExpr?: ContextKeyExpr | null; + kbExpr?: ContextKeyExpression | null; weight: number; } export interface ICommandMenuOptions { menuId: MenuId; group: string; order: number; - when?: ContextKeyExpr; + when?: ContextKeyExpression; title: string; } export interface ICommandOptions { id: string; - precondition: ContextKeyExpr | undefined; + precondition: ContextKeyExpression | undefined; kbOpts?: ICommandKeybindingsOptions; description?: ICommandHandlerDescription; menuOpts?: ICommandMenuOptions | ICommandMenuOptions[]; } export abstract class Command { public readonly id: string; - public readonly precondition: ContextKeyExpr | undefined; + public readonly precondition: ContextKeyExpression | undefined; private readonly _kbOpts: ICommandKeybindingsOptions | undefined; private readonly _menuOpts: ICommandMenuOptions | ICommandMenuOptions[] | undefined; private readonly _description: ICommandHandlerDescription | undefined; @@ -193,7 +193,7 @@ export abstract class EditorCommand extends Command { export interface IEditorActionContextMenuOptions { group: string; order: number; - when?: ContextKeyExpr; + when?: ContextKeyExpression; menuId?: MenuId; } export interface IActionOptions extends ICommandOptions { diff --git a/src/vs/editor/common/editorAction.ts b/src/vs/editor/common/editorAction.ts index 7c4ee116356..d8a1e71ade2 100644 --- a/src/vs/editor/common/editorAction.ts +++ b/src/vs/editor/common/editorAction.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IEditorAction } from 'vs/editor/common/editorCommon'; -import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; export class InternalEditorAction implements IEditorAction { @@ -12,7 +12,7 @@ export class InternalEditorAction implements IEditorAction { public readonly label: string; public readonly alias: string; - private readonly _precondition: ContextKeyExpr | undefined; + private readonly _precondition: ContextKeyExpression | undefined; private readonly _run: () => Promise; private readonly _contextKeyService: IContextKeyService; @@ -20,7 +20,7 @@ export class InternalEditorAction implements IEditorAction { id: string, label: string, alias: string, - precondition: ContextKeyExpr | undefined, + precondition: ContextKeyExpression | undefined, run: () => Promise, contextKeyService: IContextKeyService ) { diff --git a/src/vs/editor/common/editorContextKeys.ts b/src/vs/editor/common/editorContextKeys.ts index 01668420569..10337bd1bcc 100644 --- a/src/vs/editor/common/editorContextKeys.ts +++ b/src/vs/editor/common/editorContextKeys.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; export namespace EditorContextKeys { @@ -24,13 +24,13 @@ export namespace EditorContextKeys { export const readOnly = new RawContextKey('editorReadonly', false); export const columnSelection = new RawContextKey('editorColumnSelection', false); - export const writable: ContextKeyExpr = readOnly.toNegated(); + export const writable = readOnly.toNegated(); export const hasNonEmptySelection = new RawContextKey('editorHasSelection', false); - export const hasOnlyEmptySelection: ContextKeyExpr = hasNonEmptySelection.toNegated(); + export const hasOnlyEmptySelection = hasNonEmptySelection.toNegated(); export const hasMultipleSelections = new RawContextKey('editorHasMultipleSelections', false); - export const hasSingleSelection: ContextKeyExpr = hasMultipleSelections.toNegated(); + export const hasSingleSelection = hasMultipleSelections.toNegated(); export const tabMovesFocus = new RawContextKey('editorTabMovesFocus', false); - export const tabDoesNotMoveFocus: ContextKeyExpr = tabMovesFocus.toNegated(); + export const tabDoesNotMoveFocus = tabMovesFocus.toNegated(); export const isInEmbeddedEditor = new RawContextKey('isInEmbeddedEditor', false); export const canUndo = new RawContextKey('canUndo', false); export const canRedo = new RawContextKey('canRedo', false); diff --git a/src/vs/editor/contrib/find/findModel.ts b/src/vs/editor/contrib/find/findModel.ts index 0653ac4f5c4..6866bd48fec 100644 --- a/src/vs/editor/contrib/find/findModel.ts +++ b/src/vs/editor/contrib/find/findModel.ts @@ -20,12 +20,12 @@ import { FindDecorations } from 'vs/editor/contrib/find/findDecorations'; import { FindReplaceState, FindReplaceStateChangedEvent } from 'vs/editor/contrib/find/findState'; import { ReplaceAllCommand } from 'vs/editor/contrib/find/replaceAllCommand'; import { ReplacePattern, parseReplaceString } from 'vs/editor/contrib/find/replacePattern'; -import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; export const CONTEXT_FIND_WIDGET_VISIBLE = new RawContextKey('findWidgetVisible', false); -export const CONTEXT_FIND_WIDGET_NOT_VISIBLE: ContextKeyExpr = CONTEXT_FIND_WIDGET_VISIBLE.toNegated(); +export const CONTEXT_FIND_WIDGET_NOT_VISIBLE = CONTEXT_FIND_WIDGET_VISIBLE.toNegated(); // Keep ContextKey use of 'Focussed' to not break when clauses export const CONTEXT_FIND_INPUT_FOCUSED = new RawContextKey('findInputFocussed', false); export const CONTEXT_REPLACE_INPUT_FOCUSED = new RawContextKey('replaceInputFocussed', false); diff --git a/src/vs/editor/contrib/peekView/peekView.ts b/src/vs/editor/contrib/peekView/peekView.ts index 32503e62570..83c36e037d7 100644 --- a/src/vs/editor/contrib/peekView/peekView.ts +++ b/src/vs/editor/contrib/peekView/peekView.ts @@ -17,7 +17,7 @@ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; import { IOptions, IStyles, ZoneWidget } from 'vs/editor/contrib/zoneWidget/zoneWidget'; import * as nls from 'vs/nls'; -import { ContextKeyExpr, RawContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { RawContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ServicesAccessor, createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IDisposable } from 'vs/base/common/lifecycle'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -57,7 +57,7 @@ registerSingleton(IPeekViewService, class implements IPeekViewService { export namespace PeekContext { export const inPeekEditor = new RawContextKey('inReferenceSearchEditor', true); - export const notInPeekEditor: ContextKeyExpr = inPeekEditor.toNegated(); + export const notInPeekEditor = inPeekEditor.toNegated(); } class PeekContextController implements IEditorContribution { diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index caa9f3d6276..2b7a163f047 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -27,7 +27,7 @@ import { ITextResourceConfigurationService, ITextResourcePropertiesService, ITex import { CommandsRegistry, ICommand, ICommandEvent, ICommandHandler, ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationChangeEvent, IConfigurationData, IConfigurationOverrides, IConfigurationService, IConfigurationModel, IConfigurationValue, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { Configuration, ConfigurationModel, DefaultConfigurationModel, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels'; -import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { IConfirmation, IConfirmationResult, IDialogOptions, IDialogService, IShowResult } from 'vs/platform/dialogs/common/dialogs'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { AbstractKeybindingService } from 'vs/platform/keybinding/common/abstractKeybindingService'; @@ -318,7 +318,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { })); } - public addDynamicKeybinding(commandId: string, _keybinding: number, handler: ICommandHandler, when: ContextKeyExpr | undefined): IDisposable { + public addDynamicKeybinding(commandId: string, _keybinding: number, handler: ICommandHandler, when: ContextKeyExpression | undefined): IDisposable { const keybinding = createKeybinding(_keybinding, OS); const toDispose = new DisposableStore(); diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index ffef4c6d2d4..72dc61aa5af 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -7,7 +7,7 @@ import { Action } from 'vs/base/common/actions'; import { SyncDescriptor0, createSyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IConstructorSignature2, createDecorator, BrandedService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindings, KeybindingsRegistry, IKeybindingRule } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { ICommandService, CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; @@ -25,8 +25,8 @@ export interface ICommandAction { title: string | ILocalizedString; category?: string | ILocalizedString; icon?: { dark?: URI; light?: URI; } | ThemeIcon; - precondition?: ContextKeyExpr; - toggled?: ContextKeyExpr; + precondition?: ContextKeyExpression; + toggled?: ContextKeyExpression; } export type ISerializableCommandAction = UriDto; @@ -34,7 +34,7 @@ export type ISerializableCommandAction = UriDto; export interface IMenuItem { command: ICommandAction; alt?: ICommandAction; - when?: ContextKeyExpr; + when?: ContextKeyExpression; group?: 'navigation' | string; order?: number; } @@ -42,7 +42,7 @@ export interface IMenuItem { export interface ISubmenuItem { title: string | ILocalizedString; submenu: MenuId; - when?: ContextKeyExpr; + when?: ContextKeyExpression; group?: 'navigation' | string; order?: number; } @@ -314,17 +314,17 @@ export class SyncActionDescriptor { private readonly _id: string; private readonly _label?: string; private readonly _keybindings: IKeybindings | undefined; - private readonly _keybindingContext: ContextKeyExpr | undefined; + private readonly _keybindingContext: ContextKeyExpression | undefined; private readonly _keybindingWeight: number | undefined; public static create(ctor: { new(id: string, label: string, ...services: Services): Action }, - id: string, label: string | undefined, keybindings?: IKeybindings, keybindingContext?: ContextKeyExpr, keybindingWeight?: number + id: string, label: string | undefined, keybindings?: IKeybindings, keybindingContext?: ContextKeyExpression, keybindingWeight?: number ): SyncActionDescriptor { return new SyncActionDescriptor(ctor as IConstructorSignature2, id, label, keybindings, keybindingContext, keybindingWeight); } private constructor(ctor: IConstructorSignature2, - id: string, label: string | undefined, keybindings?: IKeybindings, keybindingContext?: ContextKeyExpr, keybindingWeight?: number + id: string, label: string | undefined, keybindings?: IKeybindings, keybindingContext?: ContextKeyExpression, keybindingWeight?: number ) { this._id = id; this._label = label; @@ -350,7 +350,7 @@ export class SyncActionDescriptor { return this._keybindings; } - public get keybindingContext(): ContextKeyExpr | undefined { + public get keybindingContext(): ContextKeyExpression | undefined { return this._keybindingContext; } diff --git a/src/vs/platform/contextkey/browser/contextKeyService.ts b/src/vs/platform/contextkey/browser/contextKeyService.ts index 6e033c32c6a..58d6e846e52 100644 --- a/src/vs/platform/contextkey/browser/contextKeyService.ts +++ b/src/vs/platform/contextkey/browser/contextKeyService.ts @@ -8,7 +8,7 @@ import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { keys } from 'vs/base/common/map'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ContextKeyExpr, IContext, IContextKey, IContextKeyChangeEvent, IContextKeyService, IContextKeyServiceTarget, IReadableSet, SET_CONTEXT_COMMAND_ID } from 'vs/platform/contextkey/common/contextkey'; +import { IContext, IContextKey, IContextKeyChangeEvent, IContextKeyService, IContextKeyServiceTarget, IReadableSet, SET_CONTEXT_COMMAND_ID, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver'; const KEYBINDING_CONTEXT_ATTR = 'data-keybinding-context'; @@ -265,7 +265,7 @@ export abstract class AbstractContextKeyService implements IContextKeyService { return new ScopedContextKeyService(this, domNode); } - public contextMatchesRules(rules: ContextKeyExpr | undefined): boolean { + public contextMatchesRules(rules: ContextKeyExpression | undefined): boolean { if (this._isDisposed) { throw new Error(`AbstractContextKeyService has been disposed`); } diff --git a/src/vs/platform/contextkey/common/contextkey.ts b/src/vs/platform/contextkey/common/contextkey.ts index 784f586779a..dcab732a541 100644 --- a/src/vs/platform/contextkey/common/contextkey.ts +++ b/src/vs/platform/contextkey/common/contextkey.ts @@ -19,44 +19,49 @@ export const enum ContextKeyExprType { } export interface IContextKeyExprMapper { - mapDefined(key: string): ContextKeyExpr; - mapNot(key: string): ContextKeyExpr; - mapEquals(key: string, value: any): ContextKeyExpr; - mapNotEquals(key: string, value: any): ContextKeyExpr; + mapDefined(key: string): ContextKeyExpression; + mapNot(key: string): ContextKeyExpression; + mapEquals(key: string, value: any): ContextKeyExpression; + mapNotEquals(key: string, value: any): ContextKeyExpression; mapRegex(key: string, regexp: RegExp | null): ContextKeyRegexExpr; } +export type ContextKeyExpression = ( + ContextKeyDefinedExpr | ContextKeyNotExpr | ContextKeyEqualsExpr | ContextKeyNotEqualsExpr + | ContextKeyRegexExpr | ContextKeyNotRegexExpr | ContextKeyAndExpr | ContextKeyOrExpr +); + export abstract class ContextKeyExpr { - public static has(key: string): ContextKeyExpr { + public static has(key: string): ContextKeyExpression { return ContextKeyDefinedExpr.create(key); } - public static equals(key: string, value: any): ContextKeyExpr { + public static equals(key: string, value: any): ContextKeyExpression { return ContextKeyEqualsExpr.create(key, value); } - public static notEquals(key: string, value: any): ContextKeyExpr { + public static notEquals(key: string, value: any): ContextKeyExpression { return ContextKeyNotEqualsExpr.create(key, value); } - public static regex(key: string, value: RegExp): ContextKeyExpr { + public static regex(key: string, value: RegExp): ContextKeyExpression { return ContextKeyRegexExpr.create(key, value); } - public static not(key: string): ContextKeyExpr { + public static not(key: string): ContextKeyExpression { return ContextKeyNotExpr.create(key); } - public static and(...expr: Array): ContextKeyExpr | undefined { + public static and(...expr: Array): ContextKeyExpression | undefined { return ContextKeyAndExpr.create(expr); } - public static or(...expr: Array): ContextKeyExpr | undefined { + public static or(...expr: Array): ContextKeyExpression | undefined { return ContextKeyOrExpr.create(expr); } - public static deserialize(serialized: string | null | undefined, strict: boolean = false): ContextKeyExpr | undefined { + public static deserialize(serialized: string | null | undefined, strict: boolean = false): ContextKeyExpression | undefined { if (!serialized) { return undefined; } @@ -64,17 +69,17 @@ export abstract class ContextKeyExpr { return this._deserializeOrExpression(serialized, strict); } - private static _deserializeOrExpression(serialized: string, strict: boolean): ContextKeyExpr | undefined { + private static _deserializeOrExpression(serialized: string, strict: boolean): ContextKeyExpression | undefined { let pieces = serialized.split('||'); return ContextKeyOrExpr.create(pieces.map(p => this._deserializeAndExpression(p, strict))); } - private static _deserializeAndExpression(serialized: string, strict: boolean): ContextKeyExpr | undefined { + private static _deserializeAndExpression(serialized: string, strict: boolean): ContextKeyExpression | undefined { let pieces = serialized.split('&&'); return ContextKeyAndExpr.create(pieces.map(p => this._deserializeOne(p, strict))); } - private static _deserializeOne(serializedOne: string, strict: boolean): ContextKeyExpr { + private static _deserializeOne(serializedOne: string, strict: boolean): ContextKeyExpression { serializedOne = serializedOne.trim(); if (serializedOne.indexOf('!=') >= 0) { @@ -155,15 +160,15 @@ export abstract class ContextKeyExpr { } public abstract getType(): ContextKeyExprType; - public abstract equals(other: ContextKeyExpr): boolean; + public abstract equals(other: ContextKeyExpression): boolean; public abstract evaluate(context: IContext): boolean; public abstract serialize(): string; public abstract keys(): string[]; - public abstract map(mapFnc: IContextKeyExprMapper): ContextKeyExpr; - public abstract negate(): ContextKeyExpr; + public abstract map(mapFnc: IContextKeyExprMapper): ContextKeyExpression; + public abstract negate(): ContextKeyExpression; } -function cmp(a: ContextKeyExpr, b: ContextKeyExpr): number { +function cmp(a: ContextKeyExpression, b: ContextKeyExpression): number { let aType = a.getType(); let bType = b.getType(); if (aType !== bType) { @@ -211,7 +216,7 @@ export class ContextKeyDefinedExpr implements ContextKeyExpr { return 0; } - public equals(other: ContextKeyExpr): boolean { + public equals(other: ContextKeyExpression): boolean { if (other instanceof ContextKeyDefinedExpr) { return (this.key === other.key); } @@ -230,18 +235,18 @@ export class ContextKeyDefinedExpr implements ContextKeyExpr { return [this.key]; } - public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { + public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression { return mapFnc.mapDefined(this.key); } - public negate(): ContextKeyExpr { + public negate(): ContextKeyExpression { return ContextKeyNotExpr.create(this.key); } } export class ContextKeyEqualsExpr implements ContextKeyExpr { - public static create(key: string, value: any): ContextKeyExpr { + public static create(key: string, value: any): ContextKeyExpression { if (typeof value === 'boolean') { if (value) { return ContextKeyDefinedExpr.create(key); @@ -274,7 +279,7 @@ export class ContextKeyEqualsExpr implements ContextKeyExpr { return 0; } - public equals(other: ContextKeyExpr): boolean { + public equals(other: ContextKeyExpression): boolean { if (other instanceof ContextKeyEqualsExpr) { return (this.key === other.key && this.value === other.value); } @@ -295,18 +300,18 @@ export class ContextKeyEqualsExpr implements ContextKeyExpr { return [this.key]; } - public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { + public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression { return mapFnc.mapEquals(this.key, this.value); } - public negate(): ContextKeyExpr { + public negate(): ContextKeyExpression { return ContextKeyNotEqualsExpr.create(this.key, this.value); } } export class ContextKeyNotEqualsExpr implements ContextKeyExpr { - public static create(key: string, value: any): ContextKeyExpr { + public static create(key: string, value: any): ContextKeyExpression { if (typeof value === 'boolean') { if (value) { return ContextKeyNotExpr.create(key); @@ -339,7 +344,7 @@ export class ContextKeyNotEqualsExpr implements ContextKeyExpr { return 0; } - public equals(other: ContextKeyExpr): boolean { + public equals(other: ContextKeyExpression): boolean { if (other instanceof ContextKeyNotEqualsExpr) { return (this.key === other.key && this.value === other.value); } @@ -360,18 +365,18 @@ export class ContextKeyNotEqualsExpr implements ContextKeyExpr { return [this.key]; } - public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { + public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression { return mapFnc.mapNotEquals(this.key, this.value); } - public negate(): ContextKeyExpr { + public negate(): ContextKeyExpression { return ContextKeyEqualsExpr.create(this.key, this.value); } } export class ContextKeyNotExpr implements ContextKeyExpr { - public static create(key: string): ContextKeyExpr { + public static create(key: string): ContextKeyExpression { return new ContextKeyNotExpr(key); } @@ -392,7 +397,7 @@ export class ContextKeyNotExpr implements ContextKeyExpr { return 0; } - public equals(other: ContextKeyExpr): boolean { + public equals(other: ContextKeyExpression): boolean { if (other instanceof ContextKeyNotExpr) { return (this.key === other.key); } @@ -411,11 +416,11 @@ export class ContextKeyNotExpr implements ContextKeyExpr { return [this.key]; } - public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { + public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression { return mapFnc.mapNot(this.key); } - public negate(): ContextKeyExpr { + public negate(): ContextKeyExpression { return ContextKeyDefinedExpr.create(this.key); } } @@ -452,7 +457,7 @@ export class ContextKeyRegexExpr implements ContextKeyExpr { return 0; } - public equals(other: ContextKeyExpr): boolean { + public equals(other: ContextKeyExpression): boolean { if (other instanceof ContextKeyRegexExpr) { const thisSource = this.regexp ? this.regexp.source : ''; const otherSource = other.regexp ? other.regexp.source : ''; @@ -481,14 +486,14 @@ export class ContextKeyRegexExpr implements ContextKeyExpr { return mapFnc.mapRegex(this.key, this.regexp); } - public negate(): ContextKeyExpr { + public negate(): ContextKeyExpression { return ContextKeyNotRegexExpr.create(this); } } export class ContextKeyNotRegexExpr implements ContextKeyExpr { - public static create(actual: ContextKeyRegexExpr): ContextKeyExpr { + public static create(actual: ContextKeyRegexExpr): ContextKeyExpression { return new ContextKeyNotRegexExpr(actual); } @@ -504,7 +509,7 @@ export class ContextKeyNotRegexExpr implements ContextKeyExpr { return this._actual.cmp(other._actual); } - public equals(other: ContextKeyExpr): boolean { + public equals(other: ContextKeyExpression): boolean { if (other instanceof ContextKeyNotRegexExpr) { return this._actual.equals(other._actual); } @@ -523,18 +528,18 @@ export class ContextKeyNotRegexExpr implements ContextKeyExpr { return this._actual.keys(); } - public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { + public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression { return new ContextKeyNotRegexExpr(this._actual.map(mapFnc)); } - public negate(): ContextKeyExpr { + public negate(): ContextKeyExpression { return this._actual; } } export class ContextKeyAndExpr implements ContextKeyExpr { - public static create(_expr: ReadonlyArray): ContextKeyExpr | undefined { + public static create(_expr: ReadonlyArray): ContextKeyExpression | undefined { const expr = ContextKeyAndExpr._normalizeArr(_expr); if (expr.length === 0) { return undefined; @@ -547,7 +552,7 @@ export class ContextKeyAndExpr implements ContextKeyExpr { return new ContextKeyAndExpr(expr); } - private constructor(public readonly expr: ContextKeyExpr[]) { + private constructor(public readonly expr: ContextKeyExpression[]) { } public getType(): ContextKeyExprType { @@ -570,7 +575,7 @@ export class ContextKeyAndExpr implements ContextKeyExpr { return 0; } - public equals(other: ContextKeyExpr): boolean { + public equals(other: ContextKeyExpression): boolean { if (other instanceof ContextKeyAndExpr) { if (this.expr.length !== other.expr.length) { return false; @@ -594,8 +599,8 @@ export class ContextKeyAndExpr implements ContextKeyExpr { return true; } - private static _normalizeArr(arr: ReadonlyArray): ContextKeyExpr[] { - const expr: ContextKeyExpr[] = []; + private static _normalizeArr(arr: ReadonlyArray): ContextKeyExpression[] { + const expr: ContextKeyExpression[] = []; for (const e of arr) { if (!e) { @@ -632,12 +637,12 @@ export class ContextKeyAndExpr implements ContextKeyExpr { return result; } - public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { + public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression { return new ContextKeyAndExpr(this.expr.map(expr => expr.map(mapFnc))); } - public negate(): ContextKeyExpr { - let result: ContextKeyExpr[] = []; + public negate(): ContextKeyExpression { + let result: ContextKeyExpression[] = []; for (let expr of this.expr) { result.push(expr.negate()); } @@ -647,7 +652,7 @@ export class ContextKeyAndExpr implements ContextKeyExpr { export class ContextKeyOrExpr implements ContextKeyExpr { - public static create(_expr: ReadonlyArray): ContextKeyExpr | undefined { + public static create(_expr: ReadonlyArray): ContextKeyExpression | undefined { const expr = ContextKeyOrExpr._normalizeArr(_expr); if (expr.length === 0) { return undefined; @@ -660,14 +665,14 @@ export class ContextKeyOrExpr implements ContextKeyExpr { return new ContextKeyOrExpr(expr); } - private constructor(public readonly expr: ContextKeyExpr[]) { + private constructor(public readonly expr: ContextKeyExpression[]) { } public getType(): ContextKeyExprType { return ContextKeyExprType.Or; } - public equals(other: ContextKeyExpr): boolean { + public equals(other: ContextKeyExpression): boolean { if (other instanceof ContextKeyOrExpr) { if (this.expr.length !== other.expr.length) { return false; @@ -691,12 +696,12 @@ export class ContextKeyOrExpr implements ContextKeyExpr { return false; } - private static _normalizeArr(arr: ReadonlyArray): ContextKeyExpr[] { - let expr: ContextKeyExpr[] = []; + private static _normalizeArr(arr: ReadonlyArray): ContextKeyExpression[] { + let expr: ContextKeyExpression[] = []; if (arr) { for (let i = 0, len = arr.length; i < len; i++) { - let e: ContextKeyExpr | null | undefined = arr[i]; + let e: ContextKeyExpression | null | undefined = arr[i]; if (!e) { continue; } @@ -727,17 +732,17 @@ export class ContextKeyOrExpr implements ContextKeyExpr { return result; } - public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { + public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression { return new ContextKeyOrExpr(this.expr.map(expr => expr.map(mapFnc))); } - public negate(): ContextKeyExpr { - let result: ContextKeyExpr[] = []; + public negate(): ContextKeyExpression { + let result: ContextKeyExpression[] = []; for (let expr of this.expr) { result.push(expr.negate()); } - const terminals = (node: ContextKeyExpr) => { + const terminals = (node: ContextKeyExpression) => { if (node instanceof ContextKeyOrExpr) { return node.expr; } @@ -750,7 +755,7 @@ export class ContextKeyOrExpr implements ContextKeyExpr { const LEFT = result.shift()!; const RIGHT = result.shift()!; - const all: ContextKeyExpr[] = []; + const all: ContextKeyExpression[] = []; for (const left of terminals(LEFT)) { for (const right of terminals(RIGHT)) { all.push(ContextKeyExpr.and(left, right)!); @@ -780,15 +785,15 @@ export class RawContextKey extends ContextKeyDefinedExpr { return target.getContextKeyValue(this.key); } - public toNegated(): ContextKeyExpr { + public toNegated(): ContextKeyExpression { return ContextKeyExpr.not(this.key); } - public isEqualTo(value: string): ContextKeyExpr { + public isEqualTo(value: string): ContextKeyExpression { return ContextKeyExpr.equals(this.key, value); } - public notEqualsTo(value: string): ContextKeyExpr { + public notEqualsTo(value: string): ContextKeyExpression { return ContextKeyExpr.notEquals(this.key, value); } } @@ -830,7 +835,7 @@ export interface IContextKeyService { createKey(key: string, defaultValue: T | undefined): IContextKey; - contextMatchesRules(rules: ContextKeyExpr | undefined): boolean; + contextMatchesRules(rules: ContextKeyExpression | undefined): boolean; getContextKeyValue(key: string): T | undefined; createScoped(target?: IContextKeyServiceTarget): IContextKeyService; diff --git a/src/vs/platform/contextkey/common/contextkeys.ts b/src/vs/platform/contextkey/common/contextkeys.ts index c3206a24d9a..4f8959e04ff 100644 --- a/src/vs/platform/contextkey/common/contextkeys.ts +++ b/src/vs/platform/contextkey/common/contextkeys.ts @@ -3,9 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; export const InputFocusedContextKey = 'inputFocus'; export const InputFocusedContext = new RawContextKey(InputFocusedContextKey, false); -export const FalseContext: ContextKeyExpr = new RawContextKey('__false', false); \ No newline at end of file +export const FalseContext = new RawContextKey('__false', false); diff --git a/src/vs/platform/keybinding/common/keybindingResolver.ts b/src/vs/platform/keybinding/common/keybindingResolver.ts index 439e42d9948..5e0a7fcff1a 100644 --- a/src/vs/platform/keybinding/common/keybindingResolver.ts +++ b/src/vs/platform/keybinding/common/keybindingResolver.ts @@ -6,7 +6,7 @@ import { isNonEmptyArray } from 'vs/base/common/arrays'; import { MenuRegistry } from 'vs/platform/actions/common/actions'; import { CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; -import { ContextKeyExpr, IContext, ContextKeyOrExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, IContext, ContextKeyOrExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { keys } from 'vs/base/common/map'; @@ -175,7 +175,7 @@ export class KeybindingResolver { /** * Returns true if it is provable `a` implies `b`. */ - public static whenIsEntirelyIncluded(a: ContextKeyExpr | null | undefined, b: ContextKeyExpr | null | undefined): boolean { + public static whenIsEntirelyIncluded(a: ContextKeyExpression | null | undefined, b: ContextKeyExpression | null | undefined): boolean { if (!b) { return true; } @@ -189,10 +189,10 @@ export class KeybindingResolver { /** * Returns true if it is provable `p` implies `q`. */ - private static _implies(p: ContextKeyExpr, q: ContextKeyExpr): boolean { + private static _implies(p: ContextKeyExpression, q: ContextKeyExpression): boolean { const notP = p.negate(); - const terminals = (node: ContextKeyExpr) => { + const terminals = (node: ContextKeyExpression) => { if (node instanceof ContextKeyOrExpr) { return node.expr; } diff --git a/src/vs/platform/keybinding/common/keybindingsRegistry.ts b/src/vs/platform/keybinding/common/keybindingsRegistry.ts index 5c3de02794b..6f249867f8e 100644 --- a/src/vs/platform/keybinding/common/keybindingsRegistry.ts +++ b/src/vs/platform/keybinding/common/keybindingsRegistry.ts @@ -6,14 +6,14 @@ import { KeyCode, Keybinding, SimpleKeybinding, createKeybinding } from 'vs/base/common/keyCodes'; import { OS, OperatingSystem } from 'vs/base/common/platform'; import { CommandsRegistry, ICommandHandler, ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { Registry } from 'vs/platform/registry/common/platform'; export interface IKeybindingItem { keybinding: Keybinding; command: string; commandArgs?: any; - when: ContextKeyExpr | null | undefined; + when: ContextKeyExpression | null | undefined; weight1: number; weight2: number; } @@ -39,7 +39,7 @@ export interface IKeybindingRule extends IKeybindings { id: string; weight: number; args?: any; - when: ContextKeyExpr | null | undefined; + when: ContextKeyExpression | null | undefined; } export interface IKeybindingRule2 { @@ -50,7 +50,7 @@ export interface IKeybindingRule2 { id: string; args?: any; weight: number; - when: ContextKeyExpr | undefined; + when: ContextKeyExpression | undefined; } export const enum KeybindingWeight { @@ -209,7 +209,7 @@ class KeybindingsRegistryImpl implements IKeybindingsRegistry { } } - private _registerDefaultKeybinding(keybinding: Keybinding, commandId: string, commandArgs: any, weight1: number, weight2: number, when: ContextKeyExpr | null | undefined): void { + private _registerDefaultKeybinding(keybinding: Keybinding, commandId: string, commandArgs: any, weight1: number, weight2: number, when: ContextKeyExpression | null | undefined): void { if (OS === OperatingSystem.Windows) { this._assertNoCtrlAlt(keybinding.parts[0], commandId); } diff --git a/src/vs/platform/keybinding/common/resolvedKeybindingItem.ts b/src/vs/platform/keybinding/common/resolvedKeybindingItem.ts index 00b05e05213..a32518446e7 100644 --- a/src/vs/platform/keybinding/common/resolvedKeybindingItem.ts +++ b/src/vs/platform/keybinding/common/resolvedKeybindingItem.ts @@ -5,7 +5,7 @@ import { CharCode } from 'vs/base/common/charCode'; import { ResolvedKeybinding } from 'vs/base/common/keyCodes'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; export class ResolvedKeybindingItem { _resolvedKeybindingItemBrand: void; @@ -15,10 +15,10 @@ export class ResolvedKeybindingItem { public readonly bubble: boolean; public readonly command: string | null; public readonly commandArgs: any; - public readonly when: ContextKeyExpr | undefined; + public readonly when: ContextKeyExpression | undefined; public readonly isDefault: boolean; - constructor(resolvedKeybinding: ResolvedKeybinding | undefined, command: string | null, commandArgs: any, when: ContextKeyExpr | undefined, isDefault: boolean) { + constructor(resolvedKeybinding: ResolvedKeybinding | undefined, command: string | null, commandArgs: any, when: ContextKeyExpression | undefined, isDefault: boolean) { this.resolvedKeybinding = resolvedKeybinding; this.keypressParts = resolvedKeybinding ? removeElementsAfterNulls(resolvedKeybinding.getDispatchParts()) : []; this.bubble = (command ? command.charCodeAt(0) === CharCode.Caret : false); diff --git a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts index 05a93605d42..286ea8a57ae 100644 --- a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts +++ b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts @@ -7,7 +7,7 @@ import { KeyChord, KeyCode, KeyMod, Keybinding, ResolvedKeybinding, SimpleKeybin import { OS } from 'vs/base/common/platform'; import Severity from 'vs/base/common/severity'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { ContextKeyExpr, IContext, IContextKeyService, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, IContext, IContextKeyService, IContextKeyServiceTarget, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { AbstractKeybindingService } from 'vs/platform/keybinding/common/abstractKeybindingService'; import { IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver'; @@ -182,7 +182,7 @@ suite('AbstractKeybindingService', () => { statusMessageCallsDisposed = null; }); - function kbItem(keybinding: number, command: string, when?: ContextKeyExpr): ResolvedKeybindingItem { + function kbItem(keybinding: number, command: string, when?: ContextKeyExpression): ResolvedKeybindingItem { const resolvedKeybinding = (keybinding !== 0 ? new USLayoutResolvedKeybinding(createKeybinding(keybinding, OS)!, OS) : undefined); return new ResolvedKeybindingItem( resolvedKeybinding, diff --git a/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts b/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts index c85003be1ac..7a71aad81d6 100644 --- a/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts +++ b/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { KeyChord, KeyCode, KeyMod, SimpleKeybinding, createKeybinding, createSimpleKeybinding } from 'vs/base/common/keyCodes'; import { OS } from 'vs/base/common/platform'; -import { ContextKeyExpr, IContext } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, IContext, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding'; @@ -20,7 +20,7 @@ function createContext(ctx: any) { suite('KeybindingResolver', () => { - function kbItem(keybinding: number, command: string, commandArgs: any, when: ContextKeyExpr | undefined, isDefault: boolean): ResolvedKeybindingItem { + function kbItem(keybinding: number, command: string, commandArgs: any, when: ContextKeyExpression | undefined, isDefault: boolean): ResolvedKeybindingItem { const resolvedKeybinding = (keybinding !== 0 ? new USLayoutResolvedKeybinding(createKeybinding(keybinding, OS)!, OS) : undefined); return new ResolvedKeybindingItem( resolvedKeybinding, @@ -225,7 +225,7 @@ suite('KeybindingResolver', () => { test('resolve command', function () { - function _kbItem(keybinding: number, command: string, when: ContextKeyExpr | undefined): ResolvedKeybindingItem { + function _kbItem(keybinding: number, command: string, when: ContextKeyExpression | undefined): ResolvedKeybindingItem { return kbItem(keybinding, command, null, when, true); } diff --git a/src/vs/platform/keybinding/test/common/mockKeybindingService.ts b/src/vs/platform/keybinding/test/common/mockKeybindingService.ts index 8fcb795eda0..998169968bd 100644 --- a/src/vs/platform/keybinding/test/common/mockKeybindingService.ts +++ b/src/vs/platform/keybinding/test/common/mockKeybindingService.ts @@ -6,7 +6,7 @@ import { Event } from 'vs/base/common/event'; import { Keybinding, ResolvedKeybinding, SimpleKeybinding } from 'vs/base/common/keyCodes'; import { OS } from 'vs/base/common/platform'; -import { ContextKeyExpr, IContextKey, IContextKeyChangeEvent, IContextKeyService, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKey, IContextKeyChangeEvent, IContextKeyService, IContextKeyServiceTarget, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { IKeybindingEvent, IKeybindingService, IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; import { IResolveResult } from 'vs/platform/keybinding/common/keybindingResolver'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; @@ -47,7 +47,7 @@ export class MockContextKeyService implements IContextKeyService { this._keys.set(key, ret); return ret; } - public contextMatchesRules(rules: ContextKeyExpr): boolean { + public contextMatchesRules(rules: ContextKeyExpression): boolean { return false; } public get onDidChangeContext(): Event { diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index a5d1e5f4f4b..898f33f8341 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -42,7 +42,7 @@ import * as editorCommands from 'vs/workbench/browser/parts/editor/editorCommand import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { getQuickNavigateHandler, inQuickOpenContext } from 'vs/workbench/browser/parts/quickopen/quickopen'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { isMacintosh } from 'vs/base/common/platform'; import { AllEditorsByAppearancePicker, ActiveGroupEditorsByMostRecentlyUsedPicker, AllEditorsByMostRecentlyUsedPicker } from 'vs/workbench/browser/parts/editor/editorPicker'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; @@ -511,7 +511,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands. interface IEditorToolItem { id: string; title: string; icon?: { dark?: URI; light?: URI; } | ThemeIcon; } -function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpr | undefined, order: number, alternative?: IEditorToolItem, precondition?: ContextKeyExpr | undefined): void { +function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpression | undefined, order: number, alternative?: IEditorToolItem, precondition?: ContextKeyExpression | undefined): void { const item: IMenuItem = { command: { id: primary.id, diff --git a/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts index 8c3117a0b12..b92b4457e2b 100644 --- a/src/vs/workbench/browser/parts/panel/panelActions.ts +++ b/src/vs/workbench/browser/parts/panel/panelActions.ts @@ -17,7 +17,7 @@ import { ActivityAction, ToggleCompositePinnedAction, ICompositeBar } from 'vs/w import { IActivity } from 'vs/workbench/common/activity'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ActivePanelContext, PanelPositionContext } from 'vs/workbench/common/panel'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; export class ClosePanelAction extends Action { @@ -133,7 +133,7 @@ const PositionPanelActionId = { interface PanelActionConfig { id: string; - when: ContextKeyExpr; + when: ContextKeyExpression; alias: string; label: string; value: T; diff --git a/src/vs/workbench/common/actions.ts b/src/vs/workbench/common/actions.ts index 7f5a5cbdd14..3e1068d55fe 100644 --- a/src/vs/workbench/common/actions.ts +++ b/src/vs/workbench/common/actions.ts @@ -11,7 +11,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; export const Extensions = { WorkbenchActions: 'workbench.contributions.actions' @@ -28,11 +28,11 @@ export interface IWorkbenchActionRegistry { Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionRegistry { - registerWorkbenchAction(descriptor: SyncActionDescriptor, alias: string, category?: string, when?: ContextKeyExpr): IDisposable { + registerWorkbenchAction(descriptor: SyncActionDescriptor, alias: string, category?: string, when?: ContextKeyExpression): IDisposable { return this.registerWorkbenchCommandFromAction(descriptor, alias, category, when); } - private registerWorkbenchCommandFromAction(descriptor: SyncActionDescriptor, alias: string, category?: string, when?: ContextKeyExpr): IDisposable { + private registerWorkbenchCommandFromAction(descriptor: SyncActionDescriptor, alias: string, category?: string, when?: ContextKeyExpression): IDisposable { const registrations = new DisposableStore(); // command diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index b63812fdc96..6e4802e474f 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -12,7 +12,7 @@ import { IDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle' import { IEditor as ICodeEditor, IEditorViewState, ScrollType, IDiffEditor } from 'vs/editor/common/editorCommon'; import { IEditorModel, IEditorOptions, ITextEditorOptions, IBaseResourceInput, IResourceInput, EditorActivation, EditorOpenContext, ITextEditorSelection, TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor'; import { IInstantiationService, IConstructorSignature0, ServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation'; -import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { Registry } from 'vs/platform/registry/common/platform'; import { ITextModel } from 'vs/editor/common/model'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -38,7 +38,7 @@ export const EditorsVisibleContext = new RawContextKey('editorIsOpen', export const EditorPinnedContext = new RawContextKey('editorPinned', false); export const EditorGroupActiveEditorDirtyContext = new RawContextKey('groupActiveEditorDirty', false); export const EditorGroupEditorsCountContext = new RawContextKey('groupEditorsCount', 0); -export const NoEditorsVisibleContext: ContextKeyExpr = EditorsVisibleContext.toNegated(); +export const NoEditorsVisibleContext = EditorsVisibleContext.toNegated(); export const TextCompareEditorVisibleContext = new RawContextKey('textCompareEditorVisible', false); export const TextCompareEditorActiveContext = new RawContextKey('textCompareEditorActive', false); export const ActiveEditorGroupEmptyContext = new RawContextKey('activeEditorGroupEmpty', false); diff --git a/src/vs/workbench/common/views.ts b/src/vs/workbench/common/views.ts index 6b29b27222e..8cf5db8c126 100644 --- a/src/vs/workbench/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -6,7 +6,7 @@ import { Command } from 'vs/editor/common/modes'; import { UriComponents, URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; -import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { RawContextKey, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { localize } from 'vs/nls'; import { IViewlet } from 'vs/workbench/common/viewlet'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; @@ -178,7 +178,7 @@ export interface IViewDescriptor { readonly ctorDescriptor: SyncDescriptor; - readonly when?: ContextKeyExpr; + readonly when?: ContextKeyExpression; readonly order?: number; @@ -220,13 +220,13 @@ export enum ViewContentPriority { export interface IViewContentDescriptor { readonly content: string; - readonly when?: ContextKeyExpr | 'default'; + readonly when?: ContextKeyExpression | 'default'; readonly priority?: ViewContentPriority; /** * ordered preconditions for each button in the content */ - readonly preconditions?: (ContextKeyExpr | undefined)[]; + readonly preconditions?: (ContextKeyExpression | undefined)[]; } export interface IViewsRegistry { diff --git a/src/vs/workbench/contrib/codeActions/common/documentationContribution.ts b/src/vs/workbench/contrib/codeActions/common/documentationContribution.ts index 9c2b75c277d..1b6507eed9d 100644 --- a/src/vs/workbench/contrib/codeActions/common/documentationContribution.ts +++ b/src/vs/workbench/contrib/codeActions/common/documentationContribution.ts @@ -10,7 +10,7 @@ import { Selection } from 'vs/editor/common/core/selection'; import { ITextModel } from 'vs/editor/common/model'; import * as modes from 'vs/editor/common/modes'; import { CodeActionKind } from 'vs/editor/contrib/codeAction/types'; -import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { DocumentationExtensionPoint } from './documentationExtensionPoint'; @@ -20,7 +20,7 @@ export class CodeActionDocumentationContribution extends Disposable implements I private contributions: { title: string; - when: ContextKeyExpr; + when: ContextKeyExpression; command: string; }[] = []; diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index d01fecdbb3c..06f84bae24b 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -31,7 +31,7 @@ import { IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandler import { StatusBarColorProvider } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider'; import { IViewsRegistry, Extensions as ViewExtensions, IViewContainersRegistry, ViewContainerLocation, ViewContainer } from 'vs/workbench/common/views'; import { isMacintosh } from 'vs/base/common/platform'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { URI } from 'vs/base/common/uri'; import { DebugQuickOpenHandler } from 'vs/workbench/contrib/debug/browser/debugQuickOpen'; import { DebugStatusContribution } from 'vs/workbench/contrib/debug/browser/debugStatus'; @@ -135,7 +135,7 @@ registry.registerWorkbenchAction(SyncActionDescriptor.create(DisableAllBreakpoin registry.registerWorkbenchAction(SyncActionDescriptor.create(SelectAndStartAction, SelectAndStartAction.ID, SelectAndStartAction.LABEL), 'Debug: Select and Start Debugging', debugCategory); registry.registerWorkbenchAction(SyncActionDescriptor.create(ClearReplAction, ClearReplAction.ID, ClearReplAction.LABEL), 'Debug: Clear Console', debugCategory); -const registerDebugCommandPaletteItem = (id: string, title: string, when?: ContextKeyExpr, precondition?: ContextKeyExpr) => { +const registerDebugCommandPaletteItem = (id: string, title: string, when?: ContextKeyExpression, precondition?: ContextKeyExpression) => { MenuRegistry.appendMenuItem(MenuId.CommandPalette, { when, command: { @@ -290,7 +290,7 @@ Registry.as(WorkbenchExtensions.Workbench).regi // Debug toolbar -const registerDebugToolBarItem = (id: string, title: string, order: number, icon: { light?: URI, dark?: URI } | ThemeIcon, when?: ContextKeyExpr, precondition?: ContextKeyExpr) => { +const registerDebugToolBarItem = (id: string, title: string, order: number, icon: { light?: URI, dark?: URI } | ThemeIcon, when?: ContextKeyExpression, precondition?: ContextKeyExpression) => { MenuRegistry.appendMenuItem(MenuId.DebugToolBar, { group: 'navigation', when, @@ -316,7 +316,7 @@ registerDebugToolBarItem(STEP_BACK_ID, nls.localize('stepBackDebug', "Step Back" registerDebugToolBarItem(REVERSE_CONTINUE_ID, nls.localize('reverseContinue', "Reverse"), 60, { id: 'codicon/debug-reverse-continue' }, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); // Debug callstack context menu -const registerDebugCallstackItem = (id: string, title: string, order: number, when?: ContextKeyExpr, precondition?: ContextKeyExpr, group = 'navigation') => { +const registerDebugCallstackItem = (id: string, title: string, order: number, when?: ContextKeyExpression, precondition?: ContextKeyExpression, group = 'navigation') => { MenuRegistry.appendMenuItem(MenuId.DebugCallStackContext, { group, when, @@ -558,7 +558,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarDebugMenu, { // Touch Bar if (isMacintosh) { - const registerTouchBarEntry = (id: string, title: string, order: number, when: ContextKeyExpr | undefined, iconUri: URI) => { + const registerTouchBarEntry = (id: string, title: string, order: number, when: ContextKeyExpression | undefined, iconUri: URI) => { MenuRegistry.appendMenuItem(MenuId.TouchBarContext, { command: { id, diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index 6876d783a34..5e9f7843888 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -12,7 +12,7 @@ import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/wor import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; import { openWindowCommand, COPY_PATH_COMMAND_ID, REVEAL_IN_EXPLORER_COMMAND_ID, OPEN_TO_SIDE_COMMAND_ID, REVERT_FILE_COMMAND_ID, SAVE_FILE_COMMAND_ID, SAVE_FILE_LABEL, SAVE_FILE_AS_COMMAND_ID, SAVE_FILE_AS_LABEL, SAVE_ALL_IN_GROUP_COMMAND_ID, OpenEditorsGroupContext, COMPARE_WITH_SAVED_COMMAND_ID, COMPARE_RESOURCE_COMMAND_ID, SELECT_FOR_COMPARE_COMMAND_ID, ResourceSelectedForCompareContext, DirtyEditorContext, COMPARE_SELECTED_COMMAND_ID, REMOVE_ROOT_FOLDER_COMMAND_ID, REMOVE_ROOT_FOLDER_LABEL, SAVE_FILES_COMMAND_ID, COPY_RELATIVE_PATH_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_LABEL, newWindowCommand, ReadonlyEditorContext } from 'vs/workbench/contrib/files/browser/fileCommands'; import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/commands'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { isMacintosh } from 'vs/base/common/platform'; import { FilesExplorerFocusCondition, ExplorerRootContext, ExplorerFolderContext, ExplorerResourceNotReadonlyContext, ExplorerResourceCut, IExplorerService, ExplorerResourceMoveableToTrash, ExplorerViewletVisibleContext } from 'vs/workbench/contrib/files/common/files'; @@ -170,7 +170,7 @@ appendEditorTitleContextMenuItem(COPY_PATH_COMMAND_ID, copyPathCommand.title, Re appendEditorTitleContextMenuItem(COPY_RELATIVE_PATH_COMMAND_ID, copyRelativePathCommand.title, ResourceContextKey.IsFileSystemResource, '1_cutcopypaste'); appendEditorTitleContextMenuItem(REVEAL_IN_EXPLORER_COMMAND_ID, nls.localize('revealInSideBar', "Reveal in Side Bar"), ResourceContextKey.IsFileSystemResource); -export function appendEditorTitleContextMenuItem(id: string, title: string, when: ContextKeyExpr | undefined, group?: string): void { +export function appendEditorTitleContextMenuItem(id: string, title: string, when: ContextKeyExpression | undefined, group?: string): void { // Menu MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { @@ -200,7 +200,7 @@ function appendSaveConflictEditorTitleAction(id: string, title: string, icon: Th // Menu registration - command palette -export function appendToCommandPalette(id: string, title: ILocalizedString, category: ILocalizedString, when?: ContextKeyExpr): void { +export function appendToCommandPalette(id: string, title: ILocalizedString, category: ILocalizedString, when?: ContextKeyExpression): void { MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id, diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index e58b63cc000..f834e5e5c90 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { Event } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { URI } from 'vs/base/common/uri'; import { OperatingSystem } from 'vs/base/common/platform'; @@ -19,25 +19,25 @@ export const KEYBINDING_CONTEXT_TERMINAL_IS_OPEN = new RawContextKey('t /** A context key that is set when the integrated terminal has focus. */ export const KEYBINDING_CONTEXT_TERMINAL_FOCUS = new RawContextKey('terminalFocus', false); /** A context key that is set when the integrated terminal does not have focus. */ -export const KEYBINDING_CONTEXT_TERMINAL_NOT_FOCUSED: ContextKeyExpr = KEYBINDING_CONTEXT_TERMINAL_FOCUS.toNegated(); +export const KEYBINDING_CONTEXT_TERMINAL_NOT_FOCUSED = KEYBINDING_CONTEXT_TERMINAL_FOCUS.toNegated(); /** A context key that is set when the user is navigating the accessibility tree */ export const KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS = new RawContextKey('terminalA11yTreeFocus', false); /** A keybinding context key that is set when the integrated terminal has text selected. */ export const KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED = new RawContextKey('terminalTextSelected', false); /** A keybinding context key that is set when the integrated terminal does not have text selected. */ -export const KEYBINDING_CONTEXT_TERMINAL_TEXT_NOT_SELECTED: ContextKeyExpr = KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED.toNegated(); +export const KEYBINDING_CONTEXT_TERMINAL_TEXT_NOT_SELECTED = KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED.toNegated(); /** A context key that is set when the find widget in integrated terminal is visible. */ export const KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE = new RawContextKey('terminalFindWidgetVisible', false); /** A context key that is set when the find widget in integrated terminal is not visible. */ -export const KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE: ContextKeyExpr = KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE.toNegated(); +export const KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE = KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE.toNegated(); /** A context key that is set when the find widget find input in integrated terminal is focused. */ export const KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_FOCUSED = new RawContextKey('terminalFindWidgetInputFocused', false); /** A context key that is set when the find widget in integrated terminal is focused. */ export const KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED = new RawContextKey('terminalFindWidgetFocused', false); /** A context key that is set when the find widget find input in integrated terminal is not focused. */ -export const KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_NOT_FOCUSED: ContextKeyExpr = KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_FOCUSED.toNegated(); +export const KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_NOT_FOCUSED = KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_FOCUSED.toNegated(); export const IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY = 'terminal.integrated.isWorkspaceShellAllowed'; export const NEVER_MEASURE_RENDER_TIME_STORAGE_KEY = 'terminal.integrated.neverMeasureRenderTime'; diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 4ebc626db3a..0a30e149ade 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -23,7 +23,7 @@ import { localize } from 'vs/nls'; import { MenuId, MenuRegistry, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey, ContextKeyRegexExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -835,7 +835,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } private registerShowSettingsConflictsAction(): void { - const resolveSettingsConflictsWhenContext = ContextKeyRegexExpr.create(CONTEXT_CONFLICTS_SOURCES.keys()[0], /.*settings.*/i); + const resolveSettingsConflictsWhenContext = ContextKeyExpr.regex(CONTEXT_CONFLICTS_SOURCES.keys()[0], /.*settings.*/i); CommandsRegistry.registerCommand(resolveSettingsConflictsCommand.id, () => this.handleConflicts(SyncSource.Settings)); MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { group: '5_sync', @@ -862,7 +862,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } private registerShowKeybindingsConflictsAction(): void { - const resolveKeybindingsConflictsWhenContext = ContextKeyRegexExpr.create(CONTEXT_CONFLICTS_SOURCES.keys()[0], /.*keybindings.*/i); + const resolveKeybindingsConflictsWhenContext = ContextKeyExpr.regex(CONTEXT_CONFLICTS_SOURCES.keys()[0], /.*keybindings.*/i); CommandsRegistry.registerCommand(resolveKeybindingsConflictsCommand.id, () => this.handleConflicts(SyncSource.Keybindings)); MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { group: '5_sync', diff --git a/src/vs/workbench/contrib/webview/browser/webviewCommands.ts b/src/vs/workbench/contrib/webview/browser/webviewCommands.ts index 5f870d1d15e..66a2f7f9955 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewCommands.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewCommands.ts @@ -7,7 +7,7 @@ import { Action } from 'vs/base/common/actions'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import * as nls from 'vs/nls'; import { Action2 } from 'vs/platform/actions/common/actions'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_FOCUSED, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE } from 'vs/workbench/contrib/webview/browser/webview'; @@ -19,7 +19,7 @@ export class ShowWebViewEditorFindWidgetAction extends Action2 { public static readonly ID = 'editor.action.webvieweditor.showFind'; public static readonly LABEL = nls.localize('editor.action.webvieweditor.showFind', "Show find"); - constructor(contextKeyExpr: ContextKeyExpr) { + constructor(contextKeyExpr: ContextKeyExpression) { super({ id: ShowWebViewEditorFindWidgetAction.ID, title: ShowWebViewEditorFindWidgetAction.LABEL, @@ -40,7 +40,7 @@ export class HideWebViewEditorFindCommand extends Action2 { public static readonly ID = 'editor.action.webvieweditor.hideFind'; public static readonly LABEL = nls.localize('editor.action.webvieweditor.hideFind', "Stop find"); - constructor(contextKeyExpr: ContextKeyExpr) { + constructor(contextKeyExpr: ContextKeyExpression) { super({ id: HideWebViewEditorFindCommand.ID, title: HideWebViewEditorFindCommand.LABEL, @@ -61,7 +61,7 @@ export class WebViewEditorFindNextCommand extends Action2 { public static readonly ID = 'editor.action.webvieweditor.findNext'; public static readonly LABEL = nls.localize('editor.action.webvieweditor.findNext', 'Find next'); - constructor(contextKeyExpr: ContextKeyExpr) { + constructor(contextKeyExpr: ContextKeyExpression) { super({ id: WebViewEditorFindNextCommand.ID, title: WebViewEditorFindNextCommand.LABEL, @@ -82,7 +82,7 @@ export class WebViewEditorFindPreviousCommand extends Action2 { public static readonly ID = 'editor.action.webvieweditor.findPrevious'; public static readonly LABEL = nls.localize('editor.action.webvieweditor.findPrevious', 'Find previous'); - constructor(contextKeyExpr: ContextKeyExpr) { + constructor(contextKeyExpr: ContextKeyExpression) { super({ id: WebViewEditorFindPreviousCommand.ID, title: WebViewEditorFindPreviousCommand.LABEL, @@ -103,7 +103,7 @@ export class SelectAllWebviewEditorCommand extends Action2 { public static readonly ID = 'editor.action.webvieweditor.selectAll'; public static readonly LABEL = nls.localize('editor.action.webvieweditor.selectAll', 'Select all'); - constructor(contextKeyExpr: ContextKeyExpr) { + constructor(contextKeyExpr: ContextKeyExpression) { const precondition = ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)); super({ id: SelectAllWebviewEditorCommand.ID, diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts index ebbe40c7f42..43c0e653b7f 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts @@ -9,7 +9,7 @@ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import * as nls from 'vs/nls'; import { Action2 } from 'vs/platform/actions/common/actions'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { WebviewEditorOverlay, webviewHasOwnEditFunctionsContextKey } from 'vs/workbench/contrib/webview/browser/webview'; @@ -42,7 +42,7 @@ export class CopyWebviewEditorCommand extends Action2 { public static readonly ID = 'editor.action.webvieweditor.copy'; public static readonly LABEL = nls.localize('editor.action.webvieweditor.copy', "Copy2"); - constructor(contextKeyExpr: ContextKeyExpr) { + constructor(contextKeyExpr: ContextKeyExpression) { super({ id: CopyWebviewEditorCommand.ID, title: CopyWebviewEditorCommand.LABEL, @@ -63,7 +63,7 @@ export class PasteWebviewEditorCommand extends Action2 { public static readonly ID = 'editor.action.webvieweditor.paste'; public static readonly LABEL = nls.localize('editor.action.webvieweditor.paste', 'Paste'); - constructor(contextKeyExpr: ContextKeyExpr) { + constructor(contextKeyExpr: ContextKeyExpression) { super({ id: PasteWebviewEditorCommand.ID, title: PasteWebviewEditorCommand.LABEL, @@ -84,7 +84,7 @@ export class CutWebviewEditorCommand extends Action2 { public static readonly ID = 'editor.action.webvieweditor.cut'; public static readonly LABEL = nls.localize('editor.action.webvieweditor.cut', 'Cut'); - constructor(contextKeyExpr: ContextKeyExpr) { + constructor(contextKeyExpr: ContextKeyExpression) { super({ id: CutWebviewEditorCommand.ID, title: CutWebviewEditorCommand.LABEL, @@ -105,7 +105,7 @@ export class UndoWebviewEditorCommand extends Action2 { public static readonly ID = 'editor.action.webvieweditor.undo'; public static readonly LABEL = nls.localize('editor.action.webvieweditor.undo', "Undo"); - constructor(contextKeyExpr: ContextKeyExpr) { + constructor(contextKeyExpr: ContextKeyExpression) { super({ id: UndoWebviewEditorCommand.ID, title: UndoWebviewEditorCommand.LABEL, @@ -126,7 +126,7 @@ export class RedoWebviewEditorCommand extends Action2 { public static readonly ID = 'editor.action.webvieweditor.redo'; public static readonly LABEL = nls.localize('editor.action.webvieweditor.redo', "Redo"); - constructor(contextKeyExpr: ContextKeyExpr) { + constructor(contextKeyExpr: ContextKeyExpression) { super({ id: RedoWebviewEditorCommand.ID, title: RedoWebviewEditorCommand.LABEL, diff --git a/src/vs/workbench/services/keybinding/browser/keybindingService.ts b/src/vs/workbench/services/keybinding/browser/keybindingService.ts index 7db79b0c45a..42dfc300992 100644 --- a/src/vs/workbench/services/keybinding/browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/browser/keybindingService.ts @@ -15,7 +15,7 @@ import { OS, OperatingSystem } from 'vs/base/common/platform'; import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Extensions as ConfigExtensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; -import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { Extensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { AbstractKeybindingService } from 'vs/platform/keybinding/common/abstractKeybindingService'; @@ -510,7 +510,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { let commandAction = MenuRegistry.getCommand(command); let precondition = commandAction && commandAction.precondition; - let fullWhen: ContextKeyExpr | undefined; + let fullWhen: ContextKeyExpression | undefined; if (when && precondition) { fullWhen = ContextKeyExpr.and(precondition, ContextKeyExpr.deserialize(when)); } else if (when) { diff --git a/src/vs/workbench/services/keybinding/common/keybindingIO.ts b/src/vs/workbench/services/keybinding/common/keybindingIO.ts index f7c600c0a02..2d4da1d3ff3 100644 --- a/src/vs/workbench/services/keybinding/common/keybindingIO.ts +++ b/src/vs/workbench/services/keybinding/common/keybindingIO.ts @@ -6,7 +6,7 @@ import { SimpleKeybinding } from 'vs/base/common/keyCodes'; import { KeybindingParser } from 'vs/base/common/keybindingParser'; import { ScanCodeBinding } from 'vs/base/common/scanCode'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { IUserFriendlyKeybinding } from 'vs/platform/keybinding/common/keybinding'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; @@ -14,7 +14,7 @@ export interface IUserKeybindingItem { parts: (SimpleKeybinding | ScanCodeBinding)[]; command: string | null; commandArgs?: any; - when: ContextKeyExpr | undefined; + when: ContextKeyExpression | undefined; } export class KeybindingIO { From cd8b95bbf9b3a7e2f8077bf803d467af7e1eca6a Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 28 Feb 2020 14:13:07 +0100 Subject: [PATCH 164/235] Improvements to context keys --- src/vs/platform/actions/common/menuService.ts | 4 +- .../platform/contextkey/common/contextkey.ts | 191 +++++++++--------- .../keybinding/common/keybindingResolver.ts | 8 +- 3 files changed, 104 insertions(+), 99 deletions(-) diff --git a/src/vs/platform/actions/common/menuService.ts b/src/vs/platform/actions/common/menuService.ts index fac16754098..2bfa84d15eb 100644 --- a/src/vs/platform/actions/common/menuService.ts +++ b/src/vs/platform/actions/common/menuService.ts @@ -7,7 +7,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { IMenu, IMenuActionOptions, IMenuItem, IMenuService, isIMenuItem, ISubmenuItem, MenuId, MenuItemAction, MenuRegistry, SubmenuItemAction, ILocalizedString } from 'vs/platform/actions/common/actions'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { ContextKeyExpr, IContextKeyService, IContextKeyChangeEvent } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKeyService, IContextKeyChangeEvent, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; export class MenuService implements IMenuService { @@ -125,7 +125,7 @@ class Menu implements IMenu { return result; } - private static _fillInKbExprKeys(exp: ContextKeyExpr | undefined, set: Set): void { + private static _fillInKbExprKeys(exp: ContextKeyExpression | undefined, set: Set): void { if (exp) { for (let key of exp.keys()) { set.add(key); diff --git a/src/vs/platform/contextkey/common/contextkey.ts b/src/vs/platform/contextkey/common/contextkey.ts index dcab732a541..d5f8cdb22f5 100644 --- a/src/vs/platform/contextkey/common/contextkey.ts +++ b/src/vs/platform/contextkey/common/contextkey.ts @@ -26,6 +26,17 @@ export interface IContextKeyExprMapper { mapRegex(key: string, regexp: RegExp | null): ContextKeyRegexExpr; } +export interface IContextKeyExpression { + cmp(other: ContextKeyExpression): number; + equals(other: ContextKeyExpression): boolean; + evaluate(context: IContext): boolean; + serialize(): string; + keys(): string[]; + map(mapFnc: IContextKeyExprMapper): ContextKeyExpression; + negate(): ContextKeyExpression; + +} + export type ContextKeyExpression = ( ContextKeyDefinedExpr | ContextKeyNotExpr | ContextKeyEqualsExpr | ContextKeyNotEqualsExpr | ContextKeyRegexExpr | ContextKeyNotRegexExpr | ContextKeyAndExpr | ContextKeyOrExpr @@ -158,55 +169,26 @@ export abstract class ContextKeyExpr { return null; } } - - public abstract getType(): ContextKeyExprType; - public abstract equals(other: ContextKeyExpression): boolean; - public abstract evaluate(context: IContext): boolean; - public abstract serialize(): string; - public abstract keys(): string[]; - public abstract map(mapFnc: IContextKeyExprMapper): ContextKeyExpression; - public abstract negate(): ContextKeyExpression; } function cmp(a: ContextKeyExpression, b: ContextKeyExpression): number { - let aType = a.getType(); - let bType = b.getType(); - if (aType !== bType) { - return aType - bType; - } - switch (aType) { - case ContextKeyExprType.Defined: - return (a).cmp(b); - case ContextKeyExprType.Not: - return (a).cmp(b); - case ContextKeyExprType.Equals: - return (a).cmp(b); - case ContextKeyExprType.NotEquals: - return (a).cmp(b); - case ContextKeyExprType.Regex: - return (a).cmp(b); - case ContextKeyExprType.NotRegex: - return (a).cmp(b); - case ContextKeyExprType.And: - return (a).cmp(b); - default: - throw new Error('Unknown ContextKeyExpr!'); - } + return a.cmp(b); } -export class ContextKeyDefinedExpr implements ContextKeyExpr { +export class ContextKeyDefinedExpr implements IContextKeyExpression { public static create(key: string): ContextKeyDefinedExpr { return new ContextKeyDefinedExpr(key); } - protected constructor(protected key: string) { + public readonly type = ContextKeyExprType.Defined; + + protected constructor(protected readonly key: string) { } - public getType(): ContextKeyExprType { - return ContextKeyExprType.Defined; - } - - public cmp(other: ContextKeyDefinedExpr): number { + public cmp(other: ContextKeyExpression): number { + if (other.type !== this.type) { + return this.type - other.type; + } if (this.key < other.key) { return -1; } @@ -217,7 +199,7 @@ export class ContextKeyDefinedExpr implements ContextKeyExpr { } public equals(other: ContextKeyExpression): boolean { - if (other instanceof ContextKeyDefinedExpr) { + if (other.type === this.type) { return (this.key === other.key); } return false; @@ -244,7 +226,7 @@ export class ContextKeyDefinedExpr implements ContextKeyExpr { } } -export class ContextKeyEqualsExpr implements ContextKeyExpr { +export class ContextKeyEqualsExpr implements IContextKeyExpression { public static create(key: string, value: any): ContextKeyExpression { if (typeof value === 'boolean') { @@ -256,14 +238,15 @@ export class ContextKeyEqualsExpr implements ContextKeyExpr { return new ContextKeyEqualsExpr(key, value); } + public readonly type = ContextKeyExprType.Equals; + private constructor(private readonly key: string, private readonly value: any) { } - public getType(): ContextKeyExprType { - return ContextKeyExprType.Equals; - } - - public cmp(other: ContextKeyEqualsExpr): number { + public cmp(other: ContextKeyExpression): number { + if (other.type !== this.type) { + return this.type - other.type; + } if (this.key < other.key) { return -1; } @@ -280,7 +263,7 @@ export class ContextKeyEqualsExpr implements ContextKeyExpr { } public equals(other: ContextKeyExpression): boolean { - if (other instanceof ContextKeyEqualsExpr) { + if (other.type === this.type) { return (this.key === other.key && this.value === other.value); } return false; @@ -309,7 +292,7 @@ export class ContextKeyEqualsExpr implements ContextKeyExpr { } } -export class ContextKeyNotEqualsExpr implements ContextKeyExpr { +export class ContextKeyNotEqualsExpr implements IContextKeyExpression { public static create(key: string, value: any): ContextKeyExpression { if (typeof value === 'boolean') { @@ -321,14 +304,15 @@ export class ContextKeyNotEqualsExpr implements ContextKeyExpr { return new ContextKeyNotEqualsExpr(key, value); } - private constructor(private key: string, private value: any) { + public readonly type = ContextKeyExprType.NotEquals; + + private constructor(private readonly key: string, private readonly value: any) { } - public getType(): ContextKeyExprType { - return ContextKeyExprType.NotEquals; - } - - public cmp(other: ContextKeyNotEqualsExpr): number { + public cmp(other: ContextKeyExpression): number { + if (other.type !== this.type) { + return this.type - other.type; + } if (this.key < other.key) { return -1; } @@ -345,7 +329,7 @@ export class ContextKeyNotEqualsExpr implements ContextKeyExpr { } public equals(other: ContextKeyExpression): boolean { - if (other instanceof ContextKeyNotEqualsExpr) { + if (other.type === this.type) { return (this.key === other.key && this.value === other.value); } return false; @@ -374,20 +358,21 @@ export class ContextKeyNotEqualsExpr implements ContextKeyExpr { } } -export class ContextKeyNotExpr implements ContextKeyExpr { +export class ContextKeyNotExpr implements IContextKeyExpression { public static create(key: string): ContextKeyExpression { return new ContextKeyNotExpr(key); } - private constructor(private key: string) { + public readonly type = ContextKeyExprType.Not; + + private constructor(private readonly key: string) { } - public getType(): ContextKeyExprType { - return ContextKeyExprType.Not; - } - - public cmp(other: ContextKeyNotExpr): number { + public cmp(other: ContextKeyExpression): number { + if (other.type !== this.type) { + return this.type - other.type; + } if (this.key < other.key) { return -1; } @@ -398,7 +383,7 @@ export class ContextKeyNotExpr implements ContextKeyExpr { } public equals(other: ContextKeyExpression): boolean { - if (other instanceof ContextKeyNotExpr) { + if (other.type === this.type) { return (this.key === other.key); } return false; @@ -425,21 +410,22 @@ export class ContextKeyNotExpr implements ContextKeyExpr { } } -export class ContextKeyRegexExpr implements ContextKeyExpr { +export class ContextKeyRegexExpr implements IContextKeyExpression { public static create(key: string, regexp: RegExp | null): ContextKeyRegexExpr { return new ContextKeyRegexExpr(key, regexp); } - private constructor(private key: string, private regexp: RegExp | null) { + public readonly type = ContextKeyExprType.Regex; + + private constructor(private readonly key: string, private readonly regexp: RegExp | null) { // } - public getType(): ContextKeyExprType { - return ContextKeyExprType.Regex; - } - - public cmp(other: ContextKeyRegexExpr): number { + public cmp(other: ContextKeyExpression): number { + if (other.type !== this.type) { + return this.type - other.type; + } if (this.key < other.key) { return -1; } @@ -458,7 +444,7 @@ export class ContextKeyRegexExpr implements ContextKeyExpr { } public equals(other: ContextKeyExpression): boolean { - if (other instanceof ContextKeyRegexExpr) { + if (other.type === this.type) { const thisSource = this.regexp ? this.regexp.source : ''; const otherSource = other.regexp ? other.regexp.source : ''; return (this.key === other.key && thisSource === otherSource); @@ -491,26 +477,27 @@ export class ContextKeyRegexExpr implements ContextKeyExpr { } } -export class ContextKeyNotRegexExpr implements ContextKeyExpr { +export class ContextKeyNotRegexExpr implements IContextKeyExpression { public static create(actual: ContextKeyRegexExpr): ContextKeyExpression { return new ContextKeyNotRegexExpr(actual); } + public readonly type = ContextKeyExprType.NotRegex; + private constructor(private readonly _actual: ContextKeyRegexExpr) { // } - public getType(): ContextKeyExprType { - return ContextKeyExprType.NotRegex; - } - - public cmp(other: ContextKeyNotRegexExpr): number { + public cmp(other: ContextKeyExpression): number { + if (other.type !== this.type) { + return this.type - other.type; + } return this._actual.cmp(other._actual); } public equals(other: ContextKeyExpression): boolean { - if (other instanceof ContextKeyNotRegexExpr) { + if (other.type === this.type) { return this._actual.equals(other._actual); } return false; @@ -537,7 +524,7 @@ export class ContextKeyNotRegexExpr implements ContextKeyExpr { } } -export class ContextKeyAndExpr implements ContextKeyExpr { +export class ContextKeyAndExpr implements IContextKeyExpression { public static create(_expr: ReadonlyArray): ContextKeyExpression | undefined { const expr = ContextKeyAndExpr._normalizeArr(_expr); @@ -552,14 +539,15 @@ export class ContextKeyAndExpr implements ContextKeyExpr { return new ContextKeyAndExpr(expr); } + public readonly type = ContextKeyExprType.And; + private constructor(public readonly expr: ContextKeyExpression[]) { } - public getType(): ContextKeyExprType { - return ContextKeyExprType.And; - } - - public cmp(other: ContextKeyAndExpr): number { + public cmp(other: ContextKeyExpression): number { + if (other.type !== this.type) { + return this.type - other.type; + } if (this.expr.length < other.expr.length) { return -1; } @@ -576,7 +564,7 @@ export class ContextKeyAndExpr implements ContextKeyExpr { } public equals(other: ContextKeyExpression): boolean { - if (other instanceof ContextKeyAndExpr) { + if (other.type === this.type) { if (this.expr.length !== other.expr.length) { return false; } @@ -607,12 +595,12 @@ export class ContextKeyAndExpr implements ContextKeyExpr { continue; } - if (e instanceof ContextKeyAndExpr) { + if (e.type === ContextKeyExprType.And) { expr.push(...e.expr); continue; } - if (e instanceof ContextKeyOrExpr) { + if (e.type === ContextKeyExprType.Or) { // Not allowed, because we don't have parens! throw new Error(`It is not allowed to have an or expression here due to lack of parens! For example "a && (b||c)" is not supported, use "(a&&b) || (a&&c)" instead.`); } @@ -650,7 +638,7 @@ export class ContextKeyAndExpr implements ContextKeyExpr { } } -export class ContextKeyOrExpr implements ContextKeyExpr { +export class ContextKeyOrExpr implements IContextKeyExpression { public static create(_expr: ReadonlyArray): ContextKeyExpression | undefined { const expr = ContextKeyOrExpr._normalizeArr(_expr); @@ -665,15 +653,32 @@ export class ContextKeyOrExpr implements ContextKeyExpr { return new ContextKeyOrExpr(expr); } + public readonly type = ContextKeyExprType.Or; + private constructor(public readonly expr: ContextKeyExpression[]) { } - public getType(): ContextKeyExprType { - return ContextKeyExprType.Or; + public cmp(other: ContextKeyExpression): number { + if (other.type !== this.type) { + return this.type - other.type; + } + if (this.expr.length < other.expr.length) { + return -1; + } + if (this.expr.length > other.expr.length) { + return 1; + } + for (let i = 0, len = this.expr.length; i < len; i++) { + const r = cmp(this.expr[i], other.expr[i]); + if (r !== 0) { + return r; + } + } + return 0; } public equals(other: ContextKeyExpression): boolean { - if (other instanceof ContextKeyOrExpr) { + if (other.type === this.type) { if (this.expr.length !== other.expr.length) { return false; } @@ -706,7 +711,7 @@ export class ContextKeyOrExpr implements ContextKeyExpr { continue; } - if (e instanceof ContextKeyOrExpr) { + if (e.type === ContextKeyExprType.Or) { expr = expr.concat(e.expr); continue; } @@ -743,7 +748,7 @@ export class ContextKeyOrExpr implements ContextKeyExpr { } const terminals = (node: ContextKeyExpression) => { - if (node instanceof ContextKeyOrExpr) { + if (node.type === ContextKeyExprType.Or) { return node.expr; } return [node]; @@ -770,7 +775,7 @@ export class ContextKeyOrExpr implements ContextKeyExpr { export class RawContextKey extends ContextKeyDefinedExpr { - private _defaultValue: T | undefined; + private readonly _defaultValue: T | undefined; constructor(key: string, defaultValue: T | undefined) { super(key); diff --git a/src/vs/platform/keybinding/common/keybindingResolver.ts b/src/vs/platform/keybinding/common/keybindingResolver.ts index 5e0a7fcff1a..a1821bddd85 100644 --- a/src/vs/platform/keybinding/common/keybindingResolver.ts +++ b/src/vs/platform/keybinding/common/keybindingResolver.ts @@ -6,7 +6,7 @@ import { isNonEmptyArray } from 'vs/base/common/arrays'; import { MenuRegistry } from 'vs/platform/actions/common/actions'; import { CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; -import { ContextKeyExpr, IContext, ContextKeyOrExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; +import { IContext, ContextKeyExpression, ContextKeyExprType } from 'vs/platform/contextkey/common/contextkey'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { keys } from 'vs/base/common/map'; @@ -54,7 +54,7 @@ export class KeybindingResolver { } } - private static _isTargetedForRemoval(defaultKb: ResolvedKeybindingItem, keypressFirstPart: string | null, keypressChordPart: string | null, command: string, when: ContextKeyExpr | undefined): boolean { + private static _isTargetedForRemoval(defaultKb: ResolvedKeybindingItem, keypressFirstPart: string | null, keypressChordPart: string | null, command: string, when: ContextKeyExpression | undefined): boolean { if (defaultKb.command !== command) { return false; } @@ -193,7 +193,7 @@ export class KeybindingResolver { const notP = p.negate(); const terminals = (node: ContextKeyExpression) => { - if (node instanceof ContextKeyOrExpr) { + if (node.type === ContextKeyExprType.Or) { return node.expr; } return [node]; @@ -318,7 +318,7 @@ export class KeybindingResolver { return null; } - public static contextMatchesRules(context: IContext, rules: ContextKeyExpr | null | undefined): boolean { + public static contextMatchesRules(context: IContext, rules: ContextKeyExpression | null | undefined): boolean { if (!rules) { return true; } From 86b7936c1f44b01bad8f6d880c79325eb5dbc447 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 28 Feb 2020 15:24:32 +0100 Subject: [PATCH 165/235] tests - add more tests for uncovered areas --- src/vs/base/test/common/extpath.test.ts | 16 +++ .../browser/viewParts/minimap/minimap.ts | 2 +- .../diskFileService.test.ts | 29 ++++-- .../fixtures/resolver/examples/company.js | 0 .../fixtures/resolver/examples/conway.js | 0 .../fixtures/resolver/examples/employee.js | 0 .../fixtures/resolver/examples/small.js | 0 .../fixtures/resolver/index.html | 0 .../fixtures/resolver/other/deep/company.js | 0 .../fixtures/resolver/other/deep/conway.js | 0 .../fixtures/resolver/other/deep/employee.js | 0 .../fixtures/resolver/other/deep/small.js | 0 .../fixtures/resolver/site.css | 0 .../fixtures/service/binary.txt | Bin .../fixtures/service/deep/company.js | 0 .../fixtures/service/deep/conway.js | 0 .../fixtures/service/deep/employee.js | 0 .../fixtures/service/deep/small.js | 0 .../fixtures/service/index.html | 0 .../fixtures/service/lorem.txt | 0 .../fixtures/service/small.txt | 0 .../fixtures/service/small_umlaut.txt | 0 .../fixtures/service/some_utf16le.css | Bin .../fixtures/service/some_utf8_bom.txt | 0 .../normalizer.test.ts | 0 src/vs/workbench/common/contributions.ts | 4 +- .../electron-browser/backupTracker.test.ts | 55 +++++++++- .../codeEditor/browser/saveParticipants.ts | 2 +- .../test/browser/saveParticipant.test.ts | 24 ++++- .../files/test/browser/editorAutoSave.test.ts | 33 +++++- .../test/browser/fileEditorInput.test.ts | 16 +++ ....test.ts => textFileEditorTracker.test.ts} | 81 ++++++++++----- .../test/browser/editorGroupsService.test.ts | 98 +++++++++++++----- .../editor/test/browser/editorService.test.ts | 67 ++++++++++-- .../test/browser/textFileEditorModel.test.ts | 24 ++++- .../test/browser/workbenchTestServices.ts | 75 +++++++------- .../test/common/workbenchTestServices.ts | 22 ++-- 37 files changed, 415 insertions(+), 133 deletions(-) rename src/vs/platform/files/test/{node => electron-browser}/diskFileService.test.ts (99%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/resolver/examples/company.js (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/resolver/examples/conway.js (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/resolver/examples/employee.js (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/resolver/examples/small.js (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/resolver/index.html (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/resolver/other/deep/company.js (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/resolver/other/deep/conway.js (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/resolver/other/deep/employee.js (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/resolver/other/deep/small.js (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/resolver/site.css (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/service/binary.txt (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/service/deep/company.js (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/service/deep/conway.js (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/service/deep/employee.js (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/service/deep/small.js (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/service/index.html (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/service/lorem.txt (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/service/small.txt (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/service/small_umlaut.txt (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/service/some_utf16le.css (100%) rename src/vs/platform/files/test/{node => electron-browser}/fixtures/service/some_utf8_bom.txt (100%) rename src/vs/platform/files/test/{node => electron-browser}/normalizer.test.ts (100%) rename src/vs/workbench/contrib/files/test/browser/{fileEditorTracker.test.ts => textFileEditorTracker.test.ts} (83%) diff --git a/src/vs/base/test/common/extpath.test.ts b/src/vs/base/test/common/extpath.test.ts index eb3d8da7a46..02aa3a96377 100644 --- a/src/vs/base/test/common/extpath.test.ts +++ b/src/vs/base/test/common/extpath.test.ts @@ -6,6 +6,7 @@ import * as assert from 'assert'; import * as extpath from 'vs/base/common/extpath'; import * as platform from 'vs/base/common/platform'; +import { CharCode } from 'vs/base/common/charCode'; suite('Paths', () => { @@ -114,4 +115,19 @@ suite('Paths', () => { assert.ok(!extpath.isRootOrDriveLetter('/path')); } }); + + test('isWindowsDriveLetter', () => { + assert.ok(!extpath.isWindowsDriveLetter(0)); + assert.ok(!extpath.isWindowsDriveLetter(-1)); + assert.ok(extpath.isWindowsDriveLetter(CharCode.A)); + assert.ok(extpath.isWindowsDriveLetter(CharCode.z)); + }); + + test('indexOfPath', () => { + assert.equal(extpath.indexOfPath('/foo', '/bar', true), -1); + assert.equal(extpath.indexOfPath('/foo', '/FOO', false), -1); + assert.equal(extpath.indexOfPath('/foo', '/FOO', true), 0); + assert.equal(extpath.indexOfPath('/some/long/path', '/some/long', false), 0); + assert.equal(extpath.indexOfPath('/some/long/path', '/PATH', true), 10); + }); }); diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index ed05d886991..4c1fe639300 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -163,7 +163,7 @@ class MinimapOptions { && this.fontScale === other.fontScale && this.minimapLineHeight === other.minimapLineHeight && this.minimapCharWidth === other.minimapCharWidth - && this.backgroundColor.equals(other.backgroundColor) + && this.backgroundColor && this.backgroundColor.equals(other.backgroundColor) ); } } diff --git a/src/vs/platform/files/test/node/diskFileService.test.ts b/src/vs/platform/files/test/electron-browser/diskFileService.test.ts similarity index 99% rename from src/vs/platform/files/test/node/diskFileService.test.ts rename to src/vs/platform/files/test/electron-browser/diskFileService.test.ts index 7b012bb19fd..1eff57b01fd 100644 --- a/src/vs/platform/files/test/node/diskFileService.test.ts +++ b/src/vs/platform/files/test/electron-browser/diskFileService.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { tmpdir } from 'os'; import { FileService } from 'vs/platform/files/common/fileService'; import { Schemas } from 'vs/base/common/network'; -import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; +import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider'; import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { generateUuid } from 'vs/base/common/uuid'; import { join, basename, dirname, posix } from 'vs/base/common/path'; @@ -67,6 +67,7 @@ export class TestDiskFileSystemProvider extends DiskFileSystemProvider { FileSystemProviderCapabilities.FileReadWrite | FileSystemProviderCapabilities.FileOpenReadWriteClose | FileSystemProviderCapabilities.FileReadStream | + FileSystemProviderCapabilities.Trash | FileSystemProviderCapabilities.FileFolderCopy; if (isLinux) { @@ -459,13 +460,21 @@ suite('Disk File Service', function () { }); test('deleteFile', async () => { + return testDeleteFile(false); + }); + + test('deleteFile (useTrash)', async () => { + return testDeleteFile(true); + }); + + async function testDeleteFile(useTrash: boolean): Promise { let event: FileOperationEvent; disposables.add(service.onDidRunOperation(e => event = e)); const resource = URI.file(join(testDir, 'deep', 'conway.js')); const source = await service.resolve(resource); - await service.del(source.resource); + await service.del(source.resource, { useTrash }); assert.equal(existsSync(source.resource.fsPath), false); @@ -475,14 +484,14 @@ suite('Disk File Service', function () { let error: Error | undefined = undefined; try { - await service.del(source.resource); + await service.del(source.resource, { useTrash }); } catch (e) { error = e; } assert.ok(error); assert.equal((error).fileOperationResult, FileOperationResult.FILE_NOT_FOUND); - }); + } test('deleteFile - symbolic link (exists)', async () => { if (isWindows) { @@ -531,19 +540,27 @@ suite('Disk File Service', function () { }); test('deleteFolder (recursive)', async () => { + return testDeleteFolderRecursive(false); + }); + + test('deleteFolder (recursive, useTrash)', async () => { + return testDeleteFolderRecursive(true); + }); + + async function testDeleteFolderRecursive(useTrash: boolean): Promise { let event: FileOperationEvent; disposables.add(service.onDidRunOperation(e => event = e)); const resource = URI.file(join(testDir, 'deep')); const source = await service.resolve(resource); - await service.del(source.resource, { recursive: true }); + await service.del(source.resource, { recursive: true, useTrash }); assert.equal(existsSync(source.resource.fsPath), false); assert.ok(event!); assert.equal(event!.resource.fsPath, resource.fsPath); assert.equal(event!.operation, FileOperation.DELETE); - }); + } test('deleteFolder (non recursive)', async () => { const resource = URI.file(join(testDir, 'deep')); diff --git a/src/vs/platform/files/test/node/fixtures/resolver/examples/company.js b/src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/company.js similarity index 100% rename from src/vs/platform/files/test/node/fixtures/resolver/examples/company.js rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/company.js diff --git a/src/vs/platform/files/test/node/fixtures/resolver/examples/conway.js b/src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/conway.js similarity index 100% rename from src/vs/platform/files/test/node/fixtures/resolver/examples/conway.js rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/conway.js diff --git a/src/vs/platform/files/test/node/fixtures/resolver/examples/employee.js b/src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/employee.js similarity index 100% rename from src/vs/platform/files/test/node/fixtures/resolver/examples/employee.js rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/employee.js diff --git a/src/vs/platform/files/test/node/fixtures/resolver/examples/small.js b/src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/small.js similarity index 100% rename from src/vs/platform/files/test/node/fixtures/resolver/examples/small.js rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/small.js diff --git a/src/vs/platform/files/test/node/fixtures/resolver/index.html b/src/vs/platform/files/test/electron-browser/fixtures/resolver/index.html similarity index 100% rename from src/vs/platform/files/test/node/fixtures/resolver/index.html rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/index.html diff --git a/src/vs/platform/files/test/node/fixtures/resolver/other/deep/company.js b/src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/company.js similarity index 100% rename from src/vs/platform/files/test/node/fixtures/resolver/other/deep/company.js rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/company.js diff --git a/src/vs/platform/files/test/node/fixtures/resolver/other/deep/conway.js b/src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/conway.js similarity index 100% rename from src/vs/platform/files/test/node/fixtures/resolver/other/deep/conway.js rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/conway.js diff --git a/src/vs/platform/files/test/node/fixtures/resolver/other/deep/employee.js b/src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/employee.js similarity index 100% rename from src/vs/platform/files/test/node/fixtures/resolver/other/deep/employee.js rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/employee.js diff --git a/src/vs/platform/files/test/node/fixtures/resolver/other/deep/small.js b/src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/small.js similarity index 100% rename from src/vs/platform/files/test/node/fixtures/resolver/other/deep/small.js rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/small.js diff --git a/src/vs/platform/files/test/node/fixtures/resolver/site.css b/src/vs/platform/files/test/electron-browser/fixtures/resolver/site.css similarity index 100% rename from src/vs/platform/files/test/node/fixtures/resolver/site.css rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/site.css diff --git a/src/vs/platform/files/test/node/fixtures/service/binary.txt b/src/vs/platform/files/test/electron-browser/fixtures/service/binary.txt similarity index 100% rename from src/vs/platform/files/test/node/fixtures/service/binary.txt rename to src/vs/platform/files/test/electron-browser/fixtures/service/binary.txt diff --git a/src/vs/platform/files/test/node/fixtures/service/deep/company.js b/src/vs/platform/files/test/electron-browser/fixtures/service/deep/company.js similarity index 100% rename from src/vs/platform/files/test/node/fixtures/service/deep/company.js rename to src/vs/platform/files/test/electron-browser/fixtures/service/deep/company.js diff --git a/src/vs/platform/files/test/node/fixtures/service/deep/conway.js b/src/vs/platform/files/test/electron-browser/fixtures/service/deep/conway.js similarity index 100% rename from src/vs/platform/files/test/node/fixtures/service/deep/conway.js rename to src/vs/platform/files/test/electron-browser/fixtures/service/deep/conway.js diff --git a/src/vs/platform/files/test/node/fixtures/service/deep/employee.js b/src/vs/platform/files/test/electron-browser/fixtures/service/deep/employee.js similarity index 100% rename from src/vs/platform/files/test/node/fixtures/service/deep/employee.js rename to src/vs/platform/files/test/electron-browser/fixtures/service/deep/employee.js diff --git a/src/vs/platform/files/test/node/fixtures/service/deep/small.js b/src/vs/platform/files/test/electron-browser/fixtures/service/deep/small.js similarity index 100% rename from src/vs/platform/files/test/node/fixtures/service/deep/small.js rename to src/vs/platform/files/test/electron-browser/fixtures/service/deep/small.js diff --git a/src/vs/platform/files/test/node/fixtures/service/index.html b/src/vs/platform/files/test/electron-browser/fixtures/service/index.html similarity index 100% rename from src/vs/platform/files/test/node/fixtures/service/index.html rename to src/vs/platform/files/test/electron-browser/fixtures/service/index.html diff --git a/src/vs/platform/files/test/node/fixtures/service/lorem.txt b/src/vs/platform/files/test/electron-browser/fixtures/service/lorem.txt similarity index 100% rename from src/vs/platform/files/test/node/fixtures/service/lorem.txt rename to src/vs/platform/files/test/electron-browser/fixtures/service/lorem.txt diff --git a/src/vs/platform/files/test/node/fixtures/service/small.txt b/src/vs/platform/files/test/electron-browser/fixtures/service/small.txt similarity index 100% rename from src/vs/platform/files/test/node/fixtures/service/small.txt rename to src/vs/platform/files/test/electron-browser/fixtures/service/small.txt diff --git a/src/vs/platform/files/test/node/fixtures/service/small_umlaut.txt b/src/vs/platform/files/test/electron-browser/fixtures/service/small_umlaut.txt similarity index 100% rename from src/vs/platform/files/test/node/fixtures/service/small_umlaut.txt rename to src/vs/platform/files/test/electron-browser/fixtures/service/small_umlaut.txt diff --git a/src/vs/platform/files/test/node/fixtures/service/some_utf16le.css b/src/vs/platform/files/test/electron-browser/fixtures/service/some_utf16le.css similarity index 100% rename from src/vs/platform/files/test/node/fixtures/service/some_utf16le.css rename to src/vs/platform/files/test/electron-browser/fixtures/service/some_utf16le.css diff --git a/src/vs/platform/files/test/node/fixtures/service/some_utf8_bom.txt b/src/vs/platform/files/test/electron-browser/fixtures/service/some_utf8_bom.txt similarity index 100% rename from src/vs/platform/files/test/node/fixtures/service/some_utf8_bom.txt rename to src/vs/platform/files/test/electron-browser/fixtures/service/some_utf8_bom.txt diff --git a/src/vs/platform/files/test/node/normalizer.test.ts b/src/vs/platform/files/test/electron-browser/normalizer.test.ts similarity index 100% rename from src/vs/platform/files/test/node/normalizer.test.ts rename to src/vs/platform/files/test/electron-browser/normalizer.test.ts diff --git a/src/vs/workbench/common/contributions.ts b/src/vs/workbench/common/contributions.ts index 1817e91d841..7d2a421a910 100644 --- a/src/vs/workbench/common/contributions.ts +++ b/src/vs/workbench/common/contributions.ts @@ -38,12 +38,14 @@ export interface IWorkbenchContributionsRegistry { } class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry { + private instantiationService: IInstantiationService | undefined; private lifecycleService: ILifecycleService | undefined; - private readonly toBeInstantiated: Map[]> = new Map[]>(); + private readonly toBeInstantiated = new Map[]>(); registerWorkbenchContribution(ctor: new (...services: Services) => IWorkbenchContribution, phase: LifecyclePhase = LifecyclePhase.Starting): void { + // Instantiate directly if we are already matching the provided phase if (this.instantiationService && this.lifecycleService && this.lifecycleService.phase >= phase) { this.instantiationService.createInstance(ctor); diff --git a/src/vs/workbench/contrib/backup/test/electron-browser/backupTracker.test.ts b/src/vs/workbench/contrib/backup/test/electron-browser/backupTracker.test.ts index 8420b62c436..b62e2030ec4 100644 --- a/src/vs/workbench/contrib/backup/test/electron-browser/backupTracker.test.ts +++ b/src/vs/workbench/contrib/backup/test/electron-browser/backupTracker.test.ts @@ -40,6 +40,11 @@ import { BackupTracker } from 'vs/workbench/contrib/backup/common/backupTracker' import { workbenchInstantiationService, TestServiceAccessor } from 'vs/workbench/test/electron-browser/workbenchTestServices'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { TestFilesConfigurationService, TestEnvironmentService } from 'vs/workbench/test/browser/workbenchTestServices'; +import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; const userdataDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backuprestorer'); const backupHome = path.join(userdataDir, 'Backups'); @@ -113,11 +118,23 @@ suite('BackupTracker', () => { return pfs.rimraf(backupHome, pfs.RimRafMode.MOVE); }); - async function createTracker(): Promise<[TestServiceAccessor, EditorPart, BackupTracker, IInstantiationService]> { + async function createTracker(autoSaveEnabled = false): Promise<[TestServiceAccessor, EditorPart, BackupTracker, IInstantiationService]> { const backupFileService = new NodeTestBackupFileService(workspaceBackupPath); const instantiationService = workbenchInstantiationService(); instantiationService.stub(IBackupFileService, backupFileService); + const configurationService = new TestConfigurationService(); + if (autoSaveEnabled) { + configurationService.setUserConfiguration('files', { autoSave: 'afterDelay', autoSaveDelay: 1 }); + } + instantiationService.stub(IConfigurationService, configurationService); + + instantiationService.stub(IFilesConfigurationService, new TestFilesConfigurationService( + instantiationService.createInstance(MockContextKeyService), + configurationService, + TestEnvironmentService + )); + const part = instantiationService.createInstance(EditorPart); part.create(document.createElement('div')); part.layout(400, 300); @@ -234,7 +251,41 @@ suite('BackupTracker', () => { const event = new BeforeShutdownEventImpl(); accessor.lifecycleService.fireWillShutdown(event); - assert.ok(event.value); + + const veto = event.value; + if (typeof veto === 'boolean') { + assert.ok(veto); + } else { + assert.ok((await veto)); + } + + part.dispose(); + tracker.dispose(); + }); + + test('onWillShutdown - no veto if auto save is on', async function () { + const [accessor, part, tracker] = await createTracker(true /* auto save enabled */); + + const resource = toResource.call(this, '/path/index.txt'); + await accessor.editorService.openEditor({ resource, options: { pinned: true } }); + + const model = accessor.textFileService.files.get(resource); + + await model?.load(); + model?.textEditorModel?.setValue('foo'); + assert.equal(accessor.workingCopyService.dirtyCount, 1); + + const event = new BeforeShutdownEventImpl(); + accessor.lifecycleService.fireWillShutdown(event); + + const veto = event.value; + if (typeof veto === 'boolean') { + assert.ok(!veto); + } else { + assert.ok(!(await veto)); + } + + assert.equal(accessor.workingCopyService.dirtyCount, 0); part.dispose(); tracker.dispose(); diff --git a/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts b/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts index 3386ae55dc6..32f7f4a1722 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts @@ -30,7 +30,7 @@ import { IWorkbenchContribution, Extensions as WorkbenchContributionsExtensions, import { Registry } from 'vs/platform/registry/common/platform'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -class TrimWhitespaceParticipant implements ITextFileSaveParticipant { +export class TrimWhitespaceParticipant implements ITextFileSaveParticipant { constructor( @IConfigurationService private readonly configurationService: IConfigurationService, diff --git a/src/vs/workbench/contrib/codeEditor/test/browser/saveParticipant.test.ts b/src/vs/workbench/contrib/codeEditor/test/browser/saveParticipant.test.ts index 5c7917b7350..bed0805028b 100644 --- a/src/vs/workbench/contrib/codeEditor/test/browser/saveParticipant.test.ts +++ b/src/vs/workbench/contrib/codeEditor/test/browser/saveParticipant.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { FinalNewLineParticipant, TrimFinalNewLinesParticipant } from 'vs/workbench/contrib/codeEditor/browser/saveParticipants'; +import { FinalNewLineParticipant, TrimFinalNewLinesParticipant, TrimWhitespaceParticipant } from 'vs/workbench/contrib/codeEditor/browser/saveParticipants'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { workbenchInstantiationService, TestServiceAccessor } from 'vs/workbench/test/browser/workbenchTestServices'; import { toResource } from 'vs/base/test/common/utils'; @@ -16,7 +16,7 @@ import { IResolvedTextFileEditorModel, snapshotToString } from 'vs/workbench/ser import { SaveReason } from 'vs/workbench/common/editor'; import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; -suite('MainThreadSaveParticipant', function () { +suite('Save Participants', function () { let instantiationService: IInstantiationService; let accessor: TestServiceAccessor; @@ -151,4 +151,24 @@ suite('MainThreadSaveParticipant', function () { model.textEditorModel.redo(); assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}${eol}`); }); + + test('trim whitespace', async function () { + const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel; + + await model.load(); + const configService = new TestConfigurationService(); + configService.setUserConfiguration('files', { 'trimTrailingWhitespace': true }); + const participant = new TrimWhitespaceParticipant(configService, undefined!); + const textContent = 'Test'; + let content = `${textContent} `; + model.textEditorModel.setValue(content); + + // save many times + for (let i = 0; i < 10; i++) { + await participant.participate(model, { reason: SaveReason.EXPLICIT }); + } + + // confirm trimming + assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}`); + }); }); diff --git a/src/vs/workbench/contrib/files/test/browser/editorAutoSave.test.ts b/src/vs/workbench/contrib/files/test/browser/editorAutoSave.test.ts index 4c12705aa05..33b1a26be9c 100644 --- a/src/vs/workbench/contrib/files/test/browser/editorAutoSave.test.ts +++ b/src/vs/workbench/contrib/files/test/browser/editorAutoSave.test.ts @@ -47,11 +47,11 @@ suite('EditorAutoSave', () => { disposables = []; }); - test('editor auto saves after short delay if configured', async function () { + async function createEditorAutoSave(autoSaveConfig: object): Promise<[TestServiceAccessor, EditorPart, EditorAutoSave]> { const instantiationService = workbenchInstantiationService(); const configurationService = new TestConfigurationService(); - configurationService.setUserConfiguration('files', { autoSave: 'afterDelay', autoSaveDelay: 1 }); + configurationService.setUserConfiguration('files', autoSaveConfig); instantiationService.stub(IConfigurationService, configurationService); instantiationService.stub(IFilesConfigurationService, new TestFilesConfigurationService( @@ -73,10 +73,15 @@ suite('EditorAutoSave', () => { const editorAutoSave = instantiationService.createInstance(EditorAutoSave); + return [accessor, part, editorAutoSave]; + } + + test('editor auto saves after short delay if configured', async function () { + const [accessor, part, editorAutoSave] = await createEditorAutoSave({ autoSave: 'afterDelay', autoSaveDelay: 1 }); + const resource = toResource.call(this, '/path/index.txt'); const model = await accessor.textFileService.files.resolve(resource) as IResolvedTextFileEditorModel; - model.textEditorModel.setValue('Super Good'); assert.ok(model.isDirty()); @@ -90,6 +95,28 @@ suite('EditorAutoSave', () => { (accessor.textFileService.files).dispose(); }); + test('editor auto saves on focus change if configured', async function () { + const [accessor, part, editorAutoSave] = await createEditorAutoSave({ autoSave: 'onFocusChange' }); + + const resource = toResource.call(this, '/path/index.txt'); + await accessor.editorService.openEditor({ resource, forceFile: true }); + + const model = await accessor.textFileService.files.resolve(resource) as IResolvedTextFileEditorModel; + model.textEditorModel.setValue('Super Good'); + + assert.ok(model.isDirty()); + + await accessor.editorService.openEditor({ resource: toResource.call(this, '/path/index_other.txt') }); + + await awaitModelSaved(model); + + assert.ok(!model.isDirty()); + + part.dispose(); + editorAutoSave.dispose(); + (accessor.textFileService.files).dispose(); + }); + function awaitModelSaved(model: ITextFileEditorModel): Promise { return new Promise(c => { Event.once(model.onDidChangeDirty)(c); diff --git a/src/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts b/src/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts index 9aaea5c645b..69fa0be16bf 100644 --- a/src/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts +++ b/src/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts @@ -16,6 +16,7 @@ import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textF import { timeout } from 'vs/base/common/async'; import { ModesRegistry, PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; import { DisposableStore } from 'vs/base/common/lifecycle'; +import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; suite('Files - FileEditorInput', () => { let instantiationService: IInstantiationService; @@ -196,4 +197,19 @@ suite('Files - FileEditorInput', () => { input.dispose(); listener.dispose(); }); + + test('force open text/binary', async function () { + const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined, undefined); + input.setForceOpenAsBinary(); + + let resolved = await input.resolve(); + assert.ok(resolved instanceof BinaryEditorModel); + + input.setForceOpenAsText(); + + resolved = await input.resolve(); + assert.ok(resolved instanceof TextFileEditorModel); + + resolved.dispose(); + }); }); diff --git a/src/vs/workbench/contrib/files/test/browser/fileEditorTracker.test.ts b/src/vs/workbench/contrib/files/test/browser/textFileEditorTracker.test.ts similarity index 83% rename from src/vs/workbench/contrib/files/test/browser/fileEditorTracker.test.ts rename to src/vs/workbench/contrib/files/test/browser/textFileEditorTracker.test.ts index d2b3385e6df..081e0d02d1a 100644 --- a/src/vs/workbench/contrib/files/test/browser/fileEditorTracker.test.ts +++ b/src/vs/workbench/contrib/files/test/browser/textFileEditorTracker.test.ts @@ -9,7 +9,7 @@ import { TextFileEditorTracker } from 'vs/workbench/contrib/files/browser/editor import { toResource } from 'vs/base/test/common/utils'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { workbenchInstantiationService, TestServiceAccessor } from 'vs/workbench/test/browser/workbenchTestServices'; -import { IResolvedTextFileEditorModel, snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; +import { IResolvedTextFileEditorModel, snapshotToString, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { FileChangesEvent, FileChangeType } from 'vs/platform/files/common/files'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { timeout } from 'vs/base/common/async'; @@ -25,6 +25,8 @@ import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart'; import { EditorService } from 'vs/workbench/services/editor/browser/editorService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput'; +import { isEqual } from 'vs/base/common/resources'; +import { URI } from 'vs/base/common/uri'; suite('Files - TextFileEditorTracker', () => { @@ -46,32 +48,6 @@ suite('Files - TextFileEditorTracker', () => { disposables = []; }); - test('file change event updates model', async function () { - const instantiationService = workbenchInstantiationService(); - const accessor = instantiationService.createInstance(TestServiceAccessor); - - const tracker = instantiationService.createInstance(TextFileEditorTracker); - - const resource = toResource.call(this, '/path/index.txt'); - - const model = await accessor.textFileService.files.resolve(resource) as IResolvedTextFileEditorModel; - - model.textEditorModel.setValue('Super Good'); - assert.equal(snapshotToString(model.createSnapshot()!), 'Super Good'); - - await model.save(); - - // change event (watcher) - accessor.fileService.fireFileChanges(new FileChangesEvent([{ resource, type: FileChangeType.UPDATED }])); - - await timeout(0); // due to event updating model async - - assert.equal(snapshotToString(model.createSnapshot()!), 'Hello Html'); - - tracker.dispose(); - (accessor.textFileService.files).dispose(); - }); - async function createTracker(): Promise<[EditorPart, TestServiceAccessor, TextFileEditorTracker, IInstantiationService, IEditorService]> { const instantiationService = workbenchInstantiationService(); @@ -93,6 +69,29 @@ suite('Files - TextFileEditorTracker', () => { return [part, accessor, tracker, instantiationService, editorService]; } + test('file change event updates model', async function () { + const [, accessor, tracker] = await createTracker(); + + const resource = toResource.call(this, '/path/index.txt'); + + const model = await accessor.textFileService.files.resolve(resource) as IResolvedTextFileEditorModel; + + model.textEditorModel.setValue('Super Good'); + assert.equal(snapshotToString(model.createSnapshot()!), 'Super Good'); + + await model.save(); + + // change event (watcher) + accessor.fileService.fireFileChanges(new FileChangesEvent([{ resource, type: FileChangeType.UPDATED }])); + + await timeout(0); // due to event updating model async + + assert.equal(snapshotToString(model.createSnapshot()!), 'Hello Html'); + + tracker.dispose(); + (accessor.textFileService.files).dispose(); + }); + test('dirty text file model opens as editor', async function () { const [part, accessor, tracker] = await createTracker(); @@ -135,4 +134,32 @@ suite('Files - TextFileEditorTracker', () => { Event.once(editorService.onDidActiveEditorChange)(c); }); } + + test('non-dirty files reload on window focus', async function () { + const [part, accessor, tracker] = await createTracker(); + + const resource = toResource.call(this, '/path/index.txt'); + + await accessor.editorService.openEditor(accessor.editorService.createInput({ resource, forceFile: true })); + + accessor.hostService.setFocus(false); + accessor.hostService.setFocus(true); + + await awaitModelLoadEvent(accessor.textFileService, resource); + + part.dispose(); + tracker.dispose(); + (accessor.textFileService.files).dispose(); + }); + + function awaitModelLoadEvent(textFileService: ITextFileService, resource: URI): Promise { + return new Promise(c => { + const listener = textFileService.files.onDidLoad(e => { + if (isEqual(e.model.resource, resource)) { + listener.dispose(); + c(); + } + }); + }); + } }); diff --git a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts index 4066348ec73..558339f6357 100644 --- a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts @@ -4,8 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart'; -import { workbenchInstantiationService, registerTestEditor, TestFileEditorInput } from 'vs/workbench/test/browser/workbenchTestServices'; +import { workbenchInstantiationService, registerTestEditor, TestFileEditorInput, TestEditorPart, ITestInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices'; import { GroupDirection, GroupsOrder, MergeGroupMode, GroupOrientation, GroupChangeKind, GroupLocation } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { EditorOptions, CloseDirection, IEditorPartOptions, EditorsOrder } from 'vs/workbench/common/editor'; @@ -29,18 +28,16 @@ suite('EditorGroupsService', () => { disposables = []; }); - function createPart(): EditorPart { - const instantiationService = workbenchInstantiationService(); - - const part = instantiationService.createInstance(EditorPart); + function createPart(instantiationService = workbenchInstantiationService()): [TestEditorPart, ITestInstantiationService] { + const part = instantiationService.createInstance(TestEditorPart); part.create(document.createElement('div')); part.layout(400, 300); - return part; + return [part, instantiationService]; } test('groups basics', async function () { - const part = createPart(); + const [part] = createPart(); let activeGroupChangeCounter = 0; const activeGroupChangeListener = part.onDidActiveGroupChange(() => { @@ -201,8 +198,37 @@ suite('EditorGroupsService', () => { part.dispose(); }); + test('save & restore state', async function () { + let [part, instantiationService] = createPart(); + + const rootGroup = part.groups[0]; + const rightGroup = part.addGroup(rootGroup, GroupDirection.RIGHT); + const downGroup = part.addGroup(rightGroup, GroupDirection.DOWN); + + const rootGroupInput = new TestFileEditorInput(URI.file('foo/bar1'), TEST_EDITOR_INPUT_ID); + await rootGroup.openEditor(rootGroupInput, EditorOptions.create({ pinned: true })); + + const rightGroupInput = new TestFileEditorInput(URI.file('foo/bar2'), TEST_EDITOR_INPUT_ID); + await rightGroup.openEditor(rightGroupInput, EditorOptions.create({ pinned: true })); + + assert.equal(part.groups.length, 3); + + part.saveState(); + part.dispose(); + + let [restoredPart] = createPart(instantiationService); + + assert.equal(restoredPart.groups.length, 3); + assert.ok(restoredPart.getGroup(rootGroup.id)); + assert.ok(restoredPart.getGroup(rightGroup.id)); + assert.ok(restoredPart.getGroup(downGroup.id)); + + restoredPart.clearState(); + restoredPart.dispose(); + }); + test('groups index / labels', function () { - const part = createPart(); + const [part] = createPart(); const rootGroup = part.groups[0]; const rightGroup = part.addGroup(rootGroup, GroupDirection.RIGHT); @@ -260,7 +286,7 @@ suite('EditorGroupsService', () => { }); test('copy/merge groups', async () => { - const part = createPart(); + const [part] = createPart(); let groupAddedCounter = 0; const groupAddedListener = part.onDidAddGroup(() => { @@ -301,7 +327,7 @@ suite('EditorGroupsService', () => { }); test('whenRestored', async () => { - const part = createPart(); + const [part] = createPart(); await part.whenRestored; assert.ok(true); @@ -309,7 +335,7 @@ suite('EditorGroupsService', () => { }); test('options', () => { - const part = createPart(); + const [part] = createPart(); let oldOptions!: IEditorPartOptions; let newOptions!: IEditorPartOptions; @@ -330,7 +356,7 @@ suite('EditorGroupsService', () => { }); test('editor basics', async function () { - const part = createPart(); + const [part] = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty, true); @@ -428,7 +454,7 @@ suite('EditorGroupsService', () => { }); test('openEditors / closeEditors', async () => { - const part = createPart(); + const [part] = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty, true); @@ -446,7 +472,7 @@ suite('EditorGroupsService', () => { }); test('closeEditors (except one)', async () => { - const part = createPart(); + const [part] = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty, true); @@ -467,7 +493,7 @@ suite('EditorGroupsService', () => { }); test('closeEditors (saved only)', async () => { - const part = createPart(); + const [part] = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty, true); @@ -487,7 +513,7 @@ suite('EditorGroupsService', () => { }); test('closeEditors (direction: right)', async () => { - const part = createPart(); + const [part] = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty, true); @@ -509,7 +535,7 @@ suite('EditorGroupsService', () => { }); test('closeEditors (direction: left)', async () => { - const part = createPart(); + const [part] = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty, true); @@ -531,7 +557,7 @@ suite('EditorGroupsService', () => { }); test('closeAllEditors', async () => { - const part = createPart(); + const [part] = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty, true); @@ -549,7 +575,7 @@ suite('EditorGroupsService', () => { }); test('moveEditor (same group)', async () => { - const part = createPart(); + const [part] = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty, true); @@ -577,7 +603,7 @@ suite('EditorGroupsService', () => { }); test('moveEditor (across groups)', async () => { - const part = createPart(); + const [part] = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty, true); @@ -599,7 +625,7 @@ suite('EditorGroupsService', () => { }); test('copyEditor (across groups)', async () => { - const part = createPart(); + const [part] = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty, true); @@ -622,7 +648,7 @@ suite('EditorGroupsService', () => { }); test('replaceEditors', async () => { - const part = createPart(); + const [part] = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty, true); @@ -640,7 +666,7 @@ suite('EditorGroupsService', () => { }); test('find neighbour group (left/right)', function () { - const part = createPart(); + const [part] = createPart(); const rootGroup = part.activeGroup; const rightGroup = part.addGroup(rootGroup, GroupDirection.RIGHT); @@ -651,7 +677,7 @@ suite('EditorGroupsService', () => { }); test('find neighbour group (up/down)', function () { - const part = createPart(); + const [part] = createPart(); const rootGroup = part.activeGroup; const downGroup = part.addGroup(rootGroup, GroupDirection.DOWN); @@ -662,7 +688,7 @@ suite('EditorGroupsService', () => { }); test('find group by location (left/right)', function () { - const part = createPart(); + const [part] = createPart(); const rootGroup = part.activeGroup; const rightGroup = part.addGroup(rootGroup, GroupDirection.RIGHT); const downGroup = part.addGroup(rightGroup, GroupDirection.DOWN); @@ -678,4 +704,24 @@ suite('EditorGroupsService', () => { part.dispose(); }); + + test('applyLayout (2x2)', function () { + const [part] = createPart(); + + part.applyLayout({ groups: [{ groups: [{}, {}] }, { groups: [{}, {}] }], orientation: GroupOrientation.HORIZONTAL }); + + assert.equal(part.groups.length, 4); + + part.dispose(); + }); + + test('centeredLayout', function () { + const [part] = createPart(); + + part.centerLayout(true); + + assert.equal(part.isLayoutCentered(), true); + + part.dispose(); + }); }); diff --git a/src/vs/workbench/services/editor/test/browser/editorService.test.ts b/src/vs/workbench/services/editor/test/browser/editorService.test.ts index 51024bda79e..dc7c8c63fce 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -710,9 +710,9 @@ suite('EditorService', () => { test('save, saveAll, revertAll', async function () { const [part, service] = createEditorService(); - const input1 = new TestFileEditorInput(URI.parse('my://resource1-openside'), TEST_EDITOR_INPUT_ID); + const input1 = new TestFileEditorInput(URI.parse('my://resource1'), TEST_EDITOR_INPUT_ID); input1.dirty = true; - const input2 = new TestFileEditorInput(URI.parse('my://resource2-openside'), TEST_EDITOR_INPUT_ID); + const input2 = new TestFileEditorInput(URI.parse('my://resource2'), TEST_EDITOR_INPUT_ID); input2.dirty = true; const rootGroup = part.activeGroup; @@ -753,9 +753,9 @@ suite('EditorService', () => { async function testFileDeleteEditorClose(dirty: boolean): Promise { const [part, service, accessor] = createEditorService(); - const input1 = new TestFileEditorInput(URI.parse('my://resource1-openside'), TEST_EDITOR_INPUT_ID); + const input1 = new TestFileEditorInput(URI.parse('my://resource1'), TEST_EDITOR_INPUT_ID); input1.dirty = dirty; - const input2 = new TestFileEditorInput(URI.parse('my://resource2-openside'), TEST_EDITOR_INPUT_ID); + const input2 = new TestFileEditorInput(URI.parse('my://resource2'), TEST_EDITOR_INPUT_ID); input2.dirty = dirty; const rootGroup = part.activeGroup; @@ -785,8 +785,8 @@ suite('EditorService', () => { test('file move asks input to move', async function () { const [part, service, accessor] = createEditorService(); - const input1 = new TestFileEditorInput(URI.parse('my://resource1-openside'), TEST_EDITOR_INPUT_ID); - const movedInput = new TestFileEditorInput(URI.parse('my://resource2-openside'), TEST_EDITOR_INPUT_ID); + const input1 = new TestFileEditorInput(URI.parse('my://resource1'), TEST_EDITOR_INPUT_ID); + const movedInput = new TestFileEditorInput(URI.parse('my://resource2'), TEST_EDITOR_INPUT_ID); input1.movedEditor = { editor: movedInput }; const rootGroup = part.activeGroup; @@ -803,7 +803,7 @@ suite('EditorService', () => { isDirectory: false, isFile: true, mtime: 0, - name: 'resource2-openside', + name: 'resource2', size: 0, isSymbolicLink: false })); @@ -823,8 +823,8 @@ suite('EditorService', () => { test('file watcher gets installed for out of workspace files', async function () { const [part, service, accessor] = createEditorService(); - const input1 = new TestFileEditorInput(URI.parse('file://resource1-openside'), TEST_EDITOR_INPUT_ID); - const input2 = new TestFileEditorInput(URI.parse('file://resource2-openside'), TEST_EDITOR_INPUT_ID); + const input1 = new TestFileEditorInput(URI.parse('file://resource1'), TEST_EDITOR_INPUT_ID); + const input2 = new TestFileEditorInput(URI.parse('file://resource2'), TEST_EDITOR_INPUT_ID); await part.whenRestored; @@ -841,4 +841,53 @@ suite('EditorService', () => { part.dispose(); }); + + test('invokeWithinEditorContext', async function () { + const [part, service] = createEditorService(); + + const input1 = new TestFileEditorInput(URI.parse('file://resource1'), TEST_EDITOR_INPUT_ID); + new TestFileEditorInput(URI.parse('file://resource2'), TEST_EDITOR_INPUT_ID); + + await part.whenRestored; + + await service.openEditor(input1, { pinned: true }); + + let hasAccessor = false; + service.invokeWithinEditorContext(accessor => { + hasAccessor = true; + }); + + assert.ok(hasAccessor); + + part.dispose(); + }); + + test('overrideOpenEditor', async function () { + const [part, service] = createEditorService(); + + const input1 = new TestFileEditorInput(URI.parse('file://resource1'), TEST_EDITOR_INPUT_ID); + const input2 = new TestFileEditorInput(URI.parse('file://resource2'), TEST_EDITOR_INPUT_ID); + + await part.whenRestored; + + let overrideCalled = false; + + const handler = service.overrideOpenEditor(editor => { + if (editor === input1) { + overrideCalled = true; + + return { override: service.openEditor(input2, { pinned: true }) }; + } + + return undefined; + }); + + await service.openEditor(input1, { pinned: true }); + + assert.ok(overrideCalled); + assert.equal(service.activeEditor, input2); + + handler.dispose(); + part.dispose(); + }); }); diff --git a/src/vs/workbench/services/textfile/test/browser/textFileEditorModel.test.ts b/src/vs/workbench/services/textfile/test/browser/textFileEditorModel.test.ts index 7140b161af9..b61434bb1bc 100644 --- a/src/vs/workbench/services/textfile/test/browser/textFileEditorModel.test.ts +++ b/src/vs/workbench/services/textfile/test/browser/textFileEditorModel.test.ts @@ -80,6 +80,12 @@ suite('Files - TextFileEditorModel', () => { assert.equal(accessor.workingCopyService.dirtyCount, 0); + let savedEvent = false; + model.onDidSave(() => savedEvent = true); + + await model.save(); + assert.ok(!savedEvent); + model.updateTextEditorModel(createTextBufferFactory('bar')); assert.ok(getLastModifiedTime(model) <= Date.now()); assert.ok(model.hasState(TextFileEditorModelState.DIRTY)); @@ -87,9 +93,6 @@ suite('Files - TextFileEditorModel', () => { assert.equal(accessor.workingCopyService.dirtyCount, 1); assert.equal(accessor.workingCopyService.isDirty(model.resource), true); - let savedEvent = false; - model.onDidSave(() => savedEvent = true); - let workingCopyEvent = false; accessor.workingCopyService.onDidChangeDirty(e => { if (e.resource.toString() === model.resource.toString()) { @@ -110,6 +113,11 @@ suite('Files - TextFileEditorModel', () => { assert.equal(accessor.workingCopyService.dirtyCount, 0); assert.equal(accessor.workingCopyService.isDirty(model.resource), false); + savedEvent = false; + + await model.save({ force: true }); + assert.ok(savedEvent); + model.dispose(); assert.ok(!accessor.modelService.getModel(model.resource)); }); @@ -404,7 +412,7 @@ suite('Files - TextFileEditorModel', () => { model.dispose(); }); - test('No Dirty for readonly models', async function () { + test('No Dirty or saving for readonly models', async function () { let workingCopyEvent = false; accessor.workingCopyService.onDidChangeDirty(e => { if (e.resource.toString() === model.resource.toString()) { @@ -414,10 +422,18 @@ suite('Files - TextFileEditorModel', () => { const model = instantiationService.createInstance(TestReadonlyTextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); + let saveEvent = false; + model.onDidSave(() => { + saveEvent = true; + }); + await model.load(); model.updateTextEditorModel(createTextBufferFactory('foo')); assert.ok(!model.isDirty()); + await model.save({ force: true }); + assert.equal(saveEvent, false); + await model.revert({ soft: true }); assert.ok(!model.isDirty()); diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index 7a7f9f4ee7e..4e86c5a1bb3 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -42,7 +42,7 @@ import { IPosition, Position as EditorPosition } from 'vs/editor/common/core/pos import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { MockContextKeyService, MockKeybindingService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; -import { ITextBufferFactory, DefaultEndOfLine, EndOfLinePreference, IModelDecorationOptions, ITextModel, ITextSnapshot } from 'vs/editor/common/model'; +import { ITextBufferFactory, DefaultEndOfLine, EndOfLinePreference, ITextSnapshot } from 'vs/editor/common/model'; import { Range } from 'vs/editor/common/core/range'; import { IDialogService, IPickAndOpenOptions, ISaveDialogOptions, IOpenDialogOptions, IFileDialogService, ConfirmResult } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -54,9 +54,7 @@ import { IDisposable, toDisposable, Disposable, DisposableStore } from 'vs/base/ import { IEditorGroupsService, IEditorGroup, GroupsOrder, GroupsArrangement, GroupDirection, IAddGroupOptions, IMergeGroupOptions, IMoveEditorOptions, ICopyEditorOptions, IEditorReplacement, IGroupChangeEvent, IFindGroupScope, EditorGroupLayout, ICloseEditorOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService, IOpenEditorOverrideHandler, IVisibleEditor, ISaveEditorsOptions, IRevertAllEditorsOptions, IResourceEditor } from 'vs/workbench/services/editor/common/editorService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; -import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { IEditorRegistry, EditorDescriptor, Extensions } from 'vs/workbench/browser/editor'; -import { IDecorationRenderOptions } from 'vs/editor/common/editorCommon'; import { EditorGroup } from 'vs/workbench/common/editor/editorGroup'; import { Dimension } from 'vs/base/browser/dom'; import { ILogService, NullLogService } from 'vs/platform/log/common/log'; @@ -65,7 +63,7 @@ import { timeout } from 'vs/base/common/async'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { ViewletDescriptor, Viewlet } from 'vs/workbench/browser/viewlet'; import { IViewlet } from 'vs/workbench/common/viewlet'; -import { IStorageService } from 'vs/platform/storage/common/storage'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { isLinux } from 'vs/base/common/platform'; import { LabelService } from 'vs/workbench/services/label/common/labelService'; import { IDimension } from 'vs/platform/layout/browser/layoutService'; @@ -99,6 +97,8 @@ import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { CancellationToken } from 'vs/base/common/cancellation'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { TestDialogService } from 'vs/platform/dialogs/test/common/testDialogService'; +import { CodeEditorService } from 'vs/workbench/services/editor/browser/codeEditorService'; +import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart'; export import TestTextResourcePropertiesService = CommonWorkbenchTestServices.TestTextResourcePropertiesService; export import TestContextService = CommonWorkbenchTestServices.TestContextService; @@ -151,14 +151,15 @@ export function workbenchInstantiationService(overrides?: { textFileService?: (i instantiationService.stub(ITextFileService, overrides?.textFileService ? overrides.textFileService(instantiationService) : instantiationService.createInstance(TestTextFileService)); instantiationService.stub(IHostService, instantiationService.createInstance(TestHostService)); instantiationService.stub(ITextModelService, instantiationService.createInstance(TextModelResolverService)); - instantiationService.stub(IThemeService, new TestThemeService()); + const themeService = new TestThemeService(); + instantiationService.stub(IThemeService, themeService); instantiationService.stub(ILogService, new NullLogService()); const editorGroupService = new TestEditorGroupsService([new TestEditorGroupView(0)]); instantiationService.stub(IEditorGroupsService, editorGroupService); instantiationService.stub(ILabelService, instantiationService.createInstance(LabelService)); const editorService = new TestEditorService(editorGroupService); instantiationService.stub(IEditorService, editorService); - instantiationService.stub(ICodeEditorService, new TestCodeEditorService()); + instantiationService.stub(ICodeEditorService, new CodeEditorService(editorService, themeService)); instantiationService.stub(IViewletService, new TestViewletService()); return instantiationService; @@ -181,7 +182,8 @@ export class TestServiceAccessor { @ITextModelService public textModelResolverService: ITextModelService, @IUntitledTextEditorService public untitledTextEditorService: UntitledTextEditorService, @IConfigurationService public testConfigurationService: TestConfigurationService, - @IBackupFileService public backupFileService: TestBackupFileService + @IBackupFileService public backupFileService: TestBackupFileService, + @IHostService public hostService: TestHostService ) { } } @@ -791,32 +793,6 @@ export class TestBackupFileService implements IBackupFileService { } } -export class TestCodeEditorService implements ICodeEditorService { - _serviceBrand: undefined; - - onCodeEditorAdd: Event = Event.None; - onCodeEditorRemove: Event = Event.None; - onDiffEditorAdd: Event = Event.None; - onDiffEditorRemove: Event = Event.None; - onDidChangeTransientModelProperty: Event = Event.None; - - addCodeEditor(_editor: ICodeEditor): void { } - removeCodeEditor(_editor: ICodeEditor): void { } - listCodeEditors(): ICodeEditor[] { return []; } - addDiffEditor(_editor: IDiffEditor): void { } - removeDiffEditor(_editor: IDiffEditor): void { } - listDiffEditors(): IDiffEditor[] { return []; } - getFocusedCodeEditor(): ICodeEditor | null { return null; } - registerDecorationType(_key: string, _options: IDecorationRenderOptions, _parentTypeKey?: string): void { } - removeDecorationType(_key: string): void { } - resolveDecorationOptions(_typeKey: string, _writable: boolean): IModelDecorationOptions { return Object.create(null); } - setTransientModelProperty(_model: ITextModel, _key: string, _value: any): void { } - getTransientModelProperty(_model: ITextModel, _key: string) { } - getTransientModelProperties(_model: ITextModel) { return undefined; } - getActiveCodeEditor(): ICodeEditor | null { return null; } - openCodeEditor(_input: IResourceInput, _source: ICodeEditor, _sideBySide?: boolean): Promise { return Promise.resolve(null); } -} - export class TestLifecycleService implements ILifecycleService { _serviceBrand: undefined; @@ -906,9 +882,17 @@ export class TestHostService implements IHostService { _serviceBrand: undefined; - readonly hasFocus: boolean = true; - async hadLastFocus(): Promise { return true; } - readonly onDidChangeFocus: Event = Event.None; + private _hasFocus = true; + get hasFocus() { return this._hasFocus; } + async hadLastFocus(): Promise { return this._hasFocus; } + + private _onDidChangeFocus = new Emitter(); + readonly onDidChangeFocus = this._onDidChangeFocus.event; + + setFocus(focus: boolean) { + this._hasFocus = focus; + this._onDidChangeFocus.fire(this._hasFocus); + } async restart(): Promise { } async reload(): Promise { } @@ -1059,3 +1043,22 @@ export class TestFileEditorInput extends EditorInput implements IFileEditorInput movedEditor: IMoveResult | undefined = undefined; move(): IMoveResult | undefined { return this.movedEditor; } } + +export class TestEditorPart extends EditorPart { + + saveState(): void { + return super.saveState(); + } + + clearState(): void { + const workspaceMemento = this.getMemento(StorageScope.WORKSPACE); + for (const key of Object.keys(workspaceMemento)) { + delete workspaceMemento[key]; + } + + const globalMemento = this.getMemento(StorageScope.GLOBAL); + for (const key of Object.keys(globalMemento)) { + delete globalMemento[key]; + } + } +} diff --git a/src/vs/workbench/test/common/workbenchTestServices.ts b/src/vs/workbench/test/common/workbenchTestServices.ts index dfe948f1797..82de69c0655 100644 --- a/src/vs/workbench/test/common/workbenchTestServices.ts +++ b/src/vs/workbench/test/common/workbenchTestServices.ts @@ -35,14 +35,20 @@ export class TestTextResourcePropertiesService implements ITextResourcePropertie } export class TestContextService implements IWorkspaceContextService { + _serviceBrand: undefined; private workspace: Workspace; private options: any; private readonly _onDidChangeWorkspaceName: Emitter; + get onDidChangeWorkspaceName(): Event { return this._onDidChangeWorkspaceName.event; } + private readonly _onDidChangeWorkspaceFolders: Emitter; + get onDidChangeWorkspaceFolders(): Event { return this._onDidChangeWorkspaceFolders.event; } + private readonly _onDidChangeWorkbenchState: Emitter; + get onDidChangeWorkbenchState(): Event { return this._onDidChangeWorkbenchState.event; } constructor(workspace: any = TestWorkspace, options: any = null) { this.workspace = workspace; @@ -52,18 +58,6 @@ export class TestContextService implements IWorkspaceContextService { this._onDidChangeWorkbenchState = new Emitter(); } - get onDidChangeWorkspaceName(): Event { - return this._onDidChangeWorkspaceName.event; - } - - get onDidChangeWorkspaceFolders(): Event { - return this._onDidChangeWorkspaceFolders.event; - } - - get onDidChangeWorkbenchState(): Event { - return this._onDidChangeWorkbenchState.event; - } - getFolders(): IWorkspaceFolder[] { return this.workspace ? this.workspace.folders : []; } @@ -100,9 +94,7 @@ export class TestContextService implements IWorkspaceContextService { return this.options; } - updateOptions() { - - } + updateOptions() { } isInsideWorkspace(resource: URI): boolean { if (resource && this.workspace) { From 970951b7b7f03df9fc952be1a165ce91f47f5371 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 28 Feb 2020 15:46:28 +0100 Subject: [PATCH 166/235] Introduce false & true context keys (#85058) --- .../platform/contextkey/common/contextkey.ts | 171 ++++++++++++++++-- .../contextkey/test/common/contextkey.test.ts | 17 ++ 2 files changed, 176 insertions(+), 12 deletions(-) diff --git a/src/vs/platform/contextkey/common/contextkey.ts b/src/vs/platform/contextkey/common/contextkey.ts index d5f8cdb22f5..ef1f3216812 100644 --- a/src/vs/platform/contextkey/common/contextkey.ts +++ b/src/vs/platform/contextkey/common/contextkey.ts @@ -8,14 +8,16 @@ import { isFalsyOrWhitespace } from 'vs/base/common/strings'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; export const enum ContextKeyExprType { - Defined = 1, - Not = 2, - Equals = 3, - NotEquals = 4, - And = 5, - Regex = 6, - NotRegex = 7, - Or = 8 + False = 0, + True = 1, + Defined = 2, + Not = 3, + Equals = 4, + NotEquals = 5, + And = 6, + Regex = 7, + NotRegex = 8, + Or = 9 } export interface IContextKeyExprMapper { @@ -38,12 +40,21 @@ export interface IContextKeyExpression { } export type ContextKeyExpression = ( - ContextKeyDefinedExpr | ContextKeyNotExpr | ContextKeyEqualsExpr | ContextKeyNotEqualsExpr - | ContextKeyRegexExpr | ContextKeyNotRegexExpr | ContextKeyAndExpr | ContextKeyOrExpr + ContextKeyFalseExpr | ContextKeyTrueExpr | ContextKeyDefinedExpr | ContextKeyNotExpr + | ContextKeyEqualsExpr | ContextKeyNotEqualsExpr | ContextKeyRegexExpr + | ContextKeyNotRegexExpr | ContextKeyAndExpr | ContextKeyOrExpr ); export abstract class ContextKeyExpr { + public static false(): ContextKeyExpression { + return ContextKeyFalseExpr.INSTANCE; + } + + public static true(): ContextKeyExpression { + return ContextKeyTrueExpr.INSTANCE; + } + public static has(key: string): ContextKeyExpression { return ContextKeyDefinedExpr.create(key); } @@ -175,8 +186,88 @@ function cmp(a: ContextKeyExpression, b: ContextKeyExpression): number { return a.cmp(b); } +export class ContextKeyFalseExpr implements IContextKeyExpression { + public static INSTANCE = new ContextKeyFalseExpr(); + + public readonly type = ContextKeyExprType.False; + + protected constructor() { + } + + public cmp(other: ContextKeyExpression): number { + return this.type - other.type; + } + + public equals(other: ContextKeyExpression): boolean { + return (other.type === this.type); + } + + public evaluate(context: IContext): boolean { + return false; + } + + public serialize(): string { + return 'false'; + } + + public keys(): string[] { + return []; + } + + public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression { + return this; + } + + public negate(): ContextKeyExpression { + return ContextKeyTrueExpr.INSTANCE; + } +} + +export class ContextKeyTrueExpr implements IContextKeyExpression { + public static INSTANCE = new ContextKeyTrueExpr(); + + public readonly type = ContextKeyExprType.True; + + protected constructor() { + } + + public cmp(other: ContextKeyExpression): number { + return this.type - other.type; + } + + public equals(other: ContextKeyExpression): boolean { + return (other.type === this.type); + } + + public evaluate(context: IContext): boolean { + return true; + } + + public serialize(): string { + return 'true'; + } + + public keys(): string[] { + return []; + } + + public map(mapFnc: IContextKeyExprMapper): ContextKeyExpression { + return this; + } + + public negate(): ContextKeyExpression { + return ContextKeyFalseExpr.INSTANCE; + } +} + export class ContextKeyDefinedExpr implements IContextKeyExpression { - public static create(key: string): ContextKeyDefinedExpr { + public static create(key: string): ContextKeyExpression { + if (key === 'false') { + return ContextKeyFalseExpr.INSTANCE; + } + if (key === 'true') { + return ContextKeyTrueExpr.INSTANCE; + } return new ContextKeyDefinedExpr(key); } @@ -235,6 +326,14 @@ export class ContextKeyEqualsExpr implements IContextKeyExpression { } return ContextKeyNotExpr.create(key); } + if (key === 'false') { + // false only equals false + return (value === 'false' ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE); + } + if (key === 'true') { + // true only equals true + return (value === 'true' ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE); + } return new ContextKeyEqualsExpr(key, value); } @@ -301,6 +400,14 @@ export class ContextKeyNotEqualsExpr implements IContextKeyExpression { } return ContextKeyDefinedExpr.create(key); } + if (key === 'false') { + // false only equals false + return (value === 'false' ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE); + } + if (key === 'true') { + // true only equals true + return (value === 'true' ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE); + } return new ContextKeyNotEqualsExpr(key, value); } @@ -361,6 +468,14 @@ export class ContextKeyNotEqualsExpr implements IContextKeyExpression { export class ContextKeyNotExpr implements IContextKeyExpression { public static create(key: string): ContextKeyExpression { + if (key === 'false') { + // !false + return ContextKeyTrueExpr.INSTANCE; + } + if (key === 'true') { + // !true + return ContextKeyFalseExpr.INSTANCE; + } return new ContextKeyNotExpr(key); } @@ -589,12 +704,24 @@ export class ContextKeyAndExpr implements IContextKeyExpression { private static _normalizeArr(arr: ReadonlyArray): ContextKeyExpression[] { const expr: ContextKeyExpression[] = []; + let hasTrue = false; for (const e of arr) { if (!e) { continue; } + if (e.type === ContextKeyExprType.True) { + // anything && true ==> anything + hasTrue = true; + continue; + } + + if (e.type === ContextKeyExprType.False) { + // anything && false ==> false + return [ContextKeyFalseExpr.INSTANCE]; + } + if (e.type === ContextKeyExprType.And) { expr.push(...e.expr); continue; @@ -608,6 +735,10 @@ export class ContextKeyAndExpr implements IContextKeyExpression { expr.push(e); } + if (expr.length === 0 && hasTrue) { + return [ContextKeyTrueExpr.INSTANCE]; + } + expr.sort(cmp); return expr; @@ -703,14 +834,26 @@ export class ContextKeyOrExpr implements IContextKeyExpression { private static _normalizeArr(arr: ReadonlyArray): ContextKeyExpression[] { let expr: ContextKeyExpression[] = []; + let hasFalse = false; if (arr) { for (let i = 0, len = arr.length; i < len; i++) { - let e: ContextKeyExpression | null | undefined = arr[i]; + const e = arr[i]; if (!e) { continue; } + if (e.type === ContextKeyExprType.False) { + // anything || false ==> anything + hasFalse = true; + continue; + } + + if (e.type === ContextKeyExprType.True) { + // anything || true ==> true + return [ContextKeyTrueExpr.INSTANCE]; + } + if (e.type === ContextKeyExprType.Or) { expr = expr.concat(e.expr); continue; @@ -719,6 +862,10 @@ export class ContextKeyOrExpr implements IContextKeyExpression { expr.push(e); } + if (expr.length === 0 && hasFalse) { + return [ContextKeyFalseExpr.INSTANCE]; + } + expr.sort(cmp); } diff --git a/src/vs/platform/contextkey/test/common/contextkey.test.ts b/src/vs/platform/contextkey/test/common/contextkey.test.ts index 72929eff428..636fac13da9 100644 --- a/src/vs/platform/contextkey/test/common/contextkey.test.ts +++ b/src/vs/platform/contextkey/test/common/contextkey.test.ts @@ -89,6 +89,8 @@ suite('ContextKeyExpr', () => { testBatch('d', 'd'); testBatch('z', undefined); + testExpression('true', true); + testExpression('false', false); testExpression('a && !b', true && !false); testExpression('a && b', true && false); testExpression('a && !b && c == 5', true && !false && '5' === '5'); @@ -107,10 +109,25 @@ suite('ContextKeyExpr', () => { const actual = ContextKeyExpr.deserialize(expr)!.negate().serialize(); assert.strictEqual(actual, expected); } + testNegate('true', 'false'); + testNegate('false', 'true'); testNegate('a', '!a'); testNegate('a && b || c', '!a && !c || !b && !c'); testNegate('a && b || c || d', '!a && !c && !d || !b && !c && !d'); testNegate('!a && !b || !c && !d', 'a && c || a && d || b && c || b && d'); testNegate('!a && !b || !c && !d || !e && !f', 'a && c && e || a && c && f || a && d && e || a && d && f || b && c && e || b && c && f || b && d && e || b && d && f'); }); + + test('false, true', () => { + function testNormalize(expr: string, expected: string): void { + const actual = ContextKeyExpr.deserialize(expr)!.serialize(); + assert.strictEqual(actual, expected); + } + testNormalize('true', 'true'); + testNormalize('false', 'false'); + testNormalize('a && true', 'a'); + testNormalize('a && false', 'false'); + testNormalize('a || true', 'true'); + testNormalize('a || false', 'a'); + }); }); From 1575632abce5624ce7e331f154e02923544fd37b Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Fri, 28 Feb 2020 17:00:49 +0100 Subject: [PATCH 167/235] 1.44.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 09843bf7d28..42b39fa513c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "code-oss-dev", - "version": "1.43.0", + "version": "1.44.0", "distro": "e16fca95fbe6abb7e846db3fd372c95da67a41ad", "author": { "name": "Microsoft Corporation" From 6434b8207f5fe7c00df9a8d26176eabfe2b45170 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 28 Feb 2020 17:18:11 +0100 Subject: [PATCH 168/235] Fixes #85058: Handle isMac, isLinux, isWindows directly --- .../platform/contextkey/common/contextkey.ts | 53 ++++++++----------- .../contextkey/test/common/contextkey.test.ts | 6 +++ .../keybinding/common/keybindingResolver.ts | 5 ++ 3 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/vs/platform/contextkey/common/contextkey.ts b/src/vs/platform/contextkey/common/contextkey.ts index ef1f3216812..6f7ca973cc9 100644 --- a/src/vs/platform/contextkey/common/contextkey.ts +++ b/src/vs/platform/contextkey/common/contextkey.ts @@ -6,6 +6,14 @@ import { Event } from 'vs/base/common/event'; import { isFalsyOrWhitespace } from 'vs/base/common/strings'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { isMacintosh, isLinux, isWindows } from 'vs/base/common/platform'; + +const STATIC_VALUES = new Map(); +STATIC_VALUES.set('false', false); +STATIC_VALUES.set('true', true); +STATIC_VALUES.set('isMac', isMacintosh); +STATIC_VALUES.set('isLinux', isLinux); +STATIC_VALUES.set('isWindows', isWindows); export const enum ContextKeyExprType { False = 0, @@ -262,11 +270,9 @@ export class ContextKeyTrueExpr implements IContextKeyExpression { export class ContextKeyDefinedExpr implements IContextKeyExpression { public static create(key: string): ContextKeyExpression { - if (key === 'false') { - return ContextKeyFalseExpr.INSTANCE; - } - if (key === 'true') { - return ContextKeyTrueExpr.INSTANCE; + const staticValue = STATIC_VALUES.get(key); + if (typeof staticValue === 'boolean') { + return staticValue ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE; } return new ContextKeyDefinedExpr(key); } @@ -321,18 +327,12 @@ export class ContextKeyEqualsExpr implements IContextKeyExpression { public static create(key: string, value: any): ContextKeyExpression { if (typeof value === 'boolean') { - if (value) { - return ContextKeyDefinedExpr.create(key); - } - return ContextKeyNotExpr.create(key); + return (value ? ContextKeyDefinedExpr.create(key) : ContextKeyNotExpr.create(key)); } - if (key === 'false') { - // false only equals false - return (value === 'false' ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE); - } - if (key === 'true') { - // true only equals true - return (value === 'true' ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE); + const staticValue = STATIC_VALUES.get(key); + if (typeof staticValue === 'boolean') { + const trueValue = staticValue ? 'true' : 'false'; + return (value === trueValue ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE); } return new ContextKeyEqualsExpr(key, value); } @@ -400,13 +400,10 @@ export class ContextKeyNotEqualsExpr implements IContextKeyExpression { } return ContextKeyDefinedExpr.create(key); } - if (key === 'false') { - // false only equals false - return (value === 'false' ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE); - } - if (key === 'true') { - // true only equals true - return (value === 'true' ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE); + const staticValue = STATIC_VALUES.get(key); + if (typeof staticValue === 'boolean') { + const falseValue = staticValue ? 'true' : 'false'; + return (value === falseValue ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE); } return new ContextKeyNotEqualsExpr(key, value); } @@ -468,13 +465,9 @@ export class ContextKeyNotEqualsExpr implements IContextKeyExpression { export class ContextKeyNotExpr implements IContextKeyExpression { public static create(key: string): ContextKeyExpression { - if (key === 'false') { - // !false - return ContextKeyTrueExpr.INSTANCE; - } - if (key === 'true') { - // !true - return ContextKeyFalseExpr.INSTANCE; + const staticValue = STATIC_VALUES.get(key); + if (typeof staticValue === 'boolean') { + return (staticValue ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE); } return new ContextKeyNotExpr(key); } diff --git a/src/vs/platform/contextkey/test/common/contextkey.test.ts b/src/vs/platform/contextkey/test/common/contextkey.test.ts index 636fac13da9..f5a04ce1cf2 100644 --- a/src/vs/platform/contextkey/test/common/contextkey.test.ts +++ b/src/vs/platform/contextkey/test/common/contextkey.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { isMacintosh, isLinux, isWindows } from 'vs/base/common/platform'; function createContext(ctx: any) { return { @@ -124,10 +125,15 @@ suite('ContextKeyExpr', () => { assert.strictEqual(actual, expected); } testNormalize('true', 'true'); + testNormalize('!true', 'false'); testNormalize('false', 'false'); + testNormalize('!false', 'true'); testNormalize('a && true', 'a'); testNormalize('a && false', 'false'); testNormalize('a || true', 'true'); testNormalize('a || false', 'a'); + testNormalize('isMac', isMacintosh ? 'true' : 'false'); + testNormalize('isLinux', isLinux ? 'true' : 'false'); + testNormalize('isWindows', isWindows ? 'true' : 'false'); }); }); diff --git a/src/vs/platform/keybinding/common/keybindingResolver.ts b/src/vs/platform/keybinding/common/keybindingResolver.ts index a1821bddd85..951d01f4c16 100644 --- a/src/vs/platform/keybinding/common/keybindingResolver.ts +++ b/src/vs/platform/keybinding/common/keybindingResolver.ts @@ -49,6 +49,11 @@ export class KeybindingResolver { continue; } + if (k.when && k.when.type === ContextKeyExprType.False) { + // when condition is false + continue; + } + // TODO@chords this._addKeyPress(k.keypressParts[0], k); } From cd76248370a2b3b11e6a1825d97673597eeb0a03 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 28 Feb 2020 17:20:17 +0100 Subject: [PATCH 169/235] tests - more coverage for text file editors --- .../files/browser/editors/textFileEditor.ts | 10 +- .../files/electron-browser/textFileEditor.ts | 8 +- .../files/test/browser/textFileEditor.test.ts | 110 ++++++++++++++++++ .../editor/test/browser/editorService.test.ts | 21 +++- .../test/browser/workbenchTestServices.ts | 35 +++--- 5 files changed, 162 insertions(+), 22 deletions(-) create mode 100644 src/vs/workbench/contrib/files/test/browser/textFileEditor.test.ts diff --git a/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts index 24ac77635c9..856a58552a8 100644 --- a/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts @@ -31,6 +31,7 @@ import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor'; import { createErrorWithActions } from 'vs/base/common/errorsWithActions'; import { MutableDisposable } from 'vs/base/common/lifecycle'; import { EditorActivation, IEditorOptions } from 'vs/platform/editor/common/editor'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; /** * An implementation of editor for file system resources. @@ -49,14 +50,15 @@ export class TextFileEditor extends BaseTextEditor { @IInstantiationService instantiationService: IInstantiationService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IStorageService storageService: IStorageService, - @ITextResourceConfigurationService configurationService: ITextResourceConfigurationService, + @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, @IEditorService editorService: IEditorService, @IThemeService themeService: IThemeService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService private readonly textFileService: ITextFileService, - @IExplorerService private readonly explorerService: IExplorerService + @IExplorerService private readonly explorerService: IExplorerService, + @IConfigurationService private readonly configurationService: IConfigurationService ) { - super(TextFileEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, editorService, editorGroupService); + super(TextFileEditor.ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorService, editorGroupService); this.updateRestoreViewStateConfiguration(); @@ -87,7 +89,7 @@ export class TextFileEditor extends BaseTextEditor { } private updateRestoreViewStateConfiguration(): void { - this.restoreViewState = this.textResourceConfigurationService.getValue(undefined, 'workbench.editor.restoreViewState'); + this.restoreViewState = this.configurationService.getValue('workbench.editor.restoreViewState') ?? true /* default */; } getTitle(): string { diff --git a/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts b/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts index 0390ba2cceb..4ea06a47056 100644 --- a/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts +++ b/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts @@ -24,6 +24,7 @@ import { ITextFileService } from 'vs/workbench/services/textfile/common/textfile import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import { IExplorerService } from 'vs/workbench/contrib/files/common/files'; import { IElectronService } from 'vs/platform/electron/node/electron'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; /** * An implementation of editor for file system resources. @@ -37,16 +38,17 @@ export class NativeTextFileEditor extends TextFileEditor { @IInstantiationService instantiationService: IInstantiationService, @IWorkspaceContextService contextService: IWorkspaceContextService, @IStorageService storageService: IStorageService, - @ITextResourceConfigurationService configurationService: ITextResourceConfigurationService, + @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, @IEditorService editorService: IEditorService, @IThemeService themeService: IThemeService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, @IElectronService private readonly electronService: IElectronService, @IPreferencesService private readonly preferencesService: IPreferencesService, - @IExplorerService explorerService: IExplorerService + @IExplorerService explorerService: IExplorerService, + @IConfigurationService configurationService: IConfigurationService ) { - super(telemetryService, fileService, viewletService, instantiationService, contextService, storageService, configurationService, editorService, themeService, editorGroupService, textFileService, explorerService); + super(telemetryService, fileService, viewletService, instantiationService, contextService, storageService, textResourceConfigurationService, editorService, themeService, editorGroupService, textFileService, explorerService, configurationService); } protected handleSetInputError(error: Error, input: FileEditorInput, options: EditorOptions | undefined): void { diff --git a/src/vs/workbench/contrib/files/test/browser/textFileEditor.test.ts b/src/vs/workbench/contrib/files/test/browser/textFileEditor.test.ts new file mode 100644 index 00000000000..a58dd887f65 --- /dev/null +++ b/src/vs/workbench/contrib/files/test/browser/textFileEditor.test.ts @@ -0,0 +1,110 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { toResource } from 'vs/base/test/common/utils'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { workbenchInstantiationService, TestServiceAccessor, TestFilesConfigurationService, TestEnvironmentService } from 'vs/workbench/test/browser/workbenchTestServices'; +import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { TextFileEditor } from 'vs/workbench/contrib/files/browser/editors/textFileEditor'; +import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { EditorInput } from 'vs/workbench/common/editor'; +import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; +import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; +import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart'; +import { EditorService } from 'vs/workbench/services/editor/browser/editorService'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; +import { Selection } from 'vs/editor/common/core/selection'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; + +suite('Files - TextFileEditor', () => { + + let disposables: IDisposable[] = []; + + setup(() => { + disposables.push(Registry.as(EditorExtensions.Editors).registerEditor( + EditorDescriptor.create( + TextFileEditor, + TextFileEditor.ID, + 'Text File Editor' + ), + [new SyncDescriptor(FileEditorInput)] + )); + }); + + teardown(() => { + dispose(disposables); + disposables = []; + }); + + async function createPart(restoreViewState: boolean): Promise<[EditorPart, TestServiceAccessor, IInstantiationService, IEditorService]> { + const instantiationService = workbenchInstantiationService(); + + const configurationService = new TestConfigurationService(); + configurationService.setUserConfiguration('workbench', { editor: { restoreViewState } }); + instantiationService.stub(IConfigurationService, configurationService); + + instantiationService.stub(IFilesConfigurationService, new TestFilesConfigurationService( + instantiationService.createInstance(MockContextKeyService), + configurationService, + TestEnvironmentService + )); + + const part = instantiationService.createInstance(EditorPart); + part.create(document.createElement('div')); + part.layout(400, 300); + + instantiationService.stub(IEditorGroupsService, part); + + const editorService: EditorService = instantiationService.createInstance(EditorService); + instantiationService.stub(IEditorService, editorService); + + const accessor = instantiationService.createInstance(TestServiceAccessor); + + await part.whenRestored; + + return [part, accessor, instantiationService, editorService]; + } + + test('text file editor preserves viewstate', async function () { + return viewStateTest(this, true); + }); + + test('text file editor resets viewstate if configured as such', async function () { + return viewStateTest(this, false); + }); + + async function viewStateTest(context: Mocha.ITestCallbackContext, restoreViewState: boolean): Promise { + const [part, accessor] = await createPart(restoreViewState); + + let editor = await accessor.editorService.openEditor(accessor.editorService.createInput({ resource: toResource.call(context, '/path/index.txt'), forceFile: true })); + + let codeEditor = editor?.getControl() as CodeEditorWidget; + const selection = new Selection(1, 3, 1, 4); + codeEditor.setSelection(selection); + + editor = await accessor.editorService.openEditor(accessor.editorService.createInput({ resource: toResource.call(context, '/path/index-other.txt'), forceFile: true })); + editor = await accessor.editorService.openEditor(accessor.editorService.createInput({ resource: toResource.call(context, '/path/index.txt'), forceFile: true })); + + codeEditor = editor?.getControl() as CodeEditorWidget; + + if (restoreViewState) { + assert.ok(codeEditor.getSelection()?.equalsSelection(selection)); + } else { + assert.ok(!codeEditor.getSelection()?.equalsSelection(selection)); + } + + part.dispose(); + (accessor.textFileService.files).dispose(); + } +}); diff --git a/src/vs/workbench/services/editor/test/browser/editorService.test.ts b/src/vs/workbench/services/editor/test/browser/editorService.test.ts index dc7c8c63fce..26d6709a157 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -8,7 +8,7 @@ import { EditorActivation } from 'vs/platform/editor/common/editor'; import { URI } from 'vs/base/common/uri'; import { Event } from 'vs/base/common/event'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { EditorInput, EditorsOrder } from 'vs/workbench/common/editor'; +import { EditorInput, EditorsOrder, SideBySideEditorInput } from 'vs/workbench/common/editor'; import { workbenchInstantiationService, TestStorageService, TestServiceAccessor, registerTestEditor, TestFileEditorInput } from 'vs/workbench/test/browser/workbenchTestServices'; import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; @@ -26,6 +26,7 @@ import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry'; import { UntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel'; import { NullFileSystemProvider } from 'vs/platform/files/test/common/nullFileSystemProvider'; +import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; const TEST_EDITOR_ID = 'MyTestEditorForEditorService'; const TEST_EDITOR_INPUT_ID = 'testEditorInputForEditorService'; @@ -233,6 +234,10 @@ suite('EditorService', () => { let contentInput = input; assert.strictEqual(contentInput.resource.fsPath, toResource.call(this, '/index.html').fsPath); + // Typed Input + assert.equal(service.createInput(input), input); + assert.equal(service.createInput({ editor: input }), input); + // Untyped Input (file, encoding) input = service.createInput({ resource: toResource.call(this, '/index.html'), encoding: 'utf16le', options: { selection: { startLineNumber: 1, startColumn: 1 } } }); assert(input instanceof FileEditorInput); @@ -289,6 +294,20 @@ suite('EditorService', () => { // Untyped Input (resource) input = service.createInput({ resource: URI.parse('custom:resource') }); assert(input instanceof ResourceEditorInput); + + // Untyped Input (side by side) + input = service.createInput({ + masterResource: toResource.call(this, '/master.html'), + detailResource: toResource.call(this, '/detail.html') + }); + assert(input instanceof SideBySideEditorInput); + + // Untyped Input (diff) + input = service.createInput({ + leftResource: toResource.call(this, '/master.html'), + rightResource: toResource.call(this, '/detail.html') + }); + assert(input instanceof DiffEditorInput); }); test('delegate', function (done) { diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index 4e86c5a1bb3..8147ecb50bf 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -10,7 +10,7 @@ import * as resources from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; -import { IEditorInputWithOptions, CloseDirection, IEditorIdentifier, IUntitledTextResourceInput, IResourceDiffInput, IResourceSideBySideInput, IEditorInput, IEditor, IEditorCloseEvent, IEditorPartOptions, IRevertOptions, GroupIdentifier, EditorInput, EditorOptions, EditorsOrder, IFileEditorInput, IEditorInputFactoryRegistry, IEditorInputFactory, Extensions as EditorExtensions, ISaveOptions, IMoveResult } from 'vs/workbench/common/editor'; +import { IEditorInputWithOptions, CloseDirection, IEditorIdentifier, IUntitledTextResourceInput, IResourceDiffInput, IResourceSideBySideInput, IEditorInput, IEditor, IEditorCloseEvent, IEditorPartOptions, IRevertOptions, GroupIdentifier, EditorInput, EditorOptions, EditorsOrder, IFileEditorInput, IEditorInputFactoryRegistry, IEditorInputFactory, Extensions as EditorExtensions, ISaveOptions, IMoveResult, ITextEditor, ITextDiffEditor, ITextSideBySideEditor } from 'vs/workbench/common/editor'; import { IEditorOpeningEvent, EditorServiceImpl, IEditorGroupView, IEditorGroupsAccessor } from 'vs/workbench/browser/parts/editor/editor'; import { Event, Emitter } from 'vs/base/common/event'; import { IBackupFileService, IResolvedBackup } from 'vs/workbench/services/backup/common/backup'; @@ -18,7 +18,7 @@ import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configur import { IWorkbenchLayoutService, Parts, Position as PartPosition } from 'vs/workbench/services/layout/browser/layoutService'; import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; -import { IEditorOptions, IResourceInput, IEditorModel } from 'vs/platform/editor/common/editor'; +import { IEditorOptions, IResourceInput, IEditorModel, ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { IUntitledTextEditorService, UntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { ILifecycleService, BeforeShutdownEvent, ShutdownReason, StartupKind, LifecyclePhase, WillShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle'; @@ -51,8 +51,8 @@ import { IExtensionService, NullExtensionService } from 'vs/workbench/services/e import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IDecorationsService, IResourceDecorationChangeEvent, IDecoration, IDecorationData, IDecorationsProvider } from 'vs/workbench/services/decorations/browser/decorations'; import { IDisposable, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { IEditorGroupsService, IEditorGroup, GroupsOrder, GroupsArrangement, GroupDirection, IAddGroupOptions, IMergeGroupOptions, IMoveEditorOptions, ICopyEditorOptions, IEditorReplacement, IGroupChangeEvent, IFindGroupScope, EditorGroupLayout, ICloseEditorOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { IEditorService, IOpenEditorOverrideHandler, IVisibleEditor, ISaveEditorsOptions, IRevertAllEditorsOptions, IResourceEditor } from 'vs/workbench/services/editor/common/editorService'; +import { IEditorGroupsService, IEditorGroup, GroupsOrder, GroupsArrangement, GroupDirection, IAddGroupOptions, IMergeGroupOptions, IMoveEditorOptions, ICopyEditorOptions, IEditorReplacement, IGroupChangeEvent, IFindGroupScope, EditorGroupLayout, ICloseEditorOptions, GroupOrientation } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { IEditorService, IOpenEditorOverrideHandler, IVisibleEditor, ISaveEditorsOptions, IRevertAllEditorsOptions, IResourceEditor, SIDE_GROUP_TYPE, ACTIVE_GROUP_TYPE } from 'vs/workbench/services/editor/common/editorService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { IEditorRegistry, EditorDescriptor, Extensions } from 'vs/workbench/browser/editor'; import { EditorGroup } from 'vs/workbench/common/editor/editorGroup'; @@ -104,6 +104,8 @@ export import TestTextResourcePropertiesService = CommonWorkbenchTestServices.Te export import TestContextService = CommonWorkbenchTestServices.TestContextService; export import TestStorageService = CommonWorkbenchTestServices.TestStorageService; export import TestWorkingCopyService = CommonWorkbenchTestServices.TestWorkingCopyService; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { IDiffEditor } from 'vs/editor/common/editorCommon'; export function createFileInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined); @@ -469,7 +471,7 @@ export class TestEditorGroupsService implements IEditorGroupsService { onDidLayout: Event = Event.None; onDidEditorPartOptionsChange = Event.None; - orientation: any; + orientation = GroupOrientation.HORIZONTAL; whenRestored: Promise = Promise.resolve(undefined); willRestoreEditors = false; @@ -488,7 +490,7 @@ export class TestEditorGroupsService implements IEditorGroupsService { setSize(_group: number | IEditorGroup, _size: { width: number, height: number }): void { } arrangeGroups(_arrangement: GroupsArrangement): void { } applyLayout(_layout: EditorGroupLayout): void { } - setGroupOrientation(_orientation: any): void { } + setGroupOrientation(_orientation: GroupOrientation): void { } addGroup(_location: number | IEditorGroup, _direction: GroupDirection, _options?: IAddGroupOptions): IEditorGroup { throw new Error('not implemented'); } removeGroup(_group: number | IEditorGroup): void { } moveGroup(_group: number | IEditorGroup, _location: number | IEditorGroup, _direction: GroupDirection): IEditorGroup { throw new Error('not implemented'); } @@ -591,10 +593,10 @@ export class TestEditorService implements EditorServiceImpl { onDidOpenEditorFail: Event = Event.None; onDidMostRecentlyActiveEditorsChange: Event = Event.None; - activeControl!: IVisibleEditor; - activeTextEditorWidget: any; - activeTextEditorMode: any; - activeEditor!: IEditorInput; + activeControl: IVisibleEditor | undefined; + activeTextEditorWidget: ICodeEditor | IDiffEditor | undefined; + activeTextEditorMode: string | undefined; + activeEditor: IEditorInput | undefined; editors: ReadonlyArray = []; mostRecentlyActiveEditors: ReadonlyArray = []; visibleControls: ReadonlyArray = []; @@ -606,7 +608,13 @@ export class TestEditorService implements EditorServiceImpl { getEditors() { return []; } overrideOpenEditor(_handler: IOpenEditorOverrideHandler): IDisposable { return toDisposable(() => undefined); } - openEditor(_editor: any, _options?: any, _group?: any): Promise { throw new Error('not implemented'); } + openEditor(editor: IEditorInput, options?: IEditorOptions | ITextEditorOptions, group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise; + openEditor(editor: IResourceInput | IUntitledTextResourceInput, group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise; + openEditor(editor: IResourceDiffInput, group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise; + openEditor(editor: IResourceSideBySideInput, group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise; + async openEditor(editor: IEditorInput | IResourceEditor, optionsOrGroup?: IEditorOptions | ITextEditorOptions | IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE, group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise { + throw new Error('not implemented'); + } doResolveEditorOpenRequest(editor: IEditorInput | IResourceEditor): [IEditorGroup, EditorInput, EditorOptions | undefined] | undefined { if (!this.editorGroupService) { return undefined; @@ -615,8 +623,7 @@ export class TestEditorService implements EditorServiceImpl { return [this.editorGroupService.activeGroup, editor as EditorInput, undefined]; } openEditors(_editors: any, _group?: any): Promise { throw new Error('not implemented'); } - isOpen(_editor: IEditorInput | IResourceInput | IUntitledTextResourceInput): boolean { return false; } - getOpened(_editor: IEditorInput | IResourceInput | IUntitledTextResourceInput): IEditorInput { throw new Error('not implemented'); } + isOpen(_editor: IEditorInput): boolean { return false; } replaceEditors(_editors: any, _group: any) { return Promise.resolve(undefined); } invokeWithinEditorContext(fn: (accessor: ServicesAccessor) => T): T { throw new Error('not implemented'); } createInput(_input: IResourceInput | IUntitledTextResourceInput | IResourceDiffInput | IResourceSideBySideInput): EditorInput { throw new Error('not implemented'); } @@ -946,7 +953,7 @@ export function registerTestEditor(id: string, inputs: SyncDescriptor Date: Fri, 28 Feb 2020 17:21:54 +0100 Subject: [PATCH 170/235] fix compile issues --- src/vs/base/common/strings.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index 157057415e5..4857a4896c2 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -240,7 +240,7 @@ export function regExpFlags(regexp: RegExp): string { return (regexp.global ? 'g' : '') + (regexp.ignoreCase ? 'i' : '') + (regexp.multiline ? 'm' : '') - + (regexp.unicode ? 'u' : ''); + + ((regexp as any /* standalone editor compilation */).unicode ? 'u' : ''); } /** @@ -853,7 +853,7 @@ export function removeAnsiEscapeCodes(str: string): string { } export const removeAccents: (str: string) => string = (function () { - if (typeof String.prototype.normalize !== 'function') { + if (typeof (String.prototype as any /* standalone editor compilation */).normalize !== 'function') { // ☹️ no ES6 features... return function (str: string) { return str; }; } else { @@ -861,7 +861,7 @@ export const removeAccents: (str: string) => string = (function () { // see: https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript/37511463#37511463 const regex = /[\u0300-\u036f]/g; return function (str: string) { - return str.normalize('NFD').replace(regex, ''); + return (str as any /* standalone editor compilation */).normalize('NFD').replace(regex, ''); }; } })(); From 982429716bc8e5e9f91e6fd793d4adc45fefee44 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 28 Feb 2020 17:32:42 +0100 Subject: [PATCH 171/235] Update distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 42b39fa513c..bc4220dcc3d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.44.0", - "distro": "e16fca95fbe6abb7e846db3fd372c95da67a41ad", + "distro": "231a8c6522c74e2302d7a7360e4507b1b5991373", "author": { "name": "Microsoft Corporation" }, From cdd0c156965119acca2d7f3de5a44ba5c1bc4209 Mon Sep 17 00:00:00 2001 From: SteVen Batten Date: Fri, 28 Feb 2020 08:45:04 -0800 Subject: [PATCH 172/235] candidate shrinking dropdown --- src/vs/workbench/browser/parts/panel/media/panelpart.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/panel/media/panelpart.css b/src/vs/workbench/browser/parts/panel/media/panelpart.css index 5ac0818950c..a5b9004ca72 100644 --- a/src/vs/workbench/browser/parts/panel/media/panelpart.css +++ b/src/vs/workbench/browser/parts/panel/media/panelpart.css @@ -63,7 +63,7 @@ } .monaco-workbench .part.panel > .composite.title > .composite-bar-excess { - width: 100%; + width: 100px; } .monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar { From cdde27aea0816662a290b9aa6303fbfe907a5c1e Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 28 Feb 2020 18:23:49 +0100 Subject: [PATCH 173/235] skip failing test --- .../contrib/backup/test/electron-browser/backupTracker.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/backup/test/electron-browser/backupTracker.test.ts b/src/vs/workbench/contrib/backup/test/electron-browser/backupTracker.test.ts index b62e2030ec4..d602adb338f 100644 --- a/src/vs/workbench/contrib/backup/test/electron-browser/backupTracker.test.ts +++ b/src/vs/workbench/contrib/backup/test/electron-browser/backupTracker.test.ts @@ -235,7 +235,7 @@ suite('BackupTracker', () => { tracker.dispose(); }); - test('confirm onWillShutdown - veto if user cancels', async function () { + test.skip('confirm onWillShutdown - veto if user cancels', async function () { const [accessor, part, tracker] = await createTracker(); const resource = toResource.call(this, '/path/index.txt'); From b1dfe79d37a0b728725740ab5f821e7f74443469 Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Fri, 28 Feb 2020 11:13:26 -0800 Subject: [PATCH 174/235] Fix build --- src/vs/base/browser/ui/list/listView.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index 2dbc57e900f..a07235210e3 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -283,7 +283,7 @@ export class ListView implements ISpliceable, IDisposable { if (this.items[index].size === size) { return; } - + const lastRenderRange = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight); const heightDiff = index < lastRenderRange.start ? size - this.items[index].size : 0; @@ -293,7 +293,7 @@ export class ListView implements ISpliceable, IDisposable { this.render(lastRenderRange, this.lastRenderTop + heightDiff, this.lastRenderHeight, undefined, undefined, true); this.eventuallyUpdateScrollDimensions(); - + if (this.supportDynamicHeights) { this._rerender(this.lastRenderTop, this.lastRenderHeight); } From 23850c79907753a08c373b439055993a83b4a244 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Fri, 28 Feb 2020 11:20:50 -0800 Subject: [PATCH 175/235] [typescript-language-features] Add importModuleSpecifierEnding preference (#90405) * Expose importModuleSpecifierEnding to typescript-language-features * Add default `auto` setting * Use string 'auto' for auto setting * Work with TypeScript 3.8 --- .../typescript-language-features/package.json | 36 +++++++++++++++++++ .../package.nls.json | 5 +++ .../src/features/fileConfigurationManager.ts | 16 ++++++++- 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/extensions/typescript-language-features/package.json b/extensions/typescript-language-features/package.json index 7392a267a56..b3f12439bc8 100644 --- a/extensions/typescript-language-features/package.json +++ b/extensions/typescript-language-features/package.json @@ -638,6 +638,42 @@ "description": "%typescript.preferences.importModuleSpecifier%", "scope": "resource" }, + "javascript.preferences.importModuleSpecifierEnding": { + "type": "string", + "enum": [ + "auto", + "minimal", + "index", + "js" + ], + "markdownEnumDescriptions": [ + "%typescript.preferences.importModuleSpecifierEnding.auto%", + "%typescript.preferences.importModuleSpecifierEnding.minimal%", + "%typescript.preferences.importModuleSpecifierEnding.index%", + "%typescript.preferences.importModuleSpecifierEnding.js%" + ], + "default": "auto", + "description": "%typescript.preferences.importModuleSpecifierEnding%", + "scope": "resource" + }, + "typescript.preferences.importModuleSpecifierEnding": { + "type": "string", + "enum": [ + "auto", + "minimal", + "index", + "js" + ], + "markdownEnumDescriptions": [ + "%typescript.preferences.importModuleSpecifierEnding.auto%", + "%typescript.preferences.importModuleSpecifierEnding.minimal%", + "%typescript.preferences.importModuleSpecifierEnding.index%", + "%typescript.preferences.importModuleSpecifierEnding.js%" + ], + "default": "auto", + "description": "%typescript.preferences.importModuleSpecifierEnding%", + "scope": "resource" + }, "javascript.preferences.renameShorthandProperties": { "type": "boolean", "default": true, diff --git a/extensions/typescript-language-features/package.nls.json b/extensions/typescript-language-features/package.nls.json index a421936acb9..a2bf1f3eeed 100644 --- a/extensions/typescript-language-features/package.nls.json +++ b/extensions/typescript-language-features/package.nls.json @@ -70,6 +70,11 @@ "typescript.preferences.importModuleSpecifier.auto": "Automatically select import path style. Prefers using a relative import if `baseUrl` is configured and the relative path has fewer segments than the non-relative import.", "typescript.preferences.importModuleSpecifier.relative": "Relative to the file location.", "typescript.preferences.importModuleSpecifier.nonRelative": "Based on the `baseUrl` configured in your `jsconfig.json` / `tsconfig.json`.", + "typescript.preferences.importModuleSpecifierEnding": "Preferred path ending for auto imports.", + "typescript.preferences.importModuleSpecifierEnding.auto": "Use project settings to select a default.", + "typescript.preferences.importModuleSpecifierEnding.minimal": "Shorten `./component/index.js` to `./component`.", + "typescript.preferences.importModuleSpecifierEnding.index": "Shorten `./component/index.js` to `./component/index`", + "typescript.preferences.importModuleSpecifierEnding.js": "Do not shorten path endings; include the `.js` extension.", "typescript.updateImportsOnFileMove.enabled": "Enable/disable automatic updating of import paths when you rename or move a file in VS Code. Requires using TypeScript 2.9 or newer in the workspace.", "typescript.updateImportsOnFileMove.enabled.prompt": "Prompt on each rename.", "typescript.updateImportsOnFileMove.enabled.always": "Always update paths automatically.", diff --git a/extensions/typescript-language-features/src/features/fileConfigurationManager.ts b/extensions/typescript-language-features/src/features/fileConfigurationManager.ts index 4a625231458..be7431eac9f 100644 --- a/extensions/typescript-language-features/src/features/fileConfigurationManager.ts +++ b/extensions/typescript-language-features/src/features/fileConfigurationManager.ts @@ -179,13 +179,18 @@ export default class FileConfigurationManager extends Disposable { isTypeScriptDocument(document) ? 'typescript.preferences' : 'javascript.preferences', document.uri); - return { + // `importModuleSpecifierEnding` added to `Proto.UserPreferences` in TypeScript 3.9: + // remove intersection type after upgrading TypeScript. + const preferences: Proto.UserPreferences & { importModuleSpecifierEnding?: string } = { quotePreference: this.getQuoteStylePreference(config), importModuleSpecifierPreference: getImportModuleSpecifierPreference(config), + importModuleSpecifierEnding: getImportModuleSpecifierEndingPreference(config), allowTextChangesInNewFiles: document.uri.scheme === fileSchemes.file, providePrefixAndSuffixTextForRename: config.get('renameShorthandProperties', true), allowRenameOfImportPath: true, }; + + return preferences; } private getQuoteStylePreference(config: vscode.WorkspaceConfiguration) { @@ -204,3 +209,12 @@ function getImportModuleSpecifierPreference(config: vscode.WorkspaceConfiguratio default: return undefined; } } + +function getImportModuleSpecifierEndingPreference(config: vscode.WorkspaceConfiguration) { + switch (config.get('importModuleSpecifierEnding')) { + case 'minimal': return 'minimal'; + case 'index': return 'index'; + case 'js': return 'js'; + default: return 'auto'; + } +} From a68bfa3846d789d632fd14b0d712497173c2a548 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 28 Feb 2020 11:56:25 -0800 Subject: [PATCH 176/235] Add back languages/css test. Fix #90538 --- test/smoke/src/areas/languages/css.test.ts | 43 ++++++++++++++++++++++ test/smoke/src/main.ts | 2 + 2 files changed, 45 insertions(+) create mode 100644 test/smoke/src/areas/languages/css.test.ts diff --git a/test/smoke/src/areas/languages/css.test.ts b/test/smoke/src/areas/languages/css.test.ts new file mode 100644 index 00000000000..02daa15c7b9 --- /dev/null +++ b/test/smoke/src/areas/languages/css.test.ts @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Application, ProblemSeverity, Problems } from '../../../../automation'; + +export function setup() { + describe('Languages - CSS', () => { + it('verifies quick outline', async function () { + const app = this.app as Application; + await app.workbench.quickopen.openFile('style.css'); + + await app.workbench.quickopen.openQuickOutline(); + await app.workbench.quickopen.waitForQuickOpenElements(names => names.length === 2); + }); + + it('verifies warnings for the empty rule', async function () { + const app = this.app as Application; + await app.workbench.quickopen.openFile('style.css'); + await app.workbench.editor.waitForTypeInEditor('style.css', '.foo{}'); + + await app.code.waitForElement(Problems.getSelectorInEditor(ProblemSeverity.WARNING)); + + await app.workbench.problems.showProblemsView(); + await app.code.waitForElement(Problems.getSelectorInProblemsView(ProblemSeverity.WARNING)); + await app.workbench.problems.hideProblemsView(); + }); + + it('verifies that warning becomes an error once setting changed', async function () { + const app = this.app as Application; + await app.workbench.settingsEditor.addUserSetting('css.lint.emptyRules', '"error"'); + await app.workbench.quickopen.openFile('style.css'); + + await app.code.waitForElement(Problems.getSelectorInEditor(ProblemSeverity.ERROR)); + + const problems = new Problems(app.code); + await problems.showProblemsView(); + await app.code.waitForElement(Problems.getSelectorInProblemsView(ProblemSeverity.ERROR)); + await problems.hideProblemsView(); + }); + }); +} diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index fc1f4e5569f..f4d51dba717 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -25,6 +25,7 @@ import { setup as setupDataMigrationTests } from './areas/workbench/data-migrati import { setup as setupDataLossTests } from './areas/workbench/data-loss.test'; import { setup as setupDataPreferencesTests } from './areas/preferences/preferences.test'; import { setup as setupDataSearchTests } from './areas/search/search.test'; +import { setup as setupDataLanguagesTests } from './areas/languages/css.test'; import { setup as setupDataEditorTests } from './areas/editor/editor.test'; import { setup as setupDataStatusbarTests } from './areas/statusbar/statusbar.test'; import { setup as setupDataExtensionTests } from './areas/extensions/extensions.test'; @@ -301,6 +302,7 @@ describe(`VSCode Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => { if (!opts.web) { setupDataLossTests(); } if (!opts.web) { setupDataPreferencesTests(); } setupDataSearchTests(); + setupDataLanguagesTests(); setupDataEditorTests(); setupDataStatusbarTests(!!opts.web); if (!opts.web) { setupDataExtensionTests(); } From 155fcfa5bb9aaebca0e1cb598160d7239f1bad15 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 28 Feb 2020 11:56:45 -0800 Subject: [PATCH 177/235] suggest: fix handling around long lines See: https://github.com/microsoft/vscode/issues/90552#issuecomment-592680419 `overflow: hidden` should have been `overflow: auto`. Auto displays a scrollbar which, depending on the platform, can make the items too high. Also fixes names being cut off (see the loooong) cutoff in the linked issue. `flex-shrink:0` is on the label, with a max-width of 100%. But on the left there was the 18px icon, so the right side of the label was 18px off the end and not visible. Fix it by moving the icon outside of the `.left` side. We could alternately `calc(100% - 18px)`, but since the icon was not a hardcoded size in CSS I didn't want to implicitly depend on that. --- src/vs/editor/contrib/suggest/media/suggest.css | 3 ++- src/vs/editor/contrib/suggest/suggestWidget.ts | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index af01d6da5c5..be783ef5177 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -176,7 +176,7 @@ } .monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .signature-label { - overflow: auto; + overflow: hidden; text-overflow: ellipsis; } @@ -228,6 +228,7 @@ .monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left { flex-shrink: 1; + flex-grow: 1; overflow: hidden; } .monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .monaco-icon-label { diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 91b862f2982..3613e737d07 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -144,11 +144,10 @@ class ItemRenderer implements IListRenderer Date: Fri, 28 Feb 2020 12:04:03 -0800 Subject: [PATCH 178/235] resolves #91431 --- .../services/dialogs/browser/dialogService.ts | 23 +++++++++----- .../dialogs/electron-browser/dialogService.ts | 31 ++++++++++++------- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/services/dialogs/browser/dialogService.ts b/src/vs/workbench/services/dialogs/browser/dialogService.ts index f67f9aa064c..6b42535bff5 100644 --- a/src/vs/workbench/services/dialogs/browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/dialogService.ts @@ -18,6 +18,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IProductService } from 'vs/platform/product/common/productService'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { fromNow } from 'vs/base/common/date'; export class DialogService implements IDialogService { @@ -121,18 +122,24 @@ export class DialogService implements IDialogService { } async about(): Promise { - const detail = nls.localize('aboutDetail', - "Version: {0}\nCommit: {1}\nDate: {2}\nBrowser: {3}", - this.productService.version || 'Unknown', - this.productService.commit || 'Unknown', - this.productService.date || 'Unknown', - navigator.userAgent - ); + const detailString = (useAgo: boolean): string => { + return nls.localize('aboutDetail', + "Version: {0}\nCommit: {1}\nDate: {2}\nBrowser: {3}", + this.productService.version || 'Unknown', + this.productService.commit || 'Unknown', + this.productService.date ? `${this.productService.date}${useAgo ? ' (' + fromNow(new Date(this.productService.date), true) + ')' : ''}` : 'Unknown', + navigator.userAgent + ); + }; + + const detail = detailString(true); + const detailToCopy = detailString(false); + const { choice } = await this.show(Severity.Info, this.productService.nameLong, [nls.localize('copy', "Copy"), nls.localize('ok', "OK")], { detail, cancelId: 1 }); if (choice === 0) { - this.clipboardService.writeText(detail); + this.clipboardService.writeText(detailToCopy); } } } diff --git a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts index 43caf27af2e..969a1e5a5dc 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts @@ -23,6 +23,7 @@ import { IProductService } from 'vs/platform/product/common/productService'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { IElectronService } from 'vs/platform/electron/node/electron'; import { MessageBoxOptions } from 'electron'; +import { fromNow } from 'vs/base/common/date'; interface IMassagedMessageBoxOptions { @@ -216,17 +217,23 @@ class NativeDialogService implements IDialogService { } const isSnap = process.platform === 'linux' && process.env.SNAP && process.env.SNAP_REVISION; - const detail = nls.localize('aboutDetail', - "Version: {0}\nCommit: {1}\nDate: {2}\nElectron: {3}\nChrome: {4}\nNode.js: {5}\nV8: {6}\nOS: {7}", - version, - product.commit || 'Unknown', - product.date || 'Unknown', - process.versions['electron'], - process.versions['chrome'], - process.versions['node'], - process.versions['v8'], - `${os.type()} ${os.arch()} ${os.release()}${isSnap ? ' snap' : ''}` - ); + + const detailString = (useAgo: boolean): string => { + return nls.localize('aboutDetail', + "Version: {0}\nCommit: {1}\nDate: {2}\nElectron: {3}\nChrome: {4}\nNode.js: {5}\nV8: {6}\nOS: {7}", + version, + product.commit || 'Unknown', + product.date ? `${product.date}${useAgo ? ' (' + fromNow(new Date(product.date), true) + ')' : ''}` : 'Unknown', + process.versions['electron'], + process.versions['chrome'], + process.versions['node'], + process.versions['v8'], + `${os.type()} ${os.arch()} ${os.release()}${isSnap ? ' snap' : ''}` + ); + }; + + const detail = detailString(true); + const detailToCopy = detailString(false); const ok = nls.localize('okButton', "OK"); const copy = mnemonicButtonLabel(nls.localize({ key: 'copy', comment: ['&& denotes a mnemonic'] }, "&&Copy")); @@ -249,7 +256,7 @@ class NativeDialogService implements IDialogService { }); if (buttons[result.response] === copy) { - this.clipboardService.writeText(detail); + this.clipboardService.writeText(detailToCopy); } } } From 7f1bde5cb770ea12154d09c7b311e4ad205c6932 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 28 Feb 2020 22:25:33 +0100 Subject: [PATCH 179/235] Fixes #15774: Use configured word separators for Ctrl+D --- src/vs/editor/browser/editorBrowser.ts | 7 +++++- .../editor/browser/widget/codeEditorWidget.ts | 10 +++++++- .../common/controller/cursorWordOperations.ts | 23 +++++++++++++++++++ src/vs/editor/contrib/find/findController.ts | 2 +- .../linesOperations/linesOperations.ts | 2 +- .../editor/contrib/multicursor/multicursor.ts | 4 ++-- 6 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index 85ee85e34f7..3b9f5d03e24 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -13,7 +13,7 @@ import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { IIdentifiedSingleEditOperation, IModelDecoration, IModelDeltaDecoration, ITextModel, ICursorStateComputer } from 'vs/editor/common/model'; +import { IIdentifiedSingleEditOperation, IModelDecoration, IModelDeltaDecoration, ITextModel, ICursorStateComputer, IWordAtPosition } from 'vs/editor/common/model'; import { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent } from 'vs/editor/common/model/textModelEvents'; import { OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager'; import { IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout'; @@ -567,6 +567,11 @@ export interface ICodeEditor extends editorCommon.IEditor { */ getRawOptions(): IEditorOptions; + /** + * @internal + */ + getConfiguredWordAtPosition(position: Position): IWordAtPosition | null; + /** * Get value of the current model attached to this editor. * @see `ITextModel.getValue` diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index c8be02dfba7..dd790f97f10 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -32,7 +32,7 @@ import { ISelection, Selection } from 'vs/editor/common/core/selection'; import { InternalEditorAction } from 'vs/editor/common/editorAction'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { EndOfLinePreference, IIdentifiedSingleEditOperation, IModelDecoration, IModelDecorationOptions, IModelDecorationsChangeAccessor, IModelDeltaDecoration, ITextModel, ICursorStateComputer } from 'vs/editor/common/model'; +import { EndOfLinePreference, IIdentifiedSingleEditOperation, IModelDecoration, IModelDecorationOptions, IModelDecorationsChangeAccessor, IModelDeltaDecoration, ITextModel, ICursorStateComputer, IWordAtPosition } from 'vs/editor/common/model'; import { ClassName } from 'vs/editor/common/model/intervalTree'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent } from 'vs/editor/common/model/textModelEvents'; @@ -52,6 +52,7 @@ import { IAccessibilityService } from 'vs/platform/accessibility/common/accessib import { withNullAsUndefined } from 'vs/base/common/types'; import { MonospaceLineBreaksComputerFactory } from 'vs/editor/common/viewModel/monospaceLineBreaksComputer'; import { DOMLineBreaksComputerFactory } from 'vs/editor/browser/view/domLineBreaksComputer'; +import { WordOperations } from 'vs/editor/common/controller/cursorWordOperations'; let EDITOR_ID = 0; @@ -376,6 +377,13 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE return this._configuration.getRawOptions(); } + public getConfiguredWordAtPosition(position: Position): IWordAtPosition | null { + if (!this._modelData) { + return null; + } + return WordOperations.getWordAtPosition(this._modelData.model, this._configuration.options.get(EditorOption.wordSeparators), position); + } + public getValue(options: { preserveBOM: boolean; lineEnding: string; } | null = null): string { if (!this._modelData) { return ''; diff --git a/src/vs/editor/common/controller/cursorWordOperations.ts b/src/vs/editor/common/controller/cursorWordOperations.ts index 84a9dcd96d2..ba9e5f557a2 100644 --- a/src/vs/editor/common/controller/cursorWordOperations.ts +++ b/src/vs/editor/common/controller/cursorWordOperations.ts @@ -10,6 +10,7 @@ import { WordCharacterClass, WordCharacterClassifier, getMapForWordSeparators } import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; +import { ITextModel, IWordAtPosition } from 'vs/editor/common/model'; interface IFindWordResult { /** @@ -535,6 +536,28 @@ export class WordOperations { return new Range(pos.lineNumber, pos.column, toPosition.lineNumber, toPosition.column); } + private static _createWordAtPosition(model: ITextModel, lineNumber: number, word: IFindWordResult): IWordAtPosition { + const range = new Range(lineNumber, word.start + 1, lineNumber, word.end + 1); + return { + word: model.getValueInRange(range), + startColumn: range.startColumn, + endColumn: range.endColumn + }; + } + + public static getWordAtPosition(model: ITextModel, _wordSeparators: string, position: Position): IWordAtPosition | null { + const wordSeparators = getMapForWordSeparators(_wordSeparators); + const prevWord = WordOperations._findPreviousWordOnLine(wordSeparators, model, position); + if (prevWord && prevWord.wordType === WordType.Regular && prevWord.start <= position.column - 1 && position.column - 1 <= prevWord.end) { + return WordOperations._createWordAtPosition(model, position.lineNumber, prevWord); + } + const nextWord = WordOperations._findNextWordOnLine(wordSeparators, model, position); + if (nextWord && nextWord.wordType === WordType.Regular && nextWord.start <= position.column - 1 && position.column - 1 <= nextWord.end) { + return WordOperations._createWordAtPosition(model, position.lineNumber, nextWord); + } + return null; + } + public static word(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, position: Position): SingleCursorState { const wordSeparators = getMapForWordSeparators(config.wordSeparators); let prevWord = WordOperations._findPreviousWordOnLine(wordSeparators, model, position); diff --git a/src/vs/editor/contrib/find/findController.ts b/src/vs/editor/contrib/find/findController.ts index fee09b8429d..556a6bf0ad0 100644 --- a/src/vs/editor/contrib/find/findController.ts +++ b/src/vs/editor/contrib/find/findController.ts @@ -39,7 +39,7 @@ export function getSelectionSearchString(editor: ICodeEditor): string | null { // if selection spans multiple lines, default search string to empty if (selection.startLineNumber === selection.endLineNumber) { if (selection.isEmpty()) { - let wordAtPosition = editor.getModel().getWordAtPosition(selection.getStartPosition()); + const wordAtPosition = editor.getConfiguredWordAtPosition(selection.getStartPosition()); if (wordAtPosition) { return wordAtPosition.word; } diff --git a/src/vs/editor/contrib/linesOperations/linesOperations.ts b/src/vs/editor/contrib/linesOperations/linesOperations.ts index c9bf8a68056..174302f90a1 100644 --- a/src/vs/editor/contrib/linesOperations/linesOperations.ts +++ b/src/vs/editor/contrib/linesOperations/linesOperations.ts @@ -960,7 +960,7 @@ export abstract class AbstractCaseAction extends EditorAction { let selection = selections[i]; if (selection.isEmpty()) { let cursor = selection.getStartPosition(); - let word = model.getWordAtPosition(cursor); + const word = editor.getConfiguredWordAtPosition(cursor); if (!word) { continue; diff --git a/src/vs/editor/contrib/multicursor/multicursor.ts b/src/vs/editor/contrib/multicursor/multicursor.ts index b23cc0c09f8..2388b709ff4 100644 --- a/src/vs/editor/contrib/multicursor/multicursor.ts +++ b/src/vs/editor/contrib/multicursor/multicursor.ts @@ -286,7 +286,7 @@ export class MultiCursorSession { if (s.isEmpty()) { // selection is empty => expand to current word - const word = editor.getModel().getWordAtPosition(s.getStartPosition()); + const word = editor.getConfiguredWordAtPosition(s.getStartPosition()); if (!word) { return null; } @@ -505,7 +505,7 @@ export class MultiCursorSelectionController extends Disposable implements IEdito if (!selection.isEmpty()) { return selection; } - const word = model.getWordAtPosition(selection.getStartPosition()); + const word = this._editor.getConfiguredWordAtPosition(selection.getStartPosition()); if (!word) { return selection; } From 79a5a741f8b6f18b470e67e1544c4917860520bc Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 28 Feb 2020 23:32:36 +0100 Subject: [PATCH 180/235] Fixes #91776: Adopt codicons --- src/vs/editor/browser/widget/diffReview.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/browser/widget/diffReview.ts b/src/vs/editor/browser/widget/diffReview.ts index 2da217bb864..eb22ce3dba0 100644 --- a/src/vs/editor/browser/widget/diffReview.ts +++ b/src/vs/editor/browser/widget/diffReview.ts @@ -98,7 +98,7 @@ export class DiffReview extends Disposable { this.actionBarContainer.domNode )); - this._actionBar.push(new Action('diffreview.close', nls.localize('label.close', "Close"), 'close-diff-review', true, () => { + this._actionBar.push(new Action('diffreview.close', nls.localize('label.close', "Close"), 'close-diff-review codicon-close', true, () => { this.hide(); return Promise.resolve(null); }), { label: false, icon: true }); From b393709eb20cb1ae3ca81ec85310380ccb3e518e Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 28 Feb 2020 12:17:50 -0800 Subject: [PATCH 181/235] Fix #89933 --- src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts index fd2523ba4d9..b1ec26e5c46 100644 --- a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts +++ b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts @@ -857,6 +857,6 @@ registerThemingParticipant((theme, collector) => { const linkFg = theme.getColor(textLinkForeground); if (linkFg) { collector.addRule(`.markers-panel .markers-panel-container .tree-container .monaco-tl-contents .details-container a.code-link .marker-code > span:hover { color: ${linkFg}; }`); - collector.addRule(`.markers-panel .markers-panel-container .tree-container .monaco-list:focus .monaco-tl-contents .details-container a.code-link .marker-code > span:hover { color: ${linkFg.lighten(.4)}; }`); + collector.addRule(`.markers-panel .markers-panel-container .tree-container .monaco-list:focus .monaco-tl-contents .details-container a.code-link .marker-code > span:hover { color: inherit; }`); } }); From d4dc9e09a2499da6396d2009625f5ca96369bf07 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 28 Feb 2020 14:08:15 -0800 Subject: [PATCH 182/235] Fix `command` being set twice in object --- .../typescript-language-features/src/typescriptServiceClient.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index 2d256281438..64527b2918e 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -735,7 +735,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType "command" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ - this.logTelemetry('fatalError', { command, ...(error instanceof TypeScriptServerError ? error.telemetry : {}) }); + this.logTelemetry('fatalError', { ...(error instanceof TypeScriptServerError ? error.telemetry : { command }) }); console.error(`A non-recoverable error occured while executing tsserver command: ${command}`); if (error instanceof TypeScriptServerError && error.serverErrorText) { console.error(error.serverErrorText); From 4b046579d852788a6d9d0d741caeaa4de74ea079 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 28 Feb 2020 14:08:38 -0800 Subject: [PATCH 183/235] Using private fields for more in extHostWebviews --- src/vs/workbench/api/common/extHostWebview.ts | 88 +++++++++---------- 1 file changed, 43 insertions(+), 45 deletions(-) diff --git a/src/vs/workbench/api/common/extHostWebview.ts b/src/vs/workbench/api/common/extHostWebview.ts index cfac95a00b3..17b6b4719ec 100644 --- a/src/vs/workbench/api/common/extHostWebview.ts +++ b/src/vs/workbench/api/common/extHostWebview.ts @@ -104,19 +104,20 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa private _title: string; private _iconPath?: IconPath; - private readonly _options: vscode.WebviewPanelOptions; - private readonly _webview: ExtHostWebview; - private _viewColumn: vscode.ViewColumn | undefined; - private _visible: boolean = true; - private _active: boolean = true; + readonly #options: vscode.WebviewPanelOptions; + readonly #webview: ExtHostWebview; - _isDisposed: boolean = false; + #viewColumn: vscode.ViewColumn | undefined = undefined; + #visible: boolean = true; + #active: boolean = true; - readonly _onDisposeEmitter = this._register(new Emitter()); - public readonly onDidDispose: Event = this._onDisposeEmitter.event; + #isDisposed: boolean = false; - readonly _onDidChangeViewStateEmitter = this._register(new Emitter()); - public readonly onDidChangeViewState: Event = this._onDidChangeViewStateEmitter.event; + readonly #onDidDispose = this._register(new Emitter()); + public readonly onDidDispose = this.#onDidDispose.event; + + readonly #onDidChangeViewState = this._register(new Emitter()); + public readonly onDidChangeViewState = this.#onDidChangeViewState.event; constructor( handle: WebviewPanelHandle, @@ -131,27 +132,28 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa this._handle = handle; this._proxy = proxy; this._viewType = viewType; - this._options = editorOptions; - this._viewColumn = viewColumn; + this.#options = editorOptions; + this.#viewColumn = viewColumn; this._title = title; - this._webview = webview; + this.#webview = webview; } public dispose() { - if (this._isDisposed) { + if (this.#isDisposed) { return; } - this._isDisposed = true; - this._onDisposeEmitter.fire(); + + this.#isDisposed = true; + this.#onDidDispose.fire(); this._proxy.$disposeWebview(this._handle); - this._webview.dispose(); + this.#webview.dispose(); super.dispose(); } get webview() { this.assertNotDisposed(); - return this._webview; + return this.#webview; } get viewType(): string { @@ -187,42 +189,40 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa } get options() { - return this._options; + return this.#options; } get viewColumn(): vscode.ViewColumn | undefined { this.assertNotDisposed(); - if (typeof this._viewColumn === 'number' && this._viewColumn < 0) { + if (typeof this.#viewColumn === 'number' && this.#viewColumn < 0) { // We are using a symbolic view column // Return undefined instead to indicate that the real view column is currently unknown but will be resolved. return undefined; } - return this._viewColumn; - } - - _setViewColumn(value: vscode.ViewColumn) { - this.assertNotDisposed(); - this._viewColumn = value; + return this.#viewColumn; } public get active(): boolean { this.assertNotDisposed(); - return this._active; - } - - _setActive(value: boolean) { - this.assertNotDisposed(); - this._active = value; + return this.#active; } public get visible(): boolean { this.assertNotDisposed(); - return this._visible; + return this.#visible; } - _setVisible(value: boolean) { - this.assertNotDisposed(); - this._visible = value; + _updateViewState(newState: { active: boolean; visible: boolean; viewColumn: vscode.ViewColumn; }) { + if (this.#isDisposed) { + return; + } + + if (this.active !== newState.active || this.visible !== newState.visible || this.viewColumn !== newState.viewColumn) { + this.#active = newState.active; + this.#visible = newState.visible; + this.#viewColumn = newState.viewColumn; + this.#onDidChangeViewState.fire({ webviewPanel: this }); + } } public postMessage(message: any): Promise { @@ -239,7 +239,7 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa } private assertNotDisposed() { - if (this._isDisposed) { + if (this.#isDisposed) { throw new Error('Webview is disposed'); } } @@ -585,18 +585,16 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { for (const handle of handles) { const panel = this.getWebviewPanel(handle); - if (!panel || panel._isDisposed) { + if (!panel) { continue; } const newState = newStates[handle]; - const viewColumn = typeConverters.ViewColumn.to(newState.position); - if (panel.active !== newState.active || panel.visible !== newState.visible || panel.viewColumn !== viewColumn) { - panel._setActive(newState.active); - panel._setVisible(newState.visible); - panel._setViewColumn(viewColumn); - panel._onDidChangeViewStateEmitter.fire({ webviewPanel: panel }); - } + panel._updateViewState({ + active: newState.active, + visible: newState.visible, + viewColumn: typeConverters.ViewColumn.to(newState.position), + }); } } From d685711e7cdf4afabd94e61b1881ac76b07ac093 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 28 Feb 2020 14:45:17 -0800 Subject: [PATCH 184/235] Pick up TS 3.8.3 --- extensions/package.json | 2 +- extensions/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/extensions/package.json b/extensions/package.json index b8e304b2343..7b4e8171c1f 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "3.8.2" + "typescript": "3.8.3" }, "scripts": { "postinstall": "node ./postinstall" diff --git a/extensions/yarn.lock b/extensions/yarn.lock index 43a70c058c2..83bd84cdd90 100644 --- a/extensions/yarn.lock +++ b/extensions/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -typescript@3.8.2: - version "3.8.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.2.tgz#91d6868aaead7da74f493c553aeff76c0c0b1d5a" - integrity sha512-EgOVgL/4xfVrCMbhYKUQTdF37SQn4Iw73H5BgCrF1Abdun7Kwy/QZsE/ssAy0y4LxBbvua3PIbFsbRczWWnDdQ== +typescript@3.8.3: + version "3.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" + integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== From fc9543ac88a6ddd541d319d6425e1734ccb36f72 Mon Sep 17 00:00:00 2001 From: Rachel Macfarlane Date: Fri, 28 Feb 2020 16:03:12 -0800 Subject: [PATCH 185/235] Reset settings sync token on 401, fixes #91653 (#91726) --- .../contrib/userDataSync/browser/userDataSync.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 0a30e149ade..403c7e046bd 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -155,7 +155,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo this._register(Event.debounce(userDataSyncService.onDidChangeStatus, () => undefined, 500)(() => this.onDidChangeSyncStatus(this.userDataSyncService.status))); this._register(userDataSyncService.onDidChangeConflicts(() => this.onDidChangeConflicts(this.userDataSyncService.conflictsSources))); this._register(userDataSyncService.onSyncErrors(errors => this.onSyncErrors(errors))); - this._register(this.authTokenService.onTokenFailed(_ => this.authenticationService.getSessions(this.userDataSyncStore!.authenticationProviderId))); + this._register(this.authTokenService.onTokenFailed(_ => this.onTokenFailed())); this._register(this.userDataSyncEnablementService.onDidChangeEnablement(enabled => this.onDidChangeEnablement(enabled))); this._register(this.authenticationService.onDidRegisterAuthenticationProvider(e => this.onDidRegisterAuthenticationProvider(e))); this._register(this.authenticationService.onDidUnregisterAuthenticationProvider(e => this.onDidUnregisterAuthenticationProvider(e))); @@ -255,6 +255,16 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } } + private async onTokenFailed(): Promise { + if (this.activeAccount) { + const accounts = (await this.authenticationService.getSessions(this.userDataSyncStore!.authenticationProviderId) || []); + const matchingAccount = accounts.filter(a => a.id === this.activeAccount?.id)[0]; + this.setActiveAccount(matchingAccount); + } else { + this.setActiveAccount(undefined); + } + } + private async onDidRegisterAuthenticationProvider(providerId: string) { if (providerId === this.userDataSyncStore!.authenticationProviderId) { await this.initializeActiveAccount(); From ff253a8f60d47e2982bd8cbaebf29fa12ea634f8 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Sat, 29 Feb 2020 11:45:48 -0800 Subject: [PATCH 186/235] Build VS Code with TS 3.9-nightly --- build/lib/asar.js | 1 + build/lib/bundle.js | 1 + build/lib/compilation.js | 1 + build/lib/electron.js | 1 + build/lib/eslint/utils.js | 1 + build/lib/extensions.js | 1 + build/lib/git.js | 1 + build/lib/i18n.js | 288 +++++++++++++++++++------------------- build/lib/optimize.js | 1 + build/lib/reporter.js | 1 + build/lib/standalone.js | 1 + build/lib/stats.js | 1 + build/lib/task.js | 1 + build/lib/treeshaking.js | 1 + build/lib/util.js | 1 + build/monaco/api.js | 1 + build/package.json | 2 +- build/yarn.lock | 10 +- package.json | 2 +- yarn.lock | 10 +- 20 files changed, 173 insertions(+), 154 deletions(-) diff --git a/build/lib/asar.js b/build/lib/asar.js index 21c5f65a45b..4a15a200be5 100644 --- a/build/lib/asar.js +++ b/build/lib/asar.js @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); +exports.createAsar = void 0; const path = require("path"); const es = require("event-stream"); const pickle = require('chromium-pickle-js'); diff --git a/build/lib/bundle.js b/build/lib/bundle.js index 881e8ff6c7f..7d0c8d9b55e 100644 --- a/build/lib/bundle.js +++ b/build/lib/bundle.js @@ -4,6 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); +exports.bundle = void 0; const fs = require("fs"); const path = require("path"); const vm = require("vm"); diff --git a/build/lib/compilation.js b/build/lib/compilation.js index 59bf1a250f6..c4a3230424b 100644 --- a/build/lib/compilation.js +++ b/build/lib/compilation.js @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); +exports.watchTask = exports.compileTask = void 0; const es = require("event-stream"); const fs = require("fs"); const gulp = require("gulp"); diff --git a/build/lib/electron.js b/build/lib/electron.js index b38a1f6edc9..abf6baab419 100644 --- a/build/lib/electron.js +++ b/build/lib/electron.js @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); +exports.config = exports.getElectronVersion = void 0; const fs = require("fs"); const path = require("path"); const vfs = require("vinyl-fs"); diff --git a/build/lib/eslint/utils.js b/build/lib/eslint/utils.js index ec59aef3b7d..c58e4e24be1 100644 --- a/build/lib/eslint/utils.js +++ b/build/lib/eslint/utils.js @@ -4,6 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); +exports.createImportRuleListener = void 0; function createImportRuleListener(validateImport) { function _checkImport(node) { if (node && node.type === 'Literal' && typeof node.value === 'string') { diff --git a/build/lib/extensions.js b/build/lib/extensions.js index e45b0d4e35a..8ee26bb40dd 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -4,6 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); +exports.packageMarketplaceExtensionsStream = exports.packageLocalExtensionsStream = exports.fromMarketplace = void 0; const es = require("event-stream"); const fs = require("fs"); const glob = require("glob"); diff --git a/build/lib/git.js b/build/lib/git.js index da5d66fd8d2..1726f76fcc7 100644 --- a/build/lib/git.js +++ b/build/lib/git.js @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); +exports.getVersion = void 0; const path = require("path"); const fs = require("fs"); /** diff --git a/build/lib/i18n.js b/build/lib/i18n.js index 27a4054a1e4..ea1758ee57e 100644 --- a/build/lib/i18n.js +++ b/build/lib/i18n.js @@ -4,6 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); +exports.prepareIslFiles = exports.prepareI18nPackFiles = exports.pullI18nPackFiles = exports.prepareI18nFiles = exports.pullSetupXlfFiles = exports.pullCoreAndExtensionsXlfFiles = exports.findObsoleteResources = exports.pushXlfFiles = exports.createXlfFilesForIsl = exports.createXlfFilesForExtensions = exports.createXlfFilesForCoreBundle = exports.getResource = exports.processNlsFiles = exports.Limiter = exports.XLF = exports.Line = exports.externalExtensionsWithTranslations = exports.extraLanguages = exports.defaultLanguages = void 0; const path = require("path"); const fs = require("fs"); const event_stream_1 = require("event-stream"); @@ -100,155 +101,158 @@ class TextModel { return this._lines; } } -class XLF { - constructor(project) { - this.project = project; - this.buffer = []; - this.files = Object.create(null); - this.numberOfMessages = 0; - } - toString() { - this.appendHeader(); - for (let file in this.files) { - this.appendNewLine(``, 2); - for (let item of this.files[file]) { - this.addStringItem(item); - } - this.appendNewLine('', 2); +let XLF = /** @class */ (() => { + class XLF { + constructor(project) { + this.project = project; + this.buffer = []; + this.files = Object.create(null); + this.numberOfMessages = 0; } - this.appendFooter(); - return this.buffer.join('\r\n'); - } - addFile(original, keys, messages) { - if (keys.length === 0) { - console.log('No keys in ' + original); - return; - } - if (keys.length !== messages.length) { - throw new Error(`Unmatching keys(${keys.length}) and messages(${messages.length}).`); - } - this.numberOfMessages += keys.length; - this.files[original] = []; - let existingKeys = new Set(); - for (let i = 0; i < keys.length; i++) { - let key = keys[i]; - let realKey; - let comment; - if (Is.string(key)) { - realKey = key; - comment = undefined; - } - else if (LocalizeInfo.is(key)) { - realKey = key.key; - if (key.comment && key.comment.length > 0) { - comment = key.comment.map(comment => encodeEntities(comment)).join('\r\n'); + toString() { + this.appendHeader(); + for (let file in this.files) { + this.appendNewLine(``, 2); + for (let item of this.files[file]) { + this.addStringItem(item); } + this.appendNewLine('', 2); } - if (!realKey || existingKeys.has(realKey)) { - continue; + this.appendFooter(); + return this.buffer.join('\r\n'); + } + addFile(original, keys, messages) { + if (keys.length === 0) { + console.log('No keys in ' + original); + return; } - existingKeys.add(realKey); - let message = encodeEntities(messages[i]); - this.files[original].push({ id: realKey, message: message, comment: comment }); + if (keys.length !== messages.length) { + throw new Error(`Unmatching keys(${keys.length}) and messages(${messages.length}).`); + } + this.numberOfMessages += keys.length; + this.files[original] = []; + let existingKeys = new Set(); + for (let i = 0; i < keys.length; i++) { + let key = keys[i]; + let realKey; + let comment; + if (Is.string(key)) { + realKey = key; + comment = undefined; + } + else if (LocalizeInfo.is(key)) { + realKey = key.key; + if (key.comment && key.comment.length > 0) { + comment = key.comment.map(comment => encodeEntities(comment)).join('\r\n'); + } + } + if (!realKey || existingKeys.has(realKey)) { + continue; + } + existingKeys.add(realKey); + let message = encodeEntities(messages[i]); + this.files[original].push({ id: realKey, message: message, comment: comment }); + } + } + addStringItem(item) { + if (!item.id || !item.message) { + throw new Error(`No item ID or value specified: ${JSON.stringify(item)}`); + } + this.appendNewLine(``, 4); + this.appendNewLine(`${item.message}`, 6); + if (item.comment) { + this.appendNewLine(`${item.comment}`, 6); + } + this.appendNewLine('', 4); + } + appendHeader() { + this.appendNewLine('', 0); + this.appendNewLine('', 0); + } + appendFooter() { + this.appendNewLine('', 0); + } + appendNewLine(content, indent) { + let line = new Line(indent); + line.append(content); + this.buffer.push(line.toString()); } } - addStringItem(item) { - if (!item.id || !item.message) { - throw new Error(`No item ID or value specified: ${JSON.stringify(item)}`); - } - this.appendNewLine(``, 4); - this.appendNewLine(`${item.message}`, 6); - if (item.comment) { - this.appendNewLine(`${item.comment}`, 6); - } - this.appendNewLine('', 4); - } - appendHeader() { - this.appendNewLine('', 0); - this.appendNewLine('', 0); - } - appendFooter() { - this.appendNewLine('', 0); - } - appendNewLine(content, indent) { - let line = new Line(indent); - line.append(content); - this.buffer.push(line.toString()); - } -} + XLF.parsePseudo = function (xlfString) { + return new Promise((resolve) => { + let parser = new xml2js.Parser(); + let files = []; + parser.parseString(xlfString, function (_err, result) { + const fileNodes = result['xliff']['file']; + fileNodes.forEach(file => { + const originalFilePath = file.$.original; + const messages = {}; + const transUnits = file.body[0]['trans-unit']; + if (transUnits) { + transUnits.forEach((unit) => { + const key = unit.$.id; + const val = pseudify(unit.source[0]['_'].toString()); + if (key && val) { + messages[key] = decodeEntities(val); + } + }); + files.push({ messages: messages, originalFilePath: originalFilePath, language: 'ps' }); + } + }); + resolve(files); + }); + }); + }; + XLF.parse = function (xlfString) { + return new Promise((resolve, reject) => { + let parser = new xml2js.Parser(); + let files = []; + parser.parseString(xlfString, function (err, result) { + if (err) { + reject(new Error(`XLF parsing error: Failed to parse XLIFF string. ${err}`)); + } + const fileNodes = result['xliff']['file']; + if (!fileNodes) { + reject(new Error(`XLF parsing error: XLIFF file does not contain "xliff" or "file" node(s) required for parsing.`)); + } + fileNodes.forEach((file) => { + const originalFilePath = file.$.original; + if (!originalFilePath) { + reject(new Error(`XLF parsing error: XLIFF file node does not contain original attribute to determine the original location of the resource file.`)); + } + let language = file.$['target-language']; + if (!language) { + reject(new Error(`XLF parsing error: XLIFF file node does not contain target-language attribute to determine translated language.`)); + } + const messages = {}; + const transUnits = file.body[0]['trans-unit']; + if (transUnits) { + transUnits.forEach((unit) => { + const key = unit.$.id; + if (!unit.target) { + return; // No translation available + } + let val = unit.target[0]; + if (typeof val !== 'string') { + val = val._; + } + if (key && val) { + messages[key] = decodeEntities(val); + } + else { + reject(new Error(`XLF parsing error: XLIFF file ${originalFilePath} does not contain full localization data. ID or target translation for one of the trans-unit nodes is not present.`)); + } + }); + files.push({ messages: messages, originalFilePath: originalFilePath, language: language.toLowerCase() }); + } + }); + resolve(files); + }); + }); + }; + return XLF; +})(); exports.XLF = XLF; -XLF.parsePseudo = function (xlfString) { - return new Promise((resolve) => { - let parser = new xml2js.Parser(); - let files = []; - parser.parseString(xlfString, function (_err, result) { - const fileNodes = result['xliff']['file']; - fileNodes.forEach(file => { - const originalFilePath = file.$.original; - const messages = {}; - const transUnits = file.body[0]['trans-unit']; - if (transUnits) { - transUnits.forEach((unit) => { - const key = unit.$.id; - const val = pseudify(unit.source[0]['_'].toString()); - if (key && val) { - messages[key] = decodeEntities(val); - } - }); - files.push({ messages: messages, originalFilePath: originalFilePath, language: 'ps' }); - } - }); - resolve(files); - }); - }); -}; -XLF.parse = function (xlfString) { - return new Promise((resolve, reject) => { - let parser = new xml2js.Parser(); - let files = []; - parser.parseString(xlfString, function (err, result) { - if (err) { - reject(new Error(`XLF parsing error: Failed to parse XLIFF string. ${err}`)); - } - const fileNodes = result['xliff']['file']; - if (!fileNodes) { - reject(new Error(`XLF parsing error: XLIFF file does not contain "xliff" or "file" node(s) required for parsing.`)); - } - fileNodes.forEach((file) => { - const originalFilePath = file.$.original; - if (!originalFilePath) { - reject(new Error(`XLF parsing error: XLIFF file node does not contain original attribute to determine the original location of the resource file.`)); - } - let language = file.$['target-language']; - if (!language) { - reject(new Error(`XLF parsing error: XLIFF file node does not contain target-language attribute to determine translated language.`)); - } - const messages = {}; - const transUnits = file.body[0]['trans-unit']; - if (transUnits) { - transUnits.forEach((unit) => { - const key = unit.$.id; - if (!unit.target) { - return; // No translation available - } - let val = unit.target[0]; - if (typeof val !== 'string') { - val = val._; - } - if (key && val) { - messages[key] = decodeEntities(val); - } - else { - reject(new Error(`XLF parsing error: XLIFF file ${originalFilePath} does not contain full localization data. ID or target translation for one of the trans-unit nodes is not present.`)); - } - }); - files.push({ messages: messages, originalFilePath: originalFilePath, language: language.toLowerCase() }); - } - }); - resolve(files); - }); - }); -}; class Limiter { constructor(maxDegreeOfParalellism) { this.maxDegreeOfParalellism = maxDegreeOfParalellism; diff --git a/build/lib/optimize.js b/build/lib/optimize.js index 45f11698463..f5db4afaaaa 100644 --- a/build/lib/optimize.js +++ b/build/lib/optimize.js @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); +exports.minifyTask = exports.optimizeTask = exports.loaderConfig = void 0; const es = require("event-stream"); const fs = require("fs"); const gulp = require("gulp"); diff --git a/build/lib/reporter.js b/build/lib/reporter.js index e0461dc6d9d..67615bf48dc 100644 --- a/build/lib/reporter.js +++ b/build/lib/reporter.js @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); +exports.createReporter = void 0; const es = require("event-stream"); const _ = require("underscore"); const fancyLog = require("fancy-log"); diff --git a/build/lib/standalone.js b/build/lib/standalone.js index ccfd7b45d23..531194c35fd 100644 --- a/build/lib/standalone.js +++ b/build/lib/standalone.js @@ -4,6 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); +exports.createESMSourcesAndResources2 = exports.extractEditor = void 0; const ts = require("typescript"); const fs = require("fs"); const path = require("path"); diff --git a/build/lib/stats.js b/build/lib/stats.js index 99ad665f223..2ff02e405a6 100644 --- a/build/lib/stats.js +++ b/build/lib/stats.js @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); +exports.submitAllStats = exports.createStatsStream = void 0; const es = require("event-stream"); const fancyLog = require("fancy-log"); const ansiColors = require("ansi-colors"); diff --git a/build/lib/task.js b/build/lib/task.js index f1e6e3f6245..d08ab8acde8 100644 --- a/build/lib/task.js +++ b/build/lib/task.js @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); +exports.define = exports.parallel = exports.series = void 0; const fancyLog = require("fancy-log"); const ansiColors = require("ansi-colors"); function _isPromise(p) { diff --git a/build/lib/treeshaking.js b/build/lib/treeshaking.js index 65dd88f585c..8c95751347f 100644 --- a/build/lib/treeshaking.js +++ b/build/lib/treeshaking.js @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); +exports.shake = exports.toStringShakeLevel = exports.ShakeLevel = void 0; const fs = require("fs"); const path = require("path"); const ts = require("typescript"); diff --git a/build/lib/util.js b/build/lib/util.js index 752d9fb63f0..d42670e67a5 100644 --- a/build/lib/util.js +++ b/build/lib/util.js @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); +exports.streamToPromise = exports.versionStringToNumber = exports.filter = exports.rebase = exports.getVersion = exports.ensureDir = exports.rreddir = exports.rimraf = exports.stripSourceMappingURL = exports.loadSourcemaps = exports.cleanNodeModules = exports.skipDirectories = exports.toFileUri = exports.setExecutableBit = exports.fixWin32DirectoryPermissions = exports.incremental = void 0; const es = require("event-stream"); const debounce = require("debounce"); const _filter = require("gulp-filter"); diff --git a/build/monaco/api.js b/build/monaco/api.js index bd656f2bcd1..1de24d4065c 100644 --- a/build/monaco/api.js +++ b/build/monaco/api.js @@ -4,6 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); +exports.execute = exports.run3 = exports.DeclarationResolver = exports.FSProvider = exports.RECIPE_PATH = void 0; const fs = require("fs"); const ts = require("typescript"); const path = require("path"); diff --git a/build/package.json b/build/package.json index d1cd1b063b7..8196dd52002 100644 --- a/build/package.json +++ b/build/package.json @@ -43,7 +43,7 @@ "minimist": "^1.2.0", "request": "^2.85.0", "terser": "4.3.8", - "typescript": "3.8.2", + "typescript": "^3.9.0-dev.20200229", "vsce": "1.48.0", "vscode-telemetry-extractor": "^1.5.4", "xml2js": "^0.4.17" diff --git a/build/yarn.lock b/build/yarn.lock index 53bc78757a8..fd19a1b7221 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -2453,16 +2453,16 @@ typed-rest-client@^0.9.0: tunnel "0.0.4" underscore "1.8.3" -typescript@3.8.2: - version "3.8.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.2.tgz#91d6868aaead7da74f493c553aeff76c0c0b1d5a" - integrity sha512-EgOVgL/4xfVrCMbhYKUQTdF37SQn4Iw73H5BgCrF1Abdun7Kwy/QZsE/ssAy0y4LxBbvua3PIbFsbRczWWnDdQ== - typescript@^3.0.1: version "3.5.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977" integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== +typescript@^3.9.0-dev.20200229: + version "3.9.0-dev.20200229" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.0-dev.20200229.tgz#45f0821d5c420a4c7d6d894c64531e1301dfa9bd" + integrity sha512-DtSLzxoiUir0qRc3+JJBxiAe6NvTEM3uDxnPxVWJU6sRDhUi8Ssx6DBjGWCZAQJlLk5A+jk2ptf3JvvZrQlLNQ== + typical@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" diff --git a/package.json b/package.json index bc4220dcc3d..9d1a14d30b7 100644 --- a/package.json +++ b/package.json @@ -150,7 +150,7 @@ "source-map": "^0.4.4", "style-loader": "^1.0.0", "ts-loader": "^4.4.2", - "typescript": "3.8.2", + "typescript": "^3.9.0-dev.20200229", "typescript-formatter": "7.1.0", "underscore": "^1.8.2", "vinyl": "^2.0.0", diff --git a/yarn.lock b/yarn.lock index a820c6344ac..a3f8ad9006b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9220,16 +9220,16 @@ typescript-formatter@7.1.0: commandpost "^1.0.0" editorconfig "^0.15.0" -typescript@3.8.2: - version "3.8.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.2.tgz#91d6868aaead7da74f493c553aeff76c0c0b1d5a" - integrity sha512-EgOVgL/4xfVrCMbhYKUQTdF37SQn4Iw73H5BgCrF1Abdun7Kwy/QZsE/ssAy0y4LxBbvua3PIbFsbRczWWnDdQ== - typescript@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4" integrity sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q= +typescript@^3.9.0-dev.20200229: + version "3.9.0-dev.20200229" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.0-dev.20200229.tgz#45f0821d5c420a4c7d6d894c64531e1301dfa9bd" + integrity sha512-DtSLzxoiUir0qRc3+JJBxiAe6NvTEM3uDxnPxVWJU6sRDhUi8Ssx6DBjGWCZAQJlLk5A+jk2ptf3JvvZrQlLNQ== + uc.micro@^1.0.1, uc.micro@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" From 77dcee274b19ddcdacd6df53a150157faf2ae036 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Sat, 29 Feb 2020 12:08:55 -0800 Subject: [PATCH 187/235] Fix formatting for TS 3.9 update --- src/vs/base/common/async.ts | 2 +- src/vs/editor/common/model/textModelSearch.ts | 2 +- src/vs/editor/contrib/folding/foldingModel.ts | 2 +- src/vs/platform/userDataSync/common/globalStateSync.ts | 2 +- src/vs/workbench/contrib/bulkEdit/browser/bulkEditPreview.ts | 2 +- .../contrib/terminal/browser/terminalInstanceService.ts | 2 +- .../configuration/common/configurationEditingService.ts | 2 +- src/vs/workbench/test/browser/api/extHostApiCommands.test.ts | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index e5ff745c876..9951ca26b7e 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -837,7 +837,7 @@ export class TaskSequentializer { this._pending?.cancel(); } - setPending(taskId: number, promise: Promise, onCancel?: () => void, ): Promise { + setPending(taskId: number, promise: Promise, onCancel?: () => void,): Promise { this._pending = { taskId: taskId, cancel: () => onCancel?.(), promise }; promise.then(() => this.donePending(taskId), () => this.donePending(taskId)); diff --git a/src/vs/editor/common/model/textModelSearch.ts b/src/vs/editor/common/model/textModelSearch.ts index d41d1a2a1ba..ce5b545c6f9 100644 --- a/src/vs/editor/common/model/textModelSearch.ts +++ b/src/vs/editor/common/model/textModelSearch.ts @@ -515,7 +515,7 @@ export class Searcher { private _prevMatchStartIndex: number; private _prevMatchLength: number; - constructor(wordSeparators: WordCharacterClassifier | null, searchRegex: RegExp, ) { + constructor(wordSeparators: WordCharacterClassifier | null, searchRegex: RegExp,) { this._wordSeparators = wordSeparators; this._searchRegex = searchRegex; this._prevMatchStartIndex = -1; diff --git a/src/vs/editor/contrib/folding/foldingModel.ts b/src/vs/editor/contrib/folding/foldingModel.ts index 917217b929b..e7b7858a855 100644 --- a/src/vs/editor/contrib/folding/foldingModel.ts +++ b/src/vs/editor/contrib/folding/foldingModel.ts @@ -318,7 +318,7 @@ export function setCollapseStateLevelsUp(foldingModel: FoldingModel, doCollapse: export function setCollapseStateUp(foldingModel: FoldingModel, doCollapse: boolean, lineNumbers: number[]): void { let toToggle: FoldingRegion[] = []; for (let lineNumber of lineNumbers) { - let regions = foldingModel.getAllRegionsAtLine(lineNumber, (region, ) => region.isCollapsed !== doCollapse); + let regions = foldingModel.getAllRegionsAtLine(lineNumber, (region,) => region.isCollapsed !== doCollapse); if (regions.length > 0) { toToggle.push(regions[0]); } diff --git a/src/vs/platform/userDataSync/common/globalStateSync.ts b/src/vs/platform/userDataSync/common/globalStateSync.ts index 8e00f07a9ae..e13edea154f 100644 --- a/src/vs/platform/userDataSync/common/globalStateSync.ts +++ b/src/vs/platform/userDataSync/common/globalStateSync.ts @@ -137,7 +137,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs } } - private async getPreview(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, ): Promise { + private async getPreview(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null,): Promise { const remoteGlobalState: IGlobalState = remoteUserData.syncData ? JSON.parse(remoteUserData.syncData.content) : null; const lastSyncGlobalState = lastSyncUserData && lastSyncUserData.syncData ? JSON.parse(lastSyncUserData.syncData.content) : null; diff --git a/src/vs/workbench/contrib/bulkEdit/browser/bulkEditPreview.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkEditPreview.ts index 06bdb85376a..59635e4a150 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/bulkEditPreview.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkEditPreview.ts @@ -89,7 +89,7 @@ export class BulkFileOperation { readonly parent: BulkFileOperations ) { } - addEdit(index: number, type: BulkFileOperationType, edit: WorkspaceTextEdit | WorkspaceFileEdit, ) { + addEdit(index: number, type: BulkFileOperationType, edit: WorkspaceTextEdit | WorkspaceFileEdit,) { this.type |= type; this.originalEdits.set(index, edit); if (WorkspaceTextEdit.is(edit)) { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts index df405001f97..e714542e72c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts @@ -69,7 +69,7 @@ export class TerminalInstanceService implements ITerminalInstanceService { throw new Error('Not implemented'); } - public getDefaultShellAndArgs(useAutomationShell: boolean, ): Promise<{ shell: string, args: string[] | string | undefined }> { + public getDefaultShellAndArgs(useAutomationShell: boolean,): Promise<{ shell: string, args: string[] | string | undefined }> { return new Promise(r => this._onRequestDefaultShellAndArgs.fire({ useAutomationShell, callback: (shell, args) => r({ shell, args }) diff --git a/src/vs/workbench/services/configuration/common/configurationEditingService.ts b/src/vs/workbench/services/configuration/common/configurationEditingService.ts index 29f4c406cc6..6b15032cd5c 100644 --- a/src/vs/workbench/services/configuration/common/configurationEditingService.ts +++ b/src/vs/workbench/services/configuration/common/configurationEditingService.ts @@ -230,7 +230,7 @@ export class ConfigurationEditingService { } } - private onInvalidConfigurationError(error: ConfigurationEditingError, operation: IConfigurationEditOperation, ): void { + private onInvalidConfigurationError(error: ConfigurationEditingError, operation: IConfigurationEditOperation,): void { const openStandAloneConfigurationActionLabel = operation.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY ? nls.localize('openTasksConfiguration', "Open Tasks Configuration") : operation.workspaceStandAloneConfigurationKey === LAUNCH_CONFIGURATION_KEY ? nls.localize('openLaunchConfiguration', "Open Launch Configuration") : null; diff --git a/src/vs/workbench/test/browser/api/extHostApiCommands.test.ts b/src/vs/workbench/test/browser/api/extHostApiCommands.test.ts index ccdf0740f5b..60ee0ec0087 100644 --- a/src/vs/workbench/test/browser/api/extHostApiCommands.test.ts +++ b/src/vs/workbench/test/browser/api/extHostApiCommands.test.ts @@ -895,7 +895,7 @@ suite('ExtHostLanguageFeatureCommands', function () { disposables.push(extHost.registerCallHierarchyProvider(nullExtensionDescription, defaultSelector, new class implements vscode.CallHierarchyProvider { - prepareCallHierarchy(document: vscode.TextDocument, position: vscode.Position, ): vscode.ProviderResult { + prepareCallHierarchy(document: vscode.TextDocument, position: vscode.Position,): vscode.ProviderResult { return new types.CallHierarchyItem(types.SymbolKind.Constant, 'ROOT', 'ROOT', document.uri, new types.Range(0, 0, 0, 0), new types.Range(0, 0, 0, 0)); } From afacd2bdfe7060f09df9b9139521718915949757 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 1 Mar 2020 11:29:26 -0500 Subject: [PATCH 188/235] Fixes #89509, #91464, #91628, #91619 --- .../api/browser/mainThreadTimeline.ts | 4 +- .../workbench/api/common/extHost.protocol.ts | 4 +- .../workbench/api/common/extHostTimeline.ts | 89 +++++------ .../timeline/browser/media/timelinePane.css | 18 ++- .../contrib/timeline/browser/timelinePane.ts | 144 ++++++++++++------ .../contrib/timeline/common/timeline.ts | 9 +- .../timeline/common/timelineService.ts | 98 +++++++----- 7 files changed, 218 insertions(+), 148 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadTimeline.ts b/src/vs/workbench/api/browser/mainThreadTimeline.ts index cfeb1c6c38c..c8d6d0a9a96 100644 --- a/src/vs/workbench/api/browser/mainThreadTimeline.ts +++ b/src/vs/workbench/api/browser/mainThreadTimeline.ts @@ -9,7 +9,7 @@ import { URI } from 'vs/base/common/uri'; import { ILogService } from 'vs/platform/log/common/log'; import { MainContext, MainThreadTimelineShape, IExtHostContext, ExtHostTimelineShape, ExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; -import { TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, ITimelineService } from 'vs/workbench/contrib/timeline/common/timeline'; +import { TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, ITimelineService, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline'; @extHostNamedCustomer(MainContext.MainThreadTimeline) export class MainThreadTimeline implements MainThreadTimelineShape { @@ -39,7 +39,7 @@ export class MainThreadTimeline implements MainThreadTimelineShape { this._timelineService.registerTimelineProvider({ ...provider, onDidChange: onDidChange.event, - provideTimeline(uri: URI, options: TimelineOptions, token: CancellationToken, internalOptions?: { cacheResults?: boolean }) { + provideTimeline(uri: URI, options: TimelineOptions, token: CancellationToken, internalOptions?: InternalTimelineOptions) { return proxy.$getTimeline(provider.id, uri, options, token, internalOptions); }, dispose() { diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 10f51d23548..d9b76522d9a 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -49,7 +49,7 @@ import { SaveReason } from 'vs/workbench/common/editor'; import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator'; import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService'; import { TunnelOptions } from 'vs/platform/remote/common/tunnel'; -import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor } from 'vs/workbench/contrib/timeline/common/timeline'; +import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline'; import { revive } from 'vs/base/common/marshalling'; import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; import { Dto } from 'vs/base/common/types'; @@ -1468,7 +1468,7 @@ export interface ExtHostTunnelServiceShape { } export interface ExtHostTimelineShape { - $getTimeline(source: string, uri: UriComponents, options: TimelineOptions, token: CancellationToken, internalOptions?: { cacheResults?: boolean }): Promise; + $getTimeline(source: string, uri: UriComponents, options: TimelineOptions, token: CancellationToken, internalOptions?: InternalTimelineOptions): Promise; } // --- proxy identifiers diff --git a/src/vs/workbench/api/common/extHostTimeline.ts b/src/vs/workbench/api/common/extHostTimeline.ts index 9db000d04f7..4df94da98d5 100644 --- a/src/vs/workbench/api/common/extHostTimeline.ts +++ b/src/vs/workbench/api/common/extHostTimeline.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import { UriComponents, URI } from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ExtHostTimelineShape, MainThreadTimelineShape, IMainContext, MainContext } from 'vs/workbench/api/common/extHost.protocol'; -import { Timeline, TimelineItem, TimelineOptions, TimelineProvider } from 'vs/workbench/contrib/timeline/common/timeline'; +import { Timeline, TimelineItem, TimelineOptions, TimelineProvider, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline'; import { IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { CancellationToken } from 'vs/base/common/cancellation'; import { CommandsConverter, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; @@ -16,21 +16,19 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; export interface IExtHostTimeline extends ExtHostTimelineShape { readonly _serviceBrand: undefined; - $getTimeline(id: string, uri: UriComponents, options: vscode.TimelineOptions, token: vscode.CancellationToken, internalOptions?: { cacheResults?: boolean }): Promise; + $getTimeline(id: string, uri: UriComponents, options: vscode.TimelineOptions, token: vscode.CancellationToken, internalOptions?: InternalTimelineOptions): Promise; } export const IExtHostTimeline = createDecorator('IExtHostTimeline'); export class ExtHostTimeline implements IExtHostTimeline { - private static handlePool = 0; - _serviceBrand: undefined; private _proxy: MainThreadTimelineShape; private _providers = new Map(); - private _itemsBySourceByUriMap = new Map>>(); + private _itemsBySourceAndUriMap = new Map>>(); constructor( mainContext: IMainContext, @@ -42,7 +40,7 @@ export class ExtHostTimeline implements IExtHostTimeline { processArgument: arg => { if (arg && arg.$mid === 11) { const uri = arg.uri === undefined ? undefined : URI.revive(arg.uri); - return this._itemsBySourceByUriMap.get(getUriKey(uri))?.get(arg.source)?.get(arg.handle); + return this._itemsBySourceAndUriMap.get(arg.source)?.get(getUriKey(uri))?.get(arg.handle); } return arg; @@ -50,7 +48,7 @@ export class ExtHostTimeline implements IExtHostTimeline { }); } - async $getTimeline(id: string, uri: UriComponents, options: vscode.TimelineOptions, token: vscode.CancellationToken, internalOptions?: { cacheResults?: boolean }): Promise { + async $getTimeline(id: string, uri: UriComponents, options: vscode.TimelineOptions, token: vscode.CancellationToken, internalOptions?: InternalTimelineOptions): Promise { const provider = this._providers.get(id); return provider?.provideTimeline(URI.revive(uri), options, token, internalOptions); } @@ -62,26 +60,21 @@ export class ExtHostTimeline implements IExtHostTimeline { let disposable: IDisposable | undefined; if (provider.onDidChange) { - disposable = provider.onDidChange(this.emitTimelineChangeEvent(provider.id), this); + disposable = provider.onDidChange(e => this._proxy.$emitTimelineChangeEvent({ ...e, id: provider.id }), this); } - const itemsBySourceByUriMap = this._itemsBySourceByUriMap; + const itemsBySourceAndUriMap = this._itemsBySourceAndUriMap; return this.registerTimelineProviderCore({ ...provider, scheme: scheme, onDidChange: undefined, - async provideTimeline(uri: URI, options: TimelineOptions, token: CancellationToken, internalOptions?: { cacheResults?: boolean }) { - // For now, only allow the caching of a single Uri - if (internalOptions?.cacheResults) { - if (options.cursor === undefined) { - timelineDisposables.clear(); - } - - if (!itemsBySourceByUriMap.has(getUriKey(uri))) { - itemsBySourceByUriMap.clear(); - } - } else { + async provideTimeline(uri: URI, options: TimelineOptions, token: CancellationToken, internalOptions?: InternalTimelineOptions) { + if (internalOptions?.resetCache) { timelineDisposables.clear(); + + // For now, only allow the caching of a single Uri + // itemsBySourceAndUriMap.get(provider.id)?.get(getUriKey(uri))?.clear(); + itemsBySourceAndUriMap.get(provider.id)?.clear(); } const result = await provider.provideTimeline(uri, options, token); @@ -91,8 +84,9 @@ export class ExtHostTimeline implements IExtHostTimeline { return undefined; } - // TODO: Determine if we should cache dependent on who calls us (internal vs external) - const convertItem = convertTimelineItem(uri, internalOptions?.cacheResults ?? false); + // TODO: Should we bother converting all the data if we aren't caching? Meaning it is being requested by an extension? + + const convertItem = convertTimelineItem(uri, internalOptions); return { ...result, source: provider.id, @@ -100,6 +94,10 @@ export class ExtHostTimeline implements IExtHostTimeline { }; }, dispose() { + for (const sourceMap of itemsBySourceAndUriMap.values()) { + sourceMap.get(provider.id)?.clear(); + } + disposable?.dispose(); timelineDisposables.dispose(); } @@ -107,29 +105,28 @@ export class ExtHostTimeline implements IExtHostTimeline { } private convertTimelineItem(source: string, commandConverter: CommandsConverter, disposables: DisposableStore) { - return (uri: URI, cacheResults: boolean) => { - let itemsMap: Map | undefined; - if (cacheResults) { - const uriKey = getUriKey(uri); - - let sourceMap = this._itemsBySourceByUriMap.get(uriKey); - if (sourceMap === undefined) { - sourceMap = new Map(); - this._itemsBySourceByUriMap.set(uriKey, sourceMap); + return (uri: URI, options?: InternalTimelineOptions) => { + let items: Map | undefined; + if (options?.cacheResults) { + let itemsByUri = this._itemsBySourceAndUriMap.get(source); + if (itemsByUri === undefined) { + itemsByUri = new Map(); + this._itemsBySourceAndUriMap.set(source, itemsByUri); } - itemsMap = sourceMap.get(source); - if (itemsMap === undefined) { - itemsMap = new Map(); - sourceMap.set(source, itemsMap); + const uriKey = getUriKey(uri); + items = itemsByUri.get(uriKey); + if (items === undefined) { + items = new Map(); + itemsByUri.set(uriKey, items); } } return (item: vscode.TimelineItem): TimelineItem => { const { iconPath, ...props } = item; - const handle = `${source}|${item.id ?? `${item.timestamp}-${ExtHostTimeline.handlePool++}`}`; - itemsMap?.set(handle, item); + const handle = `${source}|${item.id ?? item.timestamp}`; + items?.set(handle, item); let icon; let iconDark; @@ -161,22 +158,6 @@ export class ExtHostTimeline implements IExtHostTimeline { }; } - private emitTimelineChangeEvent(id: string) { - return (e: vscode.TimelineChangeEvent) => { - // Clear caches - if (e?.uri === undefined) { - for (const sourceMap of this._itemsBySourceByUriMap.values()) { - sourceMap.get(id)?.clear(); - } - } - else { - this._itemsBySourceByUriMap.get(getUriKey(e.uri))?.clear(); - } - - this._proxy.$emitTimelineChangeEvent({ ...e, id: id }); - }; - } - private registerTimelineProviderCore(provider: TimelineProvider): IDisposable { // console.log(`ExtHostTimeline#registerTimelineProvider: id=${provider.id}`); @@ -193,7 +174,7 @@ export class ExtHostTimeline implements IExtHostTimeline { this._providers.set(provider.id, provider); return toDisposable(() => { - for (const sourceMap of this._itemsBySourceByUriMap.values()) { + for (const sourceMap of this._itemsBySourceAndUriMap.values()) { sourceMap.get(provider.id)?.clear(); } diff --git a/src/vs/workbench/contrib/timeline/browser/media/timelinePane.css b/src/vs/workbench/contrib/timeline/browser/media/timelinePane.css index 3b036147cfc..4e6b3c4972a 100644 --- a/src/vs/workbench/contrib/timeline/browser/media/timelinePane.css +++ b/src/vs/workbench/contrib/timeline/browser/media/timelinePane.css @@ -7,9 +7,25 @@ position: relative; } +.monaco-workbench .timeline-view.pane-header .description { + margin-left: 10px; + opacity: 0.6; + text-transform: none; + font-weight: normal; +} + +.monaco-workbench .timeline-view.pane-header:not(.expanded) .description { + display: none; +} + +.monaco-workbench .timeline-view.pane-header .description span.codicon { + font-size: 9px; + margin-left: 2px; +} + .monaco-workbench .timeline-tree-view .message.timeline-subtle { - padding: 10px 22px 0 22px; opacity: 0.5; + padding: 10px 22px 0 22px; position: absolute; pointer-events: none; z-index: 1; diff --git a/src/vs/workbench/contrib/timeline/browser/timelinePane.ts b/src/vs/workbench/contrib/timeline/browser/timelinePane.ts index 29dceaaca3d..031b6f27d11 100644 --- a/src/vs/workbench/contrib/timeline/browser/timelinePane.ts +++ b/src/vs/workbench/contrib/timeline/browser/timelinePane.ts @@ -89,9 +89,10 @@ export class TimelinePane extends ViewPane { static readonly ID = 'timeline'; static readonly TITLE = localize('timeline', 'Timeline'); - private _container!: HTMLElement; - private _messageElement!: HTMLDivElement; - private _treeElement!: HTMLDivElement; + private _$container!: HTMLElement; + private _$message!: HTMLDivElement; + private _$titleDescription!: HTMLSpanElement; + private _$tree!: HTMLDivElement; private _tree!: WorkbenchObjectTree; private _treeRenderer: TimelineTreeRenderer | undefined; private _menus: TimelineMenus; @@ -100,7 +101,6 @@ export class TimelinePane extends ViewPane { private _excludedSources: Set; private _cursorsByProvider: Map = new Map(); private _items: { element: TreeElement }[] = []; - private _loadingMessageTimer: any | undefined; private _pendingRequests = new Map(); private _uri: URI | undefined; @@ -181,6 +181,17 @@ export class TimelinePane extends ViewPane { this.loadTimeline(true); } + + private _titleDescription: string | undefined; + get titleDescription(): string | undefined { + return this._titleDescription; + } + + set titleDescription(description: string | undefined) { + this._titleDescription = description; + this._$titleDescription.textContent = description ?? ''; + } + private _message: string | undefined; get message(): string | undefined { return this._message; @@ -192,7 +203,7 @@ export class TimelinePane extends ViewPane { } private updateMessage(): void { - if (this._message) { + if (this._message !== undefined) { this.showMessage(this._message); } else { this.hideMessage(); @@ -200,35 +211,32 @@ export class TimelinePane extends ViewPane { } private showMessage(message: string): void { - DOM.removeClass(this._messageElement, 'hide'); + DOM.removeClass(this._$message, 'hide'); this.resetMessageElement(); - this._messageElement.textContent = message; + this._$message.textContent = message; } private hideMessage(): void { this.resetMessageElement(); - DOM.addClass(this._messageElement, 'hide'); + DOM.addClass(this._$message, 'hide'); } private resetMessageElement(): void { - DOM.clearNode(this._messageElement); + DOM.clearNode(this._$message); } + private _pendingAnyResults: boolean = false; private async loadTimeline(reset: boolean, sources?: string[], options: TimelineOptions = {}) { const defaultPageSize = reset ? InitialPageSize : SubsequentPageSize; // If we have no source, we are reseting all sources, so cancel everything in flight and reset caches if (sources === undefined) { if (reset) { + this._pendingAnyResults = this._pendingAnyResults || this._items.length !== 0; this._items.length = 0; this._cursorsByProvider.clear(); - if (this._loadingMessageTimer) { - clearTimeout(this._loadingMessageTimer); - this._loadingMessageTimer = undefined; - } - for (const { tokenSource } of this._pendingRequests.values()) { tokenSource.dispose(true); } @@ -237,26 +245,23 @@ export class TimelinePane extends ViewPane { } // TODO[ECA]: Are these the right the list of schemes to exclude? Is there a better way? - if (this._uri && (this._uri.scheme === 'vscode-settings' || this._uri.scheme === 'webview-panel' || this._uri.scheme === 'walkThrough')) { - this.message = localize('timeline.editorCannotProvideTimeline', 'The active editor cannot provide timeline information.'); - this._tree.setChildren(null, undefined); + if (this._uri?.scheme === 'vscode-settings' || this._uri?.scheme === 'webview-panel' || this._uri?.scheme === 'walkThrough') { + this._uri = undefined; + this._items.length = 0; + this.refresh(); return; } - if (reset && this._uri !== undefined) { - this._loadingMessageTimer = setTimeout((uri: URI) => { - if (uri !== this._uri) { - return; - } - - this._tree.setChildren(null, undefined); - this.message = localize('timeline.loading', 'Loading timeline for {0}...', basename(uri.fsPath)); - }, 500, this._uri); + if (!this._pendingAnyResults && this._uri !== undefined) { + this.setLoadingUriMessage(); } } if (this._uri === undefined) { + this._items.length = 0; + this.refresh(); + return; } @@ -284,6 +289,8 @@ export class TimelinePane extends ViewPane { } } + let noRequests = true; + for (const source of filteredSources) { let request = this._pendingRequests.get(source); @@ -303,13 +310,14 @@ export class TimelinePane extends ViewPane { ...options, limit: options.limit === 0 ? undefined : options.limit ?? defaultPageSize }, - request?.tokenSource ?? new CancellationTokenSource(), { cacheResults: true } + request?.tokenSource ?? new CancellationTokenSource(), { cacheResults: true, resetCache: false } )!; if (request === undefined) { continue; } + noRequests = false; this._pendingRequests.set(source, request); if (!reusingToken) { request.tokenSource.token.onCancellationRequested(() => this._pendingRequests.delete(source)); @@ -323,19 +331,24 @@ export class TimelinePane extends ViewPane { ...options, limit: options.limit === 0 ? undefined : (reset ? cursors?.endCursors?.after : undefined) ?? options.limit ?? defaultPageSize }, - new CancellationTokenSource(), { cacheResults: true } + new CancellationTokenSource(), { cacheResults: true, resetCache: true } )!; if (request === undefined) { continue; } + noRequests = false; this._pendingRequests.set(source, request); request.tokenSource.token.onCancellationRequested(() => this._pendingRequests.delete(source)); } this.handleRequest(request); } + + if (noRequests) { + this.refresh(); + } } private async handleRequest(request: TimelineRequest) { @@ -348,13 +361,20 @@ export class TimelinePane extends ViewPane { } if ( - timeline === undefined || request.tokenSource.token.isCancellationRequested || request.uri !== this._uri ) { return; } + if (timeline === undefined) { + if (this._pendingRequests.size === 0) { + this.refresh(); + } + + return; + } + let items: TreeElement[]; const source = request.source; @@ -512,15 +532,19 @@ export class TimelinePane extends ViewPane { } private refresh() { - if (this._loadingMessageTimer) { - clearTimeout(this._loadingMessageTimer); - this._loadingMessageTimer = undefined; - } + this._pendingAnyResults = false; - if (this._items.length === 0) { - this.message = localize('timeline.noTimelineInfo', 'No timeline information was provided.'); - } else { - this.message = undefined; + if (this._uri === undefined) { + this.titleDescription = undefined; + this.message = localize('timeline.editorCannotProvideTimeline', 'The active editor cannot provide timeline information.'); + } + else { + this.titleDescription = basename(this._uri.fsPath); + if (this._items.length === 0) { + this.message = localize('timeline.noTimelineInfo', 'No timeline information was provided.'); + } else { + this.message = undefined; + } } this._tree.setChildren(null, this._items); @@ -555,23 +579,30 @@ export class TimelinePane extends ViewPane { this._tree.layout(height, width); } + protected renderHeaderTitle(container: HTMLElement): void { + super.renderHeaderTitle(container, this.title); + + DOM.addClass(container, 'timeline-view'); + this._$titleDescription = DOM.append(container, DOM.$('span.description', undefined, this.titleDescription ?? '')); + } + protected renderBody(container: HTMLElement): void { - this._container = container; + this._$container = container; DOM.addClasses(container, 'tree-explorer-viewlet-tree-view', 'timeline-tree-view'); - this._messageElement = DOM.append(this._container, DOM.$('.message')); - DOM.addClass(this._messageElement, 'timeline-subtle'); + this._$message = DOM.append(this._$container, DOM.$('.message')); + DOM.addClass(this._$message, 'timeline-subtle'); this.message = localize('timeline.editorCannotProvideTimeline', 'The active editor cannot provide timeline information.'); - this._treeElement = document.createElement('div'); - DOM.addClasses(this._treeElement, 'customview-tree', 'file-icon-themable-tree', 'hide-arrows'); + this._$tree = document.createElement('div'); + DOM.addClasses(this._$tree, 'customview-tree', 'file-icon-themable-tree', 'hide-arrows'); // DOM.addClass(this._treeElement, 'show-file-icons'); - container.appendChild(this._treeElement); + container.appendChild(this._$tree); this._treeRenderer = this.instantiationService.createInstance(TimelineTreeRenderer, this._menus); this._tree = >this.instantiationService.createInstance(WorkbenchObjectTree, 'TimelinePane', - this._treeElement, new TimelineListVirtualDelegate(), [this._treeRenderer], { + this._$tree, new TimelineListVirtualDelegate(), [this._treeRenderer], { identityProvider: new TimelineIdentityProvider(), keyboardNavigationLabelProvider: new TimelineKeyboardNavigationLabelProvider(), overrideStyles: { @@ -583,9 +614,10 @@ export class TimelinePane extends ViewPane { const customTreeNavigator = new TreeResourceNavigator(this._tree, { openOnFocus: false, openOnSelection: false }); this._register(customTreeNavigator); this._register(this._tree.onContextMenu(e => this.onContextMenu(this._menus, e))); + this._register(this._tree.onDidChangeSelection(e => this.ensureValidItems())); this._register( customTreeNavigator.onDidOpenResource(e => { - if (!e.browserEvent) { + if (!e.browserEvent || !this.ensureValidItems()) { return; } @@ -612,6 +644,24 @@ export class TimelinePane extends ViewPane { }) ); } + ensureValidItems() { + if (this._pendingAnyResults) { + this._tree.setChildren(null, undefined); + + this.setLoadingUriMessage(); + + this._pendingAnyResults = false; + return false; + } + + return true; + } + + setLoadingUriMessage() { + const file = this._uri && basename(this._uri.fsPath); + this.titleDescription = file ?? ''; + this.message = file ? localize('timeline.loading', 'Loading timeline for {0}...', file) : ''; + } private onContextMenu(menus: TimelineMenus, treeEvent: ITreeContextMenuEvent): void { const item = treeEvent.element; @@ -623,6 +673,10 @@ export class TimelinePane extends ViewPane { event.preventDefault(); event.stopPropagation(); + if (!this.ensureValidItems()) { + return; + } + this._tree.setFocus([item]); const actions = menus.getResourceContextActions(item); if (!actions.length) { diff --git a/src/vs/workbench/contrib/timeline/common/timeline.ts b/src/vs/workbench/contrib/timeline/common/timeline.ts index 3c5597d21fc..72ca602fa56 100644 --- a/src/vs/workbench/contrib/timeline/common/timeline.ts +++ b/src/vs/workbench/contrib/timeline/common/timeline.ts @@ -43,6 +43,11 @@ export interface TimelineOptions { limit?: number | string; } +export interface InternalTimelineOptions { + cacheResults: boolean; + resetCache: boolean; +} + export interface Timeline { source: string; items: TimelineItem[]; @@ -59,7 +64,7 @@ export interface Timeline { export interface TimelineProvider extends TimelineProviderDescriptor, IDisposable { onDidChange?: Event; - provideTimeline(uri: URI, options: TimelineOptions, token: CancellationToken, internalOptions?: { cacheResults?: boolean }): Promise; + provideTimeline(uri: URI, options: TimelineOptions, token: CancellationToken, internalOptions?: InternalTimelineOptions): Promise; } export interface TimelineProviderDescriptor { @@ -93,7 +98,7 @@ export interface ITimelineService { getSources(): string[]; - getTimeline(id: string, uri: URI, options: TimelineOptions, tokenSource: CancellationTokenSource, internalOptions?: { cacheResults?: boolean }): TimelineRequest | undefined; + getTimeline(id: string, uri: URI, options: TimelineOptions, tokenSource: CancellationTokenSource, internalOptions?: InternalTimelineOptions): TimelineRequest | undefined; // refresh(fetch?: 'all' | 'more'): void; reset(): void; diff --git a/src/vs/workbench/contrib/timeline/common/timelineService.ts b/src/vs/workbench/contrib/timeline/common/timelineService.ts index d017b15245d..4f61ad5ef20 100644 --- a/src/vs/workbench/contrib/timeline/common/timelineService.ts +++ b/src/vs/workbench/contrib/timeline/common/timelineService.ts @@ -9,7 +9,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; // import { basename } from 'vs/base/common/path'; import { URI } from 'vs/base/common/uri'; import { ILogService } from 'vs/platform/log/common/log'; -import { ITimelineService, TimelineChangeEvent, TimelineOptions, TimelineProvidersChangeEvent, TimelineProvider } from './timeline'; +import { ITimelineService, TimelineChangeEvent, TimelineOptions, TimelineProvidersChangeEvent, TimelineProvider, InternalTimelineOptions } from './timeline'; export class TimelineService implements ITimelineService { _serviceBrand: undefined; @@ -27,54 +27,68 @@ export class TimelineService implements ITimelineService { private readonly _providerSubscriptions = new Map(); constructor(@ILogService private readonly logService: ILogService) { + // let source = 'slow-source'; // this.registerTimelineProvider({ - // id: 'local-history', - // label: 'Local History', - // provideTimeline(uri: URI, token: CancellationToken) { + // scheme: '*', + // id: source, + // label: 'Slow Source', + // provideTimeline(uri: URI, options: TimelineOptions, token: CancellationToken, internalOptions?: { cacheResults?: boolean | undefined; }) { // return new Promise(resolve => setTimeout(() => { - // resolve([ - // { - // id: '1', - // label: 'Slow Timeline1', - // description: basename(uri.fsPath), - // timestamp: Date.now(), - // source: 'local-history' - // }, - // { - // id: '2', - // label: 'Slow Timeline2', - // description: basename(uri.fsPath), - // timestamp: new Date(0).getTime(), - // source: 'local-history' - // } - // ]); - // }, 3000)); + // resolve({ + // source: source, + // items: [ + // { + // handle: `${source}|1`, + // id: '1', + // label: 'Slow Timeline1', + // description: basename(uri.fsPath), + // timestamp: Date.now(), + // source: source + // }, + // { + // handle: `${source}|2`, + // id: '2', + // label: 'Slow Timeline2', + // description: basename(uri.fsPath), + // timestamp: new Date(0).getTime(), + // source: source + // } + // ] + // }); + // }, 5000)); // }, // dispose() { } // }); + // source = 'very-slow-source'; // this.registerTimelineProvider({ - // id: 'slow-history', - // label: 'Slow History', - // provideTimeline(uri: URI, token: CancellationToken) { + // scheme: '*', + // id: source, + // label: 'Very Slow Source', + // provideTimeline(uri: URI, options: TimelineOptions, token: CancellationToken, internalOptions?: { cacheResults?: boolean | undefined; }) { // return new Promise(resolve => setTimeout(() => { - // resolve([ - // { - // id: '1', - // label: 'VERY Slow Timeline1', - // description: basename(uri.fsPath), - // timestamp: Date.now(), - // source: 'slow-history' - // }, - // { - // id: '2', - // label: 'VERY Slow Timeline2', - // description: basename(uri.fsPath), - // timestamp: new Date(0).getTime(), - // source: 'slow-history' - // } - // ]); - // }, 6000)); + // resolve({ + // source: source, + // items: [ + // { + // handle: `${source}|1`, + // id: '1', + // label: 'VERY Slow Timeline1', + // description: basename(uri.fsPath), + // timestamp: Date.now(), + // source: source + // }, + // { + // handle: `${source}|2`, + // id: '2', + // label: 'VERY Slow Timeline2', + // description: basename(uri.fsPath), + // timestamp: new Date(0).getTime(), + // source: source + // } + // ] + // }); + // }, 10000)); // }, // dispose() { } // }); @@ -84,7 +98,7 @@ export class TimelineService implements ITimelineService { return [...this._providers.keys()]; } - getTimeline(id: string, uri: URI, options: TimelineOptions, tokenSource: CancellationTokenSource, internalOptions?: { cacheResults?: boolean }) { + getTimeline(id: string, uri: URI, options: TimelineOptions, tokenSource: CancellationTokenSource, internalOptions?: InternalTimelineOptions) { this.logService.trace(`TimelineService#getTimeline(${id}): uri=${uri.toString(true)}`); const provider = this._providers.get(id); From 634522a6ed9df8bb35a3dca4ffa67fd3a0e6a613 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 1 Mar 2020 11:32:18 -0500 Subject: [PATCH 189/235] Fixes #91381 --- extensions/git/src/timelineProvider.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/git/src/timelineProvider.ts b/extensions/git/src/timelineProvider.ts index 3fe8e306c95..1629301b0e3 100644 --- a/extensions/git/src/timelineProvider.ts +++ b/extensions/git/src/timelineProvider.ts @@ -182,7 +182,7 @@ export class GitTimelineProvider implements TimelineProvider { const item = new GitTimelineItem('~', 'HEAD', localize('git.timeline.stagedChanges', 'Staged Changes'), date.getTime(), 'index', 'git:file:index'); // TODO[ECA]: Replace with a better icon -- reflecting its status maybe? item.iconPath = new (ThemeIcon as any)('git-commit'); - item.description = you; + item.description = ''; item.detail = localize('git.timeline.detail', '{0} \u2014 {1}\n{2}\n\n{3}', you, localize('git.index', 'Index'), dateFormatter.format('MMMM Do, YYYY h:mma'), Resource.getStatusText(index.type)); item.command = { title: 'Open Comparison', @@ -201,7 +201,7 @@ export class GitTimelineProvider implements TimelineProvider { const item = new GitTimelineItem('', index ? '~' : 'HEAD', localize('git.timeline.uncommitedChanges', 'Uncommited Changes'), date.getTime(), 'working', 'git:file:working'); // TODO[ECA]: Replace with a better icon -- reflecting its status maybe? item.iconPath = new (ThemeIcon as any)('git-commit'); - item.description = you; + item.description = ''; item.detail = localize('git.timeline.detail', '{0} \u2014 {1}\n{2}\n\n{3}', you, localize('git.workingTree', 'Working Tree'), dateFormatter.format('MMMM Do, YYYY h:mma'), Resource.getStatusText(working.type)); item.command = { title: 'Open Comparison', From a5225d02a83abc25767b1c42c662d5ca5a8ef277 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 1 Mar 2020 11:32:59 -0500 Subject: [PATCH 190/235] Limits schemes for Git timeline provider --- extensions/git/src/timelineProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/git/src/timelineProvider.ts b/extensions/git/src/timelineProvider.ts index 1629301b0e3..c177f8bfcc0 100644 --- a/extensions/git/src/timelineProvider.ts +++ b/extensions/git/src/timelineProvider.ts @@ -80,7 +80,7 @@ export class GitTimelineProvider implements TimelineProvider { constructor(private readonly _model: Model) { this._disposable = Disposable.from( _model.onDidOpenRepository(this.onRepositoriesChanged, this), - workspace.registerTimelineProvider('*', this), + workspace.registerTimelineProvider(['file', 'git', 'gitlens-git'], this), ); } From 215dda4dd9d740f557d28d6229843062ec20509d Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Sun, 1 Mar 2020 22:41:39 +0100 Subject: [PATCH 191/235] Fix #91688 --- .../test/common/synchronizer.test.ts | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 src/vs/platform/userDataSync/test/common/synchronizer.test.ts diff --git a/src/vs/platform/userDataSync/test/common/synchronizer.test.ts b/src/vs/platform/userDataSync/test/common/synchronizer.test.ts new file mode 100644 index 00000000000..59a69aad7f8 --- /dev/null +++ b/src/vs/platform/userDataSync/test/common/synchronizer.test.ts @@ -0,0 +1,82 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { ResourceKey, IUserDataSyncStoreService, SyncSource, SyncStatus } from 'vs/platform/userDataSync/common/userDataSync'; +import { UserDataSyncClient, UserDataSyncTestServer } from 'vs/platform/userDataSync/test/common/userDataSyncClient'; +import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; +import { AbstractSynchroniser, IRemoteUserData } from 'vs/platform/userDataSync/common/abstractSynchronizer'; +import { Barrier } from 'vs/base/common/async'; +import { Emitter } from 'vs/base/common/event'; + +class TestSynchroniser extends AbstractSynchroniser { + + syncBarrier: Barrier = new Barrier(); + onDoSyncCall: Emitter = this._register(new Emitter()); + + readonly resourceKey: ResourceKey = 'settings'; + protected readonly version: number = 1; + + protected async doSync(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null): Promise { + try { + this.onDoSyncCall.fire(); + await this.syncBarrier.wait(); + const ref = await this.updateRemote(remoteUserData.ref); + await this.updateLastSyncUserData({ ref, syncData: { content: '', version: this.version } }); + } finally { + this.setStatus(SyncStatus.Idle); + } + } + + async updateRemote(ref: string): Promise { + return this.userDataSyncStoreService.write(this.resourceKey, '', ref); + } + +} + +suite('TestSynchronizer', () => { + + const disposableStore = new DisposableStore(); + const server = new UserDataSyncTestServer(); + let client: UserDataSyncClient; + let userDataSyncStoreService: IUserDataSyncStoreService; + + setup(async () => { + client = disposableStore.add(new UserDataSyncClient(server)); + await client.setUp(); + userDataSyncStoreService = client.instantiationService.get(IUserDataSyncStoreService); + disposableStore.add(toDisposable(() => userDataSyncStoreService.clear())); + }); + + teardown(() => disposableStore.clear()); + + test('request latest data on precondition failure', async () => { + const testObject: TestSynchroniser = client.instantiationService.createInstance(TestSynchroniser, SyncSource.Settings); + // Sync once + testObject.syncBarrier.open(); + await testObject.sync(); + testObject.syncBarrier = new Barrier(); + + // update remote data before syncing so that 412 is thrown by server + const disposable = testObject.onDoSyncCall.event(async () => { + disposable.dispose(); + await testObject.updateRemote(ref); + server.reset(); + testObject.syncBarrier.open(); + }); + + // Start sycing + const { ref } = await userDataSyncStoreService.read(testObject.resourceKey, null); + await testObject.sync(ref); + + assert.deepEqual(server.requests, [ + { type: 'POST', url: `${server.url}/v1/resource/${testObject.resourceKey}`, headers: { 'If-Match': ref } }, + { type: 'GET', url: `${server.url}/v1/resource/${testObject.resourceKey}/latest`, headers: {} }, + { type: 'POST', url: `${server.url}/v1/resource/${testObject.resourceKey}`, headers: { 'If-Match': `${parseInt(ref) + 1}` } }, + ]); + }); + + +}); From bc760053cb7da01a983b4e850854f6c7e8c6c773 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 2 Mar 2020 09:25:26 +0100 Subject: [PATCH 192/235] minor: Documentation copypasta bug. Fixes #91772 --- src/vs/editor/common/modes.ts | 4 ++-- src/vs/monaco.d.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index b93301c609d..c61f4c8e6c3 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -1246,11 +1246,11 @@ export interface SelectionRangeProvider { export interface FoldingContext { } /** - * A provider of colors for editor models. + * A provider of folding ranges for editor models. */ export interface FoldingRangeProvider { /** - * Provides the color ranges for a specific model. + * Provides the folding ranges for a specific model. */ provideFoldingRanges(model: model.ITextModel, context: FoldingContext, token: CancellationToken): ProviderResult; } diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 543ac0ca086..4ce96401a9f 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -6040,7 +6040,7 @@ declare namespace monaco.languages { */ export interface FoldingRangeProvider { /** - * Provides the color ranges for a specific model. + * Provides the folding ranges for a specific model. */ provideFoldingRanges(model: editor.ITextModel, context: FoldingContext, token: CancellationToken): ProviderResult; } From 89b4f048c7aa292932e73d4fead1daf17e9f3ee4 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 2 Mar 2020 09:44:01 +0100 Subject: [PATCH 193/235] fix tests (#91859) --- .../electron-browser/diskFileService.test.ts | 4 +- .../electron-browser/backupTracker.test.ts | 49 ++++++------------- 2 files changed, 18 insertions(+), 35 deletions(-) diff --git a/src/vs/platform/files/test/electron-browser/diskFileService.test.ts b/src/vs/platform/files/test/electron-browser/diskFileService.test.ts index 1eff57b01fd..b0af12007e7 100644 --- a/src/vs/platform/files/test/electron-browser/diskFileService.test.ts +++ b/src/vs/platform/files/test/electron-browser/diskFileService.test.ts @@ -463,7 +463,7 @@ suite('Disk File Service', function () { return testDeleteFile(false); }); - test('deleteFile (useTrash)', async () => { + (isLinux /* trash is unreliable on Linux */ ? test.skip : test)('deleteFile (useTrash)', async () => { return testDeleteFile(true); }); @@ -543,7 +543,7 @@ suite('Disk File Service', function () { return testDeleteFolderRecursive(false); }); - test('deleteFolder (recursive, useTrash)', async () => { + (isLinux /* trash is unreliable on Linux */ ? test.skip : test)('deleteFolder (recursive, useTrash)', async () => { return testDeleteFolderRecursive(true); }); diff --git a/src/vs/workbench/contrib/backup/test/electron-browser/backupTracker.test.ts b/src/vs/workbench/contrib/backup/test/electron-browser/backupTracker.test.ts index d602adb338f..b3d66ede005 100644 --- a/src/vs/workbench/contrib/backup/test/electron-browser/backupTracker.test.ts +++ b/src/vs/workbench/contrib/backup/test/electron-browser/backupTracker.test.ts @@ -215,7 +215,7 @@ suite('BackupTracker', () => { tracker.dispose(); }); - test('confirm onWillShutdown - no veto', async function () { + test('onWillShutdown - no veto if no dirty files', async function () { const [accessor, part, tracker] = await createTracker(); const resource = toResource.call(this, '/path/index.txt'); @@ -224,18 +224,14 @@ suite('BackupTracker', () => { const event = new BeforeShutdownEventImpl(); accessor.lifecycleService.fireWillShutdown(event); - const veto = event.value; - if (typeof veto === 'boolean') { - assert.ok(!veto); - } else { - assert.ok(!(await veto)); - } + const veto = await event.value; + assert.ok(!veto); part.dispose(); tracker.dispose(); }); - test.skip('confirm onWillShutdown - veto if user cancels', async function () { + test('onWillShutdown - veto if user cancels (hot.exit: off)', async function () { const [accessor, part, tracker] = await createTracker(); const resource = toResource.call(this, '/path/index.txt'); @@ -244,6 +240,7 @@ suite('BackupTracker', () => { const model = accessor.textFileService.files.get(resource); accessor.fileDialogService.setConfirmResult(ConfirmResult.CANCEL); + accessor.filesConfigurationService.onFilesConfigurationChange({ files: { hotExit: 'off' } }); await model?.load(); model?.textEditorModel?.setValue('foo'); @@ -252,12 +249,8 @@ suite('BackupTracker', () => { const event = new BeforeShutdownEventImpl(); accessor.lifecycleService.fireWillShutdown(event); - const veto = event.value; - if (typeof veto === 'boolean') { - assert.ok(veto); - } else { - assert.ok((await veto)); - } + const veto = await event.value; + assert.ok(veto); part.dispose(); tracker.dispose(); @@ -278,12 +271,8 @@ suite('BackupTracker', () => { const event = new BeforeShutdownEventImpl(); accessor.lifecycleService.fireWillShutdown(event); - const veto = event.value; - if (typeof veto === 'boolean') { - assert.ok(!veto); - } else { - assert.ok(!(await veto)); - } + const veto = await event.value; + assert.ok(!veto); assert.equal(accessor.workingCopyService.dirtyCount, 0); @@ -291,7 +280,7 @@ suite('BackupTracker', () => { tracker.dispose(); }); - test('confirm onWillShutdown - no veto and backups cleaned up if user does not want to save (hot.exit: off)', async function () { + test('onWillShutdown - no veto and backups cleaned up if user does not want to save (hot.exit: off)', async function () { const [accessor, part, tracker] = await createTracker(); const resource = toResource.call(this, '/path/index.txt'); @@ -308,21 +297,15 @@ suite('BackupTracker', () => { const event = new BeforeShutdownEventImpl(); accessor.lifecycleService.fireWillShutdown(event); - let veto = event.value; - if (typeof veto === 'boolean') { - assert.ok(accessor.backupFileService.discardedBackups.length > 0); - assert.ok(!veto); - } else { - veto = await veto; - assert.ok(accessor.backupFileService.discardedBackups.length > 0); - assert.ok(!veto); - } + const veto = await event.value; + assert.ok(!veto); + assert.ok(accessor.backupFileService.discardedBackups.length > 0); part.dispose(); tracker.dispose(); }); - test('confirm onWillShutdown - save (hot.exit: off)', async function () { + test('onWillShutdown - save (hot.exit: off)', async function () { const [accessor, part, tracker] = await createTracker(); const resource = toResource.call(this, '/path/index.txt'); @@ -339,7 +322,7 @@ suite('BackupTracker', () => { const event = new BeforeShutdownEventImpl(); accessor.lifecycleService.fireWillShutdown(event); - const veto = await (>event.value); + const veto = await event.value; assert.ok(!veto); assert.ok(!model?.isDirty()); @@ -482,7 +465,7 @@ suite('BackupTracker', () => { event.reason = shutdownReason; accessor.lifecycleService.fireWillShutdown(event); - const veto = await (>event.value); + const veto = await event.value; assert.equal(accessor.backupFileService.discardedBackups.length, 0); // When hot exit is set, backups should never be cleaned since the confirm result is cancel assert.equal(veto, shouldVeto); From 6801e4c6736f25ac3302dcb2c1fdbaa43a65af34 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 2 Mar 2020 09:47:12 +0100 Subject: [PATCH 194/235] debt - less explicit any --- src/vs/base/browser/touch.ts | 2 +- src/vs/base/browser/ui/dropdown/dropdown.ts | 6 +++--- src/vs/base/browser/ui/menu/menu.ts | 6 +++--- src/vs/base/common/cancellation.ts | 2 +- src/vs/base/common/errorsWithActions.ts | 2 +- src/vs/base/common/functional.ts | 8 ++++---- src/vs/base/common/lazy.ts | 2 +- src/vs/base/common/lifecycle.ts | 7 +++---- src/vs/base/common/normalization.ts | 2 +- src/vs/base/common/strings.ts | 7 ++++--- src/vs/monaco.d.ts | 2 +- 11 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/vs/base/browser/touch.ts b/src/vs/base/browser/touch.ts index 8eb1262df1f..9cf55c77875 100644 --- a/src/vs/base/browser/touch.ts +++ b/src/vs/base/browser/touch.ts @@ -247,7 +247,7 @@ export class Gesture extends Disposable { } private newGestureEvent(type: string, initialTarget?: EventTarget): GestureEvent { - let event = (document.createEvent('CustomEvent')); + let event = document.createEvent('CustomEvent') as unknown as GestureEvent; event.initEvent(type, false, true); event.initialTarget = initialTarget; event.tapCount = 0; diff --git a/src/vs/base/browser/ui/dropdown/dropdown.ts b/src/vs/base/browser/ui/dropdown/dropdown.ts index c36015f710b..f54d01606cb 100644 --- a/src/vs/base/browser/ui/dropdown/dropdown.ts +++ b/src/vs/base/browser/ui/dropdown/dropdown.ts @@ -271,7 +271,7 @@ export class DropdownMenu extends BaseDropdown { } export class DropdownMenuActionViewItem extends BaseActionViewItem { - private menuActionsOrProvider: any; + private menuActionsOrProvider: ReadonlyArray | IActionProvider; private dropdownMenu: DropdownMenu | undefined; private contextMenuProvider: IContextMenuProvider; private actionViewItemProvider?: IActionViewItemProvider; @@ -317,7 +317,7 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem { if (Array.isArray(this.menuActionsOrProvider)) { options.actions = this.menuActionsOrProvider; } else { - options.actionProvider = this.menuActionsOrProvider; + options.actionProvider = this.menuActionsOrProvider as IActionProvider; } this.dropdownMenu = this._register(new DropdownMenu(container, options)); @@ -341,7 +341,7 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem { } } - setActionContext(newContext: any): void { + setActionContext(newContext: unknown): void { super.setActionContext(newContext); if (this.dropdownMenu) { diff --git a/src/vs/base/browser/ui/menu/menu.ts b/src/vs/base/browser/ui/menu/menu.ts index 0adbfe23b90..3c85a375813 100644 --- a/src/vs/base/browser/ui/menu/menu.ts +++ b/src/vs/base/browser/ui/menu/menu.ts @@ -6,7 +6,7 @@ import 'vs/css!./menu'; import * as nls from 'vs/nls'; import * as strings from 'vs/base/common/strings'; -import { IActionRunner, IAction, Action, IActionViewItem } from 'vs/base/common/actions'; +import { IActionRunner, IAction, Action } from 'vs/base/common/actions'; import { ActionBar, IActionViewItemProvider, ActionsOrientation, Separator, ActionViewItem, IActionViewItemOptions, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { ResolvedKeybinding, KeyCode } from 'vs/base/common/keyCodes'; import { addClass, EventType, EventHelper, EventLike, removeTabIndexAndUpdateFocus, isAncestor, hasClass, addDisposableListener, removeClass, append, $, addClasses, removeClasses, clearNode } from 'vs/base/browser/dom'; @@ -205,7 +205,7 @@ export class Menu extends ActionBar { container.appendChild(this.scrollableElement.getDomNode()); this.scrollableElement.scanDomNode(); - this.viewItems.filter(item => !(item instanceof MenuSeparatorActionViewItem)).forEach((item: IActionViewItem, index: number, array: any[]) => { + this.viewItems.filter(item => !(item instanceof MenuSeparatorActionViewItem)).forEach((item, index, array) => { (item as BaseMenuActionViewItem).updatePositionInSet(index + 1, array.length); }); } @@ -363,7 +363,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem { private cssClass: string; protected menuStyle: IMenuStyles | undefined; - constructor(ctx: any, action: IAction, options: IMenuItemOptions = {}) { + constructor(ctx: unknown, action: IAction, options: IMenuItemOptions = {}) { options.isMenu = true; super(action, action, options); diff --git a/src/vs/base/common/cancellation.ts b/src/vs/base/common/cancellation.ts index 75b615de669..cb8c8c6da2d 100644 --- a/src/vs/base/common/cancellation.ts +++ b/src/vs/base/common/cancellation.ts @@ -31,7 +31,7 @@ const shortcutEvent: Event = Object.freeze(function (callback, context?): I export namespace CancellationToken { - export function isCancellationToken(thing: any): thing is CancellationToken { + export function isCancellationToken(thing: unknown): thing is CancellationToken { if (thing === CancellationToken.None || thing === CancellationToken.Cancelled) { return true; } diff --git a/src/vs/base/common/errorsWithActions.ts b/src/vs/base/common/errorsWithActions.ts index 133febb8453..fa92b7f4526 100644 --- a/src/vs/base/common/errorsWithActions.ts +++ b/src/vs/base/common/errorsWithActions.ts @@ -13,7 +13,7 @@ export interface IErrorWithActions { actions?: ReadonlyArray; } -export function isErrorWithActions(obj: any): obj is IErrorWithActions { +export function isErrorWithActions(obj: unknown): obj is IErrorWithActions { return obj instanceof Error && Array.isArray((obj as IErrorWithActions).actions); } diff --git a/src/vs/base/common/functional.ts b/src/vs/base/common/functional.ts index 4587a5b7542..b437cc98c46 100644 --- a/src/vs/base/common/functional.ts +++ b/src/vs/base/common/functional.ts @@ -3,10 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -export function once(this: any, fn: T): T { +export function once(this: unknown, fn: T): T { const _this = this; let didCall = false; - let result: any; + let result: unknown; return function () { if (didCall) { @@ -17,5 +17,5 @@ export function once(this: any, fn: T): T { result = fn.apply(_this, arguments); return result; - } as any as T; -} \ No newline at end of file + } as unknown as T; +} diff --git a/src/vs/base/common/lazy.ts b/src/vs/base/common/lazy.ts index 7f1bef48d65..ce6339106ef 100644 --- a/src/vs/base/common/lazy.ts +++ b/src/vs/base/common/lazy.ts @@ -21,7 +21,7 @@ export class Lazy { private _didRun: boolean = false; private _value?: T; - private _error: any; + private _error: Error | undefined; constructor( private readonly executor: () => T, diff --git a/src/vs/base/common/lifecycle.ts b/src/vs/base/common/lifecycle.ts index a99fc45bd50..7394eab4ce0 100644 --- a/src/vs/base/common/lifecycle.ts +++ b/src/vs/base/common/lifecycle.ts @@ -49,8 +49,7 @@ export interface IDisposable { } export function isDisposable(thing: E): thing is E & IDisposable { - return typeof (thing).dispose === 'function' - && (thing).dispose.length === 0; + return typeof (thing).dispose === 'function' && (thing).dispose.length === 0; } export function dispose(disposable: T): T; @@ -124,7 +123,7 @@ export class DisposableStore implements IDisposable { if (!t) { return t; } - if ((t as any as DisposableStore) === this) { + if ((t as unknown as DisposableStore) === this) { throw new Error('Cannot register a disposable on itself!'); } @@ -158,7 +157,7 @@ export abstract class Disposable implements IDisposable { } protected _register(t: T): T { - if ((t as any as Disposable) === this) { + if ((t as unknown as Disposable) === this) { throw new Error('Cannot register a disposable on itself!'); } return this._store.add(t); diff --git a/src/vs/base/common/normalization.ts b/src/vs/base/common/normalization.ts index b6304df31a0..9438f72b5ba 100644 --- a/src/vs/base/common/normalization.ts +++ b/src/vs/base/common/normalization.ts @@ -11,7 +11,7 @@ import { LRUCache } from 'vs/base/common/map'; * * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize} */ -export const canNormalize = typeof (('').normalize) === 'function'; +export const canNormalize = typeof (String.prototype as any /* standalone editor compilation */).normalize === 'function'; const nfcCache = new LRUCache(10000); // bounded to 10000 elements export function normalizeNFC(str: string): string { diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index 4857a4896c2..fd7df3e4ee2 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -5,6 +5,7 @@ import { CharCode } from 'vs/base/common/charCode'; import { Constants } from 'vs/base/common/uint'; +import { canNormalize, normalizeNFD } from 'vs/base/common/normalization'; export function isFalsyOrWhitespace(str: string | undefined): boolean { if (!str || typeof str !== 'string') { @@ -853,15 +854,15 @@ export function removeAnsiEscapeCodes(str: string): string { } export const removeAccents: (str: string) => string = (function () { - if (typeof (String.prototype as any /* standalone editor compilation */).normalize !== 'function') { - // ☹️ no ES6 features... + if (!canNormalize) { + // no ES6 features... return function (str: string) { return str; }; } else { // transform into NFD form and remove accents // see: https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript/37511463#37511463 const regex = /[\u0300-\u036f]/g; return function (str: string) { - return (str as any /* standalone editor compilation */).normalize('NFD').replace(regex, ''); + return normalizeNFD(str).replace(regex, ''); }; } })(); diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 4ce96401a9f..e740dbc105e 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -6036,7 +6036,7 @@ declare namespace monaco.languages { } /** - * A provider of colors for editor models. + * A provider of folding ranges for editor models. */ export interface FoldingRangeProvider { /** From e44c50ba93773d92d93487a25e2273b3d73afb07 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 2 Mar 2020 09:49:06 +0100 Subject: [PATCH 195/235] progress - reuse status entry if it exists --- .../progress/browser/progressService.ts | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/services/progress/browser/progressService.ts b/src/vs/workbench/services/progress/browser/progressService.ts index 3cdea6762a5..b96b974ea2d 100644 --- a/src/vs/workbench/services/progress/browser/progressService.ts +++ b/src/vs/workbench/services/progress/browser/progressService.ts @@ -6,10 +6,10 @@ import 'vs/css!./media/progressService'; import { localize } from 'vs/nls'; -import { IDisposable, dispose, DisposableStore, MutableDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, DisposableStore, Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { IProgressService, IProgressOptions, IProgressStep, ProgressLocation, IProgress, Progress, IProgressCompositeOptions, IProgressNotificationOptions, IProgressRunner, IProgressIndicator, IProgressWindowOptions } from 'vs/platform/progress/common/progress'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { StatusbarAlignment, IStatusbarService } from 'vs/workbench/services/statusbar/common/statusbar'; +import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar'; import { timeout } from 'vs/base/common/async'; import { ProgressBadge, IActivityService } from 'vs/workbench/services/activity/common/activity'; import { INotificationService, Severity, INotificationHandle } from 'vs/platform/notification/common/notification'; @@ -30,9 +30,6 @@ export class ProgressService extends Disposable implements IProgressService { _serviceBrand: undefined; - private readonly stack: [IProgressOptions, Progress][] = []; - private readonly globalStatusEntry = this._register(new MutableDisposable()); - constructor( @IActivityService private readonly activityService: IActivityService, @IViewletService private readonly viewletService: IViewletService, @@ -78,6 +75,9 @@ export class ProgressService extends Disposable implements IProgressService { } } + private readonly windowProgressStack: [IProgressOptions, Progress][] = []; + private windowProgressStatusEntry: IStatusbarEntryAccessor | undefined = undefined; + private withWindowProgress(options: IProgressWindowOptions, callback: (progress: IProgress<{ message?: string }>) => Promise): Promise { const task: [IProgressWindowOptions, Progress] = [options, new Progress(() => this.updateWindowProgress())]; @@ -85,7 +85,7 @@ export class ProgressService extends Disposable implements IProgressService { let delayHandle: any = setTimeout(() => { delayHandle = undefined; - this.stack.unshift(task); + this.windowProgressStack.unshift(task); this.updateWindowProgress(); // show progress for at least 150ms @@ -93,8 +93,8 @@ export class ProgressService extends Disposable implements IProgressService { timeout(150), promise ]).finally(() => { - const idx = this.stack.indexOf(task); - this.stack.splice(idx, 1); + const idx = this.windowProgressStack.indexOf(task); + this.windowProgressStack.splice(idx, 1); this.updateWindowProgress(); }); }, 150); @@ -104,10 +104,10 @@ export class ProgressService extends Disposable implements IProgressService { } private updateWindowProgress(idx: number = 0) { - this.globalStatusEntry.clear(); - if (idx < this.stack.length) { - const [options, progress] = this.stack[idx]; + // We still have progress to show + if (idx < this.windowProgressStack.length) { + const [options, progress] = this.windowProgressStack[idx]; let progressTitle = options.title; let progressMessage = progress.value && progress.value.message; @@ -136,11 +136,23 @@ export class ProgressService extends Disposable implements IProgressService { return; } - this.globalStatusEntry.value = this.statusbarService.addEntry({ + const statusEntryProperties: IStatusbarEntry = { text: `$(sync~spin) ${text}`, tooltip: title, command: progressCommand - }, 'status.progress', localize('status.progress', "Progress Message"), StatusbarAlignment.LEFT); + }; + + if (this.windowProgressStatusEntry) { + this.windowProgressStatusEntry.update(statusEntryProperties); + } else { + this.windowProgressStatusEntry = this.statusbarService.addEntry(statusEntryProperties, 'status.progress', localize('status.progress', "Progress Message"), StatusbarAlignment.LEFT); + } + } + + // Progress is done so we remove the status entry + else { + this.windowProgressStatusEntry?.dispose(); + this.windowProgressStatusEntry = undefined; } } From 6f7c9f38b6ab8b0d8ea5cf4fb7eb89f63863e22d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 2 Mar 2020 10:22:38 +0100 Subject: [PATCH 196/235] Notifications: Updating message recreates notification (drops progress bar) (fix #50931) --- src/vs/base/browser/ui/list/listWidget.ts | 4 + .../notifications/notificationsAlerts.ts | 8 +- .../notifications/notificationsCenter.ts | 20 ++++- .../parts/notifications/notificationsList.ts | 15 +++- .../notifications/notificationsToasts.ts | 25 +++--- .../notifications/notificationsViewer.ts | 22 +++--- src/vs/workbench/common/notifications.ts | 76 +++++++++++-------- .../test/common/notifications.test.ts | 36 ++++++--- 8 files changed, 139 insertions(+), 67 deletions(-) diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 29263345a5e..b37c69e125a 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -1310,6 +1310,10 @@ export class List implements ISpliceable, IDisposable { this.view.updateWidth(index); } + updateElementHeight(index: number, size: number): void { + this.view.updateElementHeight(index, size); + } + rerender(): void { this.view.rerender(); } diff --git a/src/vs/workbench/browser/parts/notifications/notificationsAlerts.ts b/src/vs/workbench/browser/parts/notifications/notificationsAlerts.ts index 22b683d8c68..86bf82ce942 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsAlerts.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsAlerts.ts @@ -5,7 +5,7 @@ import { alert } from 'vs/base/browser/ui/aria/aria'; import { localize } from 'vs/nls'; -import { INotificationViewItem, INotificationsModel, NotificationChangeType, INotificationChangeEvent, NotificationViewItemLabelKind } from 'vs/workbench/common/notifications'; +import { INotificationViewItem, INotificationsModel, NotificationChangeType, INotificationChangeEvent, NotificationViewItemContentChangeKind } from 'vs/workbench/common/notifications'; import { Disposable } from 'vs/base/common/lifecycle'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { Severity } from 'vs/platform/notification/common/notification'; @@ -45,9 +45,9 @@ export class NotificationsAlerts extends Disposable { private triggerAriaAlert(notifiation: INotificationViewItem): void { - // Trigger the alert again whenever the label changes - const listener = notifiation.onDidChangeLabel(e => { - if (e.kind === NotificationViewItemLabelKind.MESSAGE) { + // Trigger the alert again whenever the message changes + const listener = notifiation.onDidChangeContent(e => { + if (e.kind === NotificationViewItemContentChangeKind.MESSAGE) { this.doTriggerAriaAlert(notifiation); } }); diff --git a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts index c37af327a36..c99f963b2af 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts @@ -7,7 +7,7 @@ import 'vs/css!./media/notificationsCenter'; import 'vs/css!./media/notificationsActions'; import { Themable, NOTIFICATIONS_BORDER, NOTIFICATIONS_CENTER_HEADER_FOREGROUND, NOTIFICATIONS_CENTER_HEADER_BACKGROUND, NOTIFICATIONS_CENTER_BORDER } from 'vs/workbench/common/theme'; import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; -import { INotificationsModel, INotificationChangeEvent, NotificationChangeType } from 'vs/workbench/common/notifications'; +import { INotificationsModel, INotificationChangeEvent, NotificationChangeType, NotificationViewItemContentChangeKind } from 'vs/workbench/common/notifications'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { Emitter } from 'vs/base/common/event'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -177,7 +177,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente let focusEditor = false; - // Update notifications list based on event + // Update notifications list based on event kind const [notificationsList, notificationsCenterContainer] = assertAllDefined(this.notificationsList, this.notificationsCenterContainer); switch (e.kind) { case NotificationChangeType.ADD: @@ -185,6 +185,22 @@ export class NotificationsCenter extends Themable implements INotificationsCente e.item.updateVisibility(true); break; case NotificationChangeType.CHANGE: + // Handle content changes + // - actions: re-draw to properly show them + // - message: update notification height unless collapsed + switch (e.detail) { + case NotificationViewItemContentChangeKind.ACTIONS: + notificationsList.updateNotificationsList(e.index, 1, [e.item]); + break; + case NotificationViewItemContentChangeKind.MESSAGE: + if (e.item.expanded) { + notificationsList.updateNotificationHeight(e.item); + } + break; + } + break; + case NotificationChangeType.EXPAND_COLLAPSE: + // Re-draw entire item when expansion changes to reveal or hide details notificationsList.updateNotificationsList(e.index, 1, [e.item]); break; case NotificationChangeType.REMOVE: diff --git a/src/vs/workbench/browser/parts/notifications/notificationsList.ts b/src/vs/workbench/browser/parts/notifications/notificationsList.ts index 2d585698cb9..64085073bb4 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsList.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsList.ts @@ -21,6 +21,7 @@ import { assertIsDefined, assertAllDefined } from 'vs/base/common/types'; export class NotificationsList extends Themable { private listContainer: HTMLElement | undefined; private list: WorkbenchList | undefined; + private listDelegate: NotificationsListDelegate | undefined; private viewModel: INotificationViewItem[]; private isVisible: boolean | undefined; @@ -73,11 +74,12 @@ export class NotificationsList extends Themable { const renderer = this.instantiationService.createInstance(NotificationRenderer, actionRunner); // List + const listDelegate = this.listDelegate = new NotificationsListDelegate(this.listContainer); const list = this.list = >this._register(this.instantiationService.createInstance( WorkbenchList, 'NotificationsList', this.listContainer, - new NotificationsListDelegate(this.listContainer), + listDelegate, [renderer], { ...this.options, @@ -186,6 +188,17 @@ export class NotificationsList extends Themable { } } + updateNotificationHeight(item: INotificationViewItem): void { + const index = this.viewModel.indexOf(item); + if (index === -1) { + return; + } + + const [list, listDelegate] = assertAllDefined(this.list, this.listDelegate); + list.updateElementHeight(index, listDelegate.getHeight(item)); + list.layout(); + } + hide(): void { if (!this.isVisible || !this.list) { return; // already hidden diff --git a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts index ecee706fcb9..090488b31b0 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/notificationsToasts'; -import { INotificationsModel, NotificationChangeType, INotificationChangeEvent, INotificationViewItem, NotificationViewItemLabelKind } from 'vs/workbench/common/notifications'; +import { INotificationsModel, NotificationChangeType, INotificationChangeEvent, INotificationViewItem, NotificationViewItemContentChangeKind } from 'vs/workbench/common/notifications'; import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { addClass, removeClass, isAncestor, addDisposableListener, EventType, Dimension } from 'vs/base/browser/dom'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -196,19 +196,24 @@ export class NotificationsToasts extends Themable implements INotificationsToast // the height computation takes the content of it into account! this.layoutContainer(maxDimensions.height); - // Update when item height changes due to expansion + // Re-draw entire item when expansion changes to reveal or hide details itemDisposables.add(item.onDidChangeExpansion(() => { notificationList.updateNotificationsList(0, 1, [item]); })); - // Update when item height potentially changes due to label changes - itemDisposables.add(item.onDidChangeLabel(e => { - if (!item.expanded) { - return; // dynamic height only applies to expanded notifications - } - - if (e.kind === NotificationViewItemLabelKind.ACTIONS || e.kind === NotificationViewItemLabelKind.MESSAGE) { - notificationList.updateNotificationsList(0, 1, [item]); + // Handle content changes + // - actions: re-draw to properly show them + // - message: update notification height unless collapsed + itemDisposables.add(item.onDidChangeContent(e => { + switch (e.kind) { + case NotificationViewItemContentChangeKind.ACTIONS: + notificationList.updateNotificationsList(0, 1, [item]); + break; + case NotificationViewItemContentChangeKind.MESSAGE: + if (item.expanded) { + notificationList.updateNotificationHeight(item); + } + break; } })); diff --git a/src/vs/workbench/browser/parts/notifications/notificationsViewer.ts b/src/vs/workbench/browser/parts/notifications/notificationsViewer.ts index 41063188c35..19cd1f14f2b 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsViewer.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsViewer.ts @@ -17,7 +17,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { dispose, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdown'; -import { INotificationViewItem, NotificationViewItem, NotificationViewItemLabelKind, INotificationMessage, ChoiceAction } from 'vs/workbench/common/notifications'; +import { INotificationViewItem, NotificationViewItem, NotificationViewItemContentChangeKind, INotificationMessage, ChoiceAction } from 'vs/workbench/common/notifications'; import { ClearNotificationAction, ExpandNotificationAction, CollapseNotificationAction, ConfigureNotificationAction } from 'vs/workbench/browser/parts/notifications/notificationsActions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; @@ -46,14 +46,13 @@ export class NotificationsListDelegate implements IListVirtualDelegate { + // Label Change Events that we can handle directly + // (changes to actions require an entire redraw of + // the notification because it has an impact on + // epxansion state) + this.inputDisposables.add(notification.onDidChangeContent(event => { switch (event.kind) { - case NotificationViewItemLabelKind.SEVERITY: + case NotificationViewItemContentChangeKind.SEVERITY: this.renderSeverity(notification); break; - case NotificationViewItemLabelKind.PROGRESS: + case NotificationViewItemContentChangeKind.PROGRESS: this.renderProgress(notification); break; - case NotificationViewItemLabelKind.MESSAGE: + case NotificationViewItemContentChangeKind.MESSAGE: this.renderMessage(notification); break; } diff --git a/src/vs/workbench/common/notifications.ts b/src/vs/workbench/common/notifications.ts index 809037bf68e..425fe84ebea 100644 --- a/src/vs/workbench/common/notifications.ts +++ b/src/vs/workbench/common/notifications.ts @@ -41,8 +41,26 @@ export interface INotificationsModel { } export const enum NotificationChangeType { + + /** + * A notification was added. + */ ADD, + + /** + * A notification changed. Check `detail` property + * on the event for additional information. + */ CHANGE, + + /** + * A notification expanded or collapsed. + */ + EXPAND_COLLAPSE, + + /** + * A notification was removed. + */ REMOVE } @@ -62,6 +80,12 @@ export interface INotificationChangeEvent { * The kind of notification change. */ kind: NotificationChangeType; + + /** + * Additional detail about the item change. Only applies to + * `NotificationChangeType.CHANGE`. + */ + detail?: NotificationViewItemContentChangeKind } export const enum StatusMessageChangeType { @@ -206,26 +230,19 @@ export class NotificationsModel extends Disposable implements INotificationsMode } // Item Events - const onItemChangeEvent = () => { + const fireNotificationChangeEvent = (kind: NotificationChangeType, detail?: NotificationViewItemContentChangeKind) => { const index = this._notifications.indexOf(item); if (index >= 0) { - this._onDidChangeNotification.fire({ item, index, kind: NotificationChangeType.CHANGE }); + this._onDidChangeNotification.fire({ item, index, kind, detail }); } }; - const itemExpansionChangeListener = item.onDidChangeExpansion(() => onItemChangeEvent()); - - const itemLabelChangeListener = item.onDidChangeLabel(e => { - // a label change in the area of actions or the message is a change that potentially has an impact - // on the size of the notification and as such we emit a change event so that viewers can redraw - if (e.kind === NotificationViewItemLabelKind.ACTIONS || e.kind === NotificationViewItemLabelKind.MESSAGE) { - onItemChangeEvent(); - } - }); + const itemExpansionChangeListener = item.onDidChangeExpansion(() => fireNotificationChangeEvent(NotificationChangeType.EXPAND_COLLAPSE)); + const itemContentChangeListener = item.onDidChangeContent(e => fireNotificationChangeEvent(NotificationChangeType.CHANGE, e.kind)); Event.once(item.onDidClose)(() => { itemExpansionChangeListener.dispose(); - itemLabelChangeListener.dispose(); + itemContentChangeListener.dispose(); const index = this._notifications.indexOf(item); if (index >= 0) { @@ -272,9 +289,9 @@ export interface INotificationViewItem { readonly hasProgress: boolean; readonly onDidChangeExpansion: Event; - readonly onDidClose: Event; readonly onDidChangeVisibility: Event; - readonly onDidChangeLabel: Event; + readonly onDidChangeContent: Event; + readonly onDidClose: Event; expand(): void; collapse(skipEvents?: boolean): void; @@ -295,15 +312,15 @@ export function isNotificationViewItem(obj: unknown): obj is INotificationViewIt return obj instanceof NotificationViewItem; } -export const enum NotificationViewItemLabelKind { +export const enum NotificationViewItemContentChangeKind { SEVERITY, MESSAGE, ACTIONS, PROGRESS } -export interface INotificationViewItemLabelChangeEvent { - kind: NotificationViewItemLabelKind; +export interface INotificationViewItemContentChangeEvent { + kind: NotificationViewItemContentChangeKind; } export interface INotificationViewItemProgressState { @@ -420,8 +437,8 @@ export class NotificationViewItem extends Disposable implements INotificationVie private readonly _onDidClose = this._register(new Emitter()); readonly onDidClose = this._onDidClose.event; - private readonly _onDidChangeLabel = this._register(new Emitter()); - readonly onDidChangeLabel = this._onDidChangeLabel.event; + private readonly _onDidChangeContent = this._register(new Emitter()); + readonly onDidChangeContent = this._onDidChangeContent.event; private readonly _onDidChangeVisibility = this._register(new Emitter()); readonly onDidChangeVisibility = this._onDidChangeVisibility.event; @@ -525,7 +542,7 @@ export class NotificationViewItem extends Disposable implements INotificationVie } get canCollapse(): boolean { - return !this.hasPrompt; + return !this.hasActions; } get expanded(): boolean { @@ -541,11 +558,11 @@ export class NotificationViewItem extends Disposable implements INotificationVie return true; // explicitly sticky } - const hasPrompt = this.hasPrompt; + const hasActions = this.hasActions; if ( - (hasPrompt && this._severity === Severity.Error) || // notification errors with actions are sticky - (!hasPrompt && this._expanded) || // notifications that got expanded are sticky - (this._progress && !this._progress.state.done) // notifications with running progress are sticky + (hasActions && this._severity === Severity.Error) || // notification errors with actions are sticky + (!hasActions && this._expanded) || // notifications that got expanded are sticky + (this._progress && !this._progress.state.done) // notifications with running progress are sticky ) { return true; } @@ -557,7 +574,7 @@ export class NotificationViewItem extends Disposable implements INotificationVie return !!this._silent; } - private get hasPrompt(): boolean { + private get hasActions(): boolean { if (!this._actions) { return false; } @@ -576,7 +593,7 @@ export class NotificationViewItem extends Disposable implements INotificationVie get progress(): INotificationViewItemProgress { if (!this._progress) { this._progress = this._register(new NotificationViewItemProgress()); - this._register(this._progress.onDidChange(() => this._onDidChangeLabel.fire({ kind: NotificationViewItemLabelKind.PROGRESS }))); + this._register(this._progress.onDidChange(() => this._onDidChangeContent.fire({ kind: NotificationViewItemContentChangeKind.PROGRESS }))); } return this._progress; @@ -596,7 +613,7 @@ export class NotificationViewItem extends Disposable implements INotificationVie updateSeverity(severity: Severity): void { this._severity = severity; - this._onDidChangeLabel.fire({ kind: NotificationViewItemLabelKind.SEVERITY }); + this._onDidChangeContent.fire({ kind: NotificationViewItemContentChangeKind.SEVERITY }); } updateMessage(input: NotificationMessage): void { @@ -606,13 +623,12 @@ export class NotificationViewItem extends Disposable implements INotificationVie } this._message = message; - this._onDidChangeLabel.fire({ kind: NotificationViewItemLabelKind.MESSAGE }); + this._onDidChangeContent.fire({ kind: NotificationViewItemContentChangeKind.MESSAGE }); } updateActions(actions?: INotificationActions): void { this.setActions(actions); - - this._onDidChangeLabel.fire({ kind: NotificationViewItemLabelKind.ACTIONS }); + this._onDidChangeContent.fire({ kind: NotificationViewItemContentChangeKind.ACTIONS }); } updateVisibility(visible: boolean): void { diff --git a/src/vs/workbench/test/common/notifications.test.ts b/src/vs/workbench/test/common/notifications.test.ts index a050bc29422..765c140dc60 100644 --- a/src/vs/workbench/test/common/notifications.test.ts +++ b/src/vs/workbench/test/common/notifications.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { NotificationsModel, NotificationViewItem, INotificationChangeEvent, NotificationChangeType, NotificationViewItemLabelKind, IStatusMessageChangeEvent, StatusMessageChangeType } from 'vs/workbench/common/notifications'; +import { NotificationsModel, NotificationViewItem, INotificationChangeEvent, NotificationChangeType, NotificationViewItemContentChangeKind, IStatusMessageChangeEvent, StatusMessageChangeType } from 'vs/workbench/common/notifications'; import { Action } from 'vs/base/common/actions'; import { INotification, Severity, NotificationsFilter } from 'vs/platform/notification/common/notification'; import { createErrorWithActions } from 'vs/base/common/errorsWithActions'; @@ -58,8 +58,8 @@ suite('Notifications', () => { assert.equal(called, 2); called = 0; - item1.onDidChangeLabel(e => { - if (e.kind === NotificationViewItemLabelKind.PROGRESS) { + item1.onDidChangeContent(e => { + if (e.kind === NotificationViewItemContentChangeKind.PROGRESS) { called++; } }); @@ -70,8 +70,8 @@ suite('Notifications', () => { assert.equal(called, 2); called = 0; - item1.onDidChangeLabel(e => { - if (e.kind === NotificationViewItemLabelKind.MESSAGE) { + item1.onDidChangeContent(e => { + if (e.kind === NotificationViewItemContentChangeKind.MESSAGE) { called++; } }); @@ -79,8 +79,8 @@ suite('Notifications', () => { item1.updateMessage('message update'); called = 0; - item1.onDidChangeLabel(e => { - if (e.kind === NotificationViewItemLabelKind.SEVERITY) { + item1.onDidChangeContent(e => { + if (e.kind === NotificationViewItemContentChangeKind.SEVERITY) { called++; } }); @@ -88,8 +88,8 @@ suite('Notifications', () => { item1.updateSeverity(Severity.Error); called = 0; - item1.onDidChangeLabel(e => { - if (e.kind === NotificationViewItemLabelKind.ACTIONS) { + item1.onDidChangeContent(e => { + if (e.kind === NotificationViewItemContentChangeKind.ACTIONS) { called++; } }); @@ -159,6 +159,22 @@ suite('Notifications', () => { assert.equal(lastNotificationEvent.index, 0); assert.equal(lastNotificationEvent.kind, NotificationChangeType.ADD); + item1Handle.updateMessage('Error Message'); + assert.equal(lastNotificationEvent.kind, NotificationChangeType.CHANGE); + assert.equal(lastNotificationEvent.detail, NotificationViewItemContentChangeKind.MESSAGE); + + item1Handle.updateSeverity(Severity.Error); + assert.equal(lastNotificationEvent.kind, NotificationChangeType.CHANGE); + assert.equal(lastNotificationEvent.detail, NotificationViewItemContentChangeKind.SEVERITY); + + item1Handle.updateActions({ primary: [], secondary: [] }); + assert.equal(lastNotificationEvent.kind, NotificationChangeType.CHANGE); + assert.equal(lastNotificationEvent.detail, NotificationViewItemContentChangeKind.ACTIONS); + + item1Handle.progress.infinite(); + assert.equal(lastNotificationEvent.kind, NotificationChangeType.CHANGE); + assert.equal(lastNotificationEvent.detail, NotificationViewItemContentChangeKind.PROGRESS); + let item2Handle = model.addNotification(item2); assert.equal(lastNotificationEvent.item.severity, item2.severity); assert.equal(lastNotificationEvent.item.message.linkedText.toString(), item2.message); @@ -204,7 +220,7 @@ suite('Notifications', () => { assert.equal(lastNotificationEvent.item.severity, item3.severity); assert.equal(lastNotificationEvent.item.message.linkedText.toString(), item3.message); assert.equal(lastNotificationEvent.index, 0); - assert.equal(lastNotificationEvent.kind, NotificationChangeType.CHANGE); + assert.equal(lastNotificationEvent.kind, NotificationChangeType.EXPAND_COLLAPSE); const disposable = model.showStatusMessage('Hello World'); assert.equal(model.statusMessage!.message, 'Hello World'); From d1c1e2702857fec3f73132b89db0c2f8e40c858a Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 2 Mar 2020 04:35:43 -0500 Subject: [PATCH 197/235] =?UTF-8?q?Changes=20limit=20to=20take=20a=20curso?= =?UTF-8?q?r=20object=20=E2=80=94=20#91722?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extensions/git/src/timelineProvider.ts | 4 ++-- src/vs/vscode.proposed.d.ts | 2 +- .../contrib/timeline/browser/timelinePane.ts | 14 ++++++++++---- .../workbench/contrib/timeline/common/timeline.ts | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/extensions/git/src/timelineProvider.ts b/extensions/git/src/timelineProvider.ts index c177f8bfcc0..872e5c36a80 100644 --- a/extensions/git/src/timelineProvider.ts +++ b/extensions/git/src/timelineProvider.ts @@ -114,9 +114,9 @@ export class GitTimelineProvider implements TimelineProvider { // TODO[ECA]: Ensure that the uri is a file -- if not we could get the history of the repo? let limit: number | undefined; - if (typeof options.limit === 'string') { + if (options.limit !== undefined && typeof options.limit !== 'number') { try { - const result = await this._model.git.exec(repo.root, ['rev-list', '--count', `${options.limit}..`, '--', uri.fsPath]); + const result = await this._model.git.exec(repo.root, ['rev-list', '--count', `${options.limit.cursor}..`, '--', uri.fsPath]); if (!result.exitCode) { // Ask for 1 more than so we can determine if there are more commits limit = Number(result.stdout) + 1; diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index d1ccd81b83f..7e66d226c50 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1600,7 +1600,7 @@ declare module 'vscode' { /** * The maximum number or the ending cursor of timeline items that should be returned. */ - limit?: number | string; + limit?: number | { cursor: string }; } export interface TimelineProvider { diff --git a/src/vs/workbench/contrib/timeline/browser/timelinePane.ts b/src/vs/workbench/contrib/timeline/browser/timelinePane.ts index 031b6f27d11..976f6d73937 100644 --- a/src/vs/workbench/contrib/timeline/browser/timelinePane.ts +++ b/src/vs/workbench/contrib/timeline/browser/timelinePane.ts @@ -80,8 +80,8 @@ interface TimelineActionContext { } interface TimelineCursors { - startCursors?: { before: any; after?: any }; - endCursors?: { before: any; after?: any }; + startCursors?: { before: string; after?: string }; + endCursors?: { before: string; after?: string }; more: boolean; } @@ -308,7 +308,9 @@ export class TimelinePane extends ViewPane { { cursor: options.before ? cursors?.startCursors?.before : (cursors?.endCursors ?? cursors?.startCursors)?.after, ...options, - limit: options.limit === 0 ? undefined : options.limit ?? defaultPageSize + limit: options.limit === 0 + ? undefined + : options.limit ?? defaultPageSize }, request?.tokenSource ?? new CancellationTokenSource(), { cacheResults: true, resetCache: false } )!; @@ -329,7 +331,11 @@ export class TimelinePane extends ViewPane { source, this._uri, { ...options, - limit: options.limit === 0 ? undefined : (reset ? cursors?.endCursors?.after : undefined) ?? options.limit ?? defaultPageSize + limit: options.limit === 0 + ? undefined + : (reset && cursors?.endCursors?.after !== undefined + ? { cursor: cursors.endCursors.after } + : undefined) ?? options.limit ?? defaultPageSize }, new CancellationTokenSource(), { cacheResults: true, resetCache: true } )!; diff --git a/src/vs/workbench/contrib/timeline/common/timeline.ts b/src/vs/workbench/contrib/timeline/common/timeline.ts index 72ca602fa56..3f7cad3109e 100644 --- a/src/vs/workbench/contrib/timeline/common/timeline.ts +++ b/src/vs/workbench/contrib/timeline/common/timeline.ts @@ -40,7 +40,7 @@ export interface TimelineChangeEvent { export interface TimelineOptions { cursor?: string; before?: boolean; - limit?: number | string; + limit?: number | { cursor: string }; } export interface InternalTimelineOptions { From 704bf0f2cc0346be0482e241d9aecdfd3e6a2741 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 2 Mar 2020 10:49:33 +0100 Subject: [PATCH 198/235] contextkey - add web to statically defined ones --- .../platform/contextkey/common/contextkey.ts | 4 +++- .../platform/contextkey/common/contextkeys.ts | 12 ++++++++++-- .../browser/actions/layoutActions.ts | 2 +- .../browser/actions/windowActions.ts | 3 ++- src/vs/workbench/browser/contextkeys.ts | 19 +------------------ .../contrib/files/browser/explorerViewlet.ts | 3 ++- .../files/browser/fileActions.contribution.ts | 3 ++- .../browser/preferences.contribution.ts | 3 ++- .../contrib/update/browser/update.ts | 9 ++++----- .../electron-browser/desktop.contribution.ts | 4 ++-- 10 files changed, 29 insertions(+), 33 deletions(-) diff --git a/src/vs/platform/contextkey/common/contextkey.ts b/src/vs/platform/contextkey/common/contextkey.ts index 6f7ca973cc9..414b6a3d3c0 100644 --- a/src/vs/platform/contextkey/common/contextkey.ts +++ b/src/vs/platform/contextkey/common/contextkey.ts @@ -6,7 +6,7 @@ import { Event } from 'vs/base/common/event'; import { isFalsyOrWhitespace } from 'vs/base/common/strings'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { isMacintosh, isLinux, isWindows } from 'vs/base/common/platform'; +import { isMacintosh, isLinux, isWindows, isWeb } from 'vs/base/common/platform'; const STATIC_VALUES = new Map(); STATIC_VALUES.set('false', false); @@ -14,6 +14,8 @@ STATIC_VALUES.set('true', true); STATIC_VALUES.set('isMac', isMacintosh); STATIC_VALUES.set('isLinux', isLinux); STATIC_VALUES.set('isWindows', isWindows); +STATIC_VALUES.set('isWeb', isWeb); +STATIC_VALUES.set('isMacNative', isMacintosh && !isWeb); export const enum ContextKeyExprType { False = 0, diff --git a/src/vs/platform/contextkey/common/contextkeys.ts b/src/vs/platform/contextkey/common/contextkeys.ts index 4f8959e04ff..8c17906ab67 100644 --- a/src/vs/platform/contextkey/common/contextkeys.ts +++ b/src/vs/platform/contextkey/common/contextkeys.ts @@ -4,8 +4,16 @@ *--------------------------------------------------------------------------------------------*/ import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { isMacintosh, isLinux, isWindows, isWeb } from 'vs/base/common/platform'; + +export const IsMacContext = new RawContextKey('isMac', isMacintosh); +export const IsLinuxContext = new RawContextKey('isLinux', isLinux); +export const IsWindowsContext = new RawContextKey('isWindows', isWindows); + +export const IsWebContext = new RawContextKey('isWeb', isWeb); +export const IsMacNativeContext = new RawContextKey('isMacNative', isMacintosh && !isWeb); + +export const IsDevelopmentContext = new RawContextKey('isDevelopment', false); export const InputFocusedContextKey = 'inputFocus'; export const InputFocusedContext = new RawContextKey(InputFocusedContextKey, false); - -export const FalseContext = new RawContextKey('__false', false); diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index d8e36e8297f..cb77aab68f5 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -18,7 +18,7 @@ import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { getMenuBarVisibility } from 'vs/platform/windows/common/windows'; import { isWindows, isLinux, isWeb } from 'vs/base/common/platform'; -import { IsMacNativeContext } from 'vs/workbench/browser/contextkeys'; +import { IsMacNativeContext } from 'vs/platform/contextkey/common/contextkeys'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { InEditorZenModeContext, IsCenteredLayoutContext, EditorAreaVisibleContext } from 'vs/workbench/common/editor'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; diff --git a/src/vs/workbench/browser/actions/windowActions.ts b/src/vs/workbench/browser/actions/windowActions.ts index 707ba426404..f2c406df86a 100644 --- a/src/vs/workbench/browser/actions/windowActions.ts +++ b/src/vs/workbench/browser/actions/windowActions.ts @@ -12,7 +12,8 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { Registry } from 'vs/platform/registry/common/platform'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { IsFullscreenContext, IsDevelopmentContext, IsMacNativeContext } from 'vs/workbench/browser/contextkeys'; +import { IsFullscreenContext } from 'vs/workbench/browser/contextkeys'; +import { IsMacNativeContext, IsDevelopmentContext } from 'vs/platform/contextkey/common/contextkeys'; import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IQuickInputButton, IQuickInputService, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; diff --git a/src/vs/workbench/browser/contextkeys.ts b/src/vs/workbench/browser/contextkeys.ts index 2f138cb0c65..3b6ef87ceb7 100644 --- a/src/vs/workbench/browser/contextkeys.ts +++ b/src/vs/workbench/browser/contextkeys.ts @@ -6,8 +6,7 @@ import { Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { IContextKeyService, IContextKey, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { InputFocusedContext } from 'vs/platform/contextkey/common/contextkeys'; -import { IWindowsConfiguration } from 'vs/platform/windows/common/windows'; +import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, IsWebContext, IsMacNativeContext, IsDevelopmentContext } from 'vs/platform/contextkey/common/contextkeys'; import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorIsReadonlyContext, EditorAreaVisibleContext, DirtyWorkingCopiesContext } from 'vs/workbench/common/editor'; import { trackFocus, addDisposableListener, EventType } from 'vs/base/browser/dom'; import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -18,27 +17,15 @@ import { WorkbenchState, IWorkspaceContextService } from 'vs/platform/workspace/ import { SideBarVisibleContext } from 'vs/workbench/common/viewlet'; import { IWorkbenchLayoutService, Parts, positionToString } from 'vs/workbench/services/layout/browser/layoutService'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { isMacintosh, isLinux, isWindows, isWeb } from 'vs/base/common/platform'; import { PanelPositionContext } from 'vs/workbench/common/panel'; import { getRemoteName } from 'vs/platform/remote/common/remoteHosts'; import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; -export const IsMacContext = new RawContextKey('isMac', isMacintosh); -export const IsLinuxContext = new RawContextKey('isLinux', isLinux); -export const IsWindowsContext = new RawContextKey('isWindows', isWindows); - -export const IsWebContext = new RawContextKey('isWeb', isWeb); -export const IsMacNativeContext = new RawContextKey('isMacNative', isMacintosh && !isWeb); - export const Deprecated_RemoteAuthorityContext = new RawContextKey('remoteAuthority', ''); export const RemoteNameContext = new RawContextKey('remoteName', ''); export const RemoteConnectionState = new RawContextKey<'' | 'initializing' | 'disconnected' | 'connected'>('remoteConnectionState', ''); -export const HasMacNativeTabsContext = new RawContextKey('hasMacNativeTabs', false); - -export const IsDevelopmentContext = new RawContextKey('isDevelopment', false); - export const WorkbenchStateContext = new RawContextKey('workbenchState', undefined); export const WorkspaceFolderCountContext = new RawContextKey('workspaceFolderCount', 0); @@ -98,10 +85,6 @@ export class WorkbenchContextKeysHandler extends Disposable { RemoteNameContext.bindTo(this.contextKeyService).set(getRemoteName(this.environmentService.configuration.remoteAuthority) || ''); - // macOS Native Tabs - const windowConfig = this.configurationService.getValue(); - HasMacNativeTabsContext.bindTo(this.contextKeyService).set(windowConfig?.window?.nativeTabs); - // Development IsDevelopmentContext.bindTo(this.contextKeyService).set(!this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment); diff --git a/src/vs/workbench/contrib/files/browser/explorerViewlet.ts b/src/vs/workbench/contrib/files/browser/explorerViewlet.ts index ba4f2cae30f..dde38c2809c 100644 --- a/src/vs/workbench/contrib/files/browser/explorerViewlet.ts +++ b/src/vs/workbench/contrib/files/browser/explorerViewlet.ts @@ -34,7 +34,8 @@ import { KeyChord, KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { Registry } from 'vs/platform/registry/common/platform'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { WorkbenchStateContext, RemoteNameContext, IsWebContext } from 'vs/workbench/browser/contextkeys'; +import { WorkbenchStateContext, RemoteNameContext } from 'vs/workbench/browser/contextkeys'; +import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; import { AddRootFolderAction, OpenFolderAction, OpenFileFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; import { isMacintosh } from 'vs/base/common/platform'; diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index 5e9f7843888..4c21a261e15 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -22,7 +22,8 @@ import { AutoSaveAfterShortDelayContext } from 'vs/workbench/services/filesConfi import { ResourceContextKey } from 'vs/workbench/common/resources'; import { WorkbenchListDoubleSelection } from 'vs/platform/list/browser/listService'; import { Schemas } from 'vs/base/common/network'; -import { WorkspaceFolderCountContext, IsWebContext } from 'vs/workbench/browser/contextkeys'; +import { WorkspaceFolderCountContext } from 'vs/workbench/browser/contextkeys'; +import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { OpenFileFolderAction, OpenFileAction, OpenFolderAction, OpenWorkspaceAction } from 'vs/workbench/browser/actions/workspaceActions'; import { ActiveEditorIsReadonlyContext, DirtyWorkingCopiesContext, ActiveEditorContext } from 'vs/workbench/common/editor'; diff --git a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts index 8e94c2c2236..b450943ee2a 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts @@ -20,7 +20,8 @@ import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { IsMacNativeContext, RemoteNameContext, WorkbenchStateContext } from 'vs/workbench/browser/contextkeys'; +import { RemoteNameContext, WorkbenchStateContext } from 'vs/workbench/browser/contextkeys'; +import { IsMacNativeContext } from 'vs/platform/contextkey/common/contextkeys'; import { EditorDescriptor, Extensions as EditorExtensions, IEditorRegistry } from 'vs/workbench/browser/editor'; import { Extensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; diff --git a/src/vs/workbench/contrib/update/browser/update.ts b/src/vs/workbench/contrib/update/browser/update.ts index 786014463b6..0e39da8602f 100644 --- a/src/vs/workbench/contrib/update/browser/update.ts +++ b/src/vs/workbench/contrib/update/browser/update.ts @@ -22,10 +22,9 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { ReleaseNotesManager } from './releaseNotesEditor'; import { isWindows } from 'vs/base/common/platform'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { RawContextKey, IContextKey, IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { FalseContext } from 'vs/platform/contextkey/common/contextkeys'; import { ShowCurrentReleaseNotesActionId, CheckForVSCodeUpdateActionId } from 'vs/workbench/contrib/update/common/update'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -417,7 +416,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu command: { id: 'update.checking', title: nls.localize('checkingForUpdates', "Checking for Updates..."), - precondition: FalseContext + precondition: ContextKeyExpr.false() }, when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.CheckingForUpdates) }); @@ -438,7 +437,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu command: { id: 'update.downloading', title: nls.localize('DownloadingUpdate', "Downloading Update..."), - precondition: FalseContext + precondition: ContextKeyExpr.false() }, when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.Downloading) }); @@ -459,7 +458,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu command: { id: 'update.updating', title: nls.localize('installingUpdate', "Installing Update..."), - precondition: FalseContext + precondition: ContextKeyExpr.false() }, when: CONTEXT_UPDATE_STATE.isEqualTo(StateType.Updating) }); diff --git a/src/vs/workbench/electron-browser/desktop.contribution.ts b/src/vs/workbench/electron-browser/desktop.contribution.ts index bc750183d6e..9b594104e66 100644 --- a/src/vs/workbench/electron-browser/desktop.contribution.ts +++ b/src/vs/workbench/electron-browser/desktop.contribution.ts @@ -17,7 +17,7 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { IsMacContext, HasMacNativeTabsContext, IsDevelopmentContext } from 'vs/workbench/browser/contextkeys'; +import { IsDevelopmentContext, IsMacContext } from 'vs/platform/contextkey/common/contextkeys'; import { NoEditorsVisibleContext, SingleEditorGroupsContext } from 'vs/workbench/common/editor'; import { IElectronService } from 'vs/platform/electron/node/electron'; import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; @@ -82,7 +82,7 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema'; MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command, - when: HasMacNativeTabsContext + when: ContextKeyExpr.equals('config.window.nativeTabs', 'true') }); }); } From 01dbe67aa9a079424f5500c16296f4355f7b354d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 2 Mar 2020 10:59:15 +0100 Subject: [PATCH 199/235] editors - drop boolean result from revert() --- .../browser/parts/editor/editorGroupView.ts | 13 ++++----- src/vs/workbench/common/editor.ts | 12 ++++---- .../backup/electron-browser/backupTracker.ts | 7 ++--- .../customEditor/browser/customEditorInput.ts | 4 +-- .../customEditor/common/customEditor.ts | 2 +- .../customEditor/common/customEditorModel.ts | 7 ++--- .../test/browser/fileEditorInput.test.ts | 2 +- .../preferences/browser/preferencesEditor.ts | 2 +- .../searchEditor/browser/searchEditorInput.ts | 3 +- .../tasks/browser/abstractTaskService.ts | 4 +-- .../services/editor/browser/editorService.ts | 15 ++++------ .../services/editor/common/editorService.ts | 8 ++++-- .../editor/test/browser/editorService.test.ts | 28 +++++++++++++++++++ .../textfile/browser/textFileService.ts | 14 ++++------ .../textfile/common/textFileEditorModel.ts | 6 ++-- .../services/textfile/common/textfiles.ts | 4 +-- .../test/browser/textFileService.test.ts | 3 +- .../common/untitledTextEditorModel.ts | 4 +-- .../test/browser/untitledTextEditor.test.ts | 2 +- .../workingCopy/common/workingCopyService.ts | 2 +- .../test/common/workingCopyService.test.ts | 4 +-- .../test/browser/workbenchTestServices.ts | 7 ++--- 22 files changed, 80 insertions(+), 73 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 39ab5198646..b030a213d1c 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -1329,25 +1329,24 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Otherwise, handle accordingly switch (res) { case ConfirmResult.SAVE: - const result = await editor.save(this.id, { reason: SaveReason.EXPLICIT }); + await editor.save(this.id, { reason: SaveReason.EXPLICIT }); - return !result; + return editor.isDirty(); // veto if still dirty case ConfirmResult.DONT_SAVE: - try { // first try a normal revert where the contents of the editor are restored - const result = await editor.revert(this.id); + await editor.revert(this.id); - return !result; + return editor.isDirty(); // veto if still dirty } catch (error) { // if that fails, since we are about to close the editor, we accept that // the editor cannot be reverted and instead do a soft revert that just // enables us to close the editor. With this, a user can always close a // dirty editor even when reverting fails. - const result = await editor.revert(this.id, { soft: true }); + await editor.revert(this.id, { soft: true }); - return !result; + return editor.isDirty(); // veto if still dirty } case ConfirmResult.CANCEL: return true; // veto diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 6e4802e474f..65251653849 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -449,7 +449,7 @@ export interface IEditorInput extends IDisposable { /** * Reverts this input from the provided group. */ - revert(group: GroupIdentifier, options?: IRevertOptions): Promise; + revert(group: GroupIdentifier, options?: IRevertOptions): Promise; /** * Called to determine how to handle a resource that is moved that matches @@ -557,9 +557,7 @@ export abstract class EditorInput extends Disposable implements IEditorInput { return this; } - async revert(group: GroupIdentifier, options?: IRevertOptions): Promise { - return true; - } + async revert(group: GroupIdentifier, options?: IRevertOptions): Promise { } move(group: GroupIdentifier, target: URI): IMoveResult | undefined { return undefined; @@ -735,8 +733,8 @@ export abstract class TextResourceEditorInput extends EditorInput { return this; } - revert(group: GroupIdentifier, options?: IRevertOptions): Promise { - return this.textFileService.revert(this.resource, options); + async revert(group: GroupIdentifier, options?: IRevertOptions): Promise { + await this.textFileService.revert(this.resource, options); } } @@ -876,7 +874,7 @@ export class SideBySideEditorInput extends EditorInput { return this.master.saveAs(group, options); } - revert(group: GroupIdentifier, options?: IRevertOptions): Promise { + revert(group: GroupIdentifier, options?: IRevertOptions): Promise { return this.master.revert(group, options); } diff --git a/src/vs/workbench/contrib/backup/electron-browser/backupTracker.ts b/src/vs/workbench/contrib/backup/electron-browser/backupTracker.ts index 1aba5636ccb..ca971ffc23e 100644 --- a/src/vs/workbench/contrib/backup/electron-browser/backupTracker.ts +++ b/src/vs/workbench/contrib/backup/electron-browser/backupTracker.ts @@ -235,16 +235,13 @@ export class NativeBackupTracker extends BackupTracker implements IWorkbenchCont const revertOptions = { soft: true }; // First revert through the editor service if we revert all - let result: boolean | undefined = undefined; if (workingCopies.length === this.workingCopyService.dirtyCount) { - result = await this.editorService.revertAll(revertOptions); + await this.editorService.revertAll(revertOptions); } // If we still have dirty working copies, revert those directly // unless the revert operation was not successful (e.g. cancelled) - if (result !== false) { - await Promise.all(workingCopies.map(workingCopy => workingCopy.isDirty() ? workingCopy.revert(revertOptions) : Promise.resolve(true))); - } + await Promise.all(workingCopies.map(workingCopy => workingCopy.isDirty() ? workingCopy.revert(revertOptions) : Promise.resolve())); } private noVeto(backupsToDiscard: IWorkingCopy[]): boolean | Promise { diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts index 82ee3c38afa..d55b558f42b 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts @@ -190,9 +190,9 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { return this.handleMove(groupId, target) || this.editorService.createInput({ resource: target, forceFile: true }); } - public async revert(group: GroupIdentifier, options?: IRevertOptions): Promise { + public async revert(group: GroupIdentifier, options?: IRevertOptions): Promise { if (!this._model) { - return false; + return; } switch (this._model.type) { diff --git a/src/vs/workbench/contrib/customEditor/common/customEditor.ts b/src/vs/workbench/contrib/customEditor/common/customEditor.ts index f14ffcf0a81..277a153fd5a 100644 --- a/src/vs/workbench/contrib/customEditor/common/customEditor.ts +++ b/src/vs/workbench/contrib/customEditor/common/customEditor.ts @@ -79,7 +79,7 @@ export interface ICustomEditorModel extends IWorkingCopy { setDirty(dirty: boolean): void; undo(): void; redo(): void; - revert(options?: IRevertOptions): Promise; + revert(options?: IRevertOptions): Promise; save(options?: ISaveOptions): Promise; saveAs(resource: URI, targetResource: URI, currentOptions?: ISaveOptions): Promise; diff --git a/src/vs/workbench/contrib/customEditor/common/customEditorModel.ts b/src/vs/workbench/contrib/customEditor/common/customEditorModel.ts index 43f887a82a0..d961dec639e 100644 --- a/src/vs/workbench/contrib/customEditor/common/customEditorModel.ts +++ b/src/vs/workbench/contrib/customEditor/common/customEditorModel.ts @@ -113,12 +113,9 @@ export class CustomEditorModel extends Disposable implements ICustomEditorModel } public async revert(_options?: IRevertOptions) { - if (!this._dirty) { - return true; + if (this._dirty) { + this._onRevert.fire(); } - - this._onRevert.fire(); - return true; } public undo() { diff --git a/src/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts b/src/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts index 69fa0be16bf..5b78f85f045 100644 --- a/src/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts +++ b/src/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts @@ -149,7 +149,7 @@ suite('Files - FileEditorInput', () => { resolved.textEditorModel!.setValue('changed'); assert.ok(input.isDirty()); - assert.ok(await input.revert(0)); + await input.revert(0); assert.ok(!input.isDirty()); input.dispose(); diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts index 76786b81061..c1812459c6b 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts @@ -252,7 +252,7 @@ export class PreferencesEditor extends BaseEditor { if (this.editorService.activeControl !== this) { this.focus(); } - const promise: Promise = this.input && this.input.isDirty() ? this.editorService.save({ editor: this.input, groupId: this.group!.id }) : Promise.resolve(true); + const promise = this.input && this.input.isDirty() ? this.editorService.save({ editor: this.input, groupId: this.group!.id }) : Promise.resolve(true); promise.then(() => { if (target === ConfigurationTarget.USER_LOCAL) { this.preferencesService.switchSettings(ConfigurationTarget.USER_LOCAL, this.preferencesService.userSettingsResource, true); diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditorInput.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditorInput.ts index 44b819f8abc..73729118f5d 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditorInput.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditorInput.ts @@ -112,7 +112,7 @@ export class SearchEditorInput extends EditorInput { isDirty(): boolean { return input.isDirty(); } backup(): Promise { return input.backup(); } save(options?: ISaveOptions): Promise { return input.save(0, options).then(editor => !!editor); } - revert(options?: IRevertOptions): Promise { return input.revert(0, options); } + revert(options?: IRevertOptions): Promise { return input.revert(0, options); } }; this.workingCopyService.registerWorkingCopy(workingCopyAdapter); @@ -261,7 +261,6 @@ export class SearchEditorInput extends EditorInput { // TODO: this should actually revert the contents. But it needs to set dirty false. super.revert(group, options); this.setDirty(false); - return true; } private async backup(): Promise { diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 27418989dde..42386cce1ed 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -1284,7 +1284,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer private executeTask(task: Task, resolver: ITaskResolver): Promise { return ProblemMatcherRegistry.onReady().then(() => { - return this.editorService.saveAll().then((value) => { // make sure all dirty editors are saved + return this.editorService.saveAll().then(() => { // make sure all dirty editors are saved let executeResult = this.getTaskSystem().run(task, resolver); return this.handleExecuteResult(executeResult); }); @@ -2257,7 +2257,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } ProblemMatcherRegistry.onReady().then(() => { - return this.editorService.saveAll().then((value) => { // make sure all dirty editors are saved + return this.editorService.saveAll().then(() => { // make sure all dirty editors are saved let executeResult = this.getTaskSystem().rerun(); if (executeResult) { return this.handleExecuteResult(executeResult); diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index 2583458a30d..6042d90eb8a 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -1022,28 +1022,23 @@ export class EditorService extends Disposable implements EditorServiceImpl { return this.save(this.getAllDirtyEditors(options), options); } - async revert(editors: IEditorIdentifier | IEditorIdentifier[], options?: IRevertOptions): Promise { + async revert(editors: IEditorIdentifier | IEditorIdentifier[], options?: IRevertOptions): Promise { // Convert to array if (!Array.isArray(editors)) { editors = [editors]; } - const result = await Promise.all(editors.map(async ({ groupId, editor }) => { - if (editor.isDisposed()) { - return true; // might have been disposed from from the revert already - } + await Promise.all(editors.map(async ({ groupId, editor }) => { // Use revert as a hint to pin the editor this.editorGroupService.getGroup(groupId)?.pinEditor(editor); return editor.revert(groupId, options); })); - - return result.every(success => !!success); } - async revertAll(options?: IRevertAllEditorsOptions): Promise { + async revertAll(options?: IRevertAllEditorsOptions): Promise { return this.revert(this.getAllDirtyEditors(options), options); } @@ -1162,8 +1157,8 @@ export class DelegatingEditorService implements IEditorService { save(editors: IEditorIdentifier | IEditorIdentifier[], options?: ISaveEditorsOptions): Promise { return this.editorService.save(editors, options); } saveAll(options?: ISaveAllEditorsOptions): Promise { return this.editorService.saveAll(options); } - revert(editors: IEditorIdentifier | IEditorIdentifier[], options?: IRevertOptions): Promise { return this.editorService.revert(editors, options); } - revertAll(options?: IRevertAllEditorsOptions): Promise { return this.editorService.revertAll(options); } + revert(editors: IEditorIdentifier | IEditorIdentifier[], options?: IRevertOptions): Promise { return this.editorService.revert(editors, options); } + revertAll(options?: IRevertAllEditorsOptions): Promise { return this.editorService.revertAll(options); } //#endregion } diff --git a/src/vs/workbench/services/editor/common/editorService.ts b/src/vs/workbench/services/editor/common/editorService.ts index 5f6bb85eff3..d014673ca3d 100644 --- a/src/vs/workbench/services/editor/common/editorService.ts +++ b/src/vs/workbench/services/editor/common/editorService.ts @@ -218,21 +218,25 @@ export interface IEditorService { /** * Save the provided list of editors. + * + * @returns `true` if all editors saved and `false` otherwise. */ save(editors: IEditorIdentifier | IEditorIdentifier[], options?: ISaveEditorsOptions): Promise; /** * Save all editors. + * + * @returns `true` if all editors saved and `false` otherwise. */ saveAll(options?: ISaveAllEditorsOptions): Promise; /** * Reverts the provided list of editors. */ - revert(editors: IEditorIdentifier | IEditorIdentifier[], options?: IRevertOptions): Promise; + revert(editors: IEditorIdentifier | IEditorIdentifier[], options?: IRevertOptions): Promise; /** * Reverts all editors. */ - revertAll(options?: IRevertAllEditorsOptions): Promise; + revertAll(options?: IRevertAllEditorsOptions): Promise; } diff --git a/src/vs/workbench/services/editor/test/browser/editorService.test.ts b/src/vs/workbench/services/editor/test/browser/editorService.test.ts index 26d6709a157..45606b858d0 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -733,6 +733,8 @@ suite('EditorService', () => { input1.dirty = true; const input2 = new TestFileEditorInput(URI.parse('my://resource2'), TEST_EDITOR_INPUT_ID); input2.dirty = true; + const sameInput1 = new TestFileEditorInput(URI.parse('my://resource1'), TEST_EDITOR_INPUT_ID); + sameInput1.dirty = true; const rootGroup = part.activeGroup; @@ -740,24 +742,50 @@ suite('EditorService', () => { await service.openEditor(input1, { pinned: true }); await service.openEditor(input2, { pinned: true }); + await service.openEditor(sameInput1, { pinned: true }, SIDE_GROUP); await service.save({ groupId: rootGroup.id, editor: input1 }); assert.equal(input1.gotSaved, true); + input1.gotSaved = false; + input1.gotSavedAs = false; + input1.gotReverted = false; + await service.save({ groupId: rootGroup.id, editor: input1 }, { saveAs: true }); assert.equal(input1.gotSavedAs, true); + input1.gotSaved = false; + input1.gotSavedAs = false; + input1.gotReverted = false; + await service.revertAll(); assert.equal(input1.gotReverted, true); + input1.gotSaved = false; + input1.gotSavedAs = false; + input1.gotReverted = false; + await service.saveAll(); assert.equal(input1.gotSaved, true); assert.equal(input2.gotSaved, true); + input1.gotSaved = false; + input1.gotSavedAs = false; + input1.gotReverted = false; + input2.gotSaved = false; + input2.gotSavedAs = false; + input2.gotReverted = false; + await service.saveAll({ saveAs: true }); + assert.equal(input1.gotSavedAs, true); assert.equal(input2.gotSavedAs, true); + // services dedupes inputs automatically + assert.equal(sameInput1.gotSaved, false); + assert.equal(sameInput1.gotSavedAs, false); + assert.equal(sameInput1.gotReverted, false); + part.dispose(); }); diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index f97ce3ccfb2..ef6a97ac6ec 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -442,7 +442,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex //#region revert - async revert(resource: URI, options?: IRevertOptions): Promise { + async revert(resource: URI, options?: IRevertOptions): Promise { // Untitled if (resource.scheme === Schemas.untitled) { @@ -450,17 +450,15 @@ export abstract class AbstractTextFileService extends Disposable implements ITex if (model) { return model.revert(options); } - - return false; } // File - const model = this.files.get(resource); - if (model && (model.isDirty() || options?.force)) { - return model.revert(options); + else { + const model = this.files.get(resource); + if (model && (model.isDirty() || options?.force)) { + return model.revert(options); + } } - - return false; } //#endregion diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 949e69d12ef..17eadf382ca 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -206,9 +206,9 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil //#region Revert - async revert(options?: IRevertOptions): Promise { + async revert(options?: IRevertOptions): Promise { if (!this.isResolved()) { - return false; + return; } // Unset flags @@ -240,8 +240,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil if (wasDirty) { this._onDidChangeDirty.fire(); } - - return true; } //#endregion diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index d3531ab7b7b..07956b419a5 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -78,7 +78,7 @@ export interface ITextFileService extends IDisposable { * @param resource the resource of the file to revert. * @param force to force revert even when the file is not dirty */ - revert(resource: URI, options?: IRevertOptions): Promise; + revert(resource: URI, options?: IRevertOptions): Promise; /** * Read the contents of a file identified by the resource. @@ -411,7 +411,7 @@ export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport updatePreferredEncoding(encoding: string | undefined): void; save(options?: ITextFileSaveOptions): Promise; - revert(options?: IRevertOptions): Promise; + revert(options?: IRevertOptions): Promise; load(options?: ITextFileLoadOptions): Promise; diff --git a/src/vs/workbench/services/textfile/test/browser/textFileService.test.ts b/src/vs/workbench/services/textfile/test/browser/textFileService.test.ts index d90c11ca710..ab4d13394e2 100644 --- a/src/vs/workbench/services/textfile/test/browser/textFileService.test.ts +++ b/src/vs/workbench/services/textfile/test/browser/textFileService.test.ts @@ -97,8 +97,7 @@ suite('Files - TextFileService', () => { model!.textEditorModel!.setValue('foo'); assert.ok(accessor.textFileService.isDirty(model.resource)); - const res = await accessor.textFileService.revert(model.resource); - assert.ok(res); + await accessor.textFileService.revert(model.resource); assert.ok(!accessor.textFileService.isDirty(model.resource)); }); diff --git a/src/vs/workbench/services/untitled/common/untitledTextEditorModel.ts b/src/vs/workbench/services/untitled/common/untitledTextEditorModel.ts index e42c09b2e33..bd4f8afbc99 100644 --- a/src/vs/workbench/services/untitled/common/untitledTextEditorModel.ts +++ b/src/vs/workbench/services/untitled/common/untitledTextEditorModel.ts @@ -253,7 +253,7 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt return !!target; } - async revert(): Promise { + async revert(): Promise { this.setDirty(false); // Emit as event @@ -263,8 +263,6 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt // no actual source on disk to revert to. As such we // dispose the model. this.dispose(); - - return true; } async backup(): Promise { diff --git a/src/vs/workbench/services/untitled/test/browser/untitledTextEditor.test.ts b/src/vs/workbench/services/untitled/test/browser/untitledTextEditor.test.ts index 9b2b8015372..cf3ce106c2a 100644 --- a/src/vs/workbench/services/untitled/test/browser/untitledTextEditor.test.ts +++ b/src/vs/workbench/services/untitled/test/browser/untitledTextEditor.test.ts @@ -82,7 +82,7 @@ suite('Untitled text editors', () => { assert.ok(!workingCopyService.isDirty(input2.resource)); assert.equal(workingCopyService.dirtyCount, 0); - assert.equal(await input1.revert(0), false); + await input1.revert(0); assert.ok(input1.isDisposed()); assert.ok(!service.get(input1.resource)); diff --git a/src/vs/workbench/services/workingCopy/common/workingCopyService.ts b/src/vs/workbench/services/workingCopy/common/workingCopyService.ts index 7be4f335d23..353bce55045 100644 --- a/src/vs/workbench/services/workingCopy/common/workingCopyService.ts +++ b/src/vs/workbench/services/workingCopy/common/workingCopyService.ts @@ -91,7 +91,7 @@ export interface IWorkingCopy { save(options?: ISaveOptions): Promise; - revert(options?: IRevertOptions): Promise; + revert(options?: IRevertOptions): Promise; //#endregion } diff --git a/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts b/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts index 4e189be6867..282319778ce 100644 --- a/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts +++ b/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts @@ -56,10 +56,8 @@ suite('WorkingCopyService', () => { return true; } - async revert(options?: IRevertOptions): Promise { + async revert(options?: IRevertOptions): Promise { this.setDirty(false); - - return true; } async backup(): Promise { diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index 8147ecb50bf..b152ff1865f 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -629,8 +629,8 @@ export class TestEditorService implements EditorServiceImpl { createInput(_input: IResourceInput | IUntitledTextResourceInput | IResourceDiffInput | IResourceSideBySideInput): EditorInput { throw new Error('not implemented'); } save(editors: IEditorIdentifier[], options?: ISaveEditorsOptions): Promise { throw new Error('Method not implemented.'); } saveAll(options?: ISaveEditorsOptions): Promise { throw new Error('Method not implemented.'); } - revert(editors: IEditorIdentifier[], options?: IRevertOptions): Promise { throw new Error('Method not implemented.'); } - revertAll(options?: IRevertAllEditorsOptions): Promise { throw new Error('Method not implemented.'); } + revert(editors: IEditorIdentifier[], options?: IRevertOptions): Promise { throw new Error('Method not implemented.'); } + revertAll(options?: IRevertAllEditorsOptions): Promise { throw new Error('Method not implemented.'); } } export class TestFileService implements IFileService { @@ -1029,11 +1029,10 @@ export class TestFileEditorInput extends EditorInput implements IFileEditorInput this.gotSavedAs = true; return this; } - async revert(group: GroupIdentifier, options?: IRevertOptions): Promise { + async revert(group: GroupIdentifier, options?: IRevertOptions): Promise { this.gotReverted = true; this.gotSaved = false; this.gotSavedAs = false; - return true; } setDirty(): void { this.dirty = true; } isDirty(): boolean { From f33d982fd5545f669f713427751fc9cc5cae347c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 2 Mar 2020 11:02:27 +0100 Subject: [PATCH 200/235] editors - deduplicate editors on saveAll, revertAll --- .../services/editor/browser/editorService.ts | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index 6042d90eb8a..eb2436a1870 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -953,6 +953,10 @@ export class EditorService extends Disposable implements EditorServiceImpl { editors = [editors]; } + // Make sure to not save the same editor multiple times + // by using the `matches()` method to find duplicates + const uniqueEditors = this.getUniqueEditors(editors); + // Split editors up into a bucket that is saved in parallel // and sequentially. Unless "Save As", all non-untitled editors // can be saved in parallel to speed up the operation. Remaining @@ -961,9 +965,9 @@ export class EditorService extends Disposable implements EditorServiceImpl { const editorsToSaveParallel: IEditorIdentifier[] = []; const editorsToSaveSequentially: IEditorIdentifier[] = []; if (options?.saveAs) { - editorsToSaveSequentially.push(...editors); + editorsToSaveSequentially.push(...uniqueEditors); } else { - for (const { groupId, editor } of editors) { + for (const { groupId, editor } of uniqueEditors) { if (editor.isUntitled()) { editorsToSaveSequentially.push({ groupId, editor }); } else { @@ -973,7 +977,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { } // Editors to save in parallel - await Promise.all(editorsToSaveParallel.map(({ groupId, editor }) => { + const saveResults = await Promise.all(editorsToSaveParallel.map(({ groupId, editor }) => { // Use save as a hint to pin the editor if used explicitly if (options?.reason === SaveReason.EXPLICIT) { @@ -1000,8 +1004,10 @@ export class EditorService extends Disposable implements EditorServiceImpl { } const result = options?.saveAs ? await editor.saveAs(groupId, options) : await editor.save(groupId, options); + saveResults.push(result); + if (!result) { - return false; // failed or cancelled, abort + break; // failed or cancelled, abort } // Replace editor preserving viewstate (either across all groups or @@ -1015,7 +1021,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { } } - return true; + return saveResults.every(result => !!result); } saveAll(options?: ISaveAllEditorsOptions): Promise { @@ -1029,7 +1035,11 @@ export class EditorService extends Disposable implements EditorServiceImpl { editors = [editors]; } - await Promise.all(editors.map(async ({ groupId, editor }) => { + // Make sure to not revert the same editor multiple times + // by using the `matches()` method to find duplicates + const uniqueEditors = this.getUniqueEditors(editors); + + await Promise.all(uniqueEditors.map(async ({ groupId, editor }) => { // Use revert as a hint to pin the editor this.editorGroupService.getGroup(groupId)?.pinEditor(editor); @@ -1056,6 +1066,19 @@ export class EditorService extends Disposable implements EditorServiceImpl { return editors; } + private getUniqueEditors(editors: IEditorIdentifier[]): IEditorIdentifier[] { + const uniqueEditors: IEditorIdentifier[] = []; + for (const { editor, groupId } of editors) { + if (uniqueEditors.some(uniqueEditor => uniqueEditor.editor.matches(editor))) { + continue; + } + + uniqueEditors.push({ editor, groupId }); + } + + return uniqueEditors; + } + //#endregion dispose(): void { From f2502971b517be132e76968192fa5fc8f449c8a9 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 2 Mar 2020 11:06:59 +0100 Subject: [PATCH 201/235] labels - handle file service changes better (fix #91833) --- .../standalone/browser/simpleServices.ts | 5 ++-- src/vs/platform/label/common/label.ts | 6 ++++- src/vs/workbench/browser/labels.ts | 14 ++++++----- .../browser/parts/editor/tabsTitleControl.ts | 13 +++++++---- .../browser/parts/editor/titleControl.ts | 7 +++--- .../browser/parts/titlebar/titlebarPart.ts | 2 +- src/vs/workbench/common/editor.ts | 20 +++++++++++----- .../extensionsActions.test.ts | 4 ++-- .../services/label/common/labelService.ts | 23 ++++++++++--------- 9 files changed, 56 insertions(+), 38 deletions(-) diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 2b7a163f047..c7b2fed89ac 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -36,7 +36,7 @@ import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingReso import { IKeybindingItem, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding'; -import { ILabelService, ResourceLabelFormatter } from 'vs/platform/label/common/label'; +import { ILabelService, ResourceLabelFormatter, IFormatterChangeEvent } from 'vs/platform/label/common/label'; import { INotification, INotificationHandle, INotificationService, IPromptChoice, IPromptOptions, NoOpNotification, IStatusMessageOptions, NotificationsFilter } from 'vs/platform/notification/common/notification'; import { IProgressRunner, IEditorProgressService } from 'vs/platform/progress/common/progress'; import { ITelemetryInfo, ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -713,8 +713,7 @@ export class SimpleUriLabelService implements ILabelService { _serviceBrand: undefined; - private readonly _onDidRegisterFormatter = new Emitter(); - public readonly onDidChangeFormatters: Event = this._onDidRegisterFormatter.event; + public readonly onDidChangeFormatters: Event = Event.None; public getUriLabel(resource: URI, options?: { relative?: boolean, forceNoTildify?: boolean }): string { if (resource.scheme === 'file') { diff --git a/src/vs/platform/label/common/label.ts b/src/vs/platform/label/common/label.ts index b2422cfa473..64fe1845042 100644 --- a/src/vs/platform/label/common/label.ts +++ b/src/vs/platform/label/common/label.ts @@ -26,7 +26,11 @@ export interface ILabelService { getHostLabel(scheme: string, authority?: string): string; getSeparator(scheme: string, authority?: string): '/' | '\\'; registerFormatter(formatter: ResourceLabelFormatter): IDisposable; - onDidChangeFormatters: Event; + onDidChangeFormatters: Event; +} + +export interface IFormatterChangeEvent { + scheme: string; } export interface ResourceLabelFormatter { diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index eece5353caa..6f4aa04679a 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -137,14 +137,14 @@ export class ResourceLabels extends Disposable { })); // notify when label formatters change - this._register(this.labelService.onDidChangeFormatters(() => { - this._widgets.forEach(widget => widget.notifyFormattersChange()); + this._register(this.labelService.onDidChangeFormatters(e => { + this._widgets.forEach(widget => widget.notifyFormattersChange(e.scheme)); })); // notify when untitled labels change - this.textFileService.untitled.onDidChangeLabel(model => { + this._register(this.textFileService.untitled.onDidChangeLabel(model => { this._widgets.forEach(widget => widget.notifyUntitledLabelChange(model.resource)); - }); + })); } get(index: number): IResourceLabel { @@ -311,8 +311,10 @@ class ResourceLabelWidget extends IconLabel { this.render(true); } - notifyFormattersChange(): void { - this.render(false); + notifyFormattersChange(scheme: string): void { + if (this.label?.resource?.scheme === scheme) { + this.render(false); + } } notifyUntitledLabelChange(resource: URI): void { diff --git a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index 3509fe604e0..dffc8df1cf2 100644 --- a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -40,9 +40,9 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { BreadcrumbsControl } from 'vs/workbench/browser/parts/editor/breadcrumbsControl'; import { IFileService } from 'vs/platform/files/common/files'; import { withNullAsUndefined, assertAllDefined, assertIsDefined } from 'vs/base/common/types'; -import { ILabelService } from 'vs/platform/label/common/label'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { basenameOrAuthority } from 'vs/base/common/resources'; +import { RunOnceScheduler } from 'vs/base/common/async'; interface IEditorInputLabel { name?: string; @@ -85,10 +85,9 @@ export class TabsTitleControl extends TitleControl { @IExtensionService extensionService: IExtensionService, @IConfigurationService configurationService: IConfigurationService, @IFileService fileService: IFileService, - @ILabelService labelService: ILabelService, @IEditorService private readonly editorService: EditorServiceImpl ) { - super(parent, accessor, group, contextMenuService, instantiationService, contextKeyService, keybindingService, telemetryService, notificationService, menuService, quickOpenService, themeService, extensionService, configurationService, fileService, labelService); + super(parent, accessor, group, contextMenuService, instantiationService, contextKeyService, keybindingService, telemetryService, notificationService, menuService, quickOpenService, themeService, extensionService, configurationService, fileService); this.tabResourceLabels = this._register(this.instantiationService.createInstance(ResourceLabels, DEFAULT_LABELS_CONTAINER)); this.closeOneEditorAction = this._register(this.instantiationService.createInstance(CloseOneEditorAction, CloseOneEditorAction.ID, CloseOneEditorAction.LABEL)); @@ -392,10 +391,16 @@ export class TabsTitleControl extends TitleControl { this.layout(this.dimension); } + private updateEditorLabelAggregator = this._register(new RunOnceScheduler(() => this.updateEditorLabels(), 0)); + updateEditorLabel(editor: IEditorInput): void { // Update all labels to account for changes to tab labels - this.updateEditorLabels(); + // Since this method may be called a lot of times from + // individual editors, we collect all those requests and + // then run the update once because we have to update + // all opened tabs in the group at once. + this.updateEditorLabelAggregator.schedule(); } updateEditorLabels(): void { diff --git a/src/vs/workbench/browser/parts/editor/titleControl.ts b/src/vs/workbench/browser/parts/editor/titleControl.ts index 1077097edde..e191034f051 100644 --- a/src/vs/workbench/browser/parts/editor/titleControl.ts +++ b/src/vs/workbench/browser/parts/editor/titleControl.ts @@ -40,7 +40,6 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { IFileService } from 'vs/platform/files/common/files'; import { withNullAsUndefined, withUndefinedAsNull, assertIsDefined } from 'vs/base/common/types'; -import { ILabelService } from 'vs/platform/label/common/label'; import { isFirefox } from 'vs/base/browser/browser'; export interface IToolbarActions { @@ -82,8 +81,7 @@ export abstract class TitleControl extends Themable { @IThemeService themeService: IThemeService, @IExtensionService private readonly extensionService: IExtensionService, @IConfigurationService protected configurationService: IConfigurationService, - @IFileService private readonly fileService: IFileService, - @ILabelService private readonly labelService: ILabelService + @IFileService private readonly fileService: IFileService ) { super(themeService); @@ -97,8 +95,9 @@ export abstract class TitleControl extends Themable { } private registerListeners(): void { + + // Update actions toolbar when extension register that may contribute them this._register(this.extensionService.onDidRegisterExtensions(() => this.updateEditorActionsToolbar())); - this._register(this.labelService.onDidChangeFormatters(() => this.updateEditorLabels())); } protected abstract create(parent: HTMLElement): void; diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index f23aacde162..13dcddb9786 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -86,7 +86,7 @@ export class TitlebarPart extends Part implements ITitleService { private readonly properties: ITitleProperties = { isPure: true, isAdmin: false }; private readonly activeEditorListeners = this._register(new DisposableStore()); - private titleUpdater: RunOnceScheduler = this._register(new RunOnceScheduler(() => this.doUpdateTitle(), 0)); + private readonly titleUpdater = this._register(new RunOnceScheduler(() => this.doUpdateTitle(), 0)); private contextMenu: IMenu; diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 65251653849..35a73df65ac 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -609,8 +609,20 @@ export abstract class TextResourceEditorInput extends EditorInput { protected registerListeners(): void { // Clear label memoizer on certain events that have impact - this._register(this.labelService.onDidChangeFormatters(() => TextResourceEditorInput.MEMOIZER.clear())); - this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(() => TextResourceEditorInput.MEMOIZER.clear())); + this._register(this.labelService.onDidChangeFormatters(e => this.onLabelEvent(e.scheme))); + this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(e => this.onLabelEvent(e.scheme))); + this._register(this.fileService.onDidChangeFileSystemProviderCapabilities(e => this.onLabelEvent(e.scheme))); + } + + private onLabelEvent(scheme: string): void { + if (scheme === this.resource.scheme) { + + // Clear any cached labels from before + TextResourceEditorInput.MEMOIZER.clear(); + + // Trigger recompute of label + this._onDidChangeLabel.fire(); + } } getName(): string { @@ -685,10 +697,6 @@ export abstract class TextResourceEditorInput extends EditorInput { return false; // untitled is never readonly } - if (!this.fileService.canHandleResource(this.resource)) { - return true; // resources without file support are always readonly - } - return this.fileService.hasCapability(this.resource, FileSystemProviderCapabilities.Readonly); } diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts index 52f71ee6229..b7d2136893e 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts @@ -39,7 +39,7 @@ import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browse import { ExtensionIdentifier, IExtensionContributions, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { ILabelService } from 'vs/platform/label/common/label'; +import { ILabelService, IFormatterChangeEvent } from 'vs/platform/label/common/label'; import { ExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService'; import { IProductService } from 'vs/platform/product/common/productService'; import { Schemas } from 'vs/base/common/network'; @@ -92,7 +92,7 @@ suite('ExtensionsActions Test', () => { }()); instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); - instantiationService.stub(ILabelService, { onDidChangeFormatters: new Emitter().event }); + instantiationService.stub(ILabelService, { onDidChangeFormatters: new Emitter().event }); instantiationService.set(IExtensionTipsService, instantiationService.createInstance(ExtensionTipsService)); instantiationService.stub(IURLService, URLService); diff --git a/src/vs/workbench/services/label/common/labelService.ts b/src/vs/workbench/services/label/common/labelService.ts index 8bc3fa0db09..0c2905e2708 100644 --- a/src/vs/workbench/services/label/common/labelService.ts +++ b/src/vs/workbench/services/label/common/labelService.ts @@ -5,9 +5,9 @@ import { localize } from 'vs/nls'; import { URI } from 'vs/base/common/uri'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import * as paths from 'vs/base/common/path'; -import { Event, Emitter } from 'vs/base/common/event'; +import { Emitter } from 'vs/base/common/event'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry, IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { Registry } from 'vs/platform/registry/common/platform'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -16,7 +16,7 @@ import { isEqual, basenameOrAuthority, basename, joinPath, dirname } from 'vs/ba import { tildify, getPathLabel } from 'vs/base/common/labels'; import { ltrim, endsWith } from 'vs/base/common/strings'; import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, WORKSPACE_EXTENSION, toWorkspaceIdentifier, isWorkspaceIdentifier, isUntitledWorkspace } from 'vs/platform/workspaces/common/workspaces'; -import { ILabelService, ResourceLabelFormatter, ResourceLabelFormatting } from 'vs/platform/label/common/label'; +import { ILabelService, ResourceLabelFormatter, ResourceLabelFormatting, IFormatterChangeEvent } from 'vs/platform/label/common/label'; import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { match } from 'vs/base/common/glob'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; @@ -89,19 +89,20 @@ class ResourceLabelFormattersHandler implements IWorkbenchContribution { } Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ResourceLabelFormattersHandler, LifecyclePhase.Restored); -export class LabelService implements ILabelService { +export class LabelService extends Disposable implements ILabelService { + _serviceBrand: undefined; private formatters: ResourceLabelFormatter[] = []; - private readonly _onDidChangeFormatters = new Emitter(); + + private readonly _onDidChangeFormatters = this._register(new Emitter()); + readonly onDidChangeFormatters = this._onDidChangeFormatters.event; constructor( @IEnvironmentService private readonly environmentService: IEnvironmentService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - ) { } - - get onDidChangeFormatters(): Event { - return this._onDidChangeFormatters.event; + ) { + super(); } findFormatting(resource: URI): ResourceLabelFormatting | undefined { @@ -226,12 +227,12 @@ export class LabelService implements ILabelService { registerFormatter(formatter: ResourceLabelFormatter): IDisposable { this.formatters.push(formatter); - this._onDidChangeFormatters.fire(); + this._onDidChangeFormatters.fire({ scheme: formatter.scheme }); return { dispose: () => { this.formatters = this.formatters.filter(f => f !== formatter); - this._onDidChangeFormatters.fire(); + this._onDidChangeFormatters.fire({ scheme: formatter.scheme }); } }; } From 66c09fb60ec74700560781e5113dadc602db2897 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 2 Mar 2020 11:15:21 +0100 Subject: [PATCH 202/235] editors - add and adopt IEditorService#isOpen(resource) for fast lookups of opened editors --- src/vs/workbench/browser/dnd.ts | 2 +- .../browser/parts/editor/editorGroupView.ts | 7 +- .../browser/parts/editor/editorsObserver.ts | 63 ++++++++--- .../browser/editors/textFileEditorTracker.ts | 5 +- .../files/browser/views/openEditorsView.ts | 2 +- .../services/editor/browser/editorService.ts | 20 +++- .../services/editor/common/editorService.ts | 6 + .../editor/test/browser/editorService.test.ts | 50 +++++++++ .../test/browser/editorsObserver.test.ts | 104 ++++++++++++++++-- .../services/search/common/searchService.ts | 2 +- .../test/browser/workbenchTestServices.ts | 2 +- 11 files changed, 225 insertions(+), 38 deletions(-) diff --git a/src/vs/workbench/browser/dnd.ts b/src/vs/workbench/browser/dnd.ts index 6467fe70efd..7e26d2f9376 100644 --- a/src/vs/workbench/browser/dnd.ts +++ b/src/vs/workbench/browser/dnd.ts @@ -246,7 +246,7 @@ export class ResourcesDropHandler { } // File: ensure the file is not dirty or opened already - else if (this.textFileService.isDirty(droppedDirtyEditor.resource) || this.editorService.isOpen(this.editorService.createInput({ resource: droppedDirtyEditor.resource, forceFile: true }))) { + else if (this.textFileService.isDirty(droppedDirtyEditor.resource) || this.editorService.isOpen({ resource: droppedDirtyEditor.resource })) { return false; } diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index b030a213d1c..c57de285635 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -1075,7 +1075,10 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Update model and make sure to continue to use the editor we get from // the model. It is possible that the editor was already opened and we // want to ensure that we use the existing instance in that case. - const editor = this.group.getEditorByIndex(currentIndex)!; + const editor = this._group.getEditorByIndex(currentIndex); + if (!editor) { + return; + } // Update model this._group.moveEditor(editor, moveToIndex); @@ -1278,7 +1281,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { return false; // editor must be dirty and not saving } - if (editor instanceof SideBySideEditorInput && this.isOpened(editor.master)) { + if (editor instanceof SideBySideEditorInput && this._group.contains(editor.master)) { return false; // master-side of editor is still opened somewhere else } diff --git a/src/vs/workbench/browser/parts/editor/editorsObserver.ts b/src/vs/workbench/browser/parts/editor/editorsObserver.ts index b370de392c8..47d62dc9351 100644 --- a/src/vs/workbench/browser/parts/editor/editorsObserver.ts +++ b/src/vs/workbench/browser/parts/editor/editorsObserver.ts @@ -3,15 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IEditorInput, IEditorInputFactoryRegistry, IEditorIdentifier, GroupIdentifier, Extensions, IEditorPartOptionsChangeEvent, EditorsOrder } from 'vs/workbench/common/editor'; +import { IEditorInput, IEditorInputFactoryRegistry, IEditorIdentifier, GroupIdentifier, Extensions, IEditorPartOptionsChangeEvent, EditorsOrder, toResource, SideBySideEditor } from 'vs/workbench/common/editor'; import { dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { Registry } from 'vs/platform/registry/common/platform'; import { Event, Emitter } from 'vs/base/common/event'; import { IEditorGroupsService, IEditorGroup, GroupChangeKind, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService'; import { coalesce } from 'vs/base/common/arrays'; -import { LinkedMap, Touch } from 'vs/base/common/map'; +import { LinkedMap, Touch, ResourceMap } from 'vs/base/common/map'; import { equals } from 'vs/base/common/objects'; +import { URI } from 'vs/base/common/uri'; interface ISerializedEditorsList { entries: ISerializedEditorIdentifier[]; @@ -37,9 +38,10 @@ export class EditorsObserver extends Disposable { private readonly keyMap = new Map>(); private readonly mostRecentEditorsMap = new LinkedMap(); + private readonly editorResourcesMap = new ResourceMap(); - private readonly _onDidChange = this._register(new Emitter()); - readonly onDidChange = this._onDidChange.event; + private readonly _onDidMostRecentlyActiveEditorsChange = this._register(new Emitter()); + readonly onDidMostRecentlyActiveEditorsChange = this._onDidMostRecentlyActiveEditorsChange.event; get count(): number { return this.mostRecentEditorsMap.size; @@ -49,6 +51,10 @@ export class EditorsObserver extends Disposable { return this.mostRecentEditorsMap.values(); } + hasEditor(resource: URI): boolean { + return this.editorResourcesMap.has(resource); + } + constructor( @IEditorGroupsService private editorGroupsService: IEditorGroupsService, @IStorageService private readonly storageService: IStorageService @@ -72,12 +78,12 @@ export class EditorsObserver extends Disposable { // of the new group into our list in LRU order const groupEditorsMru = group.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE); for (let i = groupEditorsMru.length - 1; i >= 0; i--) { - this.addMostRecentEditor(group, groupEditorsMru[i], false /* is not active */); + this.addMostRecentEditor(group, groupEditorsMru[i], false /* is not active */, true /* is new */); } // Make sure that active editor is put as first if group is active if (this.editorGroupsService.activeGroup === group && group.activeEditor) { - this.addMostRecentEditor(group, group.activeEditor, true /* is active */); + this.addMostRecentEditor(group, group.activeEditor, true /* is active */, false /* already added before */); } // Group Listeners @@ -92,7 +98,7 @@ export class EditorsObserver extends Disposable { // Group gets active: put active editor as most recent case GroupChangeKind.GROUP_ACTIVE: { if (this.editorGroupsService.activeGroup === group && group.activeEditor) { - this.addMostRecentEditor(group, group.activeEditor, true /* is active */); + this.addMostRecentEditor(group, group.activeEditor, true /* is active */, false /* editor already opened */); } break; @@ -102,7 +108,7 @@ export class EditorsObserver extends Disposable { // if group is active, otherwise second most recent case GroupChangeKind.EDITOR_ACTIVE: { if (e.editor) { - this.addMostRecentEditor(group, e.editor, this.editorGroupsService.activeGroup === group); + this.addMostRecentEditor(group, e.editor, this.editorGroupsService.activeGroup === group, false /* editor already opened */); } break; @@ -114,7 +120,7 @@ export class EditorsObserver extends Disposable { // start to close oldest ones if needed. case GroupChangeKind.EDITOR_OPEN: { if (e.editor) { - this.addMostRecentEditor(group, e.editor, false /* is not active */); + this.addMostRecentEditor(group, e.editor, false /* is not active */, true /* is new */); this.ensureOpenedEditorsLimit({ groupId: group.id, editor: e.editor }, group.id); } @@ -148,7 +154,7 @@ export class EditorsObserver extends Disposable { } } - private addMostRecentEditor(group: IEditorGroup, editor: IEditorInput, isActive: boolean): void { + private addMostRecentEditor(group: IEditorGroup, editor: IEditorInput, isActive: boolean, isNew: boolean): void { const key = this.ensureKey(group, editor); const mostRecentEditor = this.mostRecentEditorsMap.first; @@ -169,11 +175,39 @@ export class EditorsObserver extends Disposable { this.mostRecentEditorsMap.set(mostRecentEditor, mostRecentEditor, Touch.AsOld /* make first */); } + // Update in resource map if this is a new editor + if (isNew) { + this.updateEditorResourcesMap(editor, true); + } + // Event - this._onDidChange.fire(); + this._onDidMostRecentlyActiveEditorsChange.fire(); + } + + private updateEditorResourcesMap(editor: IEditorInput, add: boolean): void { + const resource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }); + if (!resource) { + return; // require a resource + } + + if (add) { + this.editorResourcesMap.set(resource, (this.editorResourcesMap.get(resource) ?? 0) + 1); + } else { + const counter = this.editorResourcesMap.get(resource) ?? 0; + if (counter > 1) { + this.editorResourcesMap.set(resource, counter - 1); + } else { + this.editorResourcesMap.delete(resource); + } + } } private removeMostRecentEditor(group: IEditorGroup, editor: IEditorInput): void { + + // Update in resource map + this.updateEditorResourcesMap(editor, false); + + // Update in MRU list const key = this.findKey(group, editor); if (key) { @@ -187,7 +221,7 @@ export class EditorsObserver extends Disposable { } // Event - this._onDidChange.fire(); + this._onDidMostRecentlyActiveEditorsChange.fire(); } } @@ -361,7 +395,7 @@ export class EditorsObserver extends Disposable { const group = groups[i]; const groupEditorsMru = group.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE); for (let i = groupEditorsMru.length - 1; i >= 0; i--) { - this.addMostRecentEditor(group, groupEditorsMru[i], true /* enforce as active to preserve order */); + this.addMostRecentEditor(group, groupEditorsMru[i], true /* enforce as active to preserve order */, true /* is new */); } } } @@ -392,6 +426,9 @@ export class EditorsObserver extends Disposable { // Make sure key is registered as well const editorIdentifier = this.ensureKey(group, editor); mapValues.push([editorIdentifier, editorIdentifier]); + + // Update in resource map + this.updateEditorResourcesMap(editor, true); } // Fill map with deserialized values diff --git a/src/vs/workbench/contrib/files/browser/editors/textFileEditorTracker.ts b/src/vs/workbench/contrib/files/browser/editors/textFileEditorTracker.ts index d15f6a57e81..9d6d291ea17 100644 --- a/src/vs/workbench/contrib/files/browser/editors/textFileEditorTracker.ts +++ b/src/vs/workbench/contrib/files/browser/editors/textFileEditorTracker.ts @@ -13,7 +13,6 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { RunOnceWorker } from 'vs/base/common/async'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; -import { Schemas } from 'vs/base/common/network'; export class TextFileEditorTracker extends Disposable implements IWorkbenchContribution { @@ -45,7 +44,7 @@ export class TextFileEditorTracker extends Disposable implements IWorkbenchContr //#region Text File: Ensure every dirty text and untitled file is opened in an editor - private readonly ensureDirtyFilesAreOpenedWorker = this._register(new RunOnceWorker(units => this.ensureDirtyTextFilesAreOpened(units), 250)); + private readonly ensureDirtyFilesAreOpenedWorker = this._register(new RunOnceWorker(units => this.ensureDirtyTextFilesAreOpened(units), 50)); private ensureDirtyTextFilesAreOpened(resources: URI[]): void { this.doEnsureDirtyTextFilesAreOpened(distinct(resources.filter(resource => { @@ -58,7 +57,7 @@ export class TextFileEditorTracker extends Disposable implements IWorkbenchContr return false; // resource must not be pending to save } - if (this.editorService.isOpen(this.editorService.createInput({ resource, forceFile: resource.scheme !== Schemas.untitled, forceUntitled: resource.scheme === Schemas.untitled }))) { + if (this.editorService.isOpen({ resource })) { return false; // model must not be opened already as file } diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index 339367815bb..ebf9f42d42f 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -677,7 +677,7 @@ class OpenEditorsDragAndDrop implements IListDragAndDrop this.onEditorsRestored()); this.editorGroupService.onDidActiveGroupChange(group => this.handleActiveEditorChange(group)); this.editorGroupService.onDidAddGroup(group => this.registerGroupListeners(group as IEditorGroupView)); - this.editorsObserver.onDidChange(() => this._onDidMostRecentlyActiveEditorsChange.fire()); + this.editorsObserver.onDidMostRecentlyActiveEditorsChange(() => this._onDidMostRecentlyActiveEditorsChange.fire()); // Out of workspace file watchers this._register(this.onDidVisibleEditorsChange(() => this.handleVisibleEditorsChange())); @@ -705,8 +705,18 @@ export class EditorService extends Disposable implements EditorServiceImpl { //#region isOpen() - isOpen(editor: IEditorInput): boolean { - return this.editorGroupService.groups.some(group => group.isOpened(editor)); + isOpen(editor: IEditorInput): boolean; + isOpen(editor: IResourceInput): boolean; + isOpen(editor: IEditorInput | IResourceInput): boolean { + if (editor instanceof EditorInput) { + return this.editorGroupService.groups.some(group => group.isOpened(editor)); + } + + if (editor.resource) { + return this.editorsObserver.hasEditor(editor.resource); + } + + return false; } //#endregion @@ -1169,7 +1179,9 @@ export class DelegatingEditorService implements IEditorService { return this.editorService.replaceEditors(editors as IResourceEditorReplacement[] /* TS fail */, group); } - isOpen(editor: IEditorInput): boolean { return this.editorService.isOpen(editor); } + isOpen(editor: IEditorInput): boolean; + isOpen(editor: IResourceInput): boolean; + isOpen(editor: IEditorInput | IResourceInput): boolean { return this.editorService.isOpen(editor as IResourceInput /* TS fail */); } overrideOpenEditor(handler: IOpenEditorOverrideHandler): IDisposable { return this.editorService.overrideOpenEditor(handler); } diff --git a/src/vs/workbench/services/editor/common/editorService.ts b/src/vs/workbench/services/editor/common/editorService.ts index d014673ca3d..490ec7f1b32 100644 --- a/src/vs/workbench/services/editor/common/editorService.ts +++ b/src/vs/workbench/services/editor/common/editorService.ts @@ -196,7 +196,13 @@ export interface IEditorService { * Find out if the provided editor is opened in any editor group. * * Note: An editor can be opened but not actively visible. + * + * @param editor the editor to check for being opened. If a + * `IResourceInput` is passed in, the resource is checked on + * all opened editors. In case of a side by side editor, the + * right hand side resource is considered only. */ + isOpen(editor: IResourceInput): boolean; isOpen(editor: IEditorInput): boolean; /** diff --git a/src/vs/workbench/services/editor/test/browser/editorService.test.ts b/src/vs/workbench/services/editor/test/browser/editorService.test.ts index 45606b858d0..c80aa1cd9f3 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -105,6 +105,7 @@ suite('EditorService', () => { assert.ok(!service.activeTextEditorMode); assert.equal(service.visibleTextEditorWidgets.length, 0); assert.equal(service.isOpen(input), true); + assert.equal(service.isOpen({ resource: input.resource }), true); assert.equal(activeEditorChangeEventCounter, 1); assert.equal(visibleEditorChangeEventCounter, 1); @@ -137,7 +138,9 @@ suite('EditorService', () => { assert.equal(otherInput, service.getEditors(EditorsOrder.SEQUENTIAL)[1].editor); assert.equal(service.visibleControls.length, 1); assert.equal(service.isOpen(input), true); + assert.equal(service.isOpen({ resource: input.resource }), true); assert.equal(service.isOpen(otherInput), true); + assert.equal(service.isOpen({ resource: otherInput.resource }), true); assert.equal(activeEditorChangeEventCounter, 4); assert.equal(visibleEditorChangeEventCounter, 4); @@ -149,6 +152,53 @@ suite('EditorService', () => { part.dispose(); }); + test('isOpen() with side by side editor', async () => { + const [part, service] = createEditorService(); + + const input = new TestFileEditorInput(URI.parse('my://resource-openEditors'), TEST_EDITOR_INPUT_ID); + const otherInput = new TestFileEditorInput(URI.parse('my://resource2-openEditors'), TEST_EDITOR_INPUT_ID); + const sideBySideInput = new SideBySideEditorInput('sideBySide', '', input, otherInput); + + await part.whenRestored; + + const editor1 = await service.openEditor(sideBySideInput, { pinned: true }); + assert.equal(part.activeGroup.count, 1); + + assert.equal(service.isOpen(input), false); + assert.equal(service.isOpen(otherInput), false); + assert.equal(service.isOpen(sideBySideInput), true); + assert.equal(service.isOpen({ resource: input.resource }), false); + assert.equal(service.isOpen({ resource: otherInput.resource }), true); + + const editor2 = await service.openEditor(input, { pinned: true }); + assert.equal(part.activeGroup.count, 2); + + assert.equal(service.isOpen(input), true); + assert.equal(service.isOpen(otherInput), false); + assert.equal(service.isOpen(sideBySideInput), true); + assert.equal(service.isOpen({ resource: input.resource }), true); + assert.equal(service.isOpen({ resource: otherInput.resource }), true); + + await editor2?.group?.closeEditor(input); + assert.equal(part.activeGroup.count, 1); + + assert.equal(service.isOpen(input), false); + assert.equal(service.isOpen(otherInput), false); + assert.equal(service.isOpen(sideBySideInput), true); + assert.equal(service.isOpen({ resource: input.resource }), false); + assert.equal(service.isOpen({ resource: otherInput.resource }), true); + + await editor1?.group?.closeEditor(sideBySideInput); + + assert.equal(service.isOpen(input), false); + assert.equal(service.isOpen(otherInput), false); + assert.equal(service.isOpen(sideBySideInput), false); + assert.equal(service.isOpen({ resource: input.resource }), false); + assert.equal(service.isOpen({ resource: otherInput.resource }), false); + + part.dispose(); + }); + test('openEditors() / replaceEditors()', async () => { const [part, service] = createEditorService(); diff --git a/src/vs/workbench/services/editor/test/browser/editorsObserver.test.ts b/src/vs/workbench/services/editor/test/browser/editorsObserver.test.ts index 2f25fec289d..c0e0d8a1921 100644 --- a/src/vs/workbench/services/editor/test/browser/editorsObserver.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorsObserver.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { EditorOptions, IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; -import { workbenchInstantiationService, TestStorageService, TestFileEditorInput, registerTestEditor } from 'vs/workbench/test/browser/workbenchTestServices'; +import { workbenchInstantiationService, TestStorageService, TestFileEditorInput, registerTestEditor, TestEditorPart } from 'vs/workbench/test/browser/workbenchTestServices'; import { Registry } from 'vs/platform/registry/common/platform'; import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; @@ -34,11 +34,11 @@ suite('EditorsObserver', function () { disposables = []; }); - async function createPart(): Promise { + async function createPart(): Promise { const instantiationService = workbenchInstantiationService(); instantiationService.invokeFunction(accessor => Registry.as(EditorExtensions.EditorInputFactories).start(accessor)); - const part = instantiationService.createInstance(EditorPart); + const part = instantiationService.createInstance(TestEditorPart); part.create(document.createElement('div')); part.layout(400, 300); @@ -58,14 +58,14 @@ suite('EditorsObserver', function () { test('basics (single group)', async () => { const [part, observer] = await createEditorObserver(); - let observerChangeListenerCalled = false; - const listener = observer.onDidChange(() => { - observerChangeListenerCalled = true; + let onDidMostRecentlyActiveEditorsChangeCalled = false; + const listener = observer.onDidMostRecentlyActiveEditorsChange(() => { + onDidMostRecentlyActiveEditorsChangeCalled = true; }); let currentEditorsMRU = observer.editors; assert.equal(currentEditorsMRU.length, 0); - assert.equal(observerChangeListenerCalled, false); + assert.equal(onDidMostRecentlyActiveEditorsChangeCalled, false); const input1 = new TestFileEditorInput(URI.parse('foo://bar1'), TEST_SERIALIZABLE_EDITOR_INPUT_ID); @@ -75,7 +75,8 @@ suite('EditorsObserver', function () { assert.equal(currentEditorsMRU.length, 1); assert.equal(currentEditorsMRU[0].groupId, part.activeGroup.id); assert.equal(currentEditorsMRU[0].editor, input1); - assert.equal(observerChangeListenerCalled, true); + assert.equal(onDidMostRecentlyActiveEditorsChangeCalled, true); + assert.equal(observer.hasEditor(input1.resource), true); const input2 = new TestFileEditorInput(URI.parse('foo://bar2'), TEST_SERIALIZABLE_EDITOR_INPUT_ID); const input3 = new TestFileEditorInput(URI.parse('foo://bar3'), TEST_SERIALIZABLE_EDITOR_INPUT_ID); @@ -91,6 +92,8 @@ suite('EditorsObserver', function () { assert.equal(currentEditorsMRU[1].editor, input2); assert.equal(currentEditorsMRU[2].groupId, part.activeGroup.id); assert.equal(currentEditorsMRU[2].editor, input1); + assert.equal(observer.hasEditor(input2.resource), true); + assert.equal(observer.hasEditor(input3.resource), true); await part.activeGroup.openEditor(input2, EditorOptions.create({ pinned: true })); @@ -102,8 +105,11 @@ suite('EditorsObserver', function () { assert.equal(currentEditorsMRU[1].editor, input3); assert.equal(currentEditorsMRU[2].groupId, part.activeGroup.id); assert.equal(currentEditorsMRU[2].editor, input1); + assert.equal(observer.hasEditor(input1.resource), true); + assert.equal(observer.hasEditor(input2.resource), true); + assert.equal(observer.hasEditor(input3.resource), true); - observerChangeListenerCalled = false; + onDidMostRecentlyActiveEditorsChangeCalled = false; await part.activeGroup.closeEditor(input1); currentEditorsMRU = observer.editors; @@ -112,11 +118,17 @@ suite('EditorsObserver', function () { assert.equal(currentEditorsMRU[0].editor, input2); assert.equal(currentEditorsMRU[1].groupId, part.activeGroup.id); assert.equal(currentEditorsMRU[1].editor, input3); - assert.equal(observerChangeListenerCalled, true); + assert.equal(onDidMostRecentlyActiveEditorsChangeCalled, true); + assert.equal(observer.hasEditor(input1.resource), false); + assert.equal(observer.hasEditor(input2.resource), true); + assert.equal(observer.hasEditor(input3.resource), true); await part.activeGroup.closeAllEditors(); currentEditorsMRU = observer.editors; assert.equal(currentEditorsMRU.length, 0); + assert.equal(observer.hasEditor(input1.resource), false); + assert.equal(observer.hasEditor(input2.resource), false); + assert.equal(observer.hasEditor(input3.resource), false); part.dispose(); listener.dispose(); @@ -143,6 +155,7 @@ suite('EditorsObserver', function () { assert.equal(currentEditorsMRU[0].editor, input1); assert.equal(currentEditorsMRU[1].groupId, rootGroup.id); assert.equal(currentEditorsMRU[1].editor, input1); + assert.equal(observer.hasEditor(input1.resource), true); await rootGroup.openEditor(input1, EditorOptions.create({ pinned: true, activation: EditorActivation.ACTIVATE })); @@ -152,6 +165,7 @@ suite('EditorsObserver', function () { assert.equal(currentEditorsMRU[0].editor, input1); assert.equal(currentEditorsMRU[1].groupId, sideGroup.id); assert.equal(currentEditorsMRU[1].editor, input1); + assert.equal(observer.hasEditor(input1.resource), true); // Opening an editor inactive should not change // the most recent editor, but rather put it behind @@ -167,6 +181,8 @@ suite('EditorsObserver', function () { assert.equal(currentEditorsMRU[1].editor, input2); assert.equal(currentEditorsMRU[2].groupId, sideGroup.id); assert.equal(currentEditorsMRU[2].editor, input1); + assert.equal(observer.hasEditor(input1.resource), true); + assert.equal(observer.hasEditor(input2.resource), true); await rootGroup.closeAllEditors(); @@ -174,11 +190,15 @@ suite('EditorsObserver', function () { assert.equal(currentEditorsMRU.length, 1); assert.equal(currentEditorsMRU[0].groupId, sideGroup.id); assert.equal(currentEditorsMRU[0].editor, input1); + assert.equal(observer.hasEditor(input1.resource), true); + assert.equal(observer.hasEditor(input2.resource), false); await sideGroup.closeAllEditors(); currentEditorsMRU = observer.editors; assert.equal(currentEditorsMRU.length, 0); + assert.equal(observer.hasEditor(input1.resource), false); + assert.equal(observer.hasEditor(input2.resource), false); part.dispose(); }); @@ -204,6 +224,9 @@ suite('EditorsObserver', function () { assert.equal(currentEditorsMRU[1].editor, input2); assert.equal(currentEditorsMRU[2].groupId, rootGroup.id); assert.equal(currentEditorsMRU[2].editor, input1); + assert.equal(observer.hasEditor(input1.resource), true); + assert.equal(observer.hasEditor(input2.resource), true); + assert.equal(observer.hasEditor(input3.resource), true); const copiedGroup = part.copyGroup(rootGroup, rootGroup, GroupDirection.RIGHT); copiedGroup.setActive(true); @@ -222,6 +245,21 @@ suite('EditorsObserver', function () { assert.equal(currentEditorsMRU[4].editor, input2); assert.equal(currentEditorsMRU[5].groupId, rootGroup.id); assert.equal(currentEditorsMRU[5].editor, input1); + assert.equal(observer.hasEditor(input1.resource), true); + assert.equal(observer.hasEditor(input2.resource), true); + assert.equal(observer.hasEditor(input3.resource), true); + + await rootGroup.closeAllEditors(); + + assert.equal(observer.hasEditor(input1.resource), true); + assert.equal(observer.hasEditor(input2.resource), true); + assert.equal(observer.hasEditor(input3.resource), true); + + await copiedGroup.closeAllEditors(); + + assert.equal(observer.hasEditor(input1.resource), false); + assert.equal(observer.hasEditor(input2.resource), false); + assert.equal(observer.hasEditor(input3.resource), false); part.dispose(); }); @@ -251,6 +289,9 @@ suite('EditorsObserver', function () { assert.equal(currentEditorsMRU[1].editor, input2); assert.equal(currentEditorsMRU[2].groupId, rootGroup.id); assert.equal(currentEditorsMRU[2].editor, input1); + assert.equal(observer.hasEditor(input1.resource), true); + assert.equal(observer.hasEditor(input2.resource), true); + assert.equal(observer.hasEditor(input3.resource), true); storage._onWillSaveState.fire({ reason: WillSaveStateReason.SHUTDOWN }); @@ -265,7 +306,11 @@ suite('EditorsObserver', function () { assert.equal(currentEditorsMRU[1].editor, input2); assert.equal(currentEditorsMRU[2].groupId, rootGroup.id); assert.equal(currentEditorsMRU[2].editor, input1); + assert.equal(observer.hasEditor(input1.resource), true); + assert.equal(observer.hasEditor(input2.resource), true); + assert.equal(observer.hasEditor(input3.resource), true); + part.clearState(); part.dispose(); }); @@ -296,6 +341,9 @@ suite('EditorsObserver', function () { assert.equal(currentEditorsMRU[1].editor, input2); assert.equal(currentEditorsMRU[2].groupId, rootGroup.id); assert.equal(currentEditorsMRU[2].editor, input1); + assert.equal(observer.hasEditor(input1.resource), true); + assert.equal(observer.hasEditor(input2.resource), true); + assert.equal(observer.hasEditor(input3.resource), true); storage._onWillSaveState.fire({ reason: WillSaveStateReason.SHUTDOWN }); @@ -310,7 +358,11 @@ suite('EditorsObserver', function () { assert.equal(currentEditorsMRU[1].editor, input2); assert.equal(currentEditorsMRU[2].groupId, rootGroup.id); assert.equal(currentEditorsMRU[2].editor, input1); + assert.equal(restoredObserver.hasEditor(input1.resource), true); + assert.equal(restoredObserver.hasEditor(input2.resource), true); + assert.equal(restoredObserver.hasEditor(input3.resource), true); + part.clearState(); part.dispose(); }); @@ -331,6 +383,7 @@ suite('EditorsObserver', function () { assert.equal(currentEditorsMRU.length, 1); assert.equal(currentEditorsMRU[0].groupId, rootGroup.id); assert.equal(currentEditorsMRU[0].editor, input1); + assert.equal(observer.hasEditor(input1.resource), true); storage._onWillSaveState.fire({ reason: WillSaveStateReason.SHUTDOWN }); @@ -339,7 +392,9 @@ suite('EditorsObserver', function () { currentEditorsMRU = restoredObserver.editors; assert.equal(currentEditorsMRU.length, 0); + assert.equal(restoredObserver.hasEditor(input1.resource), false); + part.clearState(); part.dispose(); }); @@ -368,6 +423,10 @@ suite('EditorsObserver', function () { assert.equal(rootGroup.isOpened(input2), true); assert.equal(rootGroup.isOpened(input3), true); assert.equal(rootGroup.isOpened(input4), true); + assert.equal(observer.hasEditor(input1.resource), false); + assert.equal(observer.hasEditor(input2.resource), true); + assert.equal(observer.hasEditor(input3.resource), true); + assert.equal(observer.hasEditor(input4.resource), true); input2.setDirty(); part.enforcePartOptions({ limit: { enabled: true, value: 1 } }); @@ -379,6 +438,10 @@ suite('EditorsObserver', function () { assert.equal(rootGroup.isOpened(input2), true); // dirty assert.equal(rootGroup.isOpened(input3), false); assert.equal(rootGroup.isOpened(input4), true); + assert.equal(observer.hasEditor(input1.resource), false); + assert.equal(observer.hasEditor(input2.resource), true); + assert.equal(observer.hasEditor(input3.resource), false); + assert.equal(observer.hasEditor(input4.resource), true); const input5 = new TestFileEditorInput(URI.parse('foo://bar5'), TEST_EDITOR_INPUT_ID); await sideGroup.openEditor(input5, EditorOptions.create({ pinned: true })); @@ -388,8 +451,12 @@ suite('EditorsObserver', function () { assert.equal(rootGroup.isOpened(input2), true); // dirty assert.equal(rootGroup.isOpened(input3), false); assert.equal(rootGroup.isOpened(input4), false); - assert.equal(sideGroup.isOpened(input5), true); + assert.equal(observer.hasEditor(input1.resource), false); + assert.equal(observer.hasEditor(input2.resource), true); + assert.equal(observer.hasEditor(input3.resource), false); + assert.equal(observer.hasEditor(input4.resource), false); + assert.equal(observer.hasEditor(input5.resource), true); observer.dispose(); part.dispose(); @@ -415,11 +482,15 @@ suite('EditorsObserver', function () { await rootGroup.openEditor(input3, EditorOptions.create({ pinned: true })); await rootGroup.openEditor(input4, EditorOptions.create({ pinned: true })); - assert.equal(rootGroup.count, 3); + assert.equal(rootGroup.count, 3); // 1 editor got closed due to our limit! assert.equal(rootGroup.isOpened(input1), false); assert.equal(rootGroup.isOpened(input2), true); assert.equal(rootGroup.isOpened(input3), true); assert.equal(rootGroup.isOpened(input4), true); + assert.equal(observer.hasEditor(input1.resource), false); + assert.equal(observer.hasEditor(input2.resource), true); + assert.equal(observer.hasEditor(input3.resource), true); + assert.equal(observer.hasEditor(input4.resource), true); await sideGroup.openEditor(input1, EditorOptions.create({ pinned: true })); await sideGroup.openEditor(input2, EditorOptions.create({ pinned: true })); @@ -431,6 +502,10 @@ suite('EditorsObserver', function () { assert.equal(sideGroup.isOpened(input2), true); assert.equal(sideGroup.isOpened(input3), true); assert.equal(sideGroup.isOpened(input4), true); + assert.equal(observer.hasEditor(input1.resource), false); + assert.equal(observer.hasEditor(input2.resource), true); + assert.equal(observer.hasEditor(input3.resource), true); + assert.equal(observer.hasEditor(input4.resource), true); part.enforcePartOptions({ limit: { enabled: true, value: 1, perEditorGroup: true } }); @@ -448,6 +523,11 @@ suite('EditorsObserver', function () { assert.equal(sideGroup.isOpened(input3), false); assert.equal(sideGroup.isOpened(input4), true); + assert.equal(observer.hasEditor(input1.resource), false); + assert.equal(observer.hasEditor(input2.resource), false); + assert.equal(observer.hasEditor(input3.resource), false); + assert.equal(observer.hasEditor(input4.resource), true); + observer.dispose(); part.dispose(); }); diff --git a/src/vs/workbench/services/search/common/searchService.ts b/src/vs/workbench/services/search/common/searchService.ts index 990d4637b07..f87b32b45a1 100644 --- a/src/vs/workbench/services/search/common/searchService.ts +++ b/src/vs/workbench/services/search/common/searchService.ts @@ -390,7 +390,7 @@ export class SearchService extends Disposable implements ISearchService { } // Skip files that are not opened as text file - if (!this.editorService.isOpen(this.editorService.createInput({ resource, forceFile: resource.scheme !== Schemas.untitled, forceUntitled: resource.scheme === Schemas.untitled }))) { + if (!this.editorService.isOpen({ resource })) { return; } diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index b152ff1865f..3f03b1b0fcb 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -623,7 +623,7 @@ export class TestEditorService implements EditorServiceImpl { return [this.editorGroupService.activeGroup, editor as EditorInput, undefined]; } openEditors(_editors: any, _group?: any): Promise { throw new Error('not implemented'); } - isOpen(_editor: IEditorInput): boolean { return false; } + isOpen(_editor: IEditorInput | IResourceInput): boolean { return false; } replaceEditors(_editors: any, _group: any) { return Promise.resolve(undefined); } invokeWithinEditorContext(fn: (accessor: ServicesAccessor) => T): T { throw new Error('not implemented'); } createInput(_input: IResourceInput | IUntitledTextResourceInput | IResourceDiffInput | IResourceSideBySideInput): EditorInput { throw new Error('not implemented'); } From bf6c93062b2a1f05fc81bb909ba0d47e8a069949 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 2 Mar 2020 11:39:36 +0100 Subject: [PATCH 203/235] Rename CSS smoke test to language features: For #90538 --- .../areas/languages/{css.test.ts => languages.test.ts} | 8 ++++---- test/smoke/src/main.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) rename test/smoke/src/areas/languages/{css.test.ts => languages.test.ts} (89%) diff --git a/test/smoke/src/areas/languages/css.test.ts b/test/smoke/src/areas/languages/languages.test.ts similarity index 89% rename from test/smoke/src/areas/languages/css.test.ts rename to test/smoke/src/areas/languages/languages.test.ts index 02daa15c7b9..0985a614a9e 100644 --- a/test/smoke/src/areas/languages/css.test.ts +++ b/test/smoke/src/areas/languages/languages.test.ts @@ -3,10 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Application, ProblemSeverity, Problems } from '../../../../automation'; +import { Application, ProblemSeverity, Problems } from '../../../../automation/out'; export function setup() { - describe('Languages - CSS', () => { + describe('Language Features', () => { it('verifies quick outline', async function () { const app = this.app as Application; await app.workbench.quickopen.openFile('style.css'); @@ -15,7 +15,7 @@ export function setup() { await app.workbench.quickopen.waitForQuickOpenElements(names => names.length === 2); }); - it('verifies warnings for the empty rule', async function () { + it('verifies problems view', async function () { const app = this.app as Application; await app.workbench.quickopen.openFile('style.css'); await app.workbench.editor.waitForTypeInEditor('style.css', '.foo{}'); @@ -27,7 +27,7 @@ export function setup() { await app.workbench.problems.hideProblemsView(); }); - it('verifies that warning becomes an error once setting changed', async function () { + it('verifies settings', async function () { const app = this.app as Application; await app.workbench.settingsEditor.addUserSetting('css.lint.emptyRules', '"error"'); await app.workbench.quickopen.openFile('style.css'); diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index f4d51dba717..5a1dd9f11cc 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -25,7 +25,7 @@ import { setup as setupDataMigrationTests } from './areas/workbench/data-migrati import { setup as setupDataLossTests } from './areas/workbench/data-loss.test'; import { setup as setupDataPreferencesTests } from './areas/preferences/preferences.test'; import { setup as setupDataSearchTests } from './areas/search/search.test'; -import { setup as setupDataLanguagesTests } from './areas/languages/css.test'; +import { setup as setupDataLanguagesTests } from './areas/languages/languages.test'; import { setup as setupDataEditorTests } from './areas/editor/editor.test'; import { setup as setupDataStatusbarTests } from './areas/statusbar/statusbar.test'; import { setup as setupDataExtensionTests } from './areas/extensions/extensions.test'; From afba164ec2253260e6acc779a12964ef3d31561b Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Mon, 2 Mar 2020 10:48:49 +0100 Subject: [PATCH 204/235] Fixes #91870: Improve description for editor.fontLigatures --- src/vs/editor/common/config/editorOptions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 284c6f904bb..63ac7bf2133 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -1332,7 +1332,7 @@ export class EditorFontLigatures extends BaseEditorOption Date: Mon, 2 Mar 2020 12:01:35 +0100 Subject: [PATCH 205/235] Only add content widget when setting non-hidden state #90653 --- src/vs/editor/contrib/suggest/suggestWidget.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 3613e737d07..332f1dfb27d 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -473,7 +473,8 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate | null = null; @@ -644,9 +645,6 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate { @@ -810,6 +808,11 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate Date: Mon, 2 Mar 2020 12:14:44 +0100 Subject: [PATCH 206/235] Improve documentation --- src/vs/vscode.proposed.d.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 7e66d226c50..b880c7555d8 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -314,6 +314,9 @@ declare module 'vscode' { * // 1st token, 2nd token, 3rd token * [ 2,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] * ``` + * + * *NOTE*: When doing edits, it is possible that multiple edits occur until VS Code decides to invoke the semantic tokens provider. + * *NOTE*: If the provider cannot temporarily compute semantic tokens, it can indicate this by throwing an error with the message 'Busy'. */ provideDocumentSemanticTokens(document: TextDocument, token: CancellationToken): ProviderResult; @@ -366,7 +369,6 @@ declare module 'vscode' { * edit: { start: 10, deleteCount: 1, data: [1,3,5,0,2,2] } // replace integer at offset 10 with [1,3,5,0,2,2] * ``` * - * *NOTE*: When doing edits, it is possible that multiple edits occur until VS Code decides to invoke the semantic tokens provider. * *NOTE*: If the provider cannot compute `SemanticTokensEdits`, it can "give up" and return all the tokens in the document again. * *NOTE*: All edits in `SemanticTokensEdits` contain indices in the old integers array, so they all refer to the previous result state. */ From 9eedabce7b8111258fa734689566237730156871 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 2 Mar 2020 12:35:20 +0100 Subject: [PATCH 207/235] debt - move native pieces of window config into node layer --- src/bootstrap-window.js | 2 +- src/main.js | 2 +- src/vs/base/test/node/glob.test.ts | 3 - .../issue/issueReporterMain.ts | 6 +- src/vs/code/electron-main/app.ts | 2 +- src/vs/code/electron-main/window.ts | 15 +- src/vs/platform/windows/common/windows.ts | 28 +--- .../platform/windows/electron-main/windows.ts | 9 +- .../electron-main/windowsMainService.ts | 12 +- src/vs/platform/windows/node/window.ts | 32 +++- .../issue/electron-browser/issueService.ts | 3 +- .../electron-browser/remote.contribution.ts | 3 +- .../electron-browser/desktop.main.ts | 8 +- src/vs/workbench/electron-browser/window.ts | 3 +- .../accessibilityService.ts | 7 +- .../browser/configurationResolverService.ts | 2 +- .../configurationResolverService.test.ts | 27 +-- .../environment/browser/environmentService.ts | 156 ++++++------------ .../electron-browser/environmentService.ts | 11 +- .../electron-browser/telemetryService.ts | 5 +- .../timer/electron-browser/timerService.ts | 3 +- .../workspaceEditingService.ts | 3 +- .../electron-browser/workbenchTestServices.ts | 7 +- src/vs/workbench/workbench.desktop.main.ts | 2 +- 24 files changed, 160 insertions(+), 191 deletions(-) rename src/vs/workbench/services/accessibility/{node => electron-browser}/accessibilityService.ts (91%) diff --git a/src/bootstrap-window.js b/src/bootstrap-window.js index 0ab195f924f..cc925afa0b7 100644 --- a/src/bootstrap-window.js +++ b/src/bootstrap-window.js @@ -31,7 +31,7 @@ exports.load = function (modulePaths, resultCallback, options) { const args = parseURLQueryArgs(); /** - * // configuration: IWindowConfiguration + * // configuration: INativeWindowConfiguration * @type {{ * zoomLevel?: number, * extensionDevelopmentPath?: string[], diff --git a/src/main.js b/src/main.js index bc268c8cd12..e1df5deb07c 100644 --- a/src/main.js +++ b/src/main.js @@ -175,7 +175,7 @@ function configureCommandlineSwitchesSync(cliArgs) { app.commandLine.appendSwitch('js-flags', jsFlags); } - // TODO@Ben TODO@Deepak Electron 7 workaround for https://github.com/microsoft/vscode/issues/88873 + // TODO@Deepak Electron 7 workaround for https://github.com/microsoft/vscode/issues/88873 app.commandLine.appendSwitch('disable-features', 'LayoutNG'); return argvConfig; diff --git a/src/vs/base/test/node/glob.test.ts b/src/vs/base/test/node/glob.test.ts index f7e8dfd1356..2c0288e3897 100644 --- a/src/vs/base/test/node/glob.test.ts +++ b/src/vs/base/test/node/glob.test.ts @@ -239,10 +239,7 @@ suite('Glob', () => { assertGlobMatch(p, 'some/folder/project.json'); assertNoGlobMatch(p, 'some/folder/file_project.json'); assertNoGlobMatch(p, 'some/folder/fileproject.json'); - // assertNoGlobMatch(p, '/rrproject.json'); TODO@ben this still fails if T1-3 are disabled assertNoGlobMatch(p, 'some/rrproject.json'); - // assertNoGlobMatch(p, 'rrproject.json'); - // assertNoGlobMatch(p, '\\rrproject.json'); assertNoGlobMatch(p, 'some\\rrproject.json'); p = 'test/**'; diff --git a/src/vs/code/electron-browser/issue/issueReporterMain.ts b/src/vs/code/electron-browser/issue/issueReporterMain.ts index 169dbf0c326..8ed46109857 100644 --- a/src/vs/code/electron-browser/issue/issueReporterMain.ts +++ b/src/vs/code/electron-browser/issue/issueReporterMain.ts @@ -39,7 +39,7 @@ import { ITelemetryServiceConfig, TelemetryService } from 'vs/platform/telemetry import { combinedAppender, LogAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties'; import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc'; -import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; +import { INativeWindowConfiguration } from 'vs/platform/windows/node/window'; const MAX_URL_LENGTH = 2045; @@ -49,7 +49,7 @@ interface SearchResult { state?: string; } -export interface IssueReporterConfiguration extends IWindowConfiguration { +export interface IssueReporterConfiguration extends INativeWindowConfiguration { data: IssueReporterData; features: IssueReporterFeatures; } @@ -316,7 +316,7 @@ export class IssueReporter extends Disposable { } } - private initServices(configuration: IWindowConfiguration): void { + private initServices(configuration: INativeWindowConfiguration): void { const serviceCollection = new ServiceCollection(); const mainProcessService = new MainProcessService(configuration.windowId); serviceCollection.set(IMainProcessService, mainProcessService); diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 4ba8c87cb98..d91ab55a23d 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -133,7 +133,7 @@ export class CodeApplication extends Disposable { // // !!! DO NOT CHANGE without consulting the documentation !!! // - // app.on('remote-get-guest-web-contents', event => event.preventDefault()); // TODO@Ben TODO@Matt revisit this need for + // app.on('remote-get-guest-web-contents', event => event.preventDefault()); // TODO@Matt revisit this need for app.on('remote-require', (event, sender, module) => { this.logService.trace('App#on(remote-require): prevented'); diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 55600018311..7e4ddbbe0a3 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -14,10 +14,11 @@ import { ILogService } from 'vs/platform/log/common/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import product from 'vs/platform/product/common/product'; -import { IWindowSettings, MenuBarVisibility, IWindowConfiguration, ReadyState, getTitleBarStyle, getMenuBarVisibility } from 'vs/platform/windows/common/windows'; +import { IWindowSettings, MenuBarVisibility, ReadyState, getTitleBarStyle, getMenuBarVisibility } from 'vs/platform/windows/common/windows'; import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; import { ICodeWindow, IWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows'; +import { INativeWindowConfiguration } from 'vs/platform/windows/node/window'; import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IWorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService'; import { IBackupMainService } from 'vs/platform/backup/electron-main/backup'; @@ -85,7 +86,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { private readonly whenReadyCallbacks: { (window: ICodeWindow): void }[]; - private pendingLoadConfig?: IWindowConfiguration; + private pendingLoadConfig?: INativeWindowConfiguration; private marketplaceHeadersPromise: Promise; @@ -231,8 +232,8 @@ export class CodeWindow extends Disposable implements ICodeWindow { this.registerListeners(); } - private currentConfig: IWindowConfiguration | undefined; - get config(): IWindowConfiguration | undefined { return this.currentConfig; } + private currentConfig: INativeWindowConfiguration | undefined; + get config(): INativeWindowConfiguration | undefined { return this.currentConfig; } private _id: number; get id(): number { return this._id; } @@ -552,7 +553,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { } } - load(config: IWindowConfiguration, isReload?: boolean, disableExtensions?: boolean): void { + load(config: INativeWindowConfiguration, isReload?: boolean, disableExtensions?: boolean): void { // If this is the first time the window is loaded, we associate the paths // directly with the window because we assume the loading will just work @@ -612,7 +613,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { this._onLoad.fire(); } - reload(configurationIn?: IWindowConfiguration, cli?: ParsedArgs): void { + reload(configurationIn?: INativeWindowConfiguration, cli?: ParsedArgs): void { // If config is not provided, copy our current one const configuration = configurationIn ? configurationIn : objects.mixin({}, this.currentConfig); @@ -639,7 +640,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { this.load(configuration, true, disableExtensions); } - private getUrl(windowConfiguration: IWindowConfiguration): string { + private getUrl(windowConfiguration: INativeWindowConfiguration): string { // Set window ID windowConfiguration.windowId = this._win.id; diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index 78210255a5f..348d06948f6 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -3,11 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IProcessEnvironment, isMacintosh, isLinux, isWeb } from 'vs/base/common/platform'; +import { isMacintosh, isLinux, isWeb } from 'vs/base/common/platform'; import { ParsedArgs, IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { ExportData } from 'vs/base/common/performance'; -import { LogLevel } from 'vs/platform/log/common/log'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -220,41 +218,17 @@ export interface IAddFoldersRequest { } export interface IWindowConfiguration extends ParsedArgs { - machineId?: string; // NOTE: This is undefined in the web, the telemetry service directly resolves this. - windowId: number; // TODO: should we deprecate this in favor of sessionId? sessionId: string; - logLevel: LogLevel; - mainPid: number; - - appRoot: string; - execPath: string; - isInitialStartup?: boolean; - - userEnv: IProcessEnvironment; - nodeCachedDataDir?: string; - - backupPath?: string; backupWorkspaceResource?: URI; - workspace?: IWorkspaceIdentifier; - folderUri?: ISingleFolderWorkspaceIdentifier; - remoteAuthority?: string; connectionToken?: string; - zoomLevel?: number; - fullscreen?: boolean; - maximized?: boolean; highContrast?: boolean; - accessibilitySupport?: boolean; - partsSplashPath?: string; - - perfEntries: ExportData; filesToOpenOrCreate?: IPath[]; filesToDiff?: IPath[]; - filesToWait?: IPathsToWaitFor; } export interface IRunActionInWindowRequest { diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index 9d519473683..3e05c84fcd9 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -3,7 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { OpenContext, IWindowConfiguration, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { OpenContext, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; +import { INativeWindowConfiguration } from 'vs/platform/windows/node/window'; import { ParsedArgs } from 'vs/platform/environment/common/environment'; import { Event } from 'vs/base/common/event'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; @@ -39,7 +40,7 @@ export interface ICodeWindow extends IDisposable { readonly id: number; readonly win: BrowserWindow; - readonly config: IWindowConfiguration | undefined; + readonly config: INativeWindowConfiguration | undefined; readonly openedFolderUri?: URI; readonly openedWorkspace?: IWorkspaceIdentifier; @@ -60,8 +61,8 @@ export interface ICodeWindow extends IDisposable { addTabbedWindow(window: ICodeWindow): void; - load(config: IWindowConfiguration, isReload?: boolean): void; - reload(configuration?: IWindowConfiguration, cli?: ParsedArgs): void; + load(config: INativeWindowConfiguration, isReload?: boolean): void; + reload(configuration?: INativeWindowConfiguration, cli?: ParsedArgs): void; focus(): void; close(): void; diff --git a/src/vs/platform/windows/electron-main/windowsMainService.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts index bc8e53b1e21..8562c033266 100644 --- a/src/vs/platform/windows/electron-main/windowsMainService.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -18,8 +18,8 @@ import { parseLineAndColumnAware } from 'vs/code/node/paths'; import { ILifecycleMainService, UnloadReason, LifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService } from 'vs/platform/log/common/log'; -import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, IPathsToWaitFor, isFileToOpen, isWorkspaceToOpen, isFolderToOpen, IWindowOpenable, IOpenEmptyWindowOptions, IAddFoldersRequest } from 'vs/platform/windows/common/windows'; -import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnWorkspace, findWindowOnExtensionDevelopmentPath, findWindowOnWorkspaceOrFolderUri } from 'vs/platform/windows/node/window'; +import { IWindowSettings, OpenContext, IPath, IPathsToWaitFor, isFileToOpen, isWorkspaceToOpen, isFolderToOpen, IWindowOpenable, IOpenEmptyWindowOptions, IAddFoldersRequest } from 'vs/platform/windows/common/windows'; +import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnWorkspace, findWindowOnExtensionDevelopmentPath, findWindowOnWorkspaceOrFolderUri, INativeWindowConfiguration } from 'vs/platform/windows/node/window'; import { Emitter } from 'vs/base/common/event'; import product from 'vs/platform/product/common/product'; import { IWindowsMainService, IOpenConfiguration, IWindowsCountChangedEvent, ICodeWindow, IWindowState as ISingleWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows'; @@ -1354,8 +1354,8 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic private openInBrowserWindow(options: IOpenBrowserWindowOptions): ICodeWindow { - // Build IWindowConfiguration from config and options - const configuration: IWindowConfiguration = mixin({}, options.cli); // inherit all properties from CLI + // Build INativeWindowConfiguration from config and options + const configuration: INativeWindowConfiguration = mixin({}, options.cli); // inherit all properties from CLI configuration.appRoot = this.environmentService.appRoot; configuration.machineId = this.machineId; configuration.nodeCachedDataDir = this.environmentService.nodeCachedDataDir; @@ -1482,7 +1482,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic return window; } - private doOpenInBrowserWindow(window: ICodeWindow, configuration: IWindowConfiguration, options: IOpenBrowserWindowOptions): void { + private doOpenInBrowserWindow(window: ICodeWindow, configuration: INativeWindowConfiguration, options: IOpenBrowserWindowOptions): void { // Register window for backups if (!configuration.extensionDevelopmentPath) { @@ -1500,7 +1500,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic window.load(configuration); } - private getNewWindowState(configuration: IWindowConfiguration): INewWindowState { + private getNewWindowState(configuration: INativeWindowConfiguration): INewWindowState { const lastActive = this.getLastActiveWindow(); // Restore state unless we are running extension tests diff --git a/src/vs/platform/windows/node/window.ts b/src/vs/platform/windows/node/window.ts index 08a4e800d3b..ae9c2b70e58 100644 --- a/src/vs/platform/windows/node/window.ts +++ b/src/vs/platform/windows/node/window.ts @@ -3,12 +3,42 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { OpenContext, IOpenWindowOptions } from 'vs/platform/windows/common/windows'; +import { OpenContext, IOpenWindowOptions, IWindowConfiguration, IPathsToWaitFor } from 'vs/platform/windows/common/windows'; import { URI } from 'vs/base/common/uri'; import * as platform from 'vs/base/common/platform'; import * as extpath from 'vs/base/common/extpath'; import { IWorkspaceIdentifier, IResolvedWorkspace, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { isEqual, isEqualOrParent } from 'vs/base/common/resources'; +import { LogLevel } from 'vs/platform/log/common/log'; +import { ExportData } from 'vs/base/common/performance'; + +export interface INativeWindowConfiguration extends IWindowConfiguration { + mainPid: number; + + windowId: number; + machineId: string; // NOTE: This is undefined in the web, the telemetry service directly resolves this. + + appRoot: string; + execPath: string; + backupPath?: string; + + nodeCachedDataDir?: string; + partsSplashPath: string; + + workspace?: IWorkspaceIdentifier; + folderUri?: ISingleFolderWorkspaceIdentifier; + + isInitialStartup?: boolean; + logLevel: LogLevel; + zoomLevel?: number; + fullscreen?: boolean; + maximized?: boolean; + accessibilitySupport?: boolean; + perfEntries: ExportData; + + userEnv: platform.IProcessEnvironment; + filesToWait?: IPathsToWaitFor; +} export interface INativeOpenWindowOptions extends IOpenWindowOptions { diffMode?: boolean; diff --git a/src/vs/workbench/contrib/issue/electron-browser/issueService.ts b/src/vs/workbench/contrib/issue/electron-browser/issueService.ts index 6b5b4068648..e184076085a 100644 --- a/src/vs/workbench/contrib/issue/electron-browser/issueService.ts +++ b/src/vs/workbench/contrib/issue/electron-browser/issueService.ts @@ -14,6 +14,7 @@ import { assign } from 'vs/base/common/objects'; import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/electron-browser/issue'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; export class WorkbenchIssueService implements IWorkbenchIssueService { _serviceBrand: undefined; @@ -23,7 +24,7 @@ export class WorkbenchIssueService implements IWorkbenchIssueService { @IThemeService private readonly themeService: IThemeService, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, @IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService + @IWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService ) { } openReporter(dataOverrides: Partial = {}): Promise { diff --git a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts index eb03c3f76d7..67df9f76198 100644 --- a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts @@ -38,6 +38,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { RemoteConnectionState, Deprecated_RemoteAuthorityContext, RemoteFileDialogContext } from 'vs/workbench/browser/contextkeys'; import { IDownloadService } from 'vs/platform/download/common/download'; import { OpenLocalFileFolderCommand, OpenLocalFileCommand, OpenLocalFolderCommand, SaveLocalFileCommand } from 'vs/workbench/services/dialogs/browser/simpleFileDialog'; +import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; const WINDOW_ACTIONS_COMMAND_ID = 'workbench.action.remote.showMenu'; const CLOSE_REMOTE_COMMAND_ID = 'workbench.action.remote.close'; @@ -331,7 +332,7 @@ class RemoteTelemetryEnablementUpdater extends Disposable implements IWorkbenchC class RemoteEmptyWorkbenchPresentation extends Disposable implements IWorkbenchContribution { constructor( - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IWorkbenchEnvironmentService environmentService: INativeWorkbenchEnvironmentService, @IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService, @IConfigurationService configurationService: IConfigurationService, @ICommandService commandService: ICommandService, diff --git a/src/vs/workbench/electron-browser/desktop.main.ts b/src/vs/workbench/electron-browser/desktop.main.ts index e9da83b049d..cac8f21dc31 100644 --- a/src/vs/workbench/electron-browser/desktop.main.ts +++ b/src/vs/workbench/electron-browser/desktop.main.ts @@ -6,6 +6,7 @@ import * as fs from 'fs'; import * as gracefulFs from 'graceful-fs'; import { createHash } from 'crypto'; +import { webFrame } from 'electron'; import { importEntries, mark } from 'vs/base/common/performance'; import { Workbench } from 'vs/workbench/browser/workbench'; import { ElectronWindow } from 'vs/workbench/electron-browser/window'; @@ -20,8 +21,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { stat } from 'vs/base/node/pfs'; import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/nativeKeymapService'; -import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; -import { webFrame } from 'electron'; +import { INativeWindowConfiguration } from 'vs/platform/windows/node/window'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceInitializationPayload, ISingleFolderWorkspaceInitializationPayload, reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { ConsoleLogService, MultiplexLogService, ILogService, ConsoleLogInMainService } from 'vs/platform/log/common/log'; import { NativeStorageService } from 'vs/platform/storage/node/storageService'; @@ -57,7 +57,7 @@ class DesktopMain extends Disposable { private readonly environmentService: NativeWorkbenchEnvironmentService; - constructor(private configuration: IWindowConfiguration) { + constructor(private configuration: INativeWindowConfiguration) { super(); this.environmentService = new NativeWorkbenchEnvironmentService(configuration, configuration.execPath, configuration.windowId); @@ -373,7 +373,7 @@ class DesktopMain extends Disposable { } } -export function main(configuration: IWindowConfiguration): Promise { +export function main(configuration: INativeWindowConfiguration): Promise { const renderer = new DesktopMain(configuration); return renderer.open(); diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index e1c129c76f1..a528ed51106 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -62,6 +62,7 @@ import { IElectronEnvironmentService } from 'vs/workbench/services/electron/elec import { IWorkingCopyService, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { AutoSaveMode, IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { Event } from 'vs/base/common/event'; +import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; export class ElectronWindow extends Disposable { @@ -94,7 +95,7 @@ export class ElectronWindow extends Disposable { @IMenuService private readonly menuService: IMenuService, @ILifecycleService private readonly lifecycleService: ILifecycleService, @IIntegrityService private readonly integrityService: IIntegrityService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, + @IWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService, @IAccessibilityService private readonly accessibilityService: IAccessibilityService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IInstantiationService private readonly instantiationService: IInstantiationService, diff --git a/src/vs/workbench/services/accessibility/node/accessibilityService.ts b/src/vs/workbench/services/accessibility/electron-browser/accessibilityService.ts similarity index 91% rename from src/vs/workbench/services/accessibility/node/accessibilityService.ts rename to src/vs/workbench/services/accessibility/electron-browser/accessibilityService.ts index 38d831833b1..19d44947f6b 100644 --- a/src/vs/workbench/services/accessibility/node/accessibilityService.ts +++ b/src/vs/workbench/services/accessibility/electron-browser/accessibilityService.ts @@ -16,6 +16,7 @@ import { IJSONEditingService } from 'vs/workbench/services/configuration/common/ import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; interface AccessibilityMetrics { enabled: boolean; @@ -24,14 +25,14 @@ type AccessibilityMetricsClassification = { enabled: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; }; -export class NodeAccessibilityService extends AccessibilityService implements IAccessibilityService { +export class NativeAccessibilityService extends AccessibilityService implements IAccessibilityService { _serviceBrand: undefined; private didSendTelemetry = false; constructor( - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IWorkbenchEnvironmentService environmentService: INativeWorkbenchEnvironmentService, @IContextKeyService contextKeyService: IContextKeyService, @IConfigurationService configurationService: IConfigurationService, @ITelemetryService private readonly _telemetryService: ITelemetryService @@ -69,7 +70,7 @@ export class NodeAccessibilityService extends AccessibilityService implements IA } } -registerSingleton(IAccessibilityService, NodeAccessibilityService, true); +registerSingleton(IAccessibilityService, NativeAccessibilityService, true); // On linux we do not automatically detect that a screen reader is detected, thus we have to implicitly notify the renderer to enable accessibility when user configures it in settings class LinuxAccessibilityContribution implements IWorkbenchContribution { diff --git a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts index e86e00ffc4e..80b0cd54c2a 100644 --- a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts @@ -340,7 +340,7 @@ export class ConfigurationResolverService extends BaseConfigurationResolverServi @IWorkspaceContextService workspaceContextService: IWorkspaceContextService, @IQuickInputService quickInputService: IQuickInputService ) { - super(environmentService.configuration.userEnv, editorService, environmentService, configurationService, commandService, workspaceContextService, quickInputService); + super(Object.create(null), editorService, environmentService, configurationService, commandService, workspaceContextService, quickInputService); } } diff --git a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts index 5f4b1cbb52a..277923ee5be 100644 --- a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts +++ b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts @@ -9,7 +9,7 @@ import * as platform from 'vs/base/common/platform'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; -import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; +import { BaseConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { TestEditorService, TestContextService } from 'vs/workbench/test/browser/workbenchTestServices'; import { TestWindowConfiguration } from 'vs/workbench/test/electron-browser/workbenchTestServices'; @@ -21,7 +21,6 @@ import * as Types from 'vs/base/common/types'; import { EditorType } from 'vs/editor/common/editorCommon'; import { Selection } from 'vs/editor/common/core/selection'; import { NativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; const mockLineNumber = 10; class TestEditorServiceWithActiveEditor extends TestEditorService { @@ -37,10 +36,14 @@ class TestEditorServiceWithActiveEditor extends TestEditorService { } } +class TestConfigurationResolverService extends BaseConfigurationResolverService { + +} + suite('Configuration Resolver Service', () => { let configurationResolverService: IConfigurationResolverService | null; let envVariables: { [key: string]: string } = { key1: 'Value for key1', key2: 'Value for key2' }; - let environmentService: IWorkbenchEnvironmentService; + let environmentService: MockWorkbenchEnvironmentService; let mockCommandService: MockCommandService; let editorService: TestEditorServiceWithActiveEditor; let workspace: IWorkspaceFolder; @@ -57,7 +60,7 @@ suite('Configuration Resolver Service', () => { index: 0, toResource: (path: string) => uri.file(path) }; - configurationResolverService = new ConfigurationResolverService(editorService, environmentService, new MockInputsConfigurationService(), mockCommandService, new TestContextService(), quickInputService); + configurationResolverService = new TestConfigurationResolverService(environmentService.userEnv, editorService, environmentService, new MockInputsConfigurationService(), mockCommandService, new TestContextService(), quickInputService); }); teardown(() => { @@ -136,7 +139,7 @@ suite('Configuration Resolver Service', () => { } }); - let service = new ConfigurationResolverService(new TestEditorServiceWithActiveEditor(), environmentService, configurationService, mockCommandService, new TestContextService(), quickInputService); + let service = new TestConfigurationResolverService(environmentService.userEnv, new TestEditorServiceWithActiveEditor(), environmentService, configurationService, mockCommandService, new TestContextService(), quickInputService); assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} xyz'), 'abc foo xyz'); }); @@ -153,7 +156,7 @@ suite('Configuration Resolver Service', () => { } }); - let service = new ConfigurationResolverService(new TestEditorServiceWithActiveEditor(), environmentService, configurationService, mockCommandService, new TestContextService(), quickInputService); + let service = new TestConfigurationResolverService(environmentService.userEnv, new TestEditorServiceWithActiveEditor(), environmentService, configurationService, mockCommandService, new TestContextService(), quickInputService); assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} xyz'), 'abc foo bar xyz'); }); @@ -170,7 +173,7 @@ suite('Configuration Resolver Service', () => { } }); - let service = new ConfigurationResolverService(new TestEditorServiceWithActiveEditor(), environmentService, configurationService, mockCommandService, new TestContextService(), quickInputService); + let service = new TestConfigurationResolverService(environmentService.userEnv, new TestEditorServiceWithActiveEditor(), environmentService, configurationService, mockCommandService, new TestContextService(), quickInputService); if (platform.isWindows) { assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${workspaceFolder} ${env:key1} xyz'), 'abc foo \\VSCode\\workspaceLocation Value for key1 xyz'); } else { @@ -191,7 +194,7 @@ suite('Configuration Resolver Service', () => { } }); - let service = new ConfigurationResolverService(new TestEditorServiceWithActiveEditor(), environmentService, configurationService, mockCommandService, new TestContextService(), quickInputService); + let service = new TestConfigurationResolverService(environmentService.userEnv, new TestEditorServiceWithActiveEditor(), environmentService, configurationService, mockCommandService, new TestContextService(), quickInputService); if (platform.isWindows) { assert.strictEqual(service.resolve(workspace, '${config:editor.fontFamily} ${config:terminal.integrated.fontFamily} ${workspaceFolder} - ${workspaceFolder} ${env:key1} - ${env:key2}'), 'foo bar \\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation Value for key1 - Value for key2'); } else { @@ -225,7 +228,7 @@ suite('Configuration Resolver Service', () => { } }); - let service = new ConfigurationResolverService(new TestEditorServiceWithActiveEditor(), environmentService, configurationService, mockCommandService, new TestContextService(), quickInputService); + let service = new TestConfigurationResolverService(environmentService.userEnv, new TestEditorServiceWithActiveEditor(), environmentService, configurationService, mockCommandService, new TestContextService(), quickInputService); assert.strictEqual(service.resolve(workspace, 'abc ${config:editor.fontFamily} ${config:editor.lineNumbers} ${config:editor.insertSpaces} xyz'), 'abc foo 123 false xyz'); }); @@ -235,7 +238,7 @@ suite('Configuration Resolver Service', () => { editor: {} }); - let service = new ConfigurationResolverService(new TestEditorServiceWithActiveEditor(), environmentService, configurationService, mockCommandService, new TestContextService(), quickInputService); + let service = new TestConfigurationResolverService(environmentService.userEnv, new TestEditorServiceWithActiveEditor(), environmentService, configurationService, mockCommandService, new TestContextService(), quickInputService); assert.strictEqual(service.resolve(workspace, 'abc ${unknownVariable} xyz'), 'abc ${unknownVariable} xyz'); assert.strictEqual(service.resolve(workspace, 'abc ${env:unknownVariable} xyz'), 'abc xyz'); }); @@ -248,7 +251,7 @@ suite('Configuration Resolver Service', () => { } }); - let service = new ConfigurationResolverService(new TestEditorServiceWithActiveEditor(), environmentService, configurationService, mockCommandService, new TestContextService(), quickInputService); + let service = new TestConfigurationResolverService(environmentService.userEnv, new TestEditorServiceWithActiveEditor(), environmentService, configurationService, mockCommandService, new TestContextService(), quickInputService); assert.throws(() => service.resolve(workspace, 'abc ${env} xyz')); assert.throws(() => service.resolve(workspace, 'abc ${env:} xyz')); @@ -619,7 +622,7 @@ class MockInputsConfigurationService extends TestConfigurationService { class MockWorkbenchEnvironmentService extends NativeWorkbenchEnvironmentService { - constructor(userEnv: platform.IProcessEnvironment) { + constructor(public userEnv: platform.IProcessEnvironment) { super({ ...TestWindowConfiguration, userEnv }, TestWindowConfiguration.execPath, TestWindowConfiguration.windowId); } } diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 80873b34704..e093b35336c 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -4,22 +4,17 @@ *--------------------------------------------------------------------------------------------*/ import { Schemas } from 'vs/base/common/network'; -import { ExportData } from 'vs/base/common/performance'; -import { IProcessEnvironment } from 'vs/base/common/platform'; import { joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import { BACKUPS, IExtensionHostDebugParams } from 'vs/platform/environment/common/environment'; -import { LogLevel } from 'vs/platform/log/common/log'; -import { IPath, IPathsToWaitFor, IWindowConfiguration } from 'vs/platform/windows/common/windows'; -import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IPath, IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IWorkbenchConstructionOptions } from 'vs/workbench/workbench.web.api'; import product from 'vs/platform/product/common/product'; import { serializableToMap } from 'vs/base/common/map'; import { memoize } from 'vs/base/common/decorators'; -// TODO@ben remove properties that are node/electron only export class BrowserWindowConfiguration implements IWindowConfiguration { constructor( @@ -28,8 +23,6 @@ export class BrowserWindowConfiguration implements IWindowConfiguration { private readonly environment: IWorkbenchEnvironmentService ) { } - //#region PROPERLY CONFIGURED IN DESKTOP + WEB - @memoize get sessionId(): string { return generateUuid(); } @@ -54,44 +47,10 @@ export class BrowserWindowConfiguration implements IWindowConfiguration { return undefined; } - // Currently unsupported in web + // Currently unsupported in web but should look into support get filesToDiff(): IPath[] | undefined { return undefined; } - - //#endregion - - - //#region TODO MOVE TO NODE LAYER - - _!: string[]; - - windowId!: number; - mainPid!: number; - - logLevel!: LogLevel; - - appRoot!: string; - execPath!: string; - backupPath?: string; - nodeCachedDataDir?: string; - - userEnv!: IProcessEnvironment; - - workspace?: IWorkspaceIdentifier; - folderUri?: ISingleFolderWorkspaceIdentifier; - - zoomLevel?: number; - fullscreen?: boolean; - maximized?: boolean; - highContrast?: boolean; - accessibilitySupport?: boolean; - partsSplashPath?: string; - - isInitialStartup?: boolean; - perfEntries!: ExportData; - - filesToWait?: IPathsToWaitFor; - - //#endregion + highContrast = false; + _ = []; private getCookieValue(name: string): string | undefined { const m = document.cookie.match('(^|[^;]+)\\s*' + name + '\\s*=\\s*([^;]+)'); // See https://stackoverflow.com/a/25490531 @@ -116,7 +75,14 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment _serviceBrand: undefined; - //#region PROPERLY CONFIGURED IN DESKTOP + WEB + private _configuration: IWindowConfiguration | undefined = undefined; + get configuration(): IWindowConfiguration { + if (!this._configuration) { + this._configuration = new BrowserWindowConfiguration(this.options, this.payload, this); + } + + return this._configuration; + } @memoize get isBuilt(): boolean { return !!product.commit; } @@ -209,71 +175,14 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment return this.webviewExternalEndpoint.replace('{{uuid}}', '*'); } - // Currently not configurable in web + // Currently unsupported in web but should look into support get disableExtensions() { return false; } get extensionsPath(): string | undefined { return undefined; } get verbose(): boolean { return false; } get disableUpdates(): boolean { return false; } get logExtensionHostCommunication(): boolean { return false; } - - //#endregion - - - //#region TODO MOVE TO NODE LAYER - - private _configuration: IWindowConfiguration | undefined = undefined; - get configuration(): IWindowConfiguration { - if (!this._configuration) { - this._configuration = new BrowserWindowConfiguration(this.options, this.payload, this); - } - - return this._configuration; - } - - args = { _: [] }; - - wait!: boolean; - status!: boolean; - log?: string; - - mainIPCHandle!: string; - sharedIPCHandle!: string; - - nodeCachedDataDir?: string; - - disableCrashReporter!: boolean; - - driverHandle?: string; - driverVerbose!: boolean; - - installSourcePath!: string; - - builtinExtensionsPath!: string; - - globalStorageHome!: string; - workspaceStorageHome!: string; - - backupWorkspacesPath!: string; - - machineSettingsHome!: URI; - machineSettingsResource!: URI; - - userHome!: string; - userDataPath!: string; - appRoot!: string; - appSettingsHome!: URI; - execPath!: string; - cliPath!: string; - - //#endregion - - - //#region TODO ENABLE IN WEB - galleryMachineIdResource?: URI; - //#endregion - private payload: Map | undefined; constructor(readonly options: IBrowserWorkbenchEnvironmentConstructionOptions) { @@ -316,4 +225,43 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment return extensionHostDebugEnvironment; } + + //#region TODO MOVE TO NODE LAYER + + args = { _: [] }; + + wait!: boolean; + status!: boolean; + log?: string; + + mainIPCHandle!: string; + sharedIPCHandle!: string; + + nodeCachedDataDir?: string; + + disableCrashReporter!: boolean; + + driverHandle?: string; + driverVerbose!: boolean; + + installSourcePath!: string; + + builtinExtensionsPath!: string; + + globalStorageHome!: string; + workspaceStorageHome!: string; + + backupWorkspacesPath!: string; + + machineSettingsHome!: URI; + machineSettingsResource!: URI; + + userHome!: string; + userDataPath!: string; + appRoot!: string; + appSettingsHome!: URI; + execPath!: string; + cliPath!: string; + + //#endregion } diff --git a/src/vs/workbench/services/environment/electron-browser/environmentService.ts b/src/vs/workbench/services/environment/electron-browser/environmentService.ts index 8d32aff4ee6..085ac1603f3 100644 --- a/src/vs/workbench/services/environment/electron-browser/environmentService.ts +++ b/src/vs/workbench/services/environment/electron-browser/environmentService.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { memoize } from 'vs/base/common/decorators'; import { URI } from 'vs/base/common/uri'; @@ -12,8 +11,14 @@ import { Schemas } from 'vs/base/common/network'; import { toBackupWorkspaceResource } from 'vs/workbench/services/backup/electron-browser/backup'; import { join } from 'vs/base/common/path'; import product from 'vs/platform/product/common/product'; +import { INativeWindowConfiguration } from 'vs/platform/windows/node/window'; -export class NativeWorkbenchEnvironmentService extends EnvironmentService implements IWorkbenchEnvironmentService { +export interface INativeWorkbenchEnvironmentService extends IWorkbenchEnvironmentService { + + readonly configuration: INativeWindowConfiguration; +} + +export class NativeWorkbenchEnvironmentService extends EnvironmentService implements INativeWorkbenchEnvironmentService { _serviceBrand: undefined; @@ -37,7 +42,7 @@ export class NativeWorkbenchEnvironmentService extends EnvironmentService implem get logFile(): URI { return URI.file(join(this.logsPath, `renderer${this.windowId}.log`)); } constructor( - readonly configuration: IWindowConfiguration, + readonly configuration: INativeWindowConfiguration, execPath: string, private readonly windowId: number ) { diff --git a/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts b/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts index c2900691c8e..b495fda6b19 100644 --- a/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts @@ -17,6 +17,7 @@ import { resolveWorkbenchCommonProperties } from 'vs/platform/telemetry/node/wor import { TelemetryService as BaseTelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings'; +import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; export class TelemetryService extends Disposable implements ITelemetryService { @@ -25,7 +26,7 @@ export class TelemetryService extends Disposable implements ITelemetryService { private impl: ITelemetryService; constructor( - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IWorkbenchEnvironmentService environmentService: INativeWorkbenchEnvironmentService, @IProductService productService: IProductService, @ISharedProcessService sharedProcessService: ISharedProcessService, @ILogService logService: ILogService, @@ -38,7 +39,7 @@ export class TelemetryService extends Disposable implements ITelemetryService { const channel = sharedProcessService.getChannel('telemetryAppender'); const config: ITelemetryServiceConfig = { appender: combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(logService)), - commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, environmentService.configuration.machineId!, productService.msftInternalDomains, environmentService.installSourcePath, environmentService.configuration.remoteAuthority), + commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, environmentService.configuration.machineId, productService.msftInternalDomains, environmentService.installSourcePath, environmentService.configuration.remoteAuthority), piiPaths: environmentService.extensionsPath ? [environmentService.appRoot, environmentService.extensionsPath] : [environmentService.appRoot] }; diff --git a/src/vs/workbench/services/timer/electron-browser/timerService.ts b/src/vs/workbench/services/timer/electron-browser/timerService.ts index 3b3d71f9eb0..47fd9783039 100644 --- a/src/vs/workbench/services/timer/electron-browser/timerService.ts +++ b/src/vs/workbench/services/timer/electron-browser/timerService.ts @@ -18,6 +18,7 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; +import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; /* __GDPR__FRAGMENT__ "IMemoryInfo" : { @@ -303,7 +304,7 @@ class TimerService implements ITimerService { constructor( @IElectronService private readonly _electronService: IElectronService, - @IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService, + @IWorkbenchEnvironmentService private readonly _environmentService: INativeWorkbenchEnvironmentService, @ILifecycleService private readonly _lifecycleService: ILifecycleService, @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService, @IExtensionService private readonly _extensionService: IExtensionService, diff --git a/src/vs/workbench/services/workspaces/electron-browser/workspaceEditingService.ts b/src/vs/workbench/services/workspaces/electron-browser/workspaceEditingService.ts index d65ea2c055e..e3dc86a88db 100644 --- a/src/vs/workbench/services/workspaces/electron-browser/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspaces/electron-browser/workspaceEditingService.ts @@ -31,6 +31,7 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; import { isMacintosh } from 'vs/base/common/platform'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; import { BackupFileService } from 'vs/workbench/services/backup/common/backupFileService'; +import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; export class NativeWorkspaceEditingService extends AbstractWorkspaceEditingService { @@ -49,7 +50,7 @@ export class NativeWorkspaceEditingService extends AbstractWorkspaceEditingServi @IFileService fileService: IFileService, @ITextFileService textFileService: ITextFileService, @IWorkspacesService workspacesService: IWorkspacesService, - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IWorkbenchEnvironmentService protected environmentService: INativeWorkbenchEnvironmentService, @IFileDialogService fileDialogService: IFileDialogService, @IDialogService protected dialogService: IDialogService, @ILifecycleService private readonly lifecycleService: ILifecycleService, diff --git a/src/vs/workbench/test/electron-browser/workbenchTestServices.ts b/src/vs/workbench/test/electron-browser/workbenchTestServices.ts index 929d1d748ad..7ea72135d33 100644 --- a/src/vs/workbench/test/electron-browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/electron-browser/workbenchTestServices.ts @@ -25,7 +25,7 @@ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService import { URI } from 'vs/base/common/uri'; import { IReadTextFileOptions, ITextFileStreamContent, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel'; -import { IOpenedWindow, IOpenEmptyWindowOptions, IWindowOpenable, IOpenWindowOptions, IWindowConfiguration } from 'vs/platform/windows/common/windows'; +import { IOpenedWindow, IOpenEmptyWindowOptions, IWindowOpenable, IOpenWindowOptions } from 'vs/platform/windows/common/windows'; import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { LogLevel } from 'vs/platform/log/common/log'; import { IRemotePathService } from 'vs/workbench/services/path/common/remotePathService'; @@ -37,12 +37,15 @@ import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { NodeTestBackupFileService } from 'vs/workbench/services/backup/test/electron-browser/backupFileService.test'; import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { INativeWindowConfiguration } from 'vs/platform/windows/node/window'; -export const TestWindowConfiguration: IWindowConfiguration = { +export const TestWindowConfiguration: INativeWindowConfiguration = { windowId: 0, + machineId: 'testMachineId', sessionId: 'testSessionId', logLevel: LogLevel.Error, mainPid: 0, + partsSplashPath: '', appRoot: '', userEnv: {}, execPath: process.execPath, diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index fdf7e6ae5db..8393a631a59 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -43,7 +43,7 @@ import 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; import 'vs/workbench/services/telemetry/electron-browser/telemetryService'; import 'vs/workbench/services/configurationResolver/electron-browser/configurationResolverService'; import 'vs/workbench/services/extensionManagement/node/extensionManagementService'; -import 'vs/workbench/services/accessibility/node/accessibilityService'; +import 'vs/workbench/services/accessibility/electron-browser/accessibilityService'; import 'vs/workbench/services/remote/node/tunnelService'; import 'vs/workbench/services/backup/node/backupFileService'; import 'vs/workbench/services/url/electron-browser/urlService'; From e1d6bfe8b19eab7e4763f6dfb0e4bb5d1af9bf3f Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 2 Mar 2020 12:46:04 +0100 Subject: [PATCH 208/235] debt - push down more native only environment properties --- src/vs/code/electron-main/main.ts | 2 +- src/vs/platform/environment/common/environment.ts | 6 ------ src/vs/platform/environment/node/environmentService.ts | 9 +-------- .../services/environment/browser/environmentService.ts | 8 -------- .../environment/electron-browser/environmentService.ts | 4 ++++ .../extensions/electron-browser/extensionHost.ts | 3 ++- .../textfile/electron-browser/nativeTextFileService.ts | 3 ++- .../test/electron-browser/workbenchTestServices.ts | 4 ++-- 8 files changed, 12 insertions(+), 27 deletions(-) diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 7871c40dc59..12aebae23c3 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -276,7 +276,7 @@ class CodeMain { // Skip this if we are running with --wait where it is expected that we wait for a while. // Also skip when gathering diagnostics (--status) which can take a longer time. let startupWarningDialogHandle: NodeJS.Timeout | undefined = undefined; - if (!environmentService.wait && !environmentService.status) { + if (!environmentService.args.wait && !environmentService.args.status) { startupWarningDialogHandle = setTimeout(() => { this.showStartupWarningDialog( localize('secondInstanceNoResponse', "Another instance of {0} is running but not responding", product.nameShort), diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index abd1e33b185..123c84684da 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -111,7 +111,6 @@ export interface IEnvironmentService extends IUserHomeProvider { args: ParsedArgs; execPath: string; - cliPath: string; appRoot: string; userHome: string; @@ -132,7 +131,6 @@ export interface IEnvironmentService extends IUserHomeProvider { settingsSyncPreviewResource: URI; keybindingsSyncPreviewResource: URI; - machineSettingsHome: URI; machineSettingsResource: URI; globalStorageHome: string; @@ -154,10 +152,7 @@ export interface IEnvironmentService extends IUserHomeProvider { debugExtensionHost: IExtensionHostDebugParams; isBuilt: boolean; - wait: boolean; - status: boolean; - log?: string; logsPath: string; verbose: boolean; @@ -168,7 +163,6 @@ export interface IEnvironmentService extends IUserHomeProvider { installSourcePath: string; disableUpdates: boolean; - disableCrashReporter: boolean; driverHandle?: string; driverVerbose: boolean; diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index 15b5c20cbbf..58b8f6ffcd1 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -124,10 +124,7 @@ export class EnvironmentService implements IEnvironmentService { get userDataSyncLogResource(): URI { return URI.file(path.join(this.logsPath, 'userDataSync.log')); } @memoize - get machineSettingsHome(): URI { return URI.file(path.join(this.userDataPath, 'Machine')); } - - @memoize - get machineSettingsResource(): URI { return resources.joinPath(this.machineSettingsHome, 'settings.json'); } + get machineSettingsResource(): URI { return resources.joinPath(URI.file(path.join(this.userDataPath, 'Machine')), 'settings.json'); } @memoize get globalStorageHome(): string { return path.join(this.appSettingsHome.fsPath, 'globalStorage'); } @@ -248,10 +245,6 @@ export class EnvironmentService implements IEnvironmentService { get verbose(): boolean { return !!this._args.verbose; } get log(): string | undefined { return this._args.log; } - get wait(): boolean { return !!this._args.wait; } - - get status(): boolean { return !!this._args.status; } - @memoize get mainIPCHandle(): string { return getIPCHandle(this.userDataPath, 'main'); } diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index e093b35336c..fa59b3513ef 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -230,17 +230,11 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment args = { _: [] }; - wait!: boolean; - status!: boolean; - log?: string; - mainIPCHandle!: string; sharedIPCHandle!: string; nodeCachedDataDir?: string; - disableCrashReporter!: boolean; - driverHandle?: string; driverVerbose!: boolean; @@ -253,7 +247,6 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment backupWorkspacesPath!: string; - machineSettingsHome!: URI; machineSettingsResource!: URI; userHome!: string; @@ -261,7 +254,6 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment appRoot!: string; appSettingsHome!: URI; execPath!: string; - cliPath!: string; //#endregion } diff --git a/src/vs/workbench/services/environment/electron-browser/environmentService.ts b/src/vs/workbench/services/environment/electron-browser/environmentService.ts index 085ac1603f3..8adb181b7e9 100644 --- a/src/vs/workbench/services/environment/electron-browser/environmentService.ts +++ b/src/vs/workbench/services/environment/electron-browser/environmentService.ts @@ -16,6 +16,10 @@ import { INativeWindowConfiguration } from 'vs/platform/windows/node/window'; export interface INativeWorkbenchEnvironmentService extends IWorkbenchEnvironmentService { readonly configuration: INativeWindowConfiguration; + + log?: string; + cliPath: string; + disableCrashReporter: boolean; } export class NativeWorkbenchEnvironmentService extends EnvironmentService implements INativeWorkbenchEnvironmentService { diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index c45f7e5c3e3..b823db0ce9b 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -42,6 +42,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { joinPath } from 'vs/base/common/resources'; import { Registry } from 'vs/platform/registry/common/platform'; import { IOutputChannelRegistry, Extensions } from 'vs/workbench/services/output/common/output'; +import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; export class ExtensionHostProcessWorker implements IExtensionHostStarter { @@ -78,7 +79,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { @INotificationService private readonly _notificationService: INotificationService, @IElectronService private readonly _electronService: IElectronService, @ILifecycleService private readonly _lifecycleService: ILifecycleService, - @IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService, + @IWorkbenchEnvironmentService private readonly _environmentService: INativeWorkbenchEnvironmentService, @ITelemetryService private readonly _telemetryService: ITelemetryService, @ILogService private readonly _logService: ILogService, @ILabelService private readonly _labelService: ILabelService, diff --git a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts index aeff0a5f220..52d0c2f949a 100644 --- a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts @@ -39,6 +39,7 @@ import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { IRemotePathService } from 'vs/workbench/services/path/common/remotePathService'; import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService'; +import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; export class NativeTextFileService extends AbstractTextFileService { @@ -48,7 +49,7 @@ export class NativeTextFileService extends AbstractTextFileService { @ILifecycleService lifecycleService: ILifecycleService, @IInstantiationService instantiationService: IInstantiationService, @IModelService modelService: IModelService, - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IWorkbenchEnvironmentService protected environmentService: INativeWorkbenchEnvironmentService, @IDialogService dialogService: IDialogService, @IFileDialogService fileDialogService: IFileDialogService, @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, diff --git a/src/vs/workbench/test/electron-browser/workbenchTestServices.ts b/src/vs/workbench/test/electron-browser/workbenchTestServices.ts index 7ea72135d33..c08bf8098f9 100644 --- a/src/vs/workbench/test/electron-browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/electron-browser/workbenchTestServices.ts @@ -6,7 +6,7 @@ import { workbenchInstantiationService as browserWorkbenchInstantiationService, ITestInstantiationService, TestLifecycleService, TestFilesConfigurationService, TestContextService, TestFileService, TestFileDialogService } from 'vs/workbench/test/browser/workbenchTestServices'; import { Event } from 'vs/base/common/event'; import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; -import { NativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; +import { NativeWorkbenchEnvironmentService, INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; import { NativeTextFileService, EncodingOracle, IEncodingOverride } from 'vs/workbench/services/textfile/electron-browser/nativeTextFileService'; import { IElectronService } from 'vs/platform/electron/node/electron'; import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs'; @@ -64,7 +64,7 @@ export class TestTextFileService extends NativeTextFileService { @ILifecycleService lifecycleService: ILifecycleService, @IInstantiationService instantiationService: IInstantiationService, @IModelService modelService: IModelService, - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IWorkbenchEnvironmentService environmentService: INativeWorkbenchEnvironmentService, @IDialogService dialogService: IDialogService, @IFileDialogService fileDialogService: IFileDialogService, @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, From 8fac4133c5460d5344d5f265d033bad5ec8ee9fe Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 2 Mar 2020 12:51:32 +0100 Subject: [PATCH 209/235] adopt inline compile config for editor src task --- build/gulpfile.editor.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/build/gulpfile.editor.js b/build/gulpfile.editor.js index 9278f689ec3..ebda38f7bb2 100644 --- a/build/gulpfile.editor.js +++ b/build/gulpfile.editor.js @@ -74,7 +74,17 @@ const extractEditorSrcTask = task.define('extract-editor-src', () => { ], libs: [ `lib.es5.d.ts`, + `lib.es2015.core.d.ts`, + `lib.es2015.collection.d.ts`, + `lib.es2015.generator.d.ts`, + `lib.es2015.promise.d.ts`, + `lib.es2015.iterable.d.ts`, + `lib.es2015.proxy.d.ts`, + `lib.es2015.reflect.d.ts`, + `lib.es2015.symbol.d.ts`, + `lib.es2015.symbol.wellknown.d.ts`, `lib.dom.d.ts`, + `lib.dom.iterable.d.ts`, `lib.webworker.importscripts.d.ts` ], shakeLevel: 2, // 0-Files, 1-InnerFile, 2-ClassMembers From cf432e5437b32deac09246e1dd871524f1df5323 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 2 Mar 2020 13:09:09 +0100 Subject: [PATCH 210/235] search editor - register disposable --- .../workbench/contrib/searchEditor/browser/searchEditorInput.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditorInput.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditorInput.ts index 73729118f5d..698bb4c8f97 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditorInput.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditorInput.ts @@ -53,7 +53,7 @@ export class SearchEditorInput extends EditorInput { private _cachedContentsModel: ITextModel | undefined; private _cachedConfig?: SearchConfiguration; - private readonly _onDidChangeContent = new Emitter(); + private readonly _onDidChangeContent = this._register(new Emitter()); readonly onDidChangeContent: Event = this._onDidChangeContent.event; private oldDecorationsIDs: string[] = []; From af18dd70e01338f2b00834fa4c04c606bc8ecef2 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 2 Mar 2020 13:15:04 +0100 Subject: [PATCH 211/235] working copy - backup() is not optional anymore --- .../contrib/backup/common/backupTracker.ts | 6 +---- .../backup/electron-browser/backupTracker.ts | 8 +++--- .../workingCopy/common/workingCopyService.ts | 25 ++++++++++++++++--- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/contrib/backup/common/backupTracker.ts b/src/vs/workbench/contrib/backup/common/backupTracker.ts index 074a0c545aa..4121d8ae848 100644 --- a/src/vs/workbench/contrib/backup/common/backupTracker.ts +++ b/src/vs/workbench/contrib/backup/common/backupTracker.ts @@ -114,10 +114,6 @@ export abstract class BackupTracker extends Disposable { return; // skip if auto save is enabled with a short delay } - if (typeof workingCopy.backup !== 'function') { - return; // skip if working copy does not support backups - } - // Clear any running backup operation dispose(this.pendingBackups.get(workingCopy)); this.pendingBackups.delete(workingCopy); @@ -131,7 +127,7 @@ export abstract class BackupTracker extends Disposable { this.pendingBackups.delete(workingCopy); // Backup if dirty - if (workingCopy.isDirty() && typeof workingCopy.backup === 'function') { + if (workingCopy.isDirty()) { this.logService.trace(`[backup tracker] running backup`, workingCopy.resource.toString()); const backup = await workingCopy.backup(); diff --git a/src/vs/workbench/contrib/backup/electron-browser/backupTracker.ts b/src/vs/workbench/contrib/backup/electron-browser/backupTracker.ts index ca971ffc23e..b3b65134298 100644 --- a/src/vs/workbench/contrib/backup/electron-browser/backupTracker.ts +++ b/src/vs/workbench/contrib/backup/electron-browser/backupTracker.ts @@ -161,12 +161,10 @@ export class NativeBackupTracker extends BackupTracker implements IWorkbenchCont // Backup does not exist else { - if (typeof workingCopy.backup === 'function') { - const backup = await workingCopy.backup(); - await this.backupFileService.backup(workingCopy.resource, backup.content, contentVersion, backup.meta); + const backup = await workingCopy.backup(); + await this.backupFileService.backup(workingCopy.resource, backup.content, contentVersion, backup.meta); - backups.push(workingCopy); - } + backups.push(workingCopy); } })); } diff --git a/src/vs/workbench/services/workingCopy/common/workingCopyService.ts b/src/vs/workbench/services/workingCopy/common/workingCopyService.ts index 353bce55045..e29b371dfdd 100644 --- a/src/vs/workbench/services/workingCopy/common/workingCopyService.ts +++ b/src/vs/workbench/services/workingCopy/common/workingCopyService.ts @@ -42,10 +42,20 @@ export interface IWorkingCopyBackup { export interface IWorkingCopy { + /** + * The unique resource of the working copy. There can only be one + * working copy in the system with the same URI. + */ readonly resource: URI; + /** + * Human readable name of the working copy. + */ readonly name: string; + /** + * The capabilities of the working copy. + */ readonly capabilities: WorkingCopyCapabilities; @@ -83,14 +93,21 @@ export interface IWorkingCopy { * * Providers of working copies should use `IBackupFileService.resolve(workingCopy.resource)` * to retrieve the backup metadata associated when loading the working copy. - * - * Not providing this method from the working copy will disable any - * backups and hot-exit functionality for those working copies. */ - backup?(): Promise; + backup(): Promise; + /** + * Asks the working copy to save. If the working copy was dirty, it is + * expected to be non-dirty after this operation has finished. + * + * @returns `true` if the operation was successful and `false` otherwise. + */ save(options?: ISaveOptions): Promise; + /** + * Asks the working copy to revert. If the working copy was dirty, it is + * expected to be non-dirty after this operation has finished. + */ revert(options?: IRevertOptions): Promise; //#endregion From e8f005af1955ccf23abc5c5e11a6179dea017412 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 2 Mar 2020 13:16:26 +0100 Subject: [PATCH 212/235] working copy - enforce that there can only be one working copy per resource --- .../workingCopy/common/workingCopyService.ts | 47 +++++++------------ .../test/common/workingCopyService.test.ts | 37 ++------------- 2 files changed, 22 insertions(+), 62 deletions(-) diff --git a/src/vs/workbench/services/workingCopy/common/workingCopyService.ts b/src/vs/workbench/services/workingCopy/common/workingCopyService.ts index e29b371dfdd..628ca136d64 100644 --- a/src/vs/workbench/services/workingCopy/common/workingCopyService.ts +++ b/src/vs/workbench/services/workingCopy/common/workingCopyService.ts @@ -8,7 +8,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Event, Emitter } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; import { Disposable, IDisposable, toDisposable, DisposableStore, dispose } from 'vs/base/common/lifecycle'; -import { TernarySearchTree, values } from 'vs/base/common/map'; +import { values, ResourceMap } from 'vs/base/common/map'; import { ISaveOptions, IRevertOptions } from 'vs/workbench/common/editor'; import { ITextSnapshot } from 'vs/editor/common/model'; @@ -150,8 +150,12 @@ export interface IWorkingCopyService { readonly workingCopies: IWorkingCopy[]; - getWorkingCopies(resource: URI): IWorkingCopy[]; - + /** + * Register a new working copy with the service. This method will + * throw if you try to register a working copy with a resource + * that was already registered before. There can only be 1 working + * copy per resource registered to the service. + */ registerWorkingCopy(workingCopy: IWorkingCopy): IDisposable; //#endregion @@ -180,30 +184,21 @@ export class WorkingCopyService extends Disposable implements IWorkingCopyServic //#region Registry - private readonly mapResourceToWorkingCopy = TernarySearchTree.forPaths>(); - get workingCopies(): IWorkingCopy[] { return values(this._workingCopies); } private _workingCopies = new Set(); - getWorkingCopies(resource: URI): IWorkingCopy[] { - const workingCopies = this.mapResourceToWorkingCopy.get(resource.toString()); - - return workingCopies ? values(workingCopies) : []; - } + private readonly mapResourceToWorkingCopy = new ResourceMap(); registerWorkingCopy(workingCopy: IWorkingCopy): IDisposable { + if (this.mapResourceToWorkingCopy.has(workingCopy.resource)) { + throw new Error(`Cannot register more than one working copy with the same resource ${workingCopy.resource.toString()}.`); + } + const disposables = new DisposableStore(); // Registry - let workingCopiesForResource = this.mapResourceToWorkingCopy.get(workingCopy.resource.toString()); - if (!workingCopiesForResource) { - workingCopiesForResource = new Set(); - this.mapResourceToWorkingCopy.set(workingCopy.resource.toString(), workingCopiesForResource); - } - - workingCopiesForResource.add(workingCopy); - this._workingCopies.add(workingCopy); + this.mapResourceToWorkingCopy.set(workingCopy.resource, workingCopy); // Wire in Events disposables.add(workingCopy.onDidChangeContent(() => this._onDidChangeContent.fire(workingCopy))); @@ -227,12 +222,8 @@ export class WorkingCopyService extends Disposable implements IWorkingCopyServic private unregisterWorkingCopy(workingCopy: IWorkingCopy): void { // Remove from registry - const workingCopiesForResource = this.mapResourceToWorkingCopy.get(workingCopy.resource.toString()); - if (workingCopiesForResource && workingCopiesForResource.delete(workingCopy) && workingCopiesForResource.size === 0) { - this.mapResourceToWorkingCopy.delete(workingCopy.resource.toString()); - } - this._workingCopies.delete(workingCopy); + this.mapResourceToWorkingCopy.delete(workingCopy.resource); // If copy is dirty, ensure to fire an event to signal the dirty change // (a disposed working copy cannot account for being dirty in our model) @@ -273,13 +264,9 @@ export class WorkingCopyService extends Disposable implements IWorkingCopyServic } isDirty(resource: URI): boolean { - const workingCopies = this.mapResourceToWorkingCopy.get(resource.toString()); - if (workingCopies) { - for (const workingCopy of workingCopies) { - if (workingCopy.isDirty()) { - return true; - } - } + const workingCopy = this.mapResourceToWorkingCopy.get(resource); + if (workingCopy) { + return workingCopy.isDirty(); } return false; diff --git a/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts b/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts index 282319778ce..5c31dd4fb89 100644 --- a/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts +++ b/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts @@ -110,8 +110,8 @@ suite('WorkingCopyService', () => { assert.equal(service.dirtyCount, 1); assert.equal(service.dirtyWorkingCopies.length, 1); assert.equal(service.dirtyWorkingCopies[0], copy1); - assert.equal(service.getWorkingCopies(copy1.resource).length, 1); - assert.equal(service.getWorkingCopies(copy1.resource)[0], copy1); + assert.equal(service.workingCopies.length, 1); + assert.equal(service.workingCopies[0], copy1); assert.equal(service.isDirty(resource1), true); assert.equal(service.hasDirty, true); assert.equal(onDidChangeDirty.length, 1); @@ -165,7 +165,7 @@ suite('WorkingCopyService', () => { assert.equal(onDidChangeDirty[3], copy2); }); - test('registry - multiple copies on same resource', () => { + test('registry - multiple copies on same resource throws', () => { const service = new TestWorkingCopyService(); const onDidChangeDirty: IWorkingCopy[] = []; @@ -174,37 +174,10 @@ suite('WorkingCopyService', () => { const resource = URI.parse('custom://some/folder/custom.txt'); const copy1 = new TestWorkingCopy(resource); - const unregister1 = service.registerWorkingCopy(copy1); + service.registerWorkingCopy(copy1); const copy2 = new TestWorkingCopy(resource); - const unregister2 = service.registerWorkingCopy(copy2); - assert.equal(service.getWorkingCopies(copy1.resource).length, 2); - assert.equal(service.getWorkingCopies(copy1.resource)[0], copy1); - assert.equal(service.getWorkingCopies(copy1.resource)[1], copy2); - - copy1.setDirty(true); - - assert.equal(service.dirtyCount, 1); - assert.equal(onDidChangeDirty.length, 1); - assert.equal(service.isDirty(resource), true); - - copy2.setDirty(true); - - assert.equal(service.dirtyCount, 2); - assert.equal(onDidChangeDirty.length, 2); - assert.equal(service.isDirty(resource), true); - - unregister1.dispose(); - - assert.equal(service.dirtyCount, 1); - assert.equal(onDidChangeDirty.length, 3); - assert.equal(service.isDirty(resource), true); - - unregister2.dispose(); - - assert.equal(service.dirtyCount, 0); - assert.equal(onDidChangeDirty.length, 4); - assert.equal(service.isDirty(resource), false); + assert.throws(() => service.registerWorkingCopy(copy2)); }); }); From 27bc032975dada7e689459d93286b2d3f1dbcc39 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 2 Mar 2020 13:44:22 +0100 Subject: [PATCH 213/235] nuke special lib options and use compiler option's lib instead --- build/gulpfile.editor.js | 15 -------------- build/lib/treeshaking.js | 29 ++++++++++++++++++++++----- build/lib/treeshaking.ts | 43 +++++++++++++++++++++++++++++----------- 3 files changed, 55 insertions(+), 32 deletions(-) diff --git a/build/gulpfile.editor.js b/build/gulpfile.editor.js index ebda38f7bb2..cbd9da2541f 100644 --- a/build/gulpfile.editor.js +++ b/build/gulpfile.editor.js @@ -72,21 +72,6 @@ const extractEditorSrcTask = task.define('extract-editor-src', () => { apiusages, extrausages ], - libs: [ - `lib.es5.d.ts`, - `lib.es2015.core.d.ts`, - `lib.es2015.collection.d.ts`, - `lib.es2015.generator.d.ts`, - `lib.es2015.promise.d.ts`, - `lib.es2015.iterable.d.ts`, - `lib.es2015.proxy.d.ts`, - `lib.es2015.reflect.d.ts`, - `lib.es2015.symbol.d.ts`, - `lib.es2015.symbol.wellknown.d.ts`, - `lib.dom.d.ts`, - `lib.dom.iterable.d.ts`, - `lib.webworker.importscripts.d.ts` - ], shakeLevel: 2, // 0-Files, 1-InnerFile, 2-ClassMembers importIgnorePattern: /(^vs\/css!)|(promise-polyfill\/polyfill)/, destRoot: path.join(root, 'out-editor-src'), diff --git a/build/lib/treeshaking.js b/build/lib/treeshaking.js index 8c95751347f..eeb954c4fcf 100644 --- a/build/lib/treeshaking.js +++ b/build/lib/treeshaking.js @@ -76,11 +76,7 @@ function createTypeScriptLanguageService(options) { FILES[typing] = fs.readFileSync(filePath).toString(); }); // Resolve libs - const RESOLVED_LIBS = {}; - options.libs.forEach((filename) => { - const filepath = path.join(TYPESCRIPT_LIB_FOLDER, filename); - RESOLVED_LIBS[`defaultLib:${filename}`] = fs.readFileSync(filepath).toString(); - }); + const RESOLVED_LIBS = processLibFiles(options); const compilerOptions = ts.convertCompilerOptionsFromJson(options.compilerOptions, options.sourcesRoot).options; const host = new TypeScriptLanguageServiceHost(RESOLVED_LIBS, FILES, compilerOptions); return ts.createLanguageService(host); @@ -138,6 +134,29 @@ function discoverAndReadFiles(options) { } return FILES; } +/** + * Read lib files and follow lib references + */ +function processLibFiles(options) { + const stack = [...options.compilerOptions.lib]; + const result = {}; + while (stack.length > 0) { + const filename = `lib.${stack.shift().toLowerCase()}.d.ts`; + const key = `defaultLib:${filename}`; + if (!result[key]) { + // add this file + const filepath = path.join(TYPESCRIPT_LIB_FOLDER, filename); + const sourceText = fs.readFileSync(filepath).toString(); + result[key] = sourceText; + // precess dependencies and "recurse" + const info = ts.preProcessFile(sourceText); + for (let ref of info.libReferenceDirectives) { + stack.push(ref.fileName); + } + } + } + return result; +} /** * A TypeScript language service host */ diff --git a/build/lib/treeshaking.ts b/build/lib/treeshaking.ts index 89f562ad1b8..19e0dc8bb4d 100644 --- a/build/lib/treeshaking.ts +++ b/build/lib/treeshaking.ts @@ -18,7 +18,7 @@ export const enum ShakeLevel { } export function toStringShakeLevel(shakeLevel: ShakeLevel): string { - switch(shakeLevel) { + switch (shakeLevel) { case ShakeLevel.Files: return 'Files (0)'; case ShakeLevel.InnerFile: @@ -42,11 +42,6 @@ export interface ITreeShakingOptions { * Inline usages. */ inlineEntryPoints: string[]; - /** - * TypeScript libs. - * e.g. `lib.d.ts`, `lib.es2015.collection.d.ts` - */ - libs: string[]; /** * Other .d.ts files */ @@ -130,11 +125,7 @@ function createTypeScriptLanguageService(options: ITreeShakingOptions): ts.Langu }); // Resolve libs - const RESOLVED_LIBS: ILibMap = {}; - options.libs.forEach((filename) => { - const filepath = path.join(TYPESCRIPT_LIB_FOLDER, filename); - RESOLVED_LIBS[`defaultLib:${filename}`] = fs.readFileSync(filepath).toString(); - }); + const RESOLVED_LIBS = processLibFiles(options); const compilerOptions = ts.convertCompilerOptionsFromJson(options.compilerOptions, options.sourcesRoot).options; @@ -205,6 +196,34 @@ function discoverAndReadFiles(options: ITreeShakingOptions): IFileMap { return FILES; } +/** + * Read lib files and follow lib references + */ +function processLibFiles(options: ITreeShakingOptions): ILibMap { + + const stack: string[] = [...options.compilerOptions.lib]; + const result: ILibMap = {}; + + while (stack.length > 0) { + const filename = `lib.${stack.shift()!.toLowerCase()}.d.ts`; + const key = `defaultLib:${filename}`; + if (!result[key]) { + // add this file + const filepath = path.join(TYPESCRIPT_LIB_FOLDER, filename); + const sourceText = fs.readFileSync(filepath).toString(); + result[key] = sourceText; + + // precess dependencies and "recurse" + const info = ts.preProcessFile(sourceText); + for (let ref of info.libReferenceDirectives) { + stack.push(ref.fileName); + } + } + } + + return result; +} + interface ILibMap { [libName: string]: string; } interface IFileMap { [fileName: string]: string; } @@ -475,7 +494,7 @@ function markNodes(languageService: ts.LanguageService, options: ITreeShakingOpt } if (black_queue.length === 0) { - for (let i = 0; i< gray_queue.length; i++) { + for (let i = 0; i < gray_queue.length; i++) { const node = gray_queue[i]; const nodeParent = node.parent; if ((ts.isClassDeclaration(nodeParent) || ts.isInterfaceDeclaration(nodeParent)) && nodeOrChildIsBlack(nodeParent)) { From c2a604a18c5d3696f62267feadfb1d7583bcbccd Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Mon, 2 Mar 2020 13:45:03 +0100 Subject: [PATCH 214/235] Add DocumentSemanticTokensProvider.onDidChangeSemanticTokens --- src/vs/editor/common/modes.ts | 1 + .../common/services/modelServiceImpl.ts | 20 +++++++++++++++++-- src/vs/monaco.d.ts | 1 + src/vs/vscode.proposed.d.ts | 5 +++++ .../api/browser/mainThreadLanguageFeatures.ts | 20 ++++++++++++++++--- .../workbench/api/common/extHost.protocol.ts | 3 ++- .../api/common/extHostLanguageFeatures.ts | 16 ++++++++++++--- 7 files changed, 57 insertions(+), 9 deletions(-) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index c61f4c8e6c3..d892eee8f62 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -1589,6 +1589,7 @@ export interface SemanticTokensEdits { } export interface DocumentSemanticTokensProvider { + onDidChange?: Event; getLegend(): SemanticTokensLegend; provideDocumentSemanticTokens(model: model.ITextModel, lastResultId: string | null, token: CancellationToken): ProviderResult; releaseDocumentSemanticTokens(resultId: string | undefined): void; diff --git a/src/vs/editor/common/services/modelServiceImpl.ts b/src/vs/editor/common/services/modelServiceImpl.ts index 20e32b9d2a7..67deb4ee702 100644 --- a/src/vs/editor/common/services/modelServiceImpl.ts +++ b/src/vs/editor/common/services/modelServiceImpl.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, DisposableStore, dispose } from 'vs/base/common/lifecycle'; import * as platform from 'vs/base/common/platform'; import * as errors from 'vs/base/common/errors'; import { URI } from 'vs/base/common/uri'; @@ -724,6 +724,7 @@ class ModelSemanticColoring extends Disposable { private readonly _fetchSemanticTokens: RunOnceScheduler; private _currentResponse: SemanticTokensResponse | null; private _currentRequestCancellationTokenSource: CancellationTokenSource | null; + private _providersChangeListeners: IDisposable[]; constructor(model: ITextModel, themeService: IThemeService, stylingProvider: SemanticStyling) { super(); @@ -734,13 +735,28 @@ class ModelSemanticColoring extends Disposable { this._fetchSemanticTokens = this._register(new RunOnceScheduler(() => this._fetchSemanticTokensNow(), 300)); this._currentResponse = null; this._currentRequestCancellationTokenSource = null; + this._providersChangeListeners = []; this._register(this._model.onDidChangeContent(e => { if (!this._fetchSemanticTokens.isScheduled()) { this._fetchSemanticTokens.schedule(); } })); - this._register(DocumentSemanticTokensProviderRegistry.onDidChange(e => this._fetchSemanticTokens.schedule())); + const bindChangeListeners = () => { + dispose(this._providersChangeListeners); + this._providersChangeListeners = []; + for (const provider of DocumentSemanticTokensProviderRegistry.all(model)) { + if (typeof provider.onDidChange === 'function') { + this._providersChangeListeners.push(provider.onDidChange(() => this._fetchSemanticTokens.schedule(0))); + } + } + }; + bindChangeListeners(); + this._register(DocumentSemanticTokensProviderRegistry.onDidChange(e => { + bindChangeListeners(); + this._fetchSemanticTokens.schedule(); + })); + if (themeService) { // workaround for tests which use undefined... :/ this._register(themeService.onThemeChange(_ => { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index e740dbc105e..63ee827cd7e 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -6183,6 +6183,7 @@ declare namespace monaco.languages { } export interface DocumentSemanticTokensProvider { + onDidChange?: IEvent; getLegend(): SemanticTokensLegend; provideDocumentSemanticTokens(model: editor.ITextModel, lastResultId: string | null, token: CancellationToken): ProviderResult; releaseDocumentSemanticTokens(resultId: string | undefined): void; diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index b880c7555d8..c5a0c707ce5 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -257,6 +257,11 @@ declare module 'vscode' { * semantic tokens. */ export interface DocumentSemanticTokensProvider { + /** + * An optional event to signal that the semantic tokens from this provider have changed. + */ + onDidChangeSemanticTokens?: Event; + /** * A file can contain many tokens, perhaps even hundreds of thousands of tokens. Therefore, to improve * the memory consumption around describing semantic tokens, we have decided to avoid allocating an object diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index 4287e53a8c0..c079a43ef36 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IDisposable } from 'vs/base/common/lifecycle'; -import { Emitter } from 'vs/base/common/event'; +import { Emitter, Event } from 'vs/base/common/event'; import { ITextModel, ISingleEditOperation } from 'vs/editor/common/model'; import * as modes from 'vs/editor/common/modes'; import * as search from 'vs/workbench/contrib/search/common/search'; @@ -367,8 +367,21 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha // --- semantic tokens - $registerDocumentSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: modes.SemanticTokensLegend): void { - this._registrations.set(handle, modes.DocumentSemanticTokensProviderRegistry.register(selector, new MainThreadDocumentSemanticTokensProvider(this._proxy, handle, legend))); + $registerDocumentSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: modes.SemanticTokensLegend, eventHandle: number | undefined): void { + let event: Event | undefined = undefined; + if (typeof eventHandle === 'number') { + const emitter = new Emitter(); + this._registrations.set(eventHandle, emitter); + event = emitter.event; + } + this._registrations.set(handle, modes.DocumentSemanticTokensProviderRegistry.register(selector, new MainThreadDocumentSemanticTokensProvider(this._proxy, handle, legend, event))); + } + + $emitDocumentSemanticTokensEvent(eventHandle: number): void { + const obj = this._registrations.get(eventHandle); + if (obj instanceof Emitter) { + obj.fire(undefined); + } } $registerDocumentRangeSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: modes.SemanticTokensLegend): void { @@ -661,6 +674,7 @@ export class MainThreadDocumentSemanticTokensProvider implements modes.DocumentS private readonly _proxy: ExtHostLanguageFeaturesShape, private readonly _handle: number, private readonly _legend: modes.SemanticTokensLegend, + public readonly onDidChange: Event | undefined, ) { } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index d9b76522d9a..9394de339c0 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -367,7 +367,8 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable { $registerOnTypeFormattingSupport(handle: number, selector: IDocumentFilterDto[], autoFormatTriggerCharacters: string[], extensionId: ExtensionIdentifier): void; $registerNavigateTypeSupport(handle: number): void; $registerRenameSupport(handle: number, selector: IDocumentFilterDto[], supportsResolveInitialValues: boolean): void; - $registerDocumentSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: modes.SemanticTokensLegend): void; + $registerDocumentSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: modes.SemanticTokensLegend, eventHandle: number | undefined): void; + $emitDocumentSemanticTokensEvent(eventHandle: number): void; $registerDocumentRangeSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: modes.SemanticTokensLegend): void; $registerSuggestSupport(handle: number, selector: IDocumentFilterDto[], triggerCharacters: string[], supportsResolveDetails: boolean, extensionId: ExtensionIdentifier): void; $registerSignatureHelpProvider(handle: number, selector: IDocumentFilterDto[], metadata: ISignatureHelpProviderMetadataDto): void; diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 479a5126b3c..a2d7ca79b98 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -1702,9 +1702,19 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF //#region semantic coloring registerDocumentSemanticTokensProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentSemanticTokensProvider, legend: vscode.SemanticTokensLegend): vscode.Disposable { - const handle = this._addNewAdapter(new DocumentSemanticTokensAdapter(this._documents, provider), extension); - this._proxy.$registerDocumentSemanticTokensProvider(handle, this._transformDocumentSelector(selector), legend); - return this._createDisposable(handle); + const handle = this._nextHandle(); + const eventHandle = (typeof provider.onDidChangeSemanticTokens === 'function' ? this._nextHandle() : undefined); + + this._adapter.set(handle, new AdapterData(new DocumentSemanticTokensAdapter(this._documents, provider), extension)); + this._proxy.$registerDocumentSemanticTokensProvider(handle, this._transformDocumentSelector(selector), legend, eventHandle); + let result = this._createDisposable(handle); + + if (eventHandle) { + const subscription = provider.onDidChangeSemanticTokens!(_ => this._proxy.$emitDocumentSemanticTokensEvent(eventHandle)); + result = Disposable.from(result, subscription); + } + + return result; } $provideDocumentSemanticTokens(handle: number, resource: UriComponents, previousResultId: number, token: CancellationToken): Promise { From 887c46603fd97c969707afe3790ec588a9bd235e Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 2 Mar 2020 11:40:07 +0100 Subject: [PATCH 215/235] rename keybindings label to Keyboard Shortcuts --- .../workbench/contrib/userDataSync/browser/userDataSync.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 403c7e046bd..59156a2d802 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -65,7 +65,7 @@ type ConfigureSyncQuickPickItem = { id: ResourceKey, label: string, description? function getSyncAreaLabel(source: SyncSource): string { switch (source) { case SyncSource.Settings: return localize('settings', "Settings"); - case SyncSource.Keybindings: return localize('keybindings', "Keybindings"); + case SyncSource.Keybindings: return localize('keybindings', "Keyboard Shortcuts"); case SyncSource.Extensions: return localize('extensions', "Extensions"); case SyncSource.GlobalState: return localize('ui state label', "UI State"); } @@ -1146,8 +1146,8 @@ class AcceptChangesContribution extends Disposable implements IEditorContributio ? localize('Sync accept remote', "Sync: {0}", acceptRemoteLabel) : localize('Sync accept local', "Sync: {0}", acceptLocalLabel), message: isRemote - ? localize('confirm replace and overwrite local', "Would you like to accept Remote {0} and replace Local {1}?", syncAreaLabel.toLowerCase(), syncAreaLabel.toLowerCase()) - : localize('confirm replace and overwrite remote', "Would you like to accept Local {0} and replace Remote {1}?", syncAreaLabel.toLowerCase(), syncAreaLabel.toLowerCase()), + ? localize('confirm replace and overwrite local', "Would you like to accept remote {0} and replace local {1}?", syncAreaLabel.toLowerCase(), syncAreaLabel.toLowerCase()) + : localize('confirm replace and overwrite remote', "Would you like to accept local {0} and replace remote {1}?", syncAreaLabel.toLowerCase(), syncAreaLabel.toLowerCase()), primaryButton: isRemote ? acceptRemoteLabel : acceptLocalLabel }); if (result.confirmed) { From e2cca740af329c3138d17ba1417202ed08a31d6b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 2 Mar 2020 13:02:30 +0100 Subject: [PATCH 216/235] Simplify synchronizers. Add more tests. --- .../common/abstractSynchronizer.ts | 30 +++- .../userDataSync/common/extensionsSync.ts | 24 +-- .../userDataSync/common/globalStateSync.ts | 15 +- .../userDataSync/common/keybindingsSync.ts | 17 +-- .../userDataSync/common/settingsSync.ts | 19 +-- .../test/common/synchronizer.test.ts | 144 ++++++++++++++++-- .../test/common/userDataSyncClient.ts | 21 ++- 7 files changed, 184 insertions(+), 86 deletions(-) diff --git a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts index 58ea47ff8bc..7df6c45f5b6 100644 --- a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts +++ b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts @@ -91,7 +91,7 @@ export abstract class AbstractSynchroniser extends Disposable { protected get enabled(): boolean { return this.userDataSyncEnablementService.isResourceEnabled(this.resourceKey); } - async sync(ref?: string, donotUseLastSyncUserData?: boolean): Promise { + async sync(ref?: string): Promise { if (!this.enabled) { this.logService.info(`${this.source}: Skipped synchronizing ${this.source.toLowerCase()} as it is disabled.`); return; @@ -108,24 +108,40 @@ export abstract class AbstractSynchroniser extends Disposable { this.logService.trace(`${this.source}: Started synchronizing ${this.source.toLowerCase()}...`); this.setStatus(SyncStatus.Syncing); - const lastSyncUserData = donotUseLastSyncUserData ? null : await this.getLastSyncUserData(); + const lastSyncUserData = await this.getLastSyncUserData(); const remoteUserData = ref && lastSyncUserData && lastSyncUserData.ref === ref ? lastSyncUserData : await this.getRemoteUserData(lastSyncUserData); + let status: SyncStatus = SyncStatus.Idle; + try { + status = await this.doSync(remoteUserData, lastSyncUserData); + if (status === SyncStatus.HasConflicts) { + this.logService.info(`${this.source}: Detected conflicts while synchronizing ${this.source.toLowerCase()}.`); + } else if (status === SyncStatus.Idle) { + this.logService.trace(`${this.source}: Finished synchronizing ${this.source.toLowerCase()}.`); + } + } finally { + this.setStatus(status); + } + } + + protected async doSync(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null): Promise { if (remoteUserData.syncData && remoteUserData.syncData.version > this.version) { // current version is not compatible with cloud version this.telemetryService.publicLog2<{ source: string }, SyncSourceClassification>('sync/incompatible', { source: this.source }); throw new UserDataSyncError(localize('incompatible', "Cannot sync {0} as its version {1} is not compatible with cloud {2}", this.source, this.version, remoteUserData.syncData.version), UserDataSyncErrorCode.Incompatible, this.source); } - try { - await this.doSync(remoteUserData, lastSyncUserData); + const status = await this.performSync(remoteUserData, lastSyncUserData); + return status; } catch (e) { if (e instanceof UserDataSyncError) { switch (e.code) { case UserDataSyncErrorCode.RemotePreconditionFailed: // Rejected as there is a new remote version. Syncing again, this.logService.info(`${this.source}: Failed to synchronize as there is a new remote version available. Synchronizing again...`); - return this.sync(undefined, true); + // Avoid cache and get latest remote user data - https://github.com/microsoft/vscode/issues/90624 + remoteUserData = await this.getRemoteUserData(null); + return this.doSync(remoteUserData, lastSyncUserData); } } throw e; @@ -247,7 +263,7 @@ export abstract class AbstractSynchroniser extends Disposable { abstract readonly resourceKey: ResourceKey; protected abstract readonly version: number; - protected abstract doSync(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null): Promise; + protected abstract performSync(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null): Promise; } export interface IFileSyncPreviewResult { @@ -340,7 +356,7 @@ export abstract class AbstractFileSynchroniser extends AbstractSynchroniser { if (this.status === SyncStatus.HasConflicts) { this.syncPreviewResultPromise?.then(result => { this.cancel(); - this.doSync(result.remoteUserData, result.lastSyncUserData); + this.doSync(result.remoteUserData, result.lastSyncUserData).then(status => this.setStatus(status)); }); } diff --git a/src/vs/platform/userDataSync/common/extensionsSync.ts b/src/vs/platform/userDataSync/common/extensionsSync.ts index ccdf3c48517..3b76429609b 100644 --- a/src/vs/platform/userDataSync/common/extensionsSync.ts +++ b/src/vs/platform/userDataSync/common/extensionsSync.ts @@ -37,6 +37,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse readonly resourceKey: ResourceKey = 'extensions'; protected readonly version: number = 2; + protected get enabled(): boolean { return super.enabled && this.extensionGalleryService.isEnabled(); } constructor( @IEnvironmentService environmentService: IEnvironmentService, @@ -118,14 +119,6 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse } - async sync(ref?: string): Promise { - if (!this.extensionGalleryService.isEnabled()) { - this.logService.info('Extensions: Skipping synchronizing extensions as gallery is disabled.'); - return; - } - return super.sync(ref); - } - async stop(): Promise { } accept(content: string): Promise { @@ -148,17 +141,10 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse return null; } - protected async doSync(remoteUserData: IRemoteUserData, lastSyncUserData: ILastSyncUserData | null): Promise { - try { - const previewResult = await this.getPreview(remoteUserData, lastSyncUserData); - await this.apply(previewResult); - } catch (e) { - this.setStatus(SyncStatus.Idle); - throw e; - } - - this.logService.trace('Extensions: Finished synchronizing extensions.'); - this.setStatus(SyncStatus.Idle); + protected async performSync(remoteUserData: IRemoteUserData, lastSyncUserData: ILastSyncUserData | null): Promise { + const previewResult = await this.getPreview(remoteUserData, lastSyncUserData); + await this.apply(previewResult); + return SyncStatus.Idle; } private async getPreview(remoteUserData: IRemoteUserData, lastSyncUserData: ILastSyncUserData | null): Promise { diff --git a/src/vs/platform/userDataSync/common/globalStateSync.ts b/src/vs/platform/userDataSync/common/globalStateSync.ts index e13edea154f..83efb27edb2 100644 --- a/src/vs/platform/userDataSync/common/globalStateSync.ts +++ b/src/vs/platform/userDataSync/common/globalStateSync.ts @@ -124,17 +124,10 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs return null; } - protected async doSync(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null): Promise { - try { - const result = await this.getPreview(remoteUserData, lastSyncUserData); - await this.apply(result); - this.logService.trace('UI State: Finished synchronizing ui state.'); - } catch (e) { - this.setStatus(SyncStatus.Idle); - throw e; - } finally { - this.setStatus(SyncStatus.Idle); - } + protected async performSync(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null): Promise { + const result = await this.getPreview(remoteUserData, lastSyncUserData); + await this.apply(result); + return SyncStatus.Idle; } private async getPreview(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null,): Promise { diff --git a/src/vs/platform/userDataSync/common/keybindingsSync.ts b/src/vs/platform/userDataSync/common/keybindingsSync.ts index 8d1d78409fd..76e28dd0076 100644 --- a/src/vs/platform/userDataSync/common/keybindingsSync.ts +++ b/src/vs/platform/userDataSync/common/keybindingsSync.ts @@ -161,29 +161,22 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem return content !== null ? this.getKeybindingsContentFromSyncContent(content) : null; } - protected async doSync(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null): Promise { + protected async performSync(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null): Promise { try { const result = await this.getPreview(remoteUserData, lastSyncUserData); if (result.hasConflicts) { - this.logService.info('Keybindings: Detected conflicts while synchronizing keybindings.'); - this.setStatus(SyncStatus.HasConflicts); - return; - } - try { - await this.apply(); - this.logService.trace('Keybindings: Finished synchronizing keybindings...'); - } finally { - this.setStatus(SyncStatus.Idle); + return SyncStatus.HasConflicts; } + await this.apply(); + return SyncStatus.Idle; } catch (e) { this.syncPreviewResultPromise = null; - this.setStatus(SyncStatus.Idle); if (e instanceof UserDataSyncError) { switch (e.code) { case UserDataSyncErrorCode.LocalPreconditionFailed: // Rejected as there is a new local version. Syncing again. this.logService.info('Keybindings: Failed to synchronize keybindings as there is a new local version available. Synchronizing again...'); - return this.sync(remoteUserData.ref); + return this.performSync(remoteUserData, lastSyncUserData); } } throw e; diff --git a/src/vs/platform/userDataSync/common/settingsSync.ts b/src/vs/platform/userDataSync/common/settingsSync.ts index 4dcce8bb0ee..fa710cbe146 100644 --- a/src/vs/platform/userDataSync/common/settingsSync.ts +++ b/src/vs/platform/userDataSync/common/settingsSync.ts @@ -220,33 +220,26 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement if (this.status === SyncStatus.HasConflicts) { const preview = await this.syncPreviewResultPromise!; this.cancel(); - await this.doSync(preview.remoteUserData, preview.lastSyncUserData, resolvedConflicts); + await this.performSync(preview.remoteUserData, preview.lastSyncUserData, resolvedConflicts); } } - protected async doSync(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, resolvedConflicts: { key: string, value: any | undefined }[] = []): Promise { + protected async performSync(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, resolvedConflicts: { key: string, value: any | undefined }[] = []): Promise { try { const result = await this.getPreview(remoteUserData, lastSyncUserData, resolvedConflicts); if (result.hasConflicts) { - this.logService.info('Settings: Detected conflicts while synchronizing settings.'); - this.setStatus(SyncStatus.HasConflicts); - return; - } - try { - await this.apply(); - this.logService.trace('Settings: Finished synchronizing settings.'); - } finally { - this.setStatus(SyncStatus.Idle); + return SyncStatus.HasConflicts; } + await this.apply(); + return SyncStatus.Idle; } catch (e) { this.syncPreviewResultPromise = null; - this.setStatus(SyncStatus.Idle); if (e instanceof UserDataSyncError) { switch (e.code) { case UserDataSyncErrorCode.LocalPreconditionFailed: // Rejected as there is a new local version. Syncing again. this.logService.info('Settings: Failed to synchronize settings as there is a new local version available. Synchronizing again...'); - return this.sync(remoteUserData.ref); + return this.performSync(remoteUserData, lastSyncUserData, resolvedConflicts); } } throw e; diff --git a/src/vs/platform/userDataSync/test/common/synchronizer.test.ts b/src/vs/platform/userDataSync/test/common/synchronizer.test.ts index 59a69aad7f8..14c69ca7bc1 100644 --- a/src/vs/platform/userDataSync/test/common/synchronizer.test.ts +++ b/src/vs/platform/userDataSync/test/common/synchronizer.test.ts @@ -4,34 +4,49 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { ResourceKey, IUserDataSyncStoreService, SyncSource, SyncStatus } from 'vs/platform/userDataSync/common/userDataSync'; +import { ResourceKey, IUserDataSyncStoreService, SyncSource, SyncStatus, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; import { UserDataSyncClient, UserDataSyncTestServer } from 'vs/platform/userDataSync/test/common/userDataSyncClient'; import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { AbstractSynchroniser, IRemoteUserData } from 'vs/platform/userDataSync/common/abstractSynchronizer'; import { Barrier } from 'vs/base/common/async'; -import { Emitter } from 'vs/base/common/event'; +import { Emitter, Event } from 'vs/base/common/event'; class TestSynchroniser extends AbstractSynchroniser { syncBarrier: Barrier = new Barrier(); + syncResult: { status?: SyncStatus, error?: boolean } = {}; onDoSyncCall: Emitter = this._register(new Emitter()); readonly resourceKey: ResourceKey = 'settings'; protected readonly version: number = 1; - protected async doSync(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null): Promise { - try { - this.onDoSyncCall.fire(); - await this.syncBarrier.wait(); - const ref = await this.updateRemote(remoteUserData.ref); - await this.updateLastSyncUserData({ ref, syncData: { content: '', version: this.version } }); - } finally { - this.setStatus(SyncStatus.Idle); + private cancelled: boolean = false; + + protected async performSync(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null): Promise { + this.cancelled = false; + this.onDoSyncCall.fire(); + await this.syncBarrier.wait(); + + if (this.cancelled) { + return SyncStatus.Idle; } + + if (this.syncResult.error) { + throw new Error('failed'); + } + + await this.apply(remoteUserData.ref); + return this.syncResult.status || SyncStatus.Idle; } - async updateRemote(ref: string): Promise { - return this.userDataSyncStoreService.write(this.resourceKey, '', ref); + async apply(ref: string): Promise { + ref = await this.userDataSyncStoreService.write(this.resourceKey, '', ref); + await this.updateLastSyncUserData({ ref, syncData: { content: '', version: this.version } }); + } + + stop(): void { + this.cancelled = true; + this.syncBarrier.open(); } } @@ -52,6 +67,109 @@ suite('TestSynchronizer', () => { teardown(() => disposableStore.clear()); + test('status is syncing', async () => { + const testObject: TestSynchroniser = client.instantiationService.createInstance(TestSynchroniser, SyncSource.Settings); + + const actual: SyncStatus[] = []; + disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status))); + + const promise = Event.toPromise(testObject.onDoSyncCall.event); + + testObject.sync(); + await promise; + + assert.deepEqual(actual, [SyncStatus.Syncing]); + assert.deepEqual(testObject.status, SyncStatus.Syncing); + + testObject.stop(); + }); + + test('status is set correctly when sync is finished', async () => { + const testObject: TestSynchroniser = client.instantiationService.createInstance(TestSynchroniser, SyncSource.Settings); + testObject.syncBarrier.open(); + + const actual: SyncStatus[] = []; + disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status))); + await testObject.sync(); + + assert.deepEqual(actual, [SyncStatus.Syncing, SyncStatus.Idle]); + assert.deepEqual(testObject.status, SyncStatus.Idle); + }); + + test('status is set correctly when sync has conflicts', async () => { + const testObject: TestSynchroniser = client.instantiationService.createInstance(TestSynchroniser, SyncSource.Settings); + testObject.syncResult = { status: SyncStatus.HasConflicts }; + testObject.syncBarrier.open(); + + const actual: SyncStatus[] = []; + disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status))); + await testObject.sync(); + + assert.deepEqual(actual, [SyncStatus.Syncing, SyncStatus.HasConflicts]); + assert.deepEqual(testObject.status, SyncStatus.HasConflicts); + }); + + test('status is set correctly when sync has errors', async () => { + const testObject: TestSynchroniser = client.instantiationService.createInstance(TestSynchroniser, SyncSource.Settings); + testObject.syncResult = { error: true }; + testObject.syncBarrier.open(); + + const actual: SyncStatus[] = []; + disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status))); + + try { + await testObject.sync(); + assert.fail('Should fail'); + } catch (e) { + assert.deepEqual(actual, [SyncStatus.Syncing, SyncStatus.Idle]); + assert.deepEqual(testObject.status, SyncStatus.Idle); + } + }); + + test('sync should not run if syncing already', async () => { + const testObject: TestSynchroniser = client.instantiationService.createInstance(TestSynchroniser, SyncSource.Settings); + const promise = Event.toPromise(testObject.onDoSyncCall.event); + + testObject.sync(); + await promise; + + const actual: SyncStatus[] = []; + disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status))); + await testObject.sync(); + + assert.deepEqual(actual, []); + assert.deepEqual(testObject.status, SyncStatus.Syncing); + + testObject.stop(); + }); + + test('sync should not run if disabled', async () => { + const testObject: TestSynchroniser = client.instantiationService.createInstance(TestSynchroniser, SyncSource.Settings); + client.instantiationService.get(IUserDataSyncEnablementService).setResourceEnablement(testObject.resourceKey, false); + + const actual: SyncStatus[] = []; + disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status))); + + await testObject.sync(); + + assert.deepEqual(actual, []); + assert.deepEqual(testObject.status, SyncStatus.Idle); + }); + + test('sync should not run if there are conflicts', async () => { + const testObject: TestSynchroniser = client.instantiationService.createInstance(TestSynchroniser, SyncSource.Settings); + testObject.syncResult = { status: SyncStatus.HasConflicts }; + testObject.syncBarrier.open(); + await testObject.sync(); + + const actual: SyncStatus[] = []; + disposableStore.add(testObject.onDidChangeStatus(status => actual.push(status))); + await testObject.sync(); + + assert.deepEqual(actual, []); + assert.deepEqual(testObject.status, SyncStatus.HasConflicts); + }); + test('request latest data on precondition failure', async () => { const testObject: TestSynchroniser = client.instantiationService.createInstance(TestSynchroniser, SyncSource.Settings); // Sync once @@ -62,7 +180,7 @@ suite('TestSynchronizer', () => { // update remote data before syncing so that 412 is thrown by server const disposable = testObject.onDoSyncCall.event(async () => { disposable.dispose(); - await testObject.updateRemote(ref); + await testObject.apply(ref); server.reset(); testObject.syncBarrier.open(); }); diff --git a/src/vs/platform/userDataSync/test/common/userDataSyncClient.ts b/src/vs/platform/userDataSync/test/common/userDataSyncClient.ts index 74a42082391..5b95a50591e 100644 --- a/src/vs/platform/userDataSync/test/common/userDataSyncClient.ts +++ b/src/vs/platform/userDataSync/test/common/userDataSyncClient.ts @@ -61,7 +61,14 @@ export class UserDataSyncClient extends Disposable { const logService = new NullLogService(); this.instantiationService.stub(ILogService, logService); - this.instantiationService.stub(IProductService, { _serviceBrand: undefined, ...product }); + this.instantiationService.stub(IProductService, { + _serviceBrand: undefined, ...product, ...{ + 'configurationSync.store': { + url: this.testServer.url, + authenticationProviderId: 'test' + } + } + }); const fileService = this._register(new FileService(logService)); fileService.registerProvider(Schemas.inMemory, new InMemoryFileSystemProvider()); @@ -69,13 +76,6 @@ export class UserDataSyncClient extends Disposable { this.instantiationService.stub(IStorageService, new InMemoryStorageService()); - await fileService.writeFile(environmentService.settingsResource, VSBuffer.fromString(JSON.stringify({ - 'configurationSync.store': { - url: this.testServer.url, - authenticationProviderId: 'test' - } - }))); - const configurationService = new ConfigurationService(environmentService.settingsResource, fileService); await configurationService.initialize(); this.instantiationService.stub(IConfigurationService, configurationService); @@ -106,9 +106,8 @@ export class UserDataSyncClient extends Disposable { this.instantiationService.stub(ISettingsSyncService, this.instantiationService.createInstance(SettingsSynchroniser)); this.instantiationService.stub(IUserDataSyncService, this.instantiationService.createInstance(UserDataSyncService)); - if (empty) { - await fileService.del(environmentService.settingsResource); - } else { + if (!empty) { + await fileService.writeFile(environmentService.settingsResource, VSBuffer.fromString(JSON.stringify({}))); await fileService.writeFile(environmentService.keybindingsResource, VSBuffer.fromString(JSON.stringify([]))); await fileService.writeFile(environmentService.argvResource, VSBuffer.fromString(JSON.stringify({ 'locale': 'en' }))); } From 16faaa5d8161acfb8b02a2b35935e8abb4993c73 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 2 Mar 2020 14:29:05 +0100 Subject: [PATCH 217/235] Fix #69480 --- .../output/browser/output.contribution.ts | 17 +++++++++++++++++ .../contrib/output/browser/outputView.ts | 4 ++++ .../preferences/browser/settingsLayout.ts | 5 +++++ 3 files changed, 26 insertions(+) diff --git a/src/vs/workbench/contrib/output/browser/output.contribution.ts b/src/vs/workbench/contrib/output/browser/output.contribution.ts index 90a0493c1e3..fc1a2c61224 100644 --- a/src/vs/workbench/contrib/output/browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/browser/output.contribution.ts @@ -23,6 +23,7 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { ViewContainer, IViewContainersRegistry, ViewContainerLocation, Extensions as ViewContainerExtensions, IViewsRegistry } from 'vs/workbench/common/views'; import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer'; +import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; // Register Service registerSingleton(IOutputService, OutputService); @@ -145,3 +146,19 @@ MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { }, order: 1 }); + +Registry.as(ConfigurationExtensions.Configuration).registerConfiguration({ + id: 'output', + order: 30, + title: nls.localize('output', "Output"), + type: 'object', + properties: { + 'output.smartScroll.enabled': { + type: 'boolean', + description: nls.localize('output.smartScroll.enabled', "Enable/disable the ability of smart scrolling in the output view. Smart scrolling allows you to lock scrolling automatically when you click in the output view and unlocks when you click in the last line."), + default: true, + scope: ConfigurationScope.APPLICATION, + tags: ['output'] + } + } +}); diff --git a/src/vs/workbench/contrib/output/browser/outputView.ts b/src/vs/workbench/contrib/output/browser/outputView.ts index aebdb85e8b8..bcc70dcadcf 100644 --- a/src/vs/workbench/contrib/output/browser/outputView.ts +++ b/src/vs/workbench/contrib/output/browser/outputView.ts @@ -90,6 +90,10 @@ export class OutputViewPane extends ViewPane { return; } + if (!this.configurationService.getValue('output.smartScroll.enabled')) { + return; + } + const model = codeEditor.getModel(); if (model && this.actions) { const newPositionLine = e.position.lineNumber; diff --git a/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts b/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts index fb75f474a2a..4763193df8c 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts @@ -165,6 +165,11 @@ export const tocData: ITOCEntry = { label: localize('problems', "Problems"), settings: ['problems.*'] }, + { + id: 'features/output', + label: localize('output', "Output"), + settings: ['output.*'] + }, { id: 'features/comments', label: localize('comments', "Comments"), From 1bccecab0a4ebc8d49c02f21ec701f7f71ff9ce0 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 2 Mar 2020 14:36:19 +0100 Subject: [PATCH 218/235] remove more files from typings for which we have lib.*.d.ts files --- src/tsconfig.base.json | 1 + src/tsconfig.monaco.json | 1 - src/typings/lib.es2018.promise.d.ts | 27 -------------------- src/typings/lib.webworker.importscripts.d.ts | 23 ----------------- 4 files changed, 1 insertion(+), 51 deletions(-) delete mode 100644 src/typings/lib.es2018.promise.d.ts delete mode 100644 src/typings/lib.webworker.importscripts.d.ts diff --git a/src/tsconfig.base.json b/src/tsconfig.base.json index 52ace865e0b..b8dab46bfb6 100644 --- a/src/tsconfig.base.json +++ b/src/tsconfig.base.json @@ -15,6 +15,7 @@ }, "lib": [ "ES2015", + "ES2018.Promise", "DOM", "DOM.Iterable", "WebWorker.ImportScripts" diff --git a/src/tsconfig.monaco.json b/src/tsconfig.monaco.json index 61377a881ff..1e169f96b3a 100644 --- a/src/tsconfig.monaco.json +++ b/src/tsconfig.monaco.json @@ -15,7 +15,6 @@ "include": [ "typings/require.d.ts", "typings/thenable.d.ts", - "typings/lib.es2018.promise.d.ts", "typings/lib.array-ext.d.ts", "vs/css.d.ts", "vs/monaco.d.ts", diff --git a/src/typings/lib.es2018.promise.d.ts b/src/typings/lib.es2018.promise.d.ts deleted file mode 100644 index 9f7b2d38cb2..00000000000 --- a/src/typings/lib.es2018.promise.d.ts +++ /dev/null @@ -1,27 +0,0 @@ -/*! ***************************************************************************** -Copyright (c) Microsoft Corporation. All rights reserved. -Licensed under the Apache License, Version 2.0 (the "License"); you may not use -this file except in compliance with the License. You may obtain a copy of the -License at http://www.apache.org/licenses/LICENSE-2.0 - -THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -MERCHANTABLITY OR NON-INFRINGEMENT. - -See the Apache Version 2.0 License for specific language governing permissions -and limitations under the License. -***************************************************************************** */ - -/** - * Represents the completion of an asynchronous operation - */ -interface Promise { - /** - * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The - * resolved value cannot be modified from the callback. - * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). - * @returns A Promise for the completion of the callback. - */ - finally(onfinally?: (() => void) | undefined | null): Promise; -} diff --git a/src/typings/lib.webworker.importscripts.d.ts b/src/typings/lib.webworker.importscripts.d.ts deleted file mode 100644 index e84f717c9a4..00000000000 --- a/src/typings/lib.webworker.importscripts.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -/*! ***************************************************************************** -Copyright (c) Microsoft Corporation. All rights reserved. -Licensed under the Apache License, Version 2.0 (the "License"); you may not use -this file except in compliance with the License. You may obtain a copy of the -License at http://www.apache.org/licenses/LICENSE-2.0 - -THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -MERCHANTABLITY OR NON-INFRINGEMENT. - -See the Apache Version 2.0 License for specific language governing permissions -and limitations under the License. -***************************************************************************** */ - - - - -///////////////////////////// -/// WorkerGlobalScope APIs -///////////////////////////// -// These are only available in a Web Worker -declare function importScripts(...urls: string[]): void; From 452e16a1ac4c104da434fbdb52c247d362a613e1 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 2 Mar 2020 14:49:25 +0100 Subject: [PATCH 219/235] Fix #91731 --- src/vs/workbench/contrib/extensions/browser/extensionEditor.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts index 39ada55824f..e28796d1000 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts @@ -507,6 +507,7 @@ export class ExtensionEditor extends BaseEditor { if (e.enabled === false) { hide(template.subtextContainer); } + this.layout(); })); } From c2d241d963d94a886d6cfd3b138468977783bcf2 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 2 Mar 2020 15:19:59 +0100 Subject: [PATCH 220/235] fix monaco build failure --- src/vs/platform/userDataSync/common/abstractSynchronizer.ts | 6 +++--- src/vs/platform/userDataSync/common/extensionsSync.ts | 6 +++--- src/vs/platform/userDataSync/common/globalStateSync.ts | 4 ++-- src/vs/platform/userDataSync/common/keybindingsSync.ts | 4 ++-- src/vs/platform/userDataSync/common/settingsSync.ts | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts index 7df6c45f5b6..03edf498efd 100644 --- a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts +++ b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts @@ -89,10 +89,10 @@ export abstract class AbstractSynchroniser extends Disposable { } } - protected get enabled(): boolean { return this.userDataSyncEnablementService.isResourceEnabled(this.resourceKey); } + protected isEnabled(): boolean { return this.userDataSyncEnablementService.isResourceEnabled(this.resourceKey); } async sync(ref?: string): Promise { - if (!this.enabled) { + if (!this.isEnabled()) { this.logService.info(`${this.source}: Skipped synchronizing ${this.source.toLowerCase()} as it is disabled.`); return; } @@ -348,7 +348,7 @@ export abstract class AbstractFileSynchroniser extends AbstractSynchroniser { return; } - if (!this.enabled) { + if (!this.isEnabled()) { return; } diff --git a/src/vs/platform/userDataSync/common/extensionsSync.ts b/src/vs/platform/userDataSync/common/extensionsSync.ts index 3b76429609b..1e9c81523e0 100644 --- a/src/vs/platform/userDataSync/common/extensionsSync.ts +++ b/src/vs/platform/userDataSync/common/extensionsSync.ts @@ -37,7 +37,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse readonly resourceKey: ResourceKey = 'extensions'; protected readonly version: number = 2; - protected get enabled(): boolean { return super.enabled && this.extensionGalleryService.isEnabled(); } + protected isEnabled(): boolean { return super.isEnabled() && this.extensionGalleryService.isEnabled(); } constructor( @IEnvironmentService environmentService: IEnvironmentService, @@ -62,7 +62,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse } async pull(): Promise { - if (!this.enabled) { + if (!this.isEnabled()) { this.logService.info('Extensions: Skipped pulling extensions as it is disabled.'); return; } @@ -95,7 +95,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse } async push(): Promise { - if (!this.enabled) { + if (!this.isEnabled()) { this.logService.info('Extensions: Skipped pushing extensions as it is disabled.'); return; } diff --git a/src/vs/platform/userDataSync/common/globalStateSync.ts b/src/vs/platform/userDataSync/common/globalStateSync.ts index 83efb27edb2..ff9dc75d808 100644 --- a/src/vs/platform/userDataSync/common/globalStateSync.ts +++ b/src/vs/platform/userDataSync/common/globalStateSync.ts @@ -47,7 +47,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs } async pull(): Promise { - if (!this.enabled) { + if (!this.isEnabled()) { this.logService.info('UI State: Skipped pulling ui state as it is disabled.'); return; } @@ -79,7 +79,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs } async push(): Promise { - if (!this.enabled) { + if (!this.isEnabled()) { this.logService.info('UI State: Skipped pushing UI State as it is disabled.'); return; } diff --git a/src/vs/platform/userDataSync/common/keybindingsSync.ts b/src/vs/platform/userDataSync/common/keybindingsSync.ts index 76e28dd0076..e6e7e2931da 100644 --- a/src/vs/platform/userDataSync/common/keybindingsSync.ts +++ b/src/vs/platform/userDataSync/common/keybindingsSync.ts @@ -47,7 +47,7 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem } async pull(): Promise { - if (!this.enabled) { + if (!this.isEnabled()) { this.logService.info('Keybindings: Skipped pulling keybindings as it is disabled.'); return; } @@ -89,7 +89,7 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem } async push(): Promise { - if (!this.enabled) { + if (!this.isEnabled()) { this.logService.info('Keybindings: Skipped pushing keybindings as it is disabled.'); return; } diff --git a/src/vs/platform/userDataSync/common/settingsSync.ts b/src/vs/platform/userDataSync/common/settingsSync.ts index fa710cbe146..dbbe9972f31 100644 --- a/src/vs/platform/userDataSync/common/settingsSync.ts +++ b/src/vs/platform/userDataSync/common/settingsSync.ts @@ -77,7 +77,7 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement } async pull(): Promise { - if (!this.enabled) { + if (!this.isEnabled()) { this.logService.info('Settings: Skipped pulling settings as it is disabled.'); return; } @@ -123,7 +123,7 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement } async push(): Promise { - if (!this.enabled) { + if (!this.isEnabled()) { this.logService.info('Settings: Skipped pushing settings as it is disabled.'); return; } From d3da6f479289999ca9560e7d8f0b4cd799fed53b Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 2 Mar 2020 15:23:51 +0100 Subject: [PATCH 221/235] Remote: seeing an error message when not having remote extension installed. Fixes #91526 --- .../remote/common/remoteAuthorityResolver.ts | 20 +++++++++---------- .../electron-browser/extensionService.ts | 14 ++++++------- .../common/abstractRemoteAgentService.ts | 2 +- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/vs/platform/remote/common/remoteAuthorityResolver.ts b/src/vs/platform/remote/common/remoteAuthorityResolver.ts index 0f05864a61d..786adeba46b 100644 --- a/src/vs/platform/remote/common/remoteAuthorityResolver.ts +++ b/src/vs/platform/remote/common/remoteAuthorityResolver.ts @@ -40,28 +40,24 @@ export enum RemoteAuthorityResolverErrorCode { export class RemoteAuthorityResolverError extends Error { - public static isHandledNotAvailable(err: any): boolean { - if (err instanceof RemoteAuthorityResolverError) { - if (err._code === RemoteAuthorityResolverErrorCode.NotAvailable && err._detail === true) { - return true; - } - } - - return this.isTemporarilyNotAvailable(err); - } - public static isTemporarilyNotAvailable(err: any): boolean { return (err instanceof RemoteAuthorityResolverError) && err._code === RemoteAuthorityResolverErrorCode.TemporarilyNotAvailable; } - public static isNoResolverFound(err: any): boolean { + public static isNoResolverFound(err: any): err is RemoteAuthorityResolverError { return (err instanceof RemoteAuthorityResolverError) && err._code === RemoteAuthorityResolverErrorCode.NoResolverFound; } + public static isHandled(err: any): boolean { + return (err instanceof RemoteAuthorityResolverError) && err.isHandled; + } + public readonly _message: string | undefined; public readonly _code: RemoteAuthorityResolverErrorCode; public readonly _detail: any; + public isHandled: boolean; + constructor(message?: string, code: RemoteAuthorityResolverErrorCode = RemoteAuthorityResolverErrorCode.Unknown, detail?: any) { super(message); @@ -69,6 +65,8 @@ export class RemoteAuthorityResolverError extends Error { this._code = code; this._detail = detail; + this.isHandled = (code === RemoteAuthorityResolverErrorCode.NotAvailable) && detail === true; + // workaround when extending builtin objects and when compiling to ES5, see: // https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work if (typeof (Object).setPrototypeOf === 'function') { diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index b4a88b0a363..0da45d75af5 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -459,16 +459,13 @@ export class ExtensionService extends AbstractExtensionService implements IExten } catch (err) { const remoteName = getRemoteName(remoteAuthority); if (RemoteAuthorityResolverError.isNoResolverFound(err)) { - this._handleNoResolverFound(remoteName, allExtensions); + err.isHandled = await this._handleNoResolverFound(remoteName, allExtensions); } else { console.log(err); - if (RemoteAuthorityResolverError.isHandledNotAvailable(err)) { - console.log(`Not showing a notification for the error`); - } else { - this._notificationService.notify({ severity: Severity.Error, message: nls.localize('resolveAuthorityFailure', "Resolving the authority `{0}` failed", remoteName) }); + if (RemoteAuthorityResolverError.isHandled(err)) { + console.log(`Error handled: Not showing a notification for the error`); } } - this._remoteAuthorityResolverService.setResolvedAuthorityError(remoteAuthority, err); // Proceed with the local extension host @@ -584,10 +581,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten } } - private async _handleNoResolverFound(remoteName: string, allExtensions: IExtensionDescription[]): Promise { + private async _handleNoResolverFound(remoteName: string, allExtensions: IExtensionDescription[]): Promise { const recommendation = this._productService.remoteExtensionTips?.[remoteName]; if (!recommendation) { - return; + return false; } const sendTelemetry = (userReaction: 'install' | 'enable' | 'cancel') => { /* __GDPR__ @@ -641,6 +638,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten ); } + return true; } } diff --git a/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts b/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts index a97aaafe97d..bf8e93ea187 100644 --- a/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts +++ b/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts @@ -164,7 +164,7 @@ class RemoteConnectionFailureNotificationContribution implements IWorkbenchContr // Let's cover the case where connecting to fetch the remote extension info fails remoteAgentService.getEnvironment(true) .then(undefined, err => { - if (!RemoteAuthorityResolverError.isHandledNotAvailable(err)) { + if (!RemoteAuthorityResolverError.isHandled(err)) { notificationService.error(nls.localize('connectionError', "Failed to connect to the remote extension host server (Error: {0})", err ? err.message : '')); } }); From a55b3e952585d106f990e0864d2cff8d42f956a1 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 2 Mar 2020 15:27:41 +0100 Subject: [PATCH 222/235] Ok -> OK --- src/vs/code/electron-main/app.ts | 2 +- .../services/extensions/electron-browser/extensionService.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index d91ab55a23d..cda40703e32 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -511,7 +511,7 @@ export class CodeApplication extends Disposable { type: 'info', message: localize('trace.message', "Successfully created trace."), detail: localize('trace.detail', "Please create an issue and manually attach the following file:\n{0}", path), - buttons: [localize('trace.ok', "Ok")] + buttons: [localize('trace.ok', "OK")] }, withNullAsUndefined(BrowserWindow.getFocusedWindow())); } } else { diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index 0da45d75af5..75a7b78a09f 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -600,7 +600,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten const extension = allExtensions.filter(e => e.identifier.value === resolverExtensionId)[0]; if (extension) { if (this._isDisabled(extension)) { - const message = nls.localize('enableResolver', "Extension '{0}' is required to open the remote window.\nOk to enable?", recommendation.friendlyName); + const message = nls.localize('enableResolver', "Extension '{0}' is required to open the remote window.\nOK to enable?", recommendation.friendlyName); this._notificationService.prompt(Severity.Info, message, [{ label: nls.localize('enable', 'Enable and Reload'), @@ -615,7 +615,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten } } else { // Install the Extension and reload the window to handle. - const message = nls.localize('installResolver', "Extension '{0}' is required to open the remote window.\nOk to install?", recommendation.friendlyName); + const message = nls.localize('installResolver', "Extension '{0}' is required to open the remote window.\nnOK to install?", recommendation.friendlyName); this._notificationService.prompt(Severity.Info, message, [{ label: nls.localize('install', 'Install and Reload'), From 02f23e5680ddfa98731d7e5f56ba21d4f7d8e90a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 2 Mar 2020 15:30:43 +0100 Subject: [PATCH 223/235] remove polyfill promise --- .eslintignore | 1 - build/gulpfile.editor.js | 2 +- build/gulpfile.hygiene.js | 1 - .../promise-polyfill/cgmanifest.json | 17 - .../standalone/promise-polyfill/polyfill.js | 291 ------------------ .../promise-polyfill/polyfill.license.txt | 20 -- .../common/standalone/standaloneBase.ts | 1 - src/vs/monaco.d.ts | 1 - 8 files changed, 1 insertion(+), 333 deletions(-) delete mode 100644 src/vs/editor/common/standalone/promise-polyfill/cgmanifest.json delete mode 100644 src/vs/editor/common/standalone/promise-polyfill/polyfill.js delete mode 100644 src/vs/editor/common/standalone/promise-polyfill/polyfill.license.txt diff --git a/.eslintignore b/.eslintignore index dda0884b381..f186c7ecd78 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,7 +3,6 @@ **/vs/css.build.js **/vs/css.js **/vs/loader.js -**/promise-polyfill/** **/insane/** **/marked/** **/test/**/*.js diff --git a/build/gulpfile.editor.js b/build/gulpfile.editor.js index cbd9da2541f..bdc34affadc 100644 --- a/build/gulpfile.editor.js +++ b/build/gulpfile.editor.js @@ -73,7 +73,7 @@ const extractEditorSrcTask = task.define('extract-editor-src', () => { extrausages ], shakeLevel: 2, // 0-Files, 1-InnerFile, 2-ClassMembers - importIgnorePattern: /(^vs\/css!)|(promise-polyfill\/polyfill)/, + importIgnorePattern: /(^vs\/css!)/, destRoot: path.join(root, 'out-editor-src'), redirects: [] }); diff --git a/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js index ccf965a9dc4..75c8413ae5d 100644 --- a/build/gulpfile.hygiene.js +++ b/build/gulpfile.hygiene.js @@ -114,7 +114,6 @@ const copyrightFilter = [ '!**/*.disabled', '!**/*.code-workspace', '!**/*.js.map', - '!**/promise-polyfill/polyfill.js', '!build/**/*.init', '!resources/linux/snap/snapcraft.yaml', '!resources/linux/snap/electron-launch', diff --git a/src/vs/editor/common/standalone/promise-polyfill/cgmanifest.json b/src/vs/editor/common/standalone/promise-polyfill/cgmanifest.json deleted file mode 100644 index b62e25bccff..00000000000 --- a/src/vs/editor/common/standalone/promise-polyfill/cgmanifest.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "registrations": [ - { - "component": { - "type": "git", - "git": { - "name": "promise-polyfill", - "repositoryUrl": "https://github.com/taylorhakes/promise-polyfill", - "commitHash": "efe662be6ea569c439ec92a4f8662c0a7faf0b96" - } - }, - "license": "MIT", - "version": "8.0.0" - } - ], - "version": 1 -} diff --git a/src/vs/editor/common/standalone/promise-polyfill/polyfill.js b/src/vs/editor/common/standalone/promise-polyfill/polyfill.js deleted file mode 100644 index 4ddfcab7cd0..00000000000 --- a/src/vs/editor/common/standalone/promise-polyfill/polyfill.js +++ /dev/null @@ -1,291 +0,0 @@ -/*! -Copyright (c) 2014 Taylor Hakes -Copyright (c) 2014 Forbes Lindesay - */ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory() : - typeof define === 'function' && define.amd ? define(factory) : - (factory()); -}(this, (function () { - 'use strict'; - - /** - * @this {Promise} - */ - function finallyConstructor(callback) { - var constructor = this.constructor; - return this.then( - function (value) { - return constructor.resolve(callback()).then(function () { - return value; - }); - }, - function (reason) { - return constructor.resolve(callback()).then(function () { - return constructor.reject(reason); - }); - } - ); - } - - // Store setTimeout reference so promise-polyfill will be unaffected by - // other code modifying setTimeout (like sinon.useFakeTimers()) - var setTimeoutFunc = setTimeout; - - function noop() { } - - // Polyfill for Function.prototype.bind - function bind(fn, thisArg) { - return function () { - fn.apply(thisArg, arguments); - }; - } - - /** - * @constructor - * @param {Function} fn - */ - function Promise(fn) { - if (!(this instanceof Promise)) - throw new TypeError('Promises must be constructed via new'); - if (typeof fn !== 'function') throw new TypeError('not a function'); - /** @type {!number} */ - this._state = 0; - /** @type {!boolean} */ - this._handled = false; - /** @type {Promise|undefined} */ - this._value = undefined; - /** @type {!Array} */ - this._deferreds = []; - - doResolve(fn, this); - } - - function handle(self, deferred) { - while (self._state === 3) { - self = self._value; - } - if (self._state === 0) { - self._deferreds.push(deferred); - return; - } - self._handled = true; - Promise._immediateFn(function () { - var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected; - if (cb === null) { - (self._state === 1 ? resolve : reject)(deferred.promise, self._value); - return; - } - var ret; - try { - ret = cb(self._value); - } catch (e) { - reject(deferred.promise, e); - return; - } - resolve(deferred.promise, ret); - }); - } - - function resolve(self, newValue) { - try { - // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure - if (newValue === self) - throw new TypeError('A promise cannot be resolved with itself.'); - if ( - newValue && - (typeof newValue === 'object' || typeof newValue === 'function') - ) { - var then = newValue.then; - if (newValue instanceof Promise) { - self._state = 3; - self._value = newValue; - finale(self); - return; - } else if (typeof then === 'function') { - doResolve(bind(then, newValue), self); - return; - } - } - self._state = 1; - self._value = newValue; - finale(self); - } catch (e) { - reject(self, e); - } - } - - function reject(self, newValue) { - self._state = 2; - self._value = newValue; - finale(self); - } - - function finale(self) { - if (self._state === 2 && self._deferreds.length === 0) { - Promise._immediateFn(function () { - if (!self._handled) { - Promise._unhandledRejectionFn(self._value); - } - }); - } - - for (var i = 0, len = self._deferreds.length; i < len; i++) { - handle(self, self._deferreds[i]); - } - self._deferreds = null; - } - - /** - * @constructor - */ - function Handler(onFulfilled, onRejected, promise) { - this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null; - this.onRejected = typeof onRejected === 'function' ? onRejected : null; - this.promise = promise; - } - - /** - * Take a potentially misbehaving resolver function and make sure - * onFulfilled and onRejected are only called once. - * - * Makes no guarantees about asynchrony. - */ - function doResolve(fn, self) { - var done = false; - try { - fn( - function (value) { - if (done) return; - done = true; - resolve(self, value); - }, - function (reason) { - if (done) return; - done = true; - reject(self, reason); - } - ); - } catch (ex) { - if (done) return; - done = true; - reject(self, ex); - } - } - - Promise.prototype['catch'] = function (onRejected) { - return this.then(null, onRejected); - }; - - Promise.prototype.then = function (onFulfilled, onRejected) { - // @ts-ignore - var prom = new this.constructor(noop); - - handle(this, new Handler(onFulfilled, onRejected, prom)); - return prom; - }; - - Promise.prototype['finally'] = finallyConstructor; - - Promise.all = function (arr) { - return new Promise(function (resolve, reject) { - if (!arr || typeof arr.length === 'undefined') - throw new TypeError('Promise.all accepts an array'); - var args = Array.prototype.slice.call(arr); - if (args.length === 0) return resolve([]); - var remaining = args.length; - - function res(i, val) { - try { - if (val && (typeof val === 'object' || typeof val === 'function')) { - var then = val.then; - if (typeof then === 'function') { - then.call( - val, - function (val) { - res(i, val); - }, - reject - ); - return; - } - } - args[i] = val; - if (--remaining === 0) { - resolve(args); - } - } catch (ex) { - reject(ex); - } - } - - for (var i = 0; i < args.length; i++) { - res(i, args[i]); - } - }); - }; - - Promise.resolve = function (value) { - if (value && typeof value === 'object' && value.constructor === Promise) { - return value; - } - - return new Promise(function (resolve) { - resolve(value); - }); - }; - - Promise.reject = function (value) { - return new Promise(function (resolve, reject) { - reject(value); - }); - }; - - Promise.race = function (values) { - return new Promise(function (resolve, reject) { - for (var i = 0, len = values.length; i < len; i++) { - values[i].then(resolve, reject); - } - }); - }; - - // Use polyfill for setImmediate for performance gains - Promise._immediateFn = - (typeof setImmediate === 'function' && - function (fn) { - setImmediate(fn); - }) || - function (fn) { - setTimeoutFunc(fn, 0); - }; - - Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) { - if (typeof console !== 'undefined' && console) { - console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console - } - }; - - /** @suppress {undefinedVars} */ - var globalNS = (function () { - // the only reliable means to get the global object is - // `Function('return this')()` - // However, this causes CSP violations in Chrome apps. - if (typeof self !== 'undefined') { - return self; - } - if (typeof window !== 'undefined') { - return window; - } - if (typeof global !== 'undefined') { - return global; - } - throw new Error('unable to locate global object'); - })(); - - if (!('Promise' in globalNS)) { - globalNS['Promise'] = Promise; - } else if (!globalNS.Promise.prototype['finally']) { - globalNS.Promise.prototype['finally'] = finallyConstructor; - } - -}))); diff --git a/src/vs/editor/common/standalone/promise-polyfill/polyfill.license.txt b/src/vs/editor/common/standalone/promise-polyfill/polyfill.license.txt deleted file mode 100644 index 6f7c0123162..00000000000 --- a/src/vs/editor/common/standalone/promise-polyfill/polyfill.license.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2014 Taylor Hakes -Copyright (c) 2014 Forbes Lindesay - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/src/vs/editor/common/standalone/standaloneBase.ts b/src/vs/editor/common/standalone/standaloneBase.ts index 377b5185c28..2239e8d0234 100644 --- a/src/vs/editor/common/standalone/standaloneBase.ts +++ b/src/vs/editor/common/standalone/standaloneBase.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/editor/common/standalone/promise-polyfill/polyfill'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { Emitter } from 'vs/base/common/event'; import { KeyChord, KeyMod as ConstKeyMod } from 'vs/base/common/keyCodes'; diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 63ee827cd7e..ccdfcfcece0 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -381,7 +381,6 @@ declare namespace monaco { */ MAX_VALUE = 112 } - export class KeyMod { static readonly CtrlCmd: number; static readonly Shift: number; From 4f2ea532c7afe6a3383e5d112fc0f5a067a257d6 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 2 Mar 2020 15:49:35 +0100 Subject: [PATCH 224/235] Fix #91757 --- src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 59156a2d802..05c609878ac 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -34,7 +34,7 @@ import { CONTEXT_SYNC_STATE, getSyncSourceFromRemoteContentResource, getUserData import { FloatingClickWidget } from 'vs/workbench/browser/parts/editor/editorWidgets'; import { GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import type { IEditorInput } from 'vs/workbench/common/editor'; +import { IEditorInput, toResource, SideBySideEditor } from 'vs/workbench/common/editor'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import * as Constants from 'vs/workbench/contrib/logs/common/logConstants'; import { IOutputService } from 'vs/workbench/contrib/output/common/output'; @@ -468,7 +468,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo return; } const resource = source === SyncSource.Settings ? this.workbenchEnvironmentService.settingsResource : this.workbenchEnvironmentService.keybindingsResource; - if (isEqual(resource, this.editorService.activeEditor?.resource)) { + if (isEqual(resource, toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }))) { // Do not show notification if the file in error is active return; } From 2a12c9a4587271d327ffffd226fa5946941593dc Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 2 Mar 2020 16:04:03 +0100 Subject: [PATCH 225/235] add es6 deprecation messages to some utils, remove duplicated utils, https://github.com/microsoft/vscode/issues/90676 --- src/vs/base/browser/ui/tree/abstractTree.ts | 4 ++-- src/vs/base/common/arrays.ts | 20 ++++++++++++++------ src/vs/base/common/collections.ts | 5 ----- src/vs/base/common/map.ts | 13 ++++++++++++- src/vs/base/common/resourceTree.ts | 5 ++--- src/vs/base/common/strings.ts | 6 +++--- 6 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index fc78cfe1c28..ee6dd9e3a6b 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -14,7 +14,7 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { ITreeModel, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeFilter, ITreeNavigator, ICollapseStateChangeEvent, ITreeDragAndDrop, TreeDragOverBubble, TreeVisibility, TreeFilterResult, ITreeModelSpliceEvent, TreeMouseEventTarget } from 'vs/base/browser/ui/tree/tree'; import { ISpliceable } from 'vs/base/common/sequence'; import { IDragAndDropData, StaticDND, DragAndDropData } from 'vs/base/browser/dnd'; -import { range, equals, distinctES6, fromSet } from 'vs/base/common/arrays'; +import { range, equals, distinctES6 } from 'vs/base/common/arrays'; import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView'; import { domEvent } from 'vs/base/browser/event'; import { fuzzyScore, FuzzyScore } from 'vs/base/common/filters'; @@ -1320,7 +1320,7 @@ export abstract class AbstractTree implements IDisposable set.add(node); } - return fromSet(set); + return values(set); }).event; if (_options.keyboardSupport !== false) { diff --git a/src/vs/base/common/arrays.ts b/src/vs/base/common/arrays.ts index 9a9b53a100c..afb3ae9f697 100644 --- a/src/vs/base/common/arrays.ts +++ b/src/vs/base/common/arrays.ts @@ -372,12 +372,6 @@ export function distinctES6(array: ReadonlyArray): T[] { }); } -export function fromSet(set: Set): T[] { - const result: T[] = []; - set.forEach(o => result.push(o)); - return result; -} - export function uniqueFilter(keyFn: (t: T) => string): (t: T) => boolean { const seen: { [key: string]: boolean; } = Object.create(null); @@ -405,6 +399,9 @@ export function lastIndex(array: ReadonlyArray, fn: (item: T) => boolean): return -1; } +/** + * @deprecated ES6: use `Array.findIndex` + */ export function firstIndex(array: ReadonlyArray, fn: (item: T) => boolean): number { for (let i = 0; i < array.length; i++) { const element = array[i]; @@ -417,6 +414,10 @@ export function firstIndex(array: ReadonlyArray, fn: (item: T) => boolean) return -1; } + +/** + * @deprecated ES6: use `Array.find` + */ export function first(array: ReadonlyArray, fn: (item: T) => boolean, notFoundValue: T): T; export function first(array: ReadonlyArray, fn: (item: T) => boolean): T | undefined; export function first(array: ReadonlyArray, fn: (item: T) => boolean, notFoundValue: T | undefined = undefined): T | undefined { @@ -471,6 +472,9 @@ export function range(arg: number, to?: number): number[] { return result; } +/** + * @deprecated ES6: use `Array.fill` + */ export function fill(num: number, value: T, arr: T[] = []): T[] { for (let i = 0; i < num; i++) { arr[i] = value; @@ -564,6 +568,10 @@ export function pushToEnd(arr: T[], value: T): void { } } + +/** + * @deprecated ES6: use `Array.find` + */ export function find(arr: ArrayLike, predicate: (value: T, index: number, arr: ArrayLike) => any): T | undefined { for (let i = 0; i < arr.length; i++) { const element = arr[i]; diff --git a/src/vs/base/common/collections.ts b/src/vs/base/common/collections.ts index f185d439651..e2de5aadc57 100644 --- a/src/vs/base/common/collections.ts +++ b/src/vs/base/common/collections.ts @@ -95,11 +95,6 @@ export function fromMap(original: Map): IStringDictionary { return result; } -export function mapValues(map: Map): V[] { - const result: V[] = []; - map.forEach(v => result.push(v)); - return result; -} export class SetMap { diff --git a/src/vs/base/common/map.ts b/src/vs/base/common/map.ts index 4f6b55c3fe5..4d07f50b6b8 100644 --- a/src/vs/base/common/map.ts +++ b/src/vs/base/common/map.ts @@ -7,7 +7,9 @@ import { URI } from 'vs/base/common/uri'; import { CharCode } from 'vs/base/common/charCode'; import { Iterator, IteratorResult, FIN } from './iterator'; - +/** + * @deprecated ES6: use `[...SetOrMap.values()]` + */ export function values(set: Set): V[]; export function values(map: Map): V[]; export function values(forEachable: { forEach(callback: (value: V, ...more: any[]) => any): void }): V[] { @@ -16,6 +18,9 @@ export function values(forEachable: { forEach(callback: (value: V, ...more: a return result; } +/** + * @deprecated ES6: use `[...map.keys()]` + */ export function keys(map: Map): K[] { const result: K[] = []; map.forEach((_value, key) => result.push(key)); @@ -51,6 +56,9 @@ export function setToString(set: Set): string { return `Set(${set.size}) {${entries.join(', ')}}`; } +/** + * @deprecated ES6: use `...Map.entries()` + */ export function mapToSerializable(map: Map): [string, string][] { const serializable: [string, string][] = []; @@ -61,6 +69,9 @@ export function mapToSerializable(map: Map): [string, string][] return serializable; } +/** + * @deprecated ES6: use `new Map([[key1, value1],[key2, value2]])` + */ export function serializableToMap(serializable: [string, string][]): Map { const items = new Map(); diff --git a/src/vs/base/common/resourceTree.ts b/src/vs/base/common/resourceTree.ts index 4adca4ca4f2..2de60729275 100644 --- a/src/vs/base/common/resourceTree.ts +++ b/src/vs/base/common/resourceTree.ts @@ -8,8 +8,7 @@ import * as paths from 'vs/base/common/path'; import { Iterator } from 'vs/base/common/iterator'; import { relativePath, joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; -import { mapValues } from 'vs/base/common/collections'; -import { PathIterator } from 'vs/base/common/map'; +import { PathIterator, values } from 'vs/base/common/map'; export interface IResourceNode { readonly uri: URI; @@ -32,7 +31,7 @@ class Node implements IResourceNode { } get children(): Iterator> { - return Iterator.fromArray(mapValues(this._children)); + return Iterator.fromArray(values(this._children)); } @memoize diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index fd7df3e4ee2..51336f3eb99 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -15,7 +15,7 @@ export function isFalsyOrWhitespace(str: string | undefined): boolean { } /** - * @returns the provided number with the given number of preceding zeros. + * @deprecated ES6: use `String.padStart` */ export function pad(n: number, l: number, char: string = '0'): string { const str = '' + n; @@ -146,7 +146,7 @@ export function stripWildcards(pattern: string): string { } /** - * Determines if haystack starts with needle. + * @deprecated ES6: use `String.startsWith` */ export function startsWith(haystack: string, needle: string): boolean { if (haystack.length < needle.length) { @@ -167,7 +167,7 @@ export function startsWith(haystack: string, needle: string): boolean { } /** - * Determines if haystack ends with needle. + * @deprecated ES6: use `String.endsWith` */ export function endsWith(haystack: string, needle: string): boolean { const diff = haystack.length - needle.length; From f3c0ea571c8289a204ed62a3a76ddab6ccff3333 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Mon, 2 Mar 2020 16:41:47 +0100 Subject: [PATCH 226/235] Remove notice since promise-polyfill was removed --- build/monaco/ThirdPartyNotices.txt | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/build/monaco/ThirdPartyNotices.txt b/build/monaco/ThirdPartyNotices.txt index 1de70ddaab6..8b488daf191 100644 --- a/build/monaco/ThirdPartyNotices.txt +++ b/build/monaco/ThirdPartyNotices.txt @@ -33,32 +33,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. END OF nodejs path library NOTICES AND INFORMATION -%% promise-polyfill version 8.1.0 (https://github.com/taylorhakes/promise-polyfill) -========================================= -Copyright (c) 2014 Taylor Hakes -Copyright (c) 2014 Forbes Lindesay - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -========================================= -END OF winjs NOTICES AND INFORMATION - - %% string_scorer version 0.1.20 (https://github.com/joshaven/string_score) From c5dd0e558212efe1b1745383231b7f9d1264b35a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 2 Mar 2020 16:55:46 +0100 Subject: [PATCH 227/235] add Iterable-utils (completing Iterator-utils) and adopt in bulk edit preview, https://github.com/microsoft/vscode/issues/90676 --- src/vs/base/common/iterator.ts | 18 ++++++++++++++++++ .../bulkEdit/browser/bulkEditPreview.ts | 8 ++++---- .../contrib/bulkEdit/browser/bulkEditTree.ts | 5 +++-- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/vs/base/common/iterator.ts b/src/vs/base/common/iterator.ts index 6c87c85cf48..2f4e7d38561 100644 --- a/src/vs/base/common/iterator.ts +++ b/src/vs/base/common/iterator.ts @@ -34,6 +34,24 @@ export interface NativeIterator { next(): NativeIteratorResult; } +export namespace Iterable { + + export function some(iterable: IterableIterator, predicate: (t: T) => boolean): boolean { + for (const element of iterable) { + if (predicate(element)) { + return true; + } + } + return false; + } + + export function* map(iterable: IterableIterator, fn: (t: T) => R): IterableIterator { + for (const element of iterable) { + return yield fn(element); + } + } +} + export module Iterator { const _empty: Iterator = { next() { diff --git a/src/vs/workbench/contrib/bulkEdit/browser/bulkEditPreview.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkEditPreview.ts index 59635e4a150..cfc36c26499 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/bulkEditPreview.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkEditPreview.ts @@ -18,7 +18,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { Emitter, Event } from 'vs/base/common/event'; import { IIdentifiedSingleEditOperation } from 'vs/editor/common/model'; import { ConflictDetector } from 'vs/workbench/services/bulkEdit/browser/conflicts'; -import { values, ResourceMap } from 'vs/base/common/map'; +import { ResourceMap } from 'vs/base/common/map'; import { localize } from 'vs/nls'; export class CheckedStates { @@ -89,7 +89,7 @@ export class BulkFileOperation { readonly parent: BulkFileOperations ) { } - addEdit(index: number, type: BulkFileOperationType, edit: WorkspaceTextEdit | WorkspaceFileEdit,) { + addEdit(index: number, type: BulkFileOperationType, edit: WorkspaceTextEdit | WorkspaceFileEdit) { this.type |= type; this.originalEdits.set(index, edit); if (WorkspaceTextEdit.is(edit)) { @@ -126,8 +126,8 @@ export class BulkCategory { constructor(readonly metadata: WorkspaceEditMetadata = BulkCategory._defaultMetadata) { } - get fileOperations(): BulkFileOperation[] { - return values(this.operationByResource); + get fileOperations(): IterableIterator { + return this.operationByResource.values(); } } diff --git a/src/vs/workbench/contrib/bulkEdit/browser/bulkEditTree.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkEditTree.ts index 0c55961052c..39b04d94db9 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/bulkEditTree.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkEditTree.ts @@ -27,6 +27,7 @@ import { WorkspaceFileEdit } from 'vs/editor/common/modes'; import { compare } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; +import { Iterable } from 'vs/base/common/iterator'; // --- VIEW MODEL @@ -201,7 +202,7 @@ export class BulkEditDataSource implements IAsyncDataSource new FileElement(element, op)); + return [...Iterable.map(element.category.fileOperations, op => new FileElement(element, op))]; } // file: text edit @@ -283,7 +284,7 @@ export class BulkEditSorter implements ITreeSorter { } private static _needsConfirmation(a: BulkCategory): boolean { - return a.fileOperations.some(ops => ops.needsConfirmation()); + return Iterable.some(a.fileOperations, ops => ops.needsConfirmation()); } } From 5651fa0a8a482ba8427797ba2c053b1943ff15fb Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 2 Mar 2020 16:57:50 +0100 Subject: [PATCH 228/235] debt - some :lipstick: * add a few more readonly to properties * move IVisibleEditor closer to IEditor * remove options accessor from IEditor --- src/vs/platform/editor/common/editor.ts | 2 +- .../notification/common/notification.ts | 42 +++++++++---------- .../browser/parts/editor/baseEditor.ts | 4 -- .../browser/parts/editor/editorCommands.ts | 4 +- .../browser/parts/editor/editorControl.ts | 3 +- .../browser/parts/editor/editorGroupView.ts | 8 ++-- src/vs/workbench/common/editor.ts | 17 ++++---- src/vs/workbench/common/notifications.ts | 14 +++---- .../services/editor/browser/editorService.ts | 4 +- .../editor/common/editorGroupsService.ts | 3 +- .../services/editor/common/editorService.ts | 15 +++---- .../common/notificationService.ts | 9 ++-- .../browser/parts/editor/baseEditor.test.ts | 3 -- .../test/browser/workbenchTestServices.ts | 4 +- 14 files changed, 60 insertions(+), 72 deletions(-) diff --git a/src/vs/platform/editor/common/editor.ts b/src/vs/platform/editor/common/editor.ts index 11e627666d7..c973a6e3418 100644 --- a/src/vs/platform/editor/common/editor.ts +++ b/src/vs/platform/editor/common/editor.ts @@ -65,7 +65,7 @@ export interface IResourceInput extends IBaseResourceInput { /** * The resource URI of the resource to open. */ - resource: URI; + readonly resource: URI; /** * The encoding of the text input if known. diff --git a/src/vs/platform/notification/common/notification.ts b/src/vs/platform/notification/common/notification.ts index f7f2b5a3d9e..7b19313df62 100644 --- a/src/vs/platform/notification/common/notification.ts +++ b/src/vs/platform/notification/common/notification.ts @@ -21,20 +21,20 @@ export interface INotificationProperties { * Sticky notifications are not automatically removed after a certain timeout. By * default, notifications with primary actions and severity error are always sticky. */ - sticky?: boolean; + readonly sticky?: boolean; /** * Silent notifications are not shown to the user unless the notification center * is opened. The status bar will still indicate all number of notifications to * catch some attention. */ - silent?: boolean; + readonly silent?: boolean; /** * Adds an action to never show the notification again. The choice will be persisted * such as future requests will not cause the notification to show again. */ - neverShowAgain?: INeverShowAgainOptions; + readonly neverShowAgain?: INeverShowAgainOptions; } export enum NeverShowAgainScope { @@ -55,19 +55,19 @@ export interface INeverShowAgainOptions { /** * The id is used to persist the selection of not showing the notification again. */ - id: string; + readonly id: string; /** * By default the action will show up as primary action. Setting this to true will * make it a secondary action instead. */ - isSecondary?: boolean; + readonly isSecondary?: boolean; /** * Whether to persist the choice in the current workspace or for all workspaces. By * default it will be persisted for all workspaces. */ - scope?: NeverShowAgainScope; + readonly scope?: NeverShowAgainScope; } export interface INotification extends INotificationProperties { @@ -75,18 +75,18 @@ export interface INotification extends INotificationProperties { /** * The severity of the notification. Either `Info`, `Warning` or `Error`. */ - severity: Severity; + readonly severity: Severity; /** * The message of the notification. This can either be a `string` or `Error`. Messages * can optionally include links in the format: `[text](link)` */ - message: NotificationMessage; + readonly message: NotificationMessage; /** * The source of the notification appears as additional information. */ - source?: string; + readonly source?: string; /** * Actions to show as part of the notification. Primary actions show up as @@ -106,7 +106,7 @@ export interface INotification extends INotificationProperties { * The initial set of progress properties for the notification. To update progress * later on, access the `INotificationHandle.progress` property. */ - progress?: INotificationProgressProperties; + readonly progress?: INotificationProgressProperties; } export interface INotificationActions { @@ -115,14 +115,14 @@ export interface INotificationActions { * Primary actions show up as buttons as part of the message and will close * the notification once clicked. */ - primary?: ReadonlyArray; + readonly primary?: ReadonlyArray; /** * Secondary actions are meant to provide additional configuration or context * for the notification and will show up less prominent. A notification does not * close automatically when invoking a secondary action. */ - secondary?: ReadonlyArray; + readonly secondary?: ReadonlyArray; } export interface INotificationProgressProperties { @@ -130,17 +130,17 @@ export interface INotificationProgressProperties { /** * Causes the progress bar to spin infinitley. */ - infinite?: boolean; + readonly infinite?: boolean; /** * Indicate the total amount of work. */ - total?: number; + readonly total?: number; /** * Indicate that a specific chunk of work is done. */ - worked?: number; + readonly worked?: number; } export interface INotificationProgress { @@ -176,7 +176,7 @@ export interface INotificationHandle { /** * Will be fired whenever the visibility of the notification changes. * A notification can either be visible as toast or inside the notification - * center if it is visible. + * center if it is visible. */ readonly onDidChangeVisibility: Event; @@ -214,19 +214,19 @@ export interface IPromptChoice { /** * Label to show for the choice to the user. */ - label: string; + readonly label: string; /** * Primary choices show up as buttons in the notification below the message. * Secondary choices show up under the gear icon in the header of the notification. */ - isSecondary?: boolean; + readonly isSecondary?: boolean; /** * Whether to keep the notification open after the choice was selected * by the user. By default, will close the notification upon click. */ - keepOpen?: boolean; + readonly keepOpen?: boolean; /** * Triggered when the user selects the choice. @@ -249,13 +249,13 @@ export interface IStatusMessageOptions { * An optional timeout after which the status message should show. By default * the status message will show immediately. */ - showAfter?: number; + readonly showAfter?: number; /** * An optional timeout after which the status message is to be hidden. By default * the status message will not hide until another status message is displayed. */ - hideAfter?: number; + readonly hideAfter?: number; } export enum NotificationsFilter { diff --git a/src/vs/workbench/browser/parts/editor/baseEditor.ts b/src/vs/workbench/browser/parts/editor/baseEditor.ts index 1d49f9aed7a..0aa41ce8a0c 100644 --- a/src/vs/workbench/browser/parts/editor/baseEditor.ts +++ b/src/vs/workbench/browser/parts/editor/baseEditor.ts @@ -62,10 +62,6 @@ export abstract class BaseEditor extends Panel implements IEditor { return this._input; } - get options(): EditorOptions | undefined { - return this._options; - } - get group(): IEditorGroup | undefined { return this._group; } diff --git a/src/vs/workbench/browser/parts/editor/editorCommands.ts b/src/vs/workbench/browser/parts/editor/editorCommands.ts index a6c94bdaa38..924b5ce7682 100644 --- a/src/vs/workbench/browser/parts/editor/editorCommands.ts +++ b/src/vs/workbench/browser/parts/editor/editorCommands.ts @@ -7,8 +7,8 @@ import * as nls from 'vs/nls'; import * as types from 'vs/base/common/types'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { TextCompareEditorVisibleContext, EditorInput, IEditorIdentifier, IEditorCommandsContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, CloseDirection, IEditor, IEditorInput } from 'vs/workbench/common/editor'; -import { IEditorService, IVisibleEditor } from 'vs/workbench/services/editor/common/editorService'; +import { TextCompareEditorVisibleContext, EditorInput, IEditorIdentifier, IEditorCommandsContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, CloseDirection, IEditor, IEditorInput, IVisibleEditor } from 'vs/workbench/common/editor'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor'; import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes'; diff --git a/src/vs/workbench/browser/parts/editor/editorControl.ts b/src/vs/workbench/browser/parts/editor/editorControl.ts index 1cbe3fbcd53..f9e57becfeb 100644 --- a/src/vs/workbench/browser/parts/editor/editorControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorControl.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { EditorInput, EditorOptions } from 'vs/workbench/common/editor'; +import { EditorInput, EditorOptions, IVisibleEditor } from 'vs/workbench/common/editor'; import { Dimension, show, hide, addClass } from 'vs/base/browser/dom'; import { Registry } from 'vs/platform/registry/common/platform'; import { IEditorRegistry, Extensions as EditorExtensions, IEditorDescriptor } from 'vs/workbench/browser/editor'; @@ -14,7 +14,6 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IEditorProgressService, LongRunningOperation } from 'vs/platform/progress/common/progress'; import { IEditorGroupView, DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor'; import { Emitter } from 'vs/base/common/event'; -import { IVisibleEditor } from 'vs/workbench/services/editor/common/editorService'; import { assertIsDefined } from 'vs/base/common/types'; export interface IOpenEditorResult { diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index c57de285635..29fdbb4f0c5 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/editorgroupview'; import { EditorGroup, IEditorOpenOptions, EditorCloseEvent, ISerializedEditorGroup, isSerializedEditorGroup } from 'vs/workbench/common/editor/editorGroup'; -import { EditorInput, EditorOptions, GroupIdentifier, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, EditorGroupActiveEditorDirtyContext, IEditor, EditorGroupEditorsCountContext, SaveReason, IEditorPartOptionsChangeEvent, EditorsOrder } from 'vs/workbench/common/editor'; +import { EditorInput, EditorOptions, GroupIdentifier, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, EditorGroupActiveEditorDirtyContext, IEditor, EditorGroupEditorsCountContext, SaveReason, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditor } from 'vs/workbench/common/editor'; import { Event, Emitter, Relay } from 'vs/base/common/event'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { addClass, addClasses, Dimension, trackFocus, toggleClass, removeClass, addDisposableListener, EventType, EventHelper, findParentWithClass, clearNode, isAncestor } from 'vs/base/browser/dom'; @@ -25,7 +25,7 @@ import { EditorProgressIndicator } from 'vs/workbench/services/progress/browser/ import { localize } from 'vs/nls'; import { isPromiseCanceledError } from 'vs/base/common/errors'; import { dispose, MutableDisposable } from 'vs/base/common/lifecycle'; -import { Severity, INotificationService, INotificationActions } from 'vs/platform/notification/common/notification'; +import { Severity, INotificationService } from 'vs/platform/notification/common/notification'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { RunOnceWorker } from 'vs/base/common/async'; @@ -42,7 +42,7 @@ import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { isErrorWithActions, IErrorWithActions } from 'vs/base/common/errorsWithActions'; -import { IVisibleEditor, IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; import { hash } from 'vs/base/common/hash'; import { guessMimeTypes } from 'vs/base/common/mime'; @@ -980,7 +980,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Otherwise, show a background notification. else { - const actions: INotificationActions = { primary: [] }; + const actions = { primary: [] as readonly IAction[] }; if (Array.isArray(errorActions)) { actions.primary = errorActions; } diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 35a73df65ac..68cb88a96c7 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -66,17 +66,12 @@ export interface IEditor extends IPanel { /** * The assigned input of this editor. */ - input: IEditorInput | undefined; - - /** - * The assigned options of this editor. - */ - options: IEditorOptions | undefined; + readonly input: IEditorInput | undefined; /** * The assigned group this editor is showing in. */ - group: IEditorGroup | undefined; + readonly group: IEditorGroup | undefined; /** * The minimum width of this editor. @@ -114,6 +109,14 @@ export interface IEditor extends IPanel { isVisible(): boolean; } +/** + * Overrides `IEditor` where `input` and `group` are known to be set. + */ +export interface IVisibleEditor extends IEditor { + readonly input: IEditorInput; + readonly group: IEditorGroup; +} + export interface ITextEditor extends IEditor { /** diff --git a/src/vs/workbench/common/notifications.ts b/src/vs/workbench/common/notifications.ts index 425fe84ebea..c5d3cfad158 100644 --- a/src/vs/workbench/common/notifications.ts +++ b/src/vs/workbench/common/notifications.ts @@ -529,16 +529,12 @@ export class NotificationViewItem extends Disposable implements INotificationVie } private setActions(actions: INotificationActions = { primary: [], secondary: [] }): void { - if (!Array.isArray(actions.primary)) { - actions.primary = []; - } + this._actions = { + primary: Array.isArray(actions.primary) ? actions.primary : [], + secondary: Array.isArray(actions.secondary) ? actions.secondary : [] + }; - if (!Array.isArray(actions.secondary)) { - actions.secondary = []; - } - - this._actions = actions; - this._expanded = actions.primary.length > 0; + this._expanded = actions.primary && actions.primary.length > 0; } get canCollapse(): boolean { diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index d966e603ce8..fdfc4cb6d8d 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -5,7 +5,7 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IResourceInput, ITextEditorOptions, IEditorOptions, EditorActivation } from 'vs/platform/editor/common/editor'; -import { SideBySideEditor as SideBySideEditorChoice, IEditorInput, IEditor, GroupIdentifier, IFileEditorInput, IUntitledTextResourceInput, IResourceDiffInput, IResourceSideBySideInput, IEditorInputFactoryRegistry, Extensions as EditorExtensions, EditorInput, SideBySideEditorInput, IEditorInputWithOptions, isEditorInputWithOptions, EditorOptions, TextEditorOptions, IEditorIdentifier, IEditorCloseEvent, ITextEditor, ITextDiffEditor, ITextSideBySideEditor, IRevertOptions, SaveReason, EditorsOrder, isTextEditor, IWorkbenchEditorConfiguration, toResource } from 'vs/workbench/common/editor'; +import { SideBySideEditor as SideBySideEditorChoice, IEditorInput, IEditor, GroupIdentifier, IFileEditorInput, IUntitledTextResourceInput, IResourceDiffInput, IResourceSideBySideInput, IEditorInputFactoryRegistry, Extensions as EditorExtensions, EditorInput, SideBySideEditorInput, IEditorInputWithOptions, isEditorInputWithOptions, EditorOptions, TextEditorOptions, IEditorIdentifier, IEditorCloseEvent, ITextEditor, ITextDiffEditor, ITextSideBySideEditor, IRevertOptions, SaveReason, EditorsOrder, isTextEditor, IWorkbenchEditorConfiguration, toResource, IVisibleEditor } from 'vs/workbench/common/editor'; import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { Registry } from 'vs/platform/registry/common/platform'; import { ResourceMap } from 'vs/base/common/map'; @@ -17,7 +17,7 @@ import { URI } from 'vs/base/common/uri'; import { basename, isEqualOrParent, joinPath } from 'vs/base/common/resources'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { IEditorGroupsService, IEditorGroup, GroupsOrder, IEditorReplacement, GroupChangeKind, preferredSideBySideGroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { IResourceEditor, SIDE_GROUP, IResourceEditorReplacement, IOpenEditorOverrideHandler, IVisibleEditor, IEditorService, SIDE_GROUP_TYPE, ACTIVE_GROUP_TYPE, ISaveEditorsOptions, ISaveAllEditorsOptions, IRevertAllEditorsOptions, IBaseSaveRevertAllEditorOptions } from 'vs/workbench/services/editor/common/editorService'; +import { IResourceEditor, SIDE_GROUP, IResourceEditorReplacement, IOpenEditorOverrideHandler, IEditorService, SIDE_GROUP_TYPE, ACTIVE_GROUP_TYPE, ISaveEditorsOptions, ISaveAllEditorsOptions, IRevertAllEditorsOptions, IBaseSaveRevertAllEditorOptions } from 'vs/workbench/services/editor/common/editorService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Disposable, IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { coalesce, distinct } from 'vs/base/common/arrays'; diff --git a/src/vs/workbench/services/editor/common/editorGroupsService.ts b/src/vs/workbench/services/editor/common/editorGroupsService.ts index 20e6bfbb1ae..5202a0d00fe 100644 --- a/src/vs/workbench/services/editor/common/editorGroupsService.ts +++ b/src/vs/workbench/services/editor/common/editorGroupsService.ts @@ -5,10 +5,9 @@ import { Event } from 'vs/base/common/event'; import { createDecorator, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { IEditorInput, IEditor, GroupIdentifier, IEditorInputWithOptions, CloseDirection, IEditorPartOptions, IEditorPartOptionsChangeEvent, EditorsOrder } from 'vs/workbench/common/editor'; +import { IEditorInput, IEditor, GroupIdentifier, IEditorInputWithOptions, CloseDirection, IEditorPartOptions, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditor } from 'vs/workbench/common/editor'; import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IVisibleEditor } from 'vs/workbench/services/editor/common/editorService'; import { IDimension } from 'vs/editor/common/editorCommon'; import { IDisposable } from 'vs/base/common/lifecycle'; diff --git a/src/vs/workbench/services/editor/common/editorService.ts b/src/vs/workbench/services/editor/common/editorService.ts index 490ec7f1b32..b301ee5c70b 100644 --- a/src/vs/workbench/services/editor/common/editorService.ts +++ b/src/vs/workbench/services/editor/common/editorService.ts @@ -5,7 +5,7 @@ import { createDecorator, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IResourceInput, IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor'; -import { IEditorInput, IEditor, GroupIdentifier, IEditorInputWithOptions, IUntitledTextResourceInput, IResourceDiffInput, IResourceSideBySideInput, ITextEditor, ITextDiffEditor, ITextSideBySideEditor, IEditorIdentifier, ISaveOptions, IRevertOptions, EditorsOrder } from 'vs/workbench/common/editor'; +import { IEditorInput, IEditor, GroupIdentifier, IEditorInputWithOptions, IUntitledTextResourceInput, IResourceDiffInput, IResourceSideBySideInput, ITextEditor, ITextDiffEditor, ITextSideBySideEditor, IEditorIdentifier, ISaveOptions, IRevertOptions, EditorsOrder, IVisibleEditor } from 'vs/workbench/common/editor'; import { Event } from 'vs/base/common/event'; import { IEditor as ICodeEditor, IDiffEditor } from 'vs/editor/common/editorCommon'; import { IEditorGroup, IEditorReplacement } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -16,8 +16,8 @@ export const IEditorService = createDecorator('editorService'); export type IResourceEditor = IResourceInput | IUntitledTextResourceInput | IResourceDiffInput | IResourceSideBySideInput; export interface IResourceEditorReplacement { - editor: IResourceEditor; - replacement: IResourceEditor; + readonly editor: IResourceEditor; + readonly replacement: IResourceEditor; } export const ACTIVE_GROUP = -1; @@ -39,17 +39,12 @@ export interface IOpenEditorOverride { override?: Promise; } -export interface IVisibleEditor extends IEditor { - input: IEditorInput; - group: IEditorGroup; -} - export interface ISaveEditorsOptions extends ISaveOptions { /** * If true, will ask for a location of the editor to save to. */ - saveAs?: boolean; + readonly saveAs?: boolean; } export interface IBaseSaveRevertAllEditorOptions { @@ -57,7 +52,7 @@ export interface IBaseSaveRevertAllEditorOptions { /** * Whether to include untitled editors as well. */ - includeUntitled?: boolean; + readonly includeUntitled?: boolean; } export interface ISaveAllEditorsOptions extends ISaveEditorsOptions, IBaseSaveRevertAllEditorOptions { } diff --git a/src/vs/workbench/services/notification/common/notificationService.ts b/src/vs/workbench/services/notification/common/notificationService.ts index 80a451c1589..0a9c6e448be 100644 --- a/src/vs/workbench/services/notification/common/notificationService.ts +++ b/src/vs/workbench/services/notification/common/notificationService.ts @@ -87,11 +87,14 @@ export class NotificationService extends Disposable implements INotificationServ })); // Insert as primary or secondary action - const actions = notification.actions || { primary: [], secondary: [] }; + const actions = { + primary: notification.actions?.primary || [], + secondary: notification.actions?.secondary || [] + }; if (!notification.neverShowAgain.isSecondary) { - actions.primary = [neverShowAgainAction, ...(actions.primary || [])]; // action comes first + actions.primary = [neverShowAgainAction, ...actions.primary]; // action comes first } else { - actions.secondary = [...(actions.secondary || []), neverShowAgainAction]; // actions comes last + actions.secondary = [...actions.secondary, neverShowAgainAction]; // actions comes last } notification.actions = actions; diff --git a/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts b/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts index 19ba3f55d7c..e76d0813009 100644 --- a/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts +++ b/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts @@ -103,11 +103,9 @@ suite('Workbench base editor', () => { assert(!e.isVisible()); assert(!e.input); - assert(!e.options); await e.setInput(input, options, CancellationToken.None); assert.strictEqual(input, e.input); - assert.strictEqual(options, e.options); const group = new TestEditorGroupView(1); e.setVisible(true, group); assert(e.isVisible()); @@ -120,7 +118,6 @@ suite('Workbench base editor', () => { e.setVisible(false, group); assert(!e.isVisible()); assert(!e.input); - assert(!e.options); assert(!e.getControl()); }); diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index 3f03b1b0fcb..e164075d474 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -10,7 +10,7 @@ import * as resources from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; -import { IEditorInputWithOptions, CloseDirection, IEditorIdentifier, IUntitledTextResourceInput, IResourceDiffInput, IResourceSideBySideInput, IEditorInput, IEditor, IEditorCloseEvent, IEditorPartOptions, IRevertOptions, GroupIdentifier, EditorInput, EditorOptions, EditorsOrder, IFileEditorInput, IEditorInputFactoryRegistry, IEditorInputFactory, Extensions as EditorExtensions, ISaveOptions, IMoveResult, ITextEditor, ITextDiffEditor, ITextSideBySideEditor } from 'vs/workbench/common/editor'; +import { IEditorInputWithOptions, CloseDirection, IEditorIdentifier, IUntitledTextResourceInput, IResourceDiffInput, IResourceSideBySideInput, IEditorInput, IEditor, IEditorCloseEvent, IEditorPartOptions, IRevertOptions, GroupIdentifier, EditorInput, EditorOptions, EditorsOrder, IFileEditorInput, IEditorInputFactoryRegistry, IEditorInputFactory, Extensions as EditorExtensions, ISaveOptions, IMoveResult, ITextEditor, ITextDiffEditor, ITextSideBySideEditor, IVisibleEditor } from 'vs/workbench/common/editor'; import { IEditorOpeningEvent, EditorServiceImpl, IEditorGroupView, IEditorGroupsAccessor } from 'vs/workbench/browser/parts/editor/editor'; import { Event, Emitter } from 'vs/base/common/event'; import { IBackupFileService, IResolvedBackup } from 'vs/workbench/services/backup/common/backup'; @@ -52,7 +52,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IDecorationsService, IResourceDecorationChangeEvent, IDecoration, IDecorationData, IDecorationsProvider } from 'vs/workbench/services/decorations/browser/decorations'; import { IDisposable, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IEditorGroupsService, IEditorGroup, GroupsOrder, GroupsArrangement, GroupDirection, IAddGroupOptions, IMergeGroupOptions, IMoveEditorOptions, ICopyEditorOptions, IEditorReplacement, IGroupChangeEvent, IFindGroupScope, EditorGroupLayout, ICloseEditorOptions, GroupOrientation } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { IEditorService, IOpenEditorOverrideHandler, IVisibleEditor, ISaveEditorsOptions, IRevertAllEditorsOptions, IResourceEditor, SIDE_GROUP_TYPE, ACTIVE_GROUP_TYPE } from 'vs/workbench/services/editor/common/editorService'; +import { IEditorService, IOpenEditorOverrideHandler, ISaveEditorsOptions, IRevertAllEditorsOptions, IResourceEditor, SIDE_GROUP_TYPE, ACTIVE_GROUP_TYPE } from 'vs/workbench/services/editor/common/editorService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { IEditorRegistry, EditorDescriptor, Extensions } from 'vs/workbench/browser/editor'; import { EditorGroup } from 'vs/workbench/common/editor/editorGroup'; From 3b975102e71843853038695d60f15236c2c35165 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 2 Mar 2020 17:25:00 +0100 Subject: [PATCH 229/235] types :lipstick: --- src/vs/workbench/browser/parts/editor/editorStatus.ts | 8 ++++---- src/vs/workbench/services/editor/common/editorService.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index aaf1ae0f35a..574b6c7092c 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -13,7 +13,7 @@ import { URI } from 'vs/base/common/uri'; import { Action } from 'vs/base/common/actions'; import { Language } from 'vs/base/common/platform'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput'; -import { IFileEditorInput, EncodingMode, IEncodingSupport, toResource, SideBySideEditorInput, IEditor as IBaseEditor, IEditorInput, SideBySideEditor, IModeSupport } from 'vs/workbench/common/editor'; +import { IFileEditorInput, EncodingMode, IEncodingSupport, toResource, SideBySideEditorInput, IEditor, IEditorInput, SideBySideEditor, IModeSupport } from 'vs/workbench/common/editor'; import { Disposable, MutableDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IEditorAction } from 'vs/editor/common/editorCommon'; import { EndOfLineSequence } from 'vs/editor/common/model'; @@ -733,7 +733,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { this.updateState(update); } - private onMetadataChange(editor: IBaseEditor | undefined): void { + private onMetadataChange(editor: IEditor | undefined): void { const update: StateDelta = { type: 'metadata', metadata: undefined }; if (editor instanceof BaseBinaryResourceEditor || editor instanceof BinaryResourceDiffEditor) { @@ -832,7 +832,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { this.updateState(info); } - private onEncodingChange(editor: IBaseEditor | undefined, editorWidget: ICodeEditor | undefined): void { + private onEncodingChange(editor: IEditor | undefined, editorWidget: ICodeEditor | undefined): void { if (editor && !this.isActiveEditor(editor)) { return; } @@ -876,7 +876,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { this.updateState(info); } - private isActiveEditor(control: IBaseEditor): boolean { + private isActiveEditor(control: IEditor): boolean { const activeControl = this.editorService.activeControl; return !!activeControl && activeControl === control; diff --git a/src/vs/workbench/services/editor/common/editorService.ts b/src/vs/workbench/services/editor/common/editorService.ts index b301ee5c70b..20f8d2ee047 100644 --- a/src/vs/workbench/services/editor/common/editorService.ts +++ b/src/vs/workbench/services/editor/common/editorService.ts @@ -122,7 +122,7 @@ export interface IEditorService { * All text editor widgets that are currently visible across all editor groups. A text editor * widget is either a text or a diff editor. */ - readonly visibleTextEditorWidgets: ReadonlyArray; + readonly visibleTextEditorWidgets: ReadonlyArray; /** * All editors that are opened across all editor groups in sequential order From 8cbde76c84a2389ccf3265fdd73f850c39af5966 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Mon, 2 Mar 2020 11:31:41 -0500 Subject: [PATCH 230/235] Fixes missing loading message in certain cases --- .../contrib/timeline/browser/timelinePane.ts | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/timeline/browser/timelinePane.ts b/src/vs/workbench/contrib/timeline/browser/timelinePane.ts index 976f6d73937..afb28a1a2a7 100644 --- a/src/vs/workbench/contrib/timeline/browser/timelinePane.ts +++ b/src/vs/workbench/contrib/timeline/browser/timelinePane.ts @@ -354,6 +354,8 @@ export class TimelinePane extends ViewPane { if (noRequests) { this.refresh(); + } else if (this.message !== undefined) { + this.setLoadingUriMessage(); } } @@ -458,8 +460,7 @@ export class TimelinePane extends ViewPane { // If we have items already and there are other pending requests, debounce for a bit to wait for other requests if (alreadyHadItems && this._pendingRequests.size !== 0) { this.refreshDebounced(); - } - else { + } else { this.refresh(); } } @@ -538,21 +539,22 @@ export class TimelinePane extends ViewPane { } private refresh() { - this._pendingAnyResults = false; - if (this._uri === undefined) { this.titleDescription = undefined; this.message = localize('timeline.editorCannotProvideTimeline', 'The active editor cannot provide timeline information.'); - } - else { - this.titleDescription = basename(this._uri.fsPath); - if (this._items.length === 0) { - this.message = localize('timeline.noTimelineInfo', 'No timeline information was provided.'); + } else if (this._items.length === 0) { + if (this._pendingRequests.size !== 0) { + this.setLoadingUriMessage(); } else { - this.message = undefined; + this.titleDescription = basename(this._uri.fsPath); + this.message = localize('timeline.noTimelineInfo', 'No timeline information was provided.'); } + } else { + this.titleDescription = basename(this._uri.fsPath); + this.message = undefined; } + this._pendingAnyResults = false; this._tree.setChildren(null, this._items); } From 7e4c8c983d181cbb56c969662ead5f9a59bfd786 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Mon, 2 Mar 2020 17:32:02 +0100 Subject: [PATCH 231/235] Remove browser.isIE --- src/vs/base/browser/browser.ts | 3 +- src/vs/base/browser/canIUse.ts | 4 - src/vs/base/browser/dom.ts | 116 +----------------- src/vs/base/browser/globalMouseMoveMonitor.ts | 3 +- src/vs/base/browser/keyboardEvent.ts | 4 +- src/vs/base/browser/ui/inputbox/inputBox.ts | 9 -- src/vs/base/parts/tree/browser/treeView.ts | 75 +---------- .../editor/browser/controller/mouseHandler.ts | 18 +-- .../browser/controller/textAreaInput.ts | 8 -- src/vs/editor/common/standaloneStrings.ts | 1 - .../gotoSymbol/link/clickLinkGesture.ts | 3 +- .../accessibilityHelp/accessibilityHelp.ts | 3 +- .../browser/quickOpen/quickCommand.ts | 5 +- .../browser/standaloneCodeEditor.ts | 7 +- 14 files changed, 13 insertions(+), 246 deletions(-) diff --git a/src/vs/base/browser/browser.ts b/src/vs/base/browser/browser.ts index 715019d3048..8a11336f218 100644 --- a/src/vs/base/browser/browser.ts +++ b/src/vs/base/browser/browser.ts @@ -110,9 +110,8 @@ export const onDidChangeFullscreen = WindowManager.INSTANCE.onDidChangeFullscree const userAgent = navigator.userAgent; -export const isIE = (userAgent.indexOf('Trident') >= 0); export const isEdge = (userAgent.indexOf('Edge/') >= 0); -export const isEdgeOrIE = isIE || isEdge; +export const isEdgeOrIE = isEdge; export const isOpera = (userAgent.indexOf('Opera') >= 0); export const isFirefox = (userAgent.indexOf('Firefox') >= 0); diff --git a/src/vs/base/browser/canIUse.ts b/src/vs/base/browser/canIUse.ts index cf8211e919e..0a425479e59 100644 --- a/src/vs/base/browser/canIUse.ts +++ b/src/vs/base/browser/canIUse.ts @@ -27,10 +27,6 @@ export const BrowserFeatures = { || !!(navigator && navigator.clipboard && navigator.clipboard.readText) ), richText: (() => { - if (browser.isIE) { - return false; - } - if (browser.isEdge) { let index = navigator.userAgent.indexOf('Edge/'); let version = parseInt(navigator.userAgent.substring(index + 5, navigator.userAgent.indexOf('.', index)), 10); diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 69f1d93b2b7..0bcfa43b5d1 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -8,7 +8,6 @@ import { domEvent } from 'vs/base/browser/event'; import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { IMouseEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { TimeoutTimer } from 'vs/base/common/async'; -import { CharCode } from 'vs/base/common/charCode'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; @@ -49,117 +48,7 @@ interface IDomClassList { toggleClass(node: HTMLElement | SVGElement, className: string, shouldHaveIt?: boolean): void; } -const _manualClassList = new class implements IDomClassList { - - private _lastStart: number = -1; - private _lastEnd: number = -1; - - private _findClassName(node: HTMLElement, className: string): void { - - let classes = node.className; - if (!classes) { - this._lastStart = -1; - return; - } - - className = className.trim(); - - let classesLen = classes.length, - classLen = className.length; - - if (classLen === 0) { - this._lastStart = -1; - return; - } - - if (classesLen < classLen) { - this._lastStart = -1; - return; - } - - if (classes === className) { - this._lastStart = 0; - this._lastEnd = classesLen; - return; - } - - let idx = -1, - idxEnd: number; - - while ((idx = classes.indexOf(className, idx + 1)) >= 0) { - - idxEnd = idx + classLen; - - // a class that is followed by another class - if ((idx === 0 || classes.charCodeAt(idx - 1) === CharCode.Space) && classes.charCodeAt(idxEnd) === CharCode.Space) { - this._lastStart = idx; - this._lastEnd = idxEnd + 1; - return; - } - - // last class - if (idx > 0 && classes.charCodeAt(idx - 1) === CharCode.Space && idxEnd === classesLen) { - this._lastStart = idx - 1; - this._lastEnd = idxEnd; - return; - } - - // equal - duplicate of cmp above - if (idx === 0 && idxEnd === classesLen) { - this._lastStart = 0; - this._lastEnd = idxEnd; - return; - } - } - - this._lastStart = -1; - } - - hasClass(node: HTMLElement, className: string): boolean { - this._findClassName(node, className); - return this._lastStart !== -1; - } - - addClasses(node: HTMLElement, ...classNames: string[]): void { - classNames.forEach(nameValue => nameValue.split(' ').forEach(name => this.addClass(node, name))); - } - - addClass(node: HTMLElement, className: string): void { - if (!node.className) { // doesn't have it for sure - node.className = className; - } else { - this._findClassName(node, className); // see if it's already there - if (this._lastStart === -1) { - node.className = node.className + ' ' + className; - } - } - } - - removeClass(node: HTMLElement, className: string): void { - this._findClassName(node, className); - if (this._lastStart === -1) { - return; // Prevent styles invalidation if not necessary - } else { - node.className = node.className.substring(0, this._lastStart) + node.className.substring(this._lastEnd); - } - } - - removeClasses(node: HTMLElement, ...classNames: string[]): void { - classNames.forEach(nameValue => nameValue.split(' ').forEach(name => this.removeClass(node, name))); - } - - toggleClass(node: HTMLElement, className: string, shouldHaveIt?: boolean): void { - this._findClassName(node, className); - if (this._lastStart !== -1 && (shouldHaveIt === undefined || !shouldHaveIt)) { - this.removeClass(node, className); - } - if (this._lastStart === -1 && (shouldHaveIt === undefined || shouldHaveIt)) { - this.addClass(node, className); - } - } -}; - -const _nativeClassList = new class implements IDomClassList { +const _classList: IDomClassList = new class implements IDomClassList { hasClass(node: HTMLElement, className: string): boolean { return Boolean(className) && node.classList && node.classList.contains(className); } @@ -191,9 +80,6 @@ const _nativeClassList = new class implements IDomClassList { } }; -// In IE11 there is only partial support for `classList` which makes us keep our -// custom implementation. Otherwise use the native implementation, see: http://caniuse.com/#search=classlist -const _classList: IDomClassList = browser.isIE ? _manualClassList : _nativeClassList; export const hasClass: (node: HTMLElement | SVGElement, className: string) => boolean = _classList.hasClass.bind(_classList); export const addClass: (node: HTMLElement | SVGElement, className: string) => void = _classList.addClass.bind(_classList); export const addClasses: (node: HTMLElement | SVGElement, ...classNames: string[]) => void = _classList.addClasses.bind(_classList); diff --git a/src/vs/base/browser/globalMouseMoveMonitor.ts b/src/vs/base/browser/globalMouseMoveMonitor.ts index 8fddd54b7b3..328ecaee03d 100644 --- a/src/vs/base/browser/globalMouseMoveMonitor.ts +++ b/src/vs/base/browser/globalMouseMoveMonitor.ts @@ -5,7 +5,6 @@ import * as dom from 'vs/base/browser/dom'; import * as platform from 'vs/base/common/platform'; -import * as browser from 'vs/base/browser/browser'; import { IframeUtils } from 'vs/base/browser/iframe'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; @@ -103,7 +102,7 @@ export class GlobalMouseMoveMonitor implements I for (const element of listenTo) { this._hooks.add(dom.addDisposableThrottledListener(element, mouseMove, (data: R) => { - if (!browser.isIE && data.buttons !== initialButtons) { + if (data.buttons !== initialButtons) { // Buttons state has changed in the meantime this.stopMonitoring(true); return; diff --git a/src/vs/base/browser/keyboardEvent.ts b/src/vs/base/browser/keyboardEvent.ts index 03bdffc95ed..90a84b5890f 100644 --- a/src/vs/base/browser/keyboardEvent.ts +++ b/src/vs/base/browser/keyboardEvent.ts @@ -145,9 +145,7 @@ let INVERSE_KEY_CODE_MAP: KeyCode[] = new Array(KeyCode.MAX_VALUE); */ define(229, KeyCode.KEY_IN_COMPOSITION); - if (browser.isIE) { - define(91, KeyCode.Meta); - } else if (browser.isFirefox) { + if (browser.isFirefox) { define(59, KeyCode.US_SEMICOLON); define(107, KeyCode.US_EQUAL); define(109, KeyCode.US_MINUS); diff --git a/src/vs/base/browser/ui/inputbox/inputBox.ts b/src/vs/base/browser/ui/inputbox/inputBox.ts index cd57d7f772f..96d5013909b 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.ts +++ b/src/vs/base/browser/ui/inputbox/inputBox.ts @@ -6,7 +6,6 @@ import 'vs/css!./inputBox'; import * as nls from 'vs/nls'; -import * as Bal from 'vs/base/browser/browser'; import * as dom from 'vs/base/browser/dom'; import { MarkdownRenderOptions } from 'vs/base/browser/markdownRenderer'; import { renderFormattedText, renderText } from 'vs/base/browser/formattedTextRenderer'; @@ -212,14 +211,6 @@ export class InputBox extends Widget { this.onblur(this.input, () => this.onBlur()); this.onfocus(this.input, () => this.onFocus()); - // Add placeholder shim for IE because IE decides to hide the placeholder on focus (we dont want that!) - if (this.placeholder && Bal.isIE) { - this.onclick(this.input, (e) => { - dom.EventHelper.stop(e, true); - this.input.focus(); - }); - } - this.ignoreGesture(this.input); setTimeout(() => this.updateMirror(), 0); diff --git a/src/vs/base/parts/tree/browser/treeView.ts b/src/vs/base/parts/tree/browser/treeView.ts index 51d69f93036..790aeb52339 100644 --- a/src/vs/base/parts/tree/browser/treeView.ts +++ b/src/vs/base/parts/tree/browser/treeView.ts @@ -375,11 +375,6 @@ class RootViewItem extends ViewItem { } } -interface IThrottledGestureEvent { - translationX: number; - translationY: number; -} - function reactionEquals(one: _.IDragOverReaction, other: _.IDragOverReaction | null): boolean { if (!one && !other) { return true; @@ -417,7 +412,6 @@ export class TreeView extends HeightMap { private scrollableElement: ScrollableElement; private msGesture: MSGesture | undefined; private lastPointerType: string = ''; - private lastClickTimeStamp: number = 0; private horizontalScrolling: boolean; private contentWidthUpdateDelayer = new Delayer(50); @@ -520,12 +514,7 @@ export class TreeView extends HeightMap { this._onDidScroll.fire(); }); - if (Browser.isIE) { - this.wrapper.style.msTouchAction = 'none'; - this.wrapper.style.msContentZooming = 'none'; - } else { - this.gestureDisposable = Touch.Gesture.addTarget(this.wrapper); - } + this.gestureDisposable = Touch.Gesture.addTarget(this.wrapper); this.rowsContainer = document.createElement('div'); this.rowsContainer.className = 'monaco-tree-rows'; @@ -552,26 +541,6 @@ export class TreeView extends HeightMap { this.viewListeners.push(DOM.addDisposableListener(this.wrapper, Touch.EventType.Tap, (e) => this.onTap(e))); this.viewListeners.push(DOM.addDisposableListener(this.wrapper, Touch.EventType.Change, (e) => this.onTouchChange(e))); - if (Browser.isIE) { - this.viewListeners.push(DOM.addDisposableListener(this.wrapper, 'MSPointerDown', (e) => this.onMsPointerDown(e))); - this.viewListeners.push(DOM.addDisposableListener(this.wrapper, 'MSGestureTap', (e) => this.onMsGestureTap(e))); - - // these events come too fast, we throttle them - this.viewListeners.push(DOM.addDisposableThrottledListener(this.wrapper, 'MSGestureChange', e => this.onThrottledMsGestureChange(e), (lastEvent, event) => { - event.stopPropagation(); - event.preventDefault(); - - let result = { translationY: event.translationY, translationX: event.translationX }; - - if (lastEvent) { - result.translationY += lastEvent.translationY; - result.translationX += lastEvent.translationX; - } - - return result; - })); - } - this.viewListeners.push(DOM.addDisposableListener(window, 'dragover', (e) => this.onDragOver(e))); this.viewListeners.push(DOM.addDisposableListener(this.wrapper, 'drop', (e) => this.onDrop(e))); this.viewListeners.push(DOM.addDisposableListener(window, 'dragend', (e) => this.onDragEnd(e))); @@ -1144,15 +1113,6 @@ export class TreeView extends HeightMap { return; } - if (Browser.isIE && Date.now() - this.lastClickTimeStamp < 300) { - // IE10+ doesn't set the detail property correctly. While IE10 simply - // counts the number of clicks, IE11 reports always 1. To align with - // other browser, we set the value to 2 if clicks events come in a 300ms - // sequence. - event.detail = 2; - } - this.lastClickTimeStamp = Date.now(); - this.context.controller!.onClick(this.context.tree, item.model.getElement(), event); } @@ -1563,39 +1523,6 @@ export class TreeView extends HeightMap { this._onDOMBlur.fire(); } - // MS specific DOM Events - - private onMsPointerDown(event: MSPointerEvent): void { - if (!this.msGesture) { - return; - } - - // Circumvent IE11 breaking change in e.pointerType & TypeScript's stale definitions - let pointerType = event.pointerType; - if (pointerType === ((event).MSPOINTER_TYPE_MOUSE || 'mouse')) { - this.lastPointerType = 'mouse'; - return; - } else if (pointerType === ((event).MSPOINTER_TYPE_TOUCH || 'touch')) { - this.lastPointerType = 'touch'; - } else { - return; - } - - event.stopPropagation(); - event.preventDefault(); - - this.msGesture.addPointer(event.pointerId); - } - - private onThrottledMsGestureChange(event: IThrottledGestureEvent): void { - this.scrollTop -= event.translationY; - } - - private onMsGestureTap(event: MSGestureEvent): void { - (event).initialTarget = document.elementFromPoint(event.clientX, event.clientY); - this.onTap(event); - } - // DOM changes private insertItemInDOM(item: ViewItem): void { diff --git a/src/vs/editor/browser/controller/mouseHandler.ts b/src/vs/editor/browser/controller/mouseHandler.ts index 5bab90e5eb1..11b009a37aa 100644 --- a/src/vs/editor/browser/controller/mouseHandler.ts +++ b/src/vs/editor/browser/controller/mouseHandler.ts @@ -6,7 +6,7 @@ import * as browser from 'vs/base/browser/browser'; import * as dom from 'vs/base/browser/dom'; import { StandardWheelEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; -import { RunOnceScheduler, TimeoutTimer } from 'vs/base/common/async'; +import { TimeoutTimer } from 'vs/base/common/async'; import { Disposable } from 'vs/base/common/lifecycle'; import * as platform from 'vs/base/common/platform'; import { HitTestContext, IViewZoneData, MouseTarget, MouseTargetFactory, PointerHandlerLastRenderData } from 'vs/editor/browser/controller/mouseTarget'; @@ -69,7 +69,6 @@ export class MouseHandler extends ViewEventHandler { protected viewController: ViewController; protected viewHelper: IPointerHandlerHelper; protected mouseTargetFactory: MouseTargetFactory; - private readonly _asyncFocus: RunOnceScheduler; protected readonly _mouseDownOperation: MouseDownOperation; private lastMouseLeaveTime: number; @@ -89,8 +88,6 @@ export class MouseHandler extends ViewEventHandler { (e) => this._getMouseColumn(e) )); - this._asyncFocus = this._register(new RunOnceScheduler(() => this.viewHelper.focusTextArea(), 0)); - this.lastMouseLeaveTime = -1; const mouseEvents = new EditorMouseEventFactory(this.viewHelper.viewDomNode); @@ -137,9 +134,7 @@ export class MouseHandler extends ViewEventHandler { this._mouseDownOperation.onCursorStateChanged(e); return false; } - private _isFocused = false; public onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean { - this._isFocused = e.isFocused; return false; } public onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean { @@ -223,15 +218,8 @@ export class MouseHandler extends ViewEventHandler { } const focus = () => { - // In IE11, if the focus is in the browser's address bar and - // then you click in the editor, calling preventDefault() - // will not move focus properly (focus remains the address bar) - if (browser.isIE && !this._isFocused) { - this._asyncFocus.schedule(); - } else { - e.preventDefault(); - this.viewHelper.focusTextArea(); - } + e.preventDefault(); + this.viewHelper.focusTextArea(); }; if (shouldHandle && (targetIsContent || (targetIsLineNumbers && selectOnLineNumbers))) { diff --git a/src/vs/editor/browser/controller/textAreaInput.ts b/src/vs/editor/browser/controller/textAreaInput.ts index 8d0f1962ab2..672025b5d34 100644 --- a/src/vs/editor/browser/controller/textAreaInput.ts +++ b/src/vs/editor/browser/controller/textAreaInput.ts @@ -229,14 +229,6 @@ export class TextAreaInput extends Disposable { return true; } - // https://github.com/Microsoft/monaco-editor/issues/545 - // On IE11, we can't trust composition data when typing Chinese as IE11 doesn't emit correct - // events when users type numbers in IME. - // Chinese: zh-Hans-CN, zh-Hans-SG, zh-Hant-TW, zh-Hant-HK - if (browser.isIE && locale.indexOf('zh-Han') === 0) { - return true; - } - return false; }; diff --git a/src/vs/editor/common/standaloneStrings.ts b/src/vs/editor/common/standaloneStrings.ts index f0c107c0cbe..130e4884908 100644 --- a/src/vs/editor/common/standaloneStrings.ts +++ b/src/vs/editor/common/standaloneStrings.ts @@ -71,7 +71,6 @@ export namespace QuickOutlineNLS { export namespace StandaloneCodeEditorNLS { export const editorViewAccessibleLabel = nls.localize('editorViewAccessibleLabel', "Editor content"); - export const accessibilityHelpMessageIE = nls.localize('accessibilityHelpMessageIE', "Press Ctrl+F1 for Accessibility Options."); export const accessibilityHelpMessage = nls.localize('accessibilityHelpMessage', "Press Alt+F1 for Accessibility Options."); } diff --git a/src/vs/editor/contrib/gotoSymbol/link/clickLinkGesture.ts b/src/vs/editor/contrib/gotoSymbol/link/clickLinkGesture.ts index 003ed988f84..bc3e6cad236 100644 --- a/src/vs/editor/contrib/gotoSymbol/link/clickLinkGesture.ts +++ b/src/vs/editor/contrib/gotoSymbol/link/clickLinkGesture.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { KeyCode } from 'vs/base/common/keyCodes'; -import * as browser from 'vs/base/browser/browser'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { ICodeEditor, IEditorMouseEvent, IMouseTarget } from 'vs/editor/browser/editorBrowser'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -31,7 +30,7 @@ export class ClickLinkMouseEvent { this.target = source.target; this.hasTriggerModifier = hasModifier(source.event, opts.triggerModifier); this.hasSideBySideModifier = hasModifier(source.event, opts.triggerSideBySideModifier); - this.isNoneOrSingleMouseDown = (browser.isIE || source.event.detail <= 1); // IE does not support event.detail properly + this.isNoneOrSingleMouseDown = (source.event.detail <= 1); } } diff --git a/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts b/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts index ade5fe6494c..57912317852 100644 --- a/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts +++ b/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./accessibilityHelp'; -import * as browser from 'vs/base/browser/browser'; import * as dom from 'vs/base/browser/dom'; import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { renderFormattedText } from 'vs/base/browser/formattedTextRenderer'; @@ -330,7 +329,7 @@ class ShowAccessibilityHelpAction extends EditorAction { precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.focus, - primary: (browser.isIE ? KeyMod.CtrlCmd | KeyCode.F1 : KeyMod.Alt | KeyCode.F1), + primary: KeyMod.Alt | KeyCode.F1, weight: KeybindingWeight.EditorContrib } }); diff --git a/src/vs/editor/standalone/browser/quickOpen/quickCommand.ts b/src/vs/editor/standalone/browser/quickOpen/quickCommand.ts index d00c36ea973..2e49917211b 100644 --- a/src/vs/editor/standalone/browser/quickOpen/quickCommand.ts +++ b/src/vs/editor/standalone/browser/quickOpen/quickCommand.ts @@ -4,10 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import * as strings from 'vs/base/common/strings'; -import * as browser from 'vs/base/browser/browser'; import { onUnexpectedError } from 'vs/base/common/errors'; import { matchesFuzzy } from 'vs/base/common/filters'; -import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import { KeyCode } from 'vs/base/common/keyCodes'; import { IHighlight, QuickOpenEntryGroup, QuickOpenModel } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { IAutoFocus, Mode, IEntryRunContext } from 'vs/base/parts/quickopen/common/quickOpen'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -85,7 +84,7 @@ export class QuickCommandAction extends BaseEditorQuickOpenAction { precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.focus, - primary: (browser.isIE ? KeyMod.Alt | KeyCode.F1 : KeyCode.F1), + primary: KeyCode.F1, weight: KeybindingWeight.EditorContrib }, contextMenuOpts: { diff --git a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts index b9793e2a86b..6ff1f85c8f7 100644 --- a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as browser from 'vs/base/browser/browser'; import * as aria from 'vs/base/browser/ui/aria/aria'; import { Disposable, IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; @@ -233,11 +232,7 @@ export class StandaloneCodeEditor extends CodeEditorWidget implements IStandalon ) { options = options || {}; options.ariaLabel = options.ariaLabel || StandaloneCodeEditorNLS.editorViewAccessibleLabel; - options.ariaLabel = options.ariaLabel + ';' + ( - browser.isIE - ? StandaloneCodeEditorNLS.accessibilityHelpMessageIE - : StandaloneCodeEditorNLS.accessibilityHelpMessage - ); + options.ariaLabel = options.ariaLabel + ';' + (StandaloneCodeEditorNLS.accessibilityHelpMessage); super(domElement, options, {}, instantiationService, codeEditorService, commandService, contextKeyService, themeService, notificationService, accessibilityService); if (keybindingService instanceof StandaloneKeybindingService) { From 0089596fc44a0247defaef99ae4ad55208f83d11 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Mon, 2 Mar 2020 17:33:59 +0100 Subject: [PATCH 232/235] Rename isEdgeOrIE to isEdge --- src/vs/base/browser/browser.ts | 2 -- src/vs/base/browser/ui/scrollbar/scrollableElement.ts | 4 ++-- src/vs/editor/browser/controller/mouseHandler.ts | 2 +- src/vs/editor/browser/controller/textAreaHandler.ts | 4 ++-- src/vs/editor/browser/controller/textAreaInput.ts | 6 +++--- src/vs/editor/browser/viewParts/lines/viewLine.ts | 2 +- src/vs/editor/browser/viewParts/selections/selections.ts | 2 +- src/vs/editor/contrib/clipboard/clipboard.ts | 2 +- 8 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/vs/base/browser/browser.ts b/src/vs/base/browser/browser.ts index 8a11336f218..5f811db8d6b 100644 --- a/src/vs/base/browser/browser.ts +++ b/src/vs/base/browser/browser.ts @@ -111,8 +111,6 @@ export const onDidChangeFullscreen = WindowManager.INSTANCE.onDidChangeFullscree const userAgent = navigator.userAgent; export const isEdge = (userAgent.indexOf('Edge/') >= 0); -export const isEdgeOrIE = isEdge; - export const isOpera = (userAgent.indexOf('Opera') >= 0); export const isFirefox = (userAgent.indexOf('Firefox') >= 0); export const isWebKit = (userAgent.indexOf('AppleWebKit') >= 0); diff --git a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts index 309db05fe21..dcbccfbee64 100644 --- a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +++ b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/scrollbars'; -import { isEdgeOrIE } from 'vs/base/browser/browser'; +import { isEdge } from 'vs/base/browser/browser'; import * as dom from 'vs/base/browser/dom'; import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { IMouseEvent, StandardWheelEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; @@ -326,7 +326,7 @@ export abstract class AbstractScrollableElement extends Widget { this._onMouseWheel(new StandardWheelEvent(browserEvent)); }; - this._mouseWheelToDispose.push(dom.addDisposableListener(this._listenOnDomNode, isEdgeOrIE ? 'mousewheel' : 'wheel', onMouseWheel, { passive: false })); + this._mouseWheelToDispose.push(dom.addDisposableListener(this._listenOnDomNode, isEdge ? 'mousewheel' : 'wheel', onMouseWheel, { passive: false })); } } diff --git a/src/vs/editor/browser/controller/mouseHandler.ts b/src/vs/editor/browser/controller/mouseHandler.ts index 11b009a37aa..479fa090c6e 100644 --- a/src/vs/editor/browser/controller/mouseHandler.ts +++ b/src/vs/editor/browser/controller/mouseHandler.ts @@ -119,7 +119,7 @@ export class MouseHandler extends ViewEventHandler { e.stopPropagation(); } }; - this._register(dom.addDisposableListener(this.viewHelper.viewDomNode, browser.isEdgeOrIE ? 'mousewheel' : 'wheel', onMouseWheel, { capture: true, passive: false })); + this._register(dom.addDisposableListener(this.viewHelper.viewDomNode, browser.isEdge ? 'mousewheel' : 'wheel', onMouseWheel, { capture: true, passive: false })); this._context.addEventHandler(this); } diff --git a/src/vs/editor/browser/controller/textAreaHandler.ts b/src/vs/editor/browser/controller/textAreaHandler.ts index 7a22ab779d3..6bb0877f9de 100644 --- a/src/vs/editor/browser/controller/textAreaHandler.ts +++ b/src/vs/editor/browser/controller/textAreaHandler.ts @@ -53,7 +53,7 @@ class VisibleTextAreaData { } } -const canUseZeroSizeTextarea = (browser.isEdgeOrIE || browser.isFirefox); +const canUseZeroSizeTextarea = (browser.isEdge || browser.isFirefox); export class TextAreaHandler extends ViewPart { @@ -283,7 +283,7 @@ export class TextAreaHandler extends ViewPart { })); this._register(this._textAreaInput.onCompositionUpdate((e: ICompositionData) => { - if (browser.isEdgeOrIE) { + if (browser.isEdge) { // Due to isEdgeOrIE (where the textarea was not cleared initially) // we cannot assume the text consists only of the composited text this._visibleTextArea = this._visibleTextArea!.setWidth(0); diff --git a/src/vs/editor/browser/controller/textAreaInput.ts b/src/vs/editor/browser/controller/textAreaInput.ts index 672025b5d34..ba6a141c70a 100644 --- a/src/vs/editor/browser/controller/textAreaInput.ts +++ b/src/vs/editor/browser/controller/textAreaInput.ts @@ -191,7 +191,7 @@ export class TextAreaInput extends Disposable { this._isDoingComposition = true; // In IE we cannot set .value when handling 'compositionstart' because the entire composition will get canceled. - if (!browser.isEdgeOrIE) { + if (!browser.isEdge) { this._setAndWriteTextAreaState('compositionstart', TextAreaState.EMPTY); } @@ -225,7 +225,7 @@ export class TextAreaInput extends Disposable { // Multi-part Japanese compositions reset cursor in Edge/IE, Chinese and Korean IME don't have this issue. // The reason that we can't use this path for all CJK IME is IE and Edge behave differently when handling Korean IME, // which breaks this path of code. - if (browser.isEdgeOrIE && locale === 'ja') { + if (browser.isEdge && locale === 'ja') { return true; } @@ -266,7 +266,7 @@ export class TextAreaInput extends Disposable { // Due to isEdgeOrIE (where the textarea was not cleared initially) and isChrome (the textarea is not updated correctly when composition ends) // we cannot assume the text at the end consists only of the composited text - if (browser.isEdgeOrIE || browser.isChrome) { + if (browser.isEdge || browser.isChrome) { this._textAreaState = TextAreaState.readFromTextArea(this._textArea); } diff --git a/src/vs/editor/browser/viewParts/lines/viewLine.ts b/src/vs/editor/browser/viewParts/lines/viewLine.ts index 9c93f326a6f..11a33fd32a3 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLine.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLine.ts @@ -42,7 +42,7 @@ const canUseFastRenderedViewLine = (function () { return true; })(); -const alwaysRenderInlineSelection = (browser.isEdgeOrIE); +const alwaysRenderInlineSelection = (browser.isEdge); export class DomReadingContext { diff --git a/src/vs/editor/browser/viewParts/selections/selections.ts b/src/vs/editor/browser/viewParts/selections/selections.ts index d50b0f5679b..bdedea154e3 100644 --- a/src/vs/editor/browser/viewParts/selections/selections.ts +++ b/src/vs/editor/browser/viewParts/selections/selections.ts @@ -60,7 +60,7 @@ function toStyled(item: LineVisibleRanges): LineVisibleRangesWithStyle { // TODO@Alex: Remove this once IE11 fixes Bug #524217 // The problem in IE11 is that it does some sort of auto-zooming to accomodate for displays with different pixel density. // Unfortunately, this auto-zooming is buggy around dealing with rounded borders -const isIEWithZoomingIssuesNearRoundedBorders = browser.isEdgeOrIE; +const isIEWithZoomingIssuesNearRoundedBorders = browser.isEdge; export class SelectionsOverlay extends DynamicViewOverlay { diff --git a/src/vs/editor/contrib/clipboard/clipboard.ts b/src/vs/editor/contrib/clipboard/clipboard.ts index 321543523a0..afa05e3bf9f 100644 --- a/src/vs/editor/contrib/clipboard/clipboard.ts +++ b/src/vs/editor/contrib/clipboard/clipboard.ts @@ -23,7 +23,7 @@ const CLIPBOARD_CONTEXT_MENU_GROUP = '9_cutcopypaste'; const supportsCut = (platform.isNative || document.queryCommandSupported('cut')); const supportsCopy = (platform.isNative || document.queryCommandSupported('copy')); // IE and Edge have trouble with setting html content in clipboard -const supportsCopyWithSyntaxHighlighting = (supportsCopy && !browser.isEdgeOrIE); +const supportsCopyWithSyntaxHighlighting = (supportsCopy && !browser.isEdge); // Chrome incorrectly returns true for document.queryCommandSupported('paste') // when the paste feature is available but the calling script has insufficient // privileges to actually perform the action From 78b5a91c77028639753ad67983801f2257408984 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 2 Mar 2020 18:23:01 +0100 Subject: [PATCH 233/235] update distro --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 9d1a14d30b7..3cdbce18f68 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.44.0", - "distro": "231a8c6522c74e2302d7a7360e4507b1b5991373", + "distro": "5ddb4bf6f3cbd0c5940960a7dd5dd3790d1d844e", "author": { "name": "Microsoft Corporation" }, @@ -177,4 +177,4 @@ "windows-mutex": "0.3.0", "windows-process-tree": "0.2.4" } -} +} \ No newline at end of file From 018b3fe7df3a4aa7eb81c134b616a5f5aa7aa7ec Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 2 Mar 2020 10:19:41 -0800 Subject: [PATCH 234/235] Allow menu bar mnemonics in the terminal (setting) Fixes #91908 --- .../terminal/browser/terminal.contribution.ts | 5 +++++ .../terminal/browser/terminalInstance.ts | 19 +++++++++++++++---- .../contrib/terminal/common/terminal.ts | 1 + 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts index 9ad11415ffe..a355f69febd 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts @@ -282,6 +282,11 @@ configurationRegistry.registerConfiguration({ type: 'boolean', default: true }, + 'terminal.integrated.allowMenubarMnemonics': { + markdownDescription: nls.localize('terminal.integrated.allowMenubarMnemonics', "Whether to allow menubar mnemonics (eg. alt+f) to trigger the open the menubar. Note that this will cause all alt keystrokes will skip the shell when true."), + type: 'boolean', + default: false + }, 'terminal.integrated.inheritEnv': { markdownDescription: nls.localize('terminal.integrated.inheritEnv', "Whether new shells should inherit their environment from VS Code. This is not supported on Windows."), type: 'boolean', diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index a391706e51f..b3375193099 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -595,19 +595,30 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return false; } - // Skip processing by xterm.js of keyboard events that resolve to commands described - // within commandsToSkipShell const standardKeyboardEvent = new StandardKeyboardEvent(event); const resolveResult = this._keybindingService.softDispatch(standardKeyboardEvent, standardKeyboardEvent.target); + // Respect chords if the allowChords setting is set and it's not Escape. Escape is // handled specially for Zen Mode's Escape, Escape chord, plus it's important in // terminals generally - const allowChords = resolveResult?.enterChord && this._configHelper.config.allowChords && event.key !== 'Escape'; - if (this._keybindingService.inChordMode || allowChords || resolveResult && this._skipTerminalCommands.some(k => k === resolveResult.commandId)) { + const isValidChord = resolveResult?.enterChord && this._configHelper.config.allowChords && event.key !== 'Escape'; + if (this._keybindingService.inChordMode || isValidChord) { event.preventDefault(); return false; } + // Skip processing by xterm.js of keyboard events that resolve to commands described + // within commandsToSkipShell + if (resolveResult && this._skipTerminalCommands.some(k => k === resolveResult.commandId)) { + event.preventDefault(); + return false; + } + + // Skip processing by xterm.js of keyboard events that match menu bar mnemonics + if (this._configHelper.config.allowMenubarMnemonics && event.altKey) { + return false; + } + // If tab focus mode is on, tab is not passed to the terminal if (TabFocus.getTabFocusMode() && event.keyCode === 9) { return false; diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index f834e5e5c90..4b9abc01604 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -107,6 +107,7 @@ export interface ITerminalConfiguration { scrollback: number; commandsToSkipShell: string[]; allowChords: boolean; + allowMenubarMnemonics: boolean; cwd: string; confirmOnExit: boolean; enableBell: boolean; From 21912655218364b02cf564f8a56689c272d0c046 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 28 Feb 2020 16:13:07 -0800 Subject: [PATCH 235/235] Revert "make sure unnotarized build is published even if notarization fails" This reverts commit 7298bf4bd1c1cd2d0d39d06cccf4ef18d48b8c95. --- build/azure-pipelines/darwin/product-build-darwin.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index cbfcbfc50ea..795bc78556e 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -179,13 +179,6 @@ steps: zip -d $(agent.builddirectory)/VSCode-darwin.zip "*.pkg" displayName: Clean Archive -- script: | - set -e - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ - node build/azure-pipelines/common/createAsset.js darwin-unnotarized archive "VSCode-darwin-$VSCODE_QUALITY.zip" $(agent.builddirectory)/VSCode-darwin.zip - displayName: Publish Unnotarized Build - - script: | APP_ROOT=$(agent.builddirectory)/VSCode-darwin APP_NAME="`ls $APP_ROOT | head -n 1`"