Merge from vscode 2cfc8172e533e50c90e6a3152f6bfb1f82f963f3 (#6516)

* Merge from vscode 2cfc8172e533e50c90e6a3152f6bfb1f82f963f3

* fix tests
This commit is contained in:
Anthony Dresser
2019-07-28 15:15:24 -07:00
committed by GitHub
parent aacf1e7f1c
commit 1d56a17f32
292 changed files with 19784 additions and 1873 deletions

View File

@@ -0,0 +1,43 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vs/base/common/lifecycle';
import { IAccessibilityService, AccessibilitySupport, CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility';
import { Event, Emitter } from 'vs/base/common/event';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
export abstract class AbstractAccessibilityService extends Disposable implements IAccessibilityService {
_serviceBrand: any;
private _accessibilityModeEnabledContext: IContextKey<boolean>;
protected readonly _onDidChangeAccessibilitySupport = new Emitter<void>();
readonly onDidChangeAccessibilitySupport: Event<void> = this._onDidChangeAccessibilitySupport.event;
constructor(
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
) {
super();
this._accessibilityModeEnabledContext = CONTEXT_ACCESSIBILITY_MODE_ENABLED.bindTo(this._contextKeyService);
this._register(this._configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('editor.accessibilitySupport')) {
this._updateContextKey();
}
}));
this._updateContextKey();
this.onDidChangeAccessibilitySupport(() => this._updateContextKey());
}
abstract alwaysUnderlineAccessKeys(): Promise<boolean>;
abstract getAccessibilitySupport(): AccessibilitySupport;
abstract setAccessibilitySupport(accessibilitySupport: AccessibilitySupport): void;
private _updateContextKey(): void {
const detected = this.getAccessibilitySupport() === AccessibilitySupport.Enabled;
const config = this._configurationService.getValue('editor.accessibilitySupport');
this._accessibilityModeEnabledContext.set(config === 'on' || (config === 'auto' && detected));
}
}

View File

@@ -5,6 +5,7 @@
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Event } from 'vs/base/common/event';
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
export const IAccessibilityService = createDecorator<IAccessibilityService>('accessibilityService');
@@ -28,3 +29,5 @@ export const enum AccessibilitySupport {
Enabled = 2
}
export const CONTEXT_ACCESSIBILITY_MODE_ENABLED = new RawContextKey<boolean>('accessibilityModeEnabled', false);

View File

@@ -4,17 +4,34 @@
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from 'vs/base/common/event';
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
import { IAccessibilityService, AccessibilitySupport, CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility';
import { Disposable } from 'vs/base/common/lifecycle';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
export class BrowserAccessibilityService extends Disposable implements IAccessibilityService {
_serviceBrand: any;
private _accessibilitySupport = AccessibilitySupport.Unknown;
private _accessibilityModeEnabledContext: IContextKey<boolean>;
private readonly _onDidChangeAccessibilitySupport = new Emitter<void>();
readonly onDidChangeAccessibilitySupport: Event<void> = this._onDidChangeAccessibilitySupport.event;
constructor(
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
) {
super();
this._accessibilityModeEnabledContext = CONTEXT_ACCESSIBILITY_MODE_ENABLED.bindTo(this._contextKeyService);
this._register(this._configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('editor.accessibilitySupport')) {
this._updateContextKey();
}
}));
this._updateContextKey();
}
alwaysUnderlineAccessKeys(): Promise<boolean> {
return Promise.resolve(false);
}
@@ -26,9 +43,16 @@ export class BrowserAccessibilityService extends Disposable implements IAccessib
this._accessibilitySupport = accessibilitySupport;
this._onDidChangeAccessibilitySupport.fire();
this._updateContextKey();
}
getAccessibilitySupport(): AccessibilitySupport {
return this._accessibilitySupport;
}
private _updateContextKey(): void {
const detected = this.getAccessibilitySupport() === AccessibilitySupport.Enabled;
const config = this._configurationService.getValue('editor.accessibilitySupport');
this._accessibilityModeEnabledContext.set(config === 'on' || (config === 'auto' && detected));
}
}

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IContextKeyService, ContextKeyDefinedExpr, ContextKeyExpr, ContextKeyAndExpr, ContextKeyEqualsExpr, RawContextKey, IContextKey, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey';
import { IContextKeyService, ContextKeyExpr, RawContextKey, IContextKey, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey';
import { HistoryInputBox, IHistoryInputOptions } from 'vs/base/browser/ui/inputbox/inputBox';
import { FindInput, IFindInputOptions } from 'vs/base/browser/ui/findinput/findInput';
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
@@ -66,7 +66,7 @@ export class ContextScopedFindInput extends FindInput {
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'history.showPrevious',
weight: KeybindingWeight.WorkbenchContrib,
when: ContextKeyExpr.and(new ContextKeyDefinedExpr(HistoryNavigationWidgetContext), new ContextKeyEqualsExpr(HistoryNavigationEnablementContext, true)),
when: ContextKeyExpr.and(ContextKeyExpr.has(HistoryNavigationWidgetContext), ContextKeyExpr.equals(HistoryNavigationEnablementContext, true)),
primary: KeyCode.UpArrow,
secondary: [KeyMod.Alt | KeyCode.UpArrow],
handler: (accessor, arg2) => {
@@ -81,7 +81,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'history.showNext',
weight: KeybindingWeight.WorkbenchContrib,
when: new ContextKeyAndExpr([new ContextKeyDefinedExpr(HistoryNavigationWidgetContext), new ContextKeyEqualsExpr(HistoryNavigationEnablementContext, true)]),
when: ContextKeyExpr.and(ContextKeyExpr.has(HistoryNavigationWidgetContext), ContextKeyExpr.equals(HistoryNavigationEnablementContext, true)),
primary: KeyCode.DownArrow,
secondary: [KeyMod.Alt | KeyCode.DownArrow],
handler: (accessor, arg2) => {

View File

@@ -15,11 +15,13 @@ export const ICommandService = createDecorator<ICommandService>('commandService'
export interface ICommandEvent {
commandId: string;
args: any[];
}
export interface ICommandService {
_serviceBrand: any;
onWillExecuteCommand: Event<ICommandEvent>;
onDidExecuteCommand: Event<ICommandEvent>;
executeCommand<T = any>(commandId: string, ...args: any[]): Promise<T | undefined>;
}
@@ -135,6 +137,7 @@ export const CommandsRegistry: ICommandRegistry = new class implements ICommandR
export const NullCommandService: ICommandService = {
_serviceBrand: undefined,
onWillExecuteCommand: () => ({ dispose: () => { } }),
onDidExecuteCommand: () => ({ dispose: () => { } }),
executeCommand() {
return Promise.resolve(undefined);
}

View File

@@ -94,7 +94,8 @@ suite('ConfigurationService - Node', () => {
const service = new ConfigurationService(URI.file(res.testFile));
await service.initialize();
return new Promise((c, e) => {
service.onDidChangeConfiguration(() => {
const disposable = service.onDidChangeConfiguration(() => {
disposable.dispose();
assert.equal(service.getValue('foo'), 'bar');
service.dispose();
c();

View File

@@ -14,10 +14,10 @@ export const enum ContextKeyExprType {
NotEquals = 4,
And = 5,
Regex = 6,
// {{SQL CARBON EDIT}}
GreaterThanEquals = 7,
LessThanEquals = 8
//
NotRegex = 7,
Or = 8,
GreaterThanEquals = 9, // {{SQL CARBON EDIT}} add value
LessThanEquals = 10 // {{SQL CARBON EDIT}} add value
}
export interface IContextKeyExprMapper {
@@ -31,27 +31,31 @@ export interface IContextKeyExprMapper {
export abstract class ContextKeyExpr {
public static has(key: string): ContextKeyExpr {
return new ContextKeyDefinedExpr(key);
return ContextKeyDefinedExpr.create(key);
}
public static equals(key: string, value: any): ContextKeyExpr {
return new ContextKeyEqualsExpr(key, value);
return ContextKeyEqualsExpr.create(key, value);
}
public static notEquals(key: string, value: any): ContextKeyExpr {
return new ContextKeyNotEqualsExpr(key, value);
return ContextKeyNotEqualsExpr.create(key, value);
}
public static regex(key: string, value: RegExp): ContextKeyExpr {
return new ContextKeyRegexExpr(key, value);
return ContextKeyRegexExpr.create(key, value);
}
public static not(key: string): ContextKeyExpr {
return new ContextKeyNotExpr(key);
return ContextKeyNotExpr.create(key);
}
public static and(...expr: Array<ContextKeyExpr | undefined | null>): ContextKeyExpr {
return new ContextKeyAndExpr(expr);
public static and(...expr: Array<ContextKeyExpr | undefined | null>): ContextKeyExpr | undefined {
return ContextKeyAndExpr.create(expr);
}
public static or(...expr: Array<ContextKeyExpr | undefined | null>): ContextKeyExpr | undefined {
return ContextKeyOrExpr.create(expr);
}
// {{SQL CARBON EDIT}}
@@ -69,9 +73,17 @@ export abstract class ContextKeyExpr {
return undefined;
}
return this._deserializeOrExpression(serialized, strict);
}
private static _deserializeOrExpression(serialized: string, strict: boolean): ContextKeyExpr | undefined {
let pieces = serialized.split('||');
return ContextKeyOrExpr.create(pieces.map(p => this._deserializeAndExpression(p, strict)));
}
private static _deserializeAndExpression(serialized: string, strict: boolean): ContextKeyExpr | undefined {
let pieces = serialized.split('&&');
let result = new ContextKeyAndExpr(pieces.map(p => this._deserializeOne(p, strict)));
return result.normalize();
return ContextKeyAndExpr.create(pieces.map(p => this._deserializeOne(p, strict)));
}
private static _deserializeOne(serializedOne: string, strict: boolean): ContextKeyExpr {
@@ -79,17 +91,17 @@ export abstract class ContextKeyExpr {
if (serializedOne.indexOf('!=') >= 0) {
let pieces = serializedOne.split('!=');
return new ContextKeyNotEqualsExpr(pieces[0].trim(), this._deserializeValue(pieces[1], strict));
return ContextKeyNotEqualsExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict));
}
if (serializedOne.indexOf('==') >= 0) {
let pieces = serializedOne.split('==');
return new ContextKeyEqualsExpr(pieces[0].trim(), this._deserializeValue(pieces[1], strict));
return ContextKeyEqualsExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict));
}
if (serializedOne.indexOf('=~') >= 0) {
let pieces = serializedOne.split('=~');
return new ContextKeyRegexExpr(pieces[0].trim(), this._deserializeRegexValue(pieces[1], strict));
return ContextKeyRegexExpr.create(pieces[0].trim(), this._deserializeRegexValue(pieces[1], strict));
}
// {{SQL CARBON EDIT}}
@@ -104,10 +116,10 @@ export abstract class ContextKeyExpr {
//
if (/^\!\s*/.test(serializedOne)) {
return new ContextKeyNotExpr(serializedOne.substr(1).trim());
return ContextKeyNotExpr.create(serializedOne.substr(1).trim());
}
return new ContextKeyDefinedExpr(serializedOne);
return ContextKeyDefinedExpr.create(serializedOne);
}
private static _deserializeValue(serializedValue: string, strict: boolean): any {
@@ -168,10 +180,10 @@ export abstract class ContextKeyExpr {
public abstract getType(): ContextKeyExprType;
public abstract equals(other: ContextKeyExpr): boolean;
public abstract evaluate(context: IContext): boolean;
public abstract normalize(): ContextKeyExpr | undefined;
public abstract serialize(): string;
public abstract keys(): string[];
public abstract map(mapFnc: IContextKeyExprMapper): ContextKeyExpr;
public abstract negate(): ContextKeyExpr;
}
function cmp(a: ContextKeyExpr, b: ContextKeyExpr): number {
@@ -191,19 +203,25 @@ function cmp(a: ContextKeyExpr, b: ContextKeyExpr): number {
return (<ContextKeyNotEqualsExpr>a).cmp(<ContextKeyNotEqualsExpr>b);
case ContextKeyExprType.Regex:
return (<ContextKeyRegexExpr>a).cmp(<ContextKeyRegexExpr>b);
// {{SQL CARBON EDIT}}
case ContextKeyExprType.GreaterThanEquals:
case ContextKeyExprType.GreaterThanEquals: // {{SQL CARBON EDIT}} add case
return (<ContextKeyGreaterThanEqualsExpr>a).cmp(<ContextKeyGreaterThanEqualsExpr>b);
case ContextKeyExprType.LessThanEquals:
case ContextKeyExprType.LessThanEquals: // {{SQL CARBON EDIT}} add case
return (<ContextKeyLessThanEqualsExpr>a).cmp(<ContextKeyLessThanEqualsExpr>b);
//
case ContextKeyExprType.NotRegex:
return (<ContextKeyNotRegexExpr>a).cmp(<ContextKeyNotRegexExpr>b);
case ContextKeyExprType.And:
return (<ContextKeyAndExpr>a).cmp(<ContextKeyAndExpr>b);
default:
throw new Error('Unknown ContextKeyExpr!');
}
}
export class ContextKeyDefinedExpr implements ContextKeyExpr {
constructor(protected key: string) {
public static create(key: string): ContextKeyExpr {
return new ContextKeyDefinedExpr(key);
}
protected constructor(protected key: string) {
}
public getType(): ContextKeyExprType {
@@ -231,10 +249,6 @@ export class ContextKeyDefinedExpr implements ContextKeyExpr {
return (!!context.getValue(this.key));
}
public normalize(): ContextKeyExpr {
return this;
}
public serialize(): string {
return this.key;
}
@@ -246,10 +260,25 @@ export class ContextKeyDefinedExpr implements ContextKeyExpr {
public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr {
return mapFnc.mapDefined(this.key);
}
public negate(): ContextKeyExpr {
return ContextKeyNotExpr.create(this.key);
}
}
export class ContextKeyEqualsExpr implements ContextKeyExpr {
constructor(private readonly key: string, private readonly value: any) {
public static create(key: string, value: any): ContextKeyExpr {
if (typeof value === 'boolean') {
if (value) {
return ContextKeyDefinedExpr.create(key);
}
return ContextKeyNotExpr.create(key);
}
return new ContextKeyEqualsExpr(key, value);
}
private constructor(private readonly key: string, private readonly value: any) {
}
public getType(): ContextKeyExprType {
@@ -286,21 +315,7 @@ export class ContextKeyEqualsExpr implements ContextKeyExpr {
/* tslint:enable:triple-equals */
}
public normalize(): ContextKeyExpr {
if (typeof this.value === 'boolean') {
if (this.value) {
return new ContextKeyDefinedExpr(this.key);
}
return new ContextKeyNotExpr(this.key);
}
return this;
}
public serialize(): string {
if (typeof this.value === 'boolean') {
return this.normalize().serialize();
}
return this.key + ' == \'' + this.value + '\'';
}
@@ -311,10 +326,25 @@ export class ContextKeyEqualsExpr implements ContextKeyExpr {
public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr {
return mapFnc.mapEquals(this.key, this.value);
}
public negate(): ContextKeyExpr {
return ContextKeyNotEqualsExpr.create(this.key, this.value);
}
}
export class ContextKeyNotEqualsExpr implements ContextKeyExpr {
constructor(private key: string, private value: any) {
public static create(key: string, value: any): ContextKeyExpr {
if (typeof value === 'boolean') {
if (value) {
return ContextKeyNotExpr.create(key);
}
return ContextKeyDefinedExpr.create(key);
}
return new ContextKeyNotEqualsExpr(key, value);
}
private constructor(private key: string, private value: any) {
}
public getType(): ContextKeyExprType {
@@ -351,21 +381,7 @@ export class ContextKeyNotEqualsExpr implements ContextKeyExpr {
/* tslint:enable:triple-equals */
}
public normalize(): ContextKeyExpr {
if (typeof this.value === 'boolean') {
if (this.value) {
return new ContextKeyNotExpr(this.key);
}
return new ContextKeyDefinedExpr(this.key);
}
return this;
}
public serialize(): string {
if (typeof this.value === 'boolean') {
return this.normalize().serialize();
}
return this.key + ' != \'' + this.value + '\'';
}
@@ -376,10 +392,19 @@ export class ContextKeyNotEqualsExpr implements ContextKeyExpr {
public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr {
return mapFnc.mapNotEquals(this.key, this.value);
}
public negate(): ContextKeyExpr {
return ContextKeyEqualsExpr.create(this.key, this.value);
}
}
export class ContextKeyNotExpr implements ContextKeyExpr {
constructor(private key: string) {
public static create(key: string): ContextKeyExpr {
return new ContextKeyNotExpr(key);
}
private constructor(private key: string) {
}
public getType(): ContextKeyExprType {
@@ -407,10 +432,6 @@ export class ContextKeyNotExpr implements ContextKeyExpr {
return (!context.getValue(this.key));
}
public normalize(): ContextKeyExpr {
return this;
}
public serialize(): string {
return '!' + this.key;
}
@@ -422,11 +443,19 @@ export class ContextKeyNotExpr implements ContextKeyExpr {
public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr {
return mapFnc.mapNot(this.key);
}
public negate(): ContextKeyExpr {
return ContextKeyDefinedExpr.create(this.key);
}
}
export class ContextKeyRegexExpr implements ContextKeyExpr {
constructor(private key: string, private regexp: RegExp | null) {
public static create(key: string, regexp: RegExp | null): ContextKeyExpr {
return new ContextKeyRegexExpr(key, regexp);
}
private constructor(private key: string, private regexp: RegExp | null) {
//
}
@@ -466,10 +495,6 @@ export class ContextKeyRegexExpr implements ContextKeyExpr {
return this.regexp ? this.regexp.test(value) : false;
}
public normalize(): ContextKeyExpr {
return this;
}
public serialize(): string {
const value = this.regexp
? `/${this.regexp.source}/${this.regexp.ignoreCase ? 'i' : ''}`
@@ -481,22 +506,99 @@ export class ContextKeyRegexExpr implements ContextKeyExpr {
return [this.key];
}
public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr {
public map(mapFnc: IContextKeyExprMapper): ContextKeyRegexExpr {
return mapFnc.mapRegex(this.key, this.regexp);
}
public negate(): ContextKeyExpr {
return ContextKeyNotRegexExpr.create(this);
}
}
export class ContextKeyNotRegexExpr implements ContextKeyExpr {
public static create(actual: ContextKeyRegexExpr): ContextKeyExpr {
return new ContextKeyNotRegexExpr(actual);
}
private constructor(private readonly _actual: ContextKeyRegexExpr) {
//
}
public getType(): ContextKeyExprType {
return ContextKeyExprType.NotRegex;
}
public cmp(other: ContextKeyNotRegexExpr): number {
return this._actual.cmp(other._actual);
}
public equals(other: ContextKeyExpr): boolean {
if (other instanceof ContextKeyNotRegexExpr) {
return this._actual.equals(other._actual);
}
return false;
}
public evaluate(context: IContext): boolean {
return !this._actual.evaluate(context);
}
public serialize(): string {
throw new Error('Method not implemented.');
}
public keys(): string[] {
return this._actual.keys();
}
public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr {
return new ContextKeyNotRegexExpr(this._actual.map(mapFnc));
}
public negate(): ContextKeyExpr {
return this._actual;
}
}
export class ContextKeyAndExpr implements ContextKeyExpr {
public readonly expr: ContextKeyExpr[];
constructor(expr: Array<ContextKeyExpr | null | undefined>) {
this.expr = ContextKeyAndExpr._normalizeArr(expr);
public static create(_expr: Array<ContextKeyExpr | null | undefined>): ContextKeyExpr | undefined {
const expr = ContextKeyAndExpr._normalizeArr(_expr);
if (expr.length === 0) {
return undefined;
}
if (expr.length === 1) {
return expr[0];
}
return new ContextKeyAndExpr(expr);
}
private constructor(public readonly expr: ContextKeyExpr[]) {
}
public getType(): ContextKeyExprType {
return ContextKeyExprType.And;
}
public cmp(other: ContextKeyAndExpr): number {
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: ContextKeyExpr): boolean {
if (other instanceof ContextKeyAndExpr) {
if (this.expr.length !== other.expr.length) {
@@ -531,16 +633,16 @@ export class ContextKeyAndExpr implements ContextKeyExpr {
continue;
}
e = e.normalize();
if (!e) {
continue;
}
if (e instanceof ContextKeyAndExpr) {
expr = expr.concat(e.expr);
continue;
}
if (e instanceof ContextKeyOrExpr) {
// 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!`);
}
expr.push(e);
}
@@ -550,29 +652,7 @@ export class ContextKeyAndExpr implements ContextKeyExpr {
return expr;
}
public normalize(): ContextKeyExpr | undefined {
if (this.expr.length === 0) {
return undefined;
}
if (this.expr.length === 1) {
return this.expr[0];
}
return this;
}
public serialize(): string {
if (this.expr.length === 0) {
return '';
}
if (this.expr.length === 1) {
const normalized = this.normalize();
if (!normalized) {
return '';
}
return normalized.serialize();
}
return this.expr.map(e => e.serialize()).join(' && ');
}
@@ -587,6 +667,132 @@ export class ContextKeyAndExpr implements ContextKeyExpr {
public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr {
return new ContextKeyAndExpr(this.expr.map(expr => expr.map(mapFnc)));
}
public negate(): ContextKeyExpr {
let result: ContextKeyExpr[] = [];
for (let expr of this.expr) {
result.push(expr.negate());
}
return ContextKeyOrExpr.create(result)!;
}
}
export class ContextKeyOrExpr implements ContextKeyExpr {
public static create(_expr: Array<ContextKeyExpr | null | undefined>): ContextKeyExpr | undefined {
const expr = ContextKeyOrExpr._normalizeArr(_expr);
if (expr.length === 0) {
return undefined;
}
if (expr.length === 1) {
return expr[0];
}
return new ContextKeyOrExpr(expr);
}
private constructor(public readonly expr: ContextKeyExpr[]) {
}
public getType(): ContextKeyExprType {
return ContextKeyExprType.Or;
}
public equals(other: ContextKeyExpr): boolean {
if (other instanceof ContextKeyOrExpr) {
if (this.expr.length !== other.expr.length) {
return false;
}
for (let i = 0, len = this.expr.length; i < len; i++) {
if (!this.expr[i].equals(other.expr[i])) {
return false;
}
}
return true;
}
return false;
}
public evaluate(context: IContext): boolean {
for (let i = 0, len = this.expr.length; i < len; i++) {
if (this.expr[i].evaluate(context)) {
return true;
}
}
return false;
}
private static _normalizeArr(arr: Array<ContextKeyExpr | null | undefined>): ContextKeyExpr[] {
let expr: ContextKeyExpr[] = [];
if (arr) {
for (let i = 0, len = arr.length; i < len; i++) {
let e: ContextKeyExpr | null | undefined = arr[i];
if (!e) {
continue;
}
if (e instanceof ContextKeyOrExpr) {
expr = expr.concat(e.expr);
continue;
}
expr.push(e);
}
expr.sort(cmp);
}
return expr;
}
public serialize(): string {
return this.expr.map(e => e.serialize()).join(' || ');
}
public keys(): string[] {
const result: string[] = [];
for (let expr of this.expr) {
result.push(...expr.keys());
}
return result;
}
public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr {
return new ContextKeyOrExpr(this.expr.map(expr => expr.map(mapFnc)));
}
public negate(): ContextKeyExpr {
let result: ContextKeyExpr[] = [];
for (let expr of this.expr) {
result.push(expr.negate());
}
const terminals = (node: ContextKeyExpr) => {
if (node instanceof ContextKeyOrExpr) {
return node.expr;
}
return [node];
};
// We don't support parens, so here we distribute the AND over the OR terminals
// We always take the first 2 AND pairs and distribute them
while (result.length > 1) {
const LEFT = result.shift()!;
const RIGHT = result.shift()!;
const all: ContextKeyExpr[] = [];
for (const left of terminals(LEFT)) {
for (const right of terminals(RIGHT)) {
all.push(ContextKeyExpr.and(left, right)!);
}
}
result.unshift(ContextKeyExpr.or(...all)!);
}
return result[0];
}
}
// {{SQL CARBON EDIT}}
@@ -621,6 +827,10 @@ export class ContextKeyGreaterThanEqualsExpr implements ContextKeyExpr {
return false;
}
public negate(): ContextKeyExpr {
throw new Error('Method not implemented.'); // @TODO anthonydresser need to figure out what to do in this case
}
public evaluate(context: IContext): boolean {
const keyVal = context.getValue<string>(this.key);
if (!keyVal) {
@@ -694,6 +904,10 @@ export class ContextKeyLessThanEqualsExpr implements ContextKeyExpr {
return this;
}
public negate(): ContextKeyExpr {
throw new Error('Method not implemented.'); // @TODO anthonydresser need to figure out what to do in this case
}
public serialize(): string {
return this.key + ' <= \'' + this.value + '\'';
}

View File

@@ -27,31 +27,28 @@ suite('ContextKeyExpr', () => {
ContextKeyExpr.notEquals('c2', 'cc2'),
ContextKeyExpr.not('d1'),
ContextKeyExpr.not('d2'),
// {{SQL CARBON EDIT}}
ContextKeyExpr.greaterThanEquals('e1', 'ee1'),
ContextKeyExpr.greaterThanEquals('e2', 'ee2'),
ContextKeyExpr.lessThanEquals('f1', 'ff1'),
ContextKeyExpr.lessThanEquals('f2', 'ff2')
//
);
ContextKeyExpr.greaterThanEquals('e1', 'ee1'), // {{SQL CARBON EDIT}} add test case
ContextKeyExpr.greaterThanEquals('e2', 'ee2'), // {{SQL CARBON EDIT}} add test case
ContextKeyExpr.lessThanEquals('f1', 'ff1'), // {{SQL CARBON EDIT}} add test case
ContextKeyExpr.lessThanEquals('f2', 'ff2'), // {{SQL CARBON EDIT}} add test case
)!;
let b = ContextKeyExpr.and(
// {{SQL CARBON EDIT}}
ContextKeyExpr.greaterThanEquals('e2', 'ee2'),
ContextKeyExpr.lessThanEquals('f1', 'ff1'), // {{SQL CARBON EDIT}}
ContextKeyExpr.lessThanEquals('f2', 'ff2'), // {{SQL CARBON EDIT}}
ContextKeyExpr.greaterThanEquals('e2', 'ee2'), // {{SQL CARBON EDIT}}
ContextKeyExpr.greaterThanEquals('e1', 'ee1'), // {{SQL CARBON EDIT}}
ContextKeyExpr.equals('b2', 'bb2'),
ContextKeyExpr.notEquals('c1', 'cc1'),
ContextKeyExpr.not('d1'),
ContextKeyExpr.lessThanEquals('f1', 'ff1'),
ContextKeyExpr.regex('d4', /\*\*3*/),
ContextKeyExpr.greaterThanEquals('e1', 'ee1'),
ContextKeyExpr.notEquals('c2', 'cc2'),
ContextKeyExpr.has('a2'),
ContextKeyExpr.equals('b1', 'bb1'),
ContextKeyExpr.regex('d3', /d.*/),
ContextKeyExpr.has('a1'),
ContextKeyExpr.lessThanEquals('f2', 'ff2'),
ContextKeyExpr.and(ContextKeyExpr.equals('and.a', true)),
ContextKeyExpr.not('d2')
);
)!;
assert(a.equals(b), 'expressions should be equal');
});
@@ -61,10 +58,10 @@ suite('ContextKeyExpr', () => {
let key1IsFalse = ContextKeyExpr.equals('key1', false);
let key1IsNotTrue = ContextKeyExpr.notEquals('key1', true);
assert.ok(key1IsTrue.normalize()!.equals(ContextKeyExpr.has('key1')));
assert.ok(key1IsNotFalse.normalize()!.equals(ContextKeyExpr.has('key1')));
assert.ok(key1IsFalse.normalize()!.equals(ContextKeyExpr.not('key1')));
assert.ok(key1IsNotTrue.normalize()!.equals(ContextKeyExpr.not('key1')));
assert.ok(key1IsTrue.equals(ContextKeyExpr.has('key1')));
assert.ok(key1IsNotFalse.equals(ContextKeyExpr.has('key1')));
assert.ok(key1IsFalse.equals(ContextKeyExpr.not('key1')));
assert.ok(key1IsNotTrue.equals(ContextKeyExpr.not('key1')));
});
test('evaluate', () => {
@@ -108,5 +105,24 @@ suite('ContextKeyExpr', () => {
testExpression('a && !b && c == 5', true && !false && '5' == '5');
testExpression('d =~ /e.*/', false);
/* tslint:enable:triple-equals */
// precedence test: false && true || true === true because && is evaluated first
testExpression('b && a || a', true);
testExpression('a || b', true);
testExpression('b || b', false);
testExpression('b && a || a && b', false);
});
test('negate', () => {
function testNegate(expr: string, expected: string): void {
const actual = ContextKeyExpr.deserialize(expr)!.negate().serialize();
assert.strictEqual(actual, expected);
}
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');
});
});

View File

@@ -206,7 +206,7 @@ class WindowDriver implements IWindowDriver {
throw new Error(`Xterm not found: ${selector}`);
}
xterm._core.handler(text);
xterm._core._coreService.triggerDataEvent(text);
}
async openDevTools(): Promise<void> {

View File

@@ -47,6 +47,7 @@ export interface ParsedArgs {
'disable-extension'?: string | string[];
'list-extensions'?: boolean;
'show-versions'?: boolean;
'category'?: string;
'install-extension'?: string | string[];
'uninstall-extension'?: string | string[];
'locate-extension'?: string | string[];

View File

@@ -48,6 +48,7 @@ export const options: Option[] = [
{ id: 'extensions-dir', type: 'string', deprecates: 'extensionHomePath', cat: 'e', args: 'dir', description: localize('extensionHomePath', "Set the root path for extensions.") },
{ id: 'list-extensions', type: 'boolean', cat: 'e', description: localize('listExtensions', "List the installed extensions.") },
{ id: 'show-versions', type: 'boolean', cat: 'e', description: localize('showVersions', "Show versions of installed extensions, when using --list-extension.") },
{ id: 'category', type: 'string', cat: 'e', description: localize('category', "Filters installed extensions by provided category, when using --list-extension.") },
{ id: 'install-extension', type: 'string', cat: 'e', args: 'extension-id | path-to-vsix', description: localize('installExtension', "Installs or updates the extension. Use `--force` argument to avoid prompts.") },
{ id: 'uninstall-extension', type: 'string', cat: 'e', args: 'extension-id', description: localize('uninstallExtension', "Uninstalls an extension.") },
{ id: 'enable-proposed-api', type: 'string', cat: 'e', args: 'extension-id', description: localize('experimentalApis', "Enables proposed API features for extensions. Can receive one or more extension IDs to enable individually.") },

View File

@@ -27,6 +27,7 @@ import { joinPath } from 'vs/base/common/resources';
import { VSBuffer } from 'vs/base/common/buffer';
import { IProductService } from 'vs/platform/product/common/product';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { optional } from 'vs/platform/instantiation/common/instantiation';
interface IRawGalleryExtensionFile {
assetType: string;
@@ -389,7 +390,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
@IConfigurationService private configurationService: IConfigurationService,
@IFileService private readonly fileService: IFileService,
@IProductService private readonly productService: IProductService,
@IStorageService private readonly storageService: IStorageService,
@optional(IStorageService) private readonly storageService: IStorageService,
) {
const config = productService.extensionsGallery;
this.extensionsGalleryUrl = config && config.serviceUrl;

View File

@@ -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 { ContextKeyAndExpr, ContextKeyExpr, IContext } from 'vs/platform/contextkey/common/contextkey';
import { ContextKeyExpr, IContext, ContextKeyOrExpr } from 'vs/platform/contextkey/common/contextkey';
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
import { keys } from 'vs/base/common/map';
@@ -171,7 +171,6 @@ export class KeybindingResolver {
/**
* Returns true if it is provable `a` implies `b`.
* **Precondition**: Assumes `a` and `b` are normalized!
*/
public static whenIsEntirelyIncluded(a: ContextKeyExpr | null | undefined, b: ContextKeyExpr | null | undefined): boolean {
if (!b) {
@@ -181,26 +180,35 @@ export class KeybindingResolver {
return false;
}
const aExpressions: ContextKeyExpr[] = ((a instanceof ContextKeyAndExpr) ? a.expr : [a]);
const bExpressions: ContextKeyExpr[] = ((b instanceof ContextKeyAndExpr) ? b.expr : [b]);
return this._implies(a, b);
}
let aIndex = 0;
for (const bExpr of bExpressions) {
let bExprMatched = false;
while (!bExprMatched && aIndex < aExpressions.length) {
let aExpr = aExpressions[aIndex];
if (aExpr.equals(bExpr)) {
bExprMatched = true;
}
aIndex++;
/**
* Returns true if it is provable `p` implies `q`.
*/
private static _implies(p: ContextKeyExpr, q: ContextKeyExpr): boolean {
const notP = p.negate();
const terminals = (node: ContextKeyExpr) => {
if (node instanceof ContextKeyOrExpr) {
return node.expr;
}
return [node];
};
if (!bExprMatched) {
return false;
let expr = terminals(notP).concat(terminals(q));
for (let i = 0; i < expr.length; i++) {
const a = expr[i];
const notA = a.negate();
for (let j = i + 1; j < expr.length; j++) {
const b = expr[j];
if (notA.equals(b)) {
return true;
}
}
}
return true;
return false;
}
public getDefaultBoundCommands(): Map<string, boolean> {

View File

@@ -121,6 +121,7 @@ suite('AbstractKeybindingService', () => {
let commandService: ICommandService = {
_serviceBrand: undefined,
onWillExecuteCommand: () => ({ dispose: () => { } }),
onDidExecuteCommand: () => ({ dispose: () => { } }),
executeCommand: (commandId: string, ...args: any[]): Promise<any> => {
executeCommandCalls.push({
commandId: commandId,

View File

@@ -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 { ContextKeyAndExpr, ContextKeyExpr, IContext } from 'vs/platform/contextkey/common/contextkey';
import { ContextKeyExpr, IContext } 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,13 +20,13 @@ function createContext(ctx: any) {
suite('KeybindingResolver', () => {
function kbItem(keybinding: number, command: string, commandArgs: any, when: ContextKeyExpr, isDefault: boolean): ResolvedKeybindingItem {
function kbItem(keybinding: number, command: string, commandArgs: any, when: ContextKeyExpr | undefined, isDefault: boolean): ResolvedKeybindingItem {
const resolvedKeybinding = (keybinding !== 0 ? new USLayoutResolvedKeybinding(createKeybinding(keybinding, OS)!, OS) : undefined);
return new ResolvedKeybindingItem(
resolvedKeybinding,
command,
commandArgs,
when ? when.normalize() : undefined,
when,
isDefault
);
}
@@ -191,64 +191,41 @@ suite('KeybindingResolver', () => {
});
test('contextIsEntirelyIncluded', () => {
let assertIsIncluded = (a: ContextKeyExpr[], b: ContextKeyExpr[]) => {
let tmpA = new ContextKeyAndExpr(a).normalize();
let tmpB = new ContextKeyAndExpr(b).normalize();
assert.equal(KeybindingResolver.whenIsEntirelyIncluded(tmpA, tmpB), true);
const assertIsIncluded = (a: string | null, b: string | null) => {
assert.equal(KeybindingResolver.whenIsEntirelyIncluded(ContextKeyExpr.deserialize(a), ContextKeyExpr.deserialize(b)), true);
};
let assertIsNotIncluded = (a: ContextKeyExpr[], b: ContextKeyExpr[]) => {
let tmpA = new ContextKeyAndExpr(a).normalize();
let tmpB = new ContextKeyAndExpr(b).normalize();
assert.equal(KeybindingResolver.whenIsEntirelyIncluded(tmpA, tmpB), false);
const assertIsNotIncluded = (a: string | null, b: string | null) => {
assert.equal(KeybindingResolver.whenIsEntirelyIncluded(ContextKeyExpr.deserialize(a), ContextKeyExpr.deserialize(b)), false);
};
let key1IsTrue = ContextKeyExpr.equals('key1', true);
let key1IsNotFalse = ContextKeyExpr.notEquals('key1', false);
let key1IsFalse = ContextKeyExpr.equals('key1', false);
let key1IsNotTrue = ContextKeyExpr.notEquals('key1', true);
let key2IsTrue = ContextKeyExpr.equals('key2', true);
let key2IsNotFalse = ContextKeyExpr.notEquals('key2', false);
let key3IsTrue = ContextKeyExpr.equals('key3', true);
let key4IsTrue = ContextKeyExpr.equals('key4', true);
assertIsIncluded([key1IsTrue], null!);
assertIsIncluded([key1IsTrue], []);
assertIsIncluded([key1IsTrue], [key1IsTrue]);
assertIsIncluded([key1IsTrue], [key1IsNotFalse]);
assertIsIncluded('key1', null);
assertIsIncluded('key1', '');
assertIsIncluded('key1', 'key1');
assertIsIncluded('!key1', '');
assertIsIncluded('!key1', '!key1');
assertIsIncluded('key2', '');
assertIsIncluded('key2', 'key2');
assertIsIncluded('key1 && key1 && key2 && key2', 'key2');
assertIsIncluded('key1 && key2', 'key2');
assertIsIncluded('key1 && key2', 'key1');
assertIsIncluded('key1 && key2', '');
assertIsIncluded('key1', 'key1 || key2');
assertIsIncluded('key1 || !key1', 'key2 || !key2');
assertIsIncluded('key1', 'key1 || key2 && key3');
assertIsIncluded([key1IsFalse], []);
assertIsIncluded([key1IsFalse], [key1IsFalse]);
assertIsIncluded([key1IsFalse], [key1IsNotTrue]);
assertIsIncluded([key2IsNotFalse], []);
assertIsIncluded([key2IsNotFalse], [key2IsNotFalse]);
assertIsIncluded([key2IsNotFalse], [key2IsTrue]);
assertIsIncluded([key1IsTrue, key2IsNotFalse], [key2IsTrue]);
assertIsIncluded([key1IsTrue, key2IsNotFalse], [key2IsNotFalse]);
assertIsIncluded([key1IsTrue, key2IsNotFalse], [key1IsTrue]);
assertIsIncluded([key1IsTrue, key2IsNotFalse], [key1IsNotFalse]);
assertIsIncluded([key1IsTrue, key2IsNotFalse], []);
assertIsNotIncluded([key1IsTrue], [key1IsFalse]);
assertIsNotIncluded([key1IsTrue], [key1IsNotTrue]);
assertIsNotIncluded([key1IsNotFalse], [key1IsFalse]);
assertIsNotIncluded([key1IsNotFalse], [key1IsNotTrue]);
assertIsNotIncluded([key1IsFalse], [key1IsTrue]);
assertIsNotIncluded([key1IsFalse], [key1IsNotFalse]);
assertIsNotIncluded([key1IsNotTrue], [key1IsTrue]);
assertIsNotIncluded([key1IsNotTrue], [key1IsNotFalse]);
assertIsNotIncluded([key1IsTrue, key2IsNotFalse], [key3IsTrue]);
assertIsNotIncluded([key1IsTrue, key2IsNotFalse], [key4IsTrue]);
assertIsNotIncluded([key1IsTrue], [key2IsTrue]);
assertIsNotIncluded([], [key2IsTrue]);
assertIsNotIncluded(null!, [key2IsTrue]);
assertIsNotIncluded('key1', '!key1');
assertIsNotIncluded('!key1', 'key1');
assertIsNotIncluded('key1 && key2', 'key3');
assertIsNotIncluded('key1 && key2', 'key4');
assertIsNotIncluded('key1', 'key2');
assertIsNotIncluded('key1 || key2', 'key2');
assertIsNotIncluded('', 'key2');
assertIsNotIncluded(null, 'key2');
});
test('resolve command', function () {
function _kbItem(keybinding: number, command: string, when: ContextKeyExpr): ResolvedKeybindingItem {
function _kbItem(keybinding: number, command: string, when: ContextKeyExpr | undefined): ResolvedKeybindingItem {
return kbItem(keybinding, command, null, when, true);
}

View File

@@ -247,7 +247,7 @@ export class WorkbenchList<T> extends List<T> {
constructor(
container: HTMLElement,
delegate: IListVirtualDelegate<T>,
renderers: IListRenderer<any /* TODO@joao */, any>[],
renderers: IListRenderer<T, any>[],
options: IListOptions<T>,
@IContextKeyService contextKeyService: IContextKeyService,
@IListService listService: IListService,
@@ -787,7 +787,7 @@ export class WorkbenchObjectTree<T extends NonNullable<any>, TFilterData = void>
constructor(
container: HTMLElement,
delegate: IListVirtualDelegate<T>,
renderers: ITreeRenderer<any /* TODO@joao */, TFilterData, any>[],
renderers: ITreeRenderer<T, TFilterData, any>[],
options: IObjectTreeOptions<T, TFilterData>,
@IContextKeyService contextKeyService: IContextKeyService,
@IListService listService: IListService,
@@ -813,7 +813,7 @@ export class WorkbenchDataTree<TInput, T, TFilterData = void> extends DataTree<T
constructor(
container: HTMLElement,
delegate: IListVirtualDelegate<T>,
renderers: ITreeRenderer<any /* TODO@joao */, TFilterData, any>[],
renderers: ITreeRenderer<T, TFilterData, any>[],
dataSource: IDataSource<TInput, T>,
options: IDataTreeOptions<T, TFilterData>,
@IContextKeyService contextKeyService: IContextKeyService,
@@ -840,7 +840,7 @@ export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends Async
constructor(
container: HTMLElement,
delegate: IListVirtualDelegate<T>,
renderers: ITreeRenderer<any /* TODO@joao */, TFilterData, any>[],
renderers: ITreeRenderer<T, TFilterData, any>[],
dataSource: IAsyncDataSource<TInput, T>,
options: IAsyncDataTreeOptions<T, TFilterData>,
@IContextKeyService contextKeyService: IContextKeyService,

View File

@@ -39,6 +39,7 @@ export interface IRelatedInformation {
export const enum MarkerTag {
Unnecessary = 1,
Deprecated = 2
}
export enum MarkerSeverity {

View File

@@ -73,10 +73,9 @@ export interface IProductConfiguration {
readonly recommendationsUrl: string;
};
extensionTips: { [id: string]: string; };
// {{SQL CARBON EDIT}}
recommendedExtensions: string[];
extensionImportantTips: { [id: string]: { name: string; pattern: string; }; };
readonly exeBasedExtensionTips: { [id: string]: { friendlyName: string, windowsPath?: string, recommendations: readonly string[] }; };
recommendedExtensions: string[]; // {{SQL CARBON EDIT}}
extensionImportantTips: { [id: string]: { name: string; pattern: string; isExtensionPack?: boolean }; };
readonly exeBasedExtensionTips: { [id: string]: IExeBasedExtensionTip; };
readonly extensionKeywords: { [extension: string]: readonly string[]; };
readonly extensionAllowedBadgeProviders: readonly string[];
readonly extensionAllowedProposedApi: readonly string[];
@@ -125,6 +124,14 @@ export interface IProductConfiguration {
readonly uiExtensions?: readonly string[];
}
export interface IExeBasedExtensionTip {
friendlyName: string;
windowsPath?: string;
recommendations: readonly string[];
important?: boolean;
exeFriendlyName?: string;
}
export interface ISurveyData {
surveyId: string;
surveyUrl: string;

View File

@@ -0,0 +1,146 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ISocketFactory, IConnectCallback } from 'vs/platform/remote/common/remoteAgentConnection';
import { ISocket } from 'vs/base/parts/ipc/common/ipc.net';
import { VSBuffer } from 'vs/base/common/buffer';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event';
export interface IWebSocketFactory {
create(url: string): IWebSocket;
}
export interface IWebSocket {
readonly onData: Event<ArrayBuffer>;
readonly onOpen: Event<void>;
readonly onClose: Event<void>;
readonly onError: Event<any>;
send(data: ArrayBuffer | ArrayBufferView): void;
close(): void;
}
class BrowserWebSocket implements IWebSocket {
private readonly _onData = new Emitter<ArrayBuffer>();
public readonly onData = this._onData.event;
public readonly onOpen: Event<void>;
public readonly onClose: Event<void>;
public readonly onError: Event<any>;
private readonly _socket: WebSocket;
private readonly _fileReader: FileReader;
private readonly _queue: Blob[];
private _isReading: boolean;
private readonly _socketMessageListener: (ev: MessageEvent) => void;
constructor(socket: WebSocket) {
this._socket = socket;
this._fileReader = new FileReader();
this._queue = [];
this._isReading = false;
this._fileReader.onload = (event) => {
this._isReading = false;
const buff = <ArrayBuffer>(<any>event.target).result;
this._onData.fire(buff);
if (this._queue.length > 0) {
enqueue(this._queue.shift()!);
}
};
const enqueue = (blob: Blob) => {
if (this._isReading) {
this._queue.push(blob);
return;
}
this._isReading = true;
this._fileReader.readAsArrayBuffer(blob);
};
this._socketMessageListener = (ev: MessageEvent) => {
enqueue(<Blob>ev.data);
};
this._socket.addEventListener('message', this._socketMessageListener);
this.onOpen = Event.fromDOMEventEmitter(this._socket, 'open');
this.onClose = Event.fromDOMEventEmitter(this._socket, 'close');
this.onError = Event.fromDOMEventEmitter(this._socket, 'error');
}
send(data: ArrayBuffer | ArrayBufferView): void {
this._socket.send(data);
}
close(): void {
this._socket.close();
this._socket.removeEventListener('message', this._socketMessageListener);
}
}
export const defaultWebSocketFactory = new class implements IWebSocketFactory {
create(url: string): IWebSocket {
return new BrowserWebSocket(new WebSocket(url));
}
};
class BrowserSocket implements ISocket {
public readonly socket: IWebSocket;
constructor(socket: IWebSocket) {
this.socket = socket;
}
public dispose(): void {
this.socket.close();
}
public onData(listener: (e: VSBuffer) => void): IDisposable {
return this.socket.onData((data) => listener(VSBuffer.wrap(new Uint8Array(data))));
}
public onClose(listener: () => void): IDisposable {
return this.socket.onClose(listener);
}
public onEnd(listener: () => void): IDisposable {
return Disposable.None;
}
public write(buffer: VSBuffer): void {
this.socket.send(buffer.buffer);
}
public end(): void {
this.socket.close();
}
}
export class BrowserSocketFactory implements ISocketFactory {
private readonly _webSocketFactory: IWebSocketFactory;
constructor(webSocketFactory: IWebSocketFactory | null | undefined) {
this._webSocketFactory = webSocketFactory || defaultWebSocketFactory;
}
connect(host: string, port: number, query: string, callback: IConnectCallback): void {
const socket = this._webSocketFactory.create(`ws://${host}:${port}/?${query}&skipWebSocketFrames=false`);
const errorListener = socket.onError((err) => callback(err, undefined));
socket.onOpen(() => {
errorListener.dispose();
callback(undefined, new BrowserSocket(socket));
});
}
}

View File

@@ -1,89 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IWebSocketFactory, IConnectCallback } from 'vs/platform/remote/common/remoteAgentConnection';
import { ISocket } from 'vs/base/parts/ipc/common/ipc.net';
import { VSBuffer } from 'vs/base/common/buffer';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { onUnexpectedError } from 'vs/base/common/errors';
class BrowserSocket implements ISocket {
public readonly socket: WebSocket;
constructor(socket: WebSocket) {
this.socket = socket;
}
public dispose(): void {
this.socket.close();
}
public onData(_listener: (e: VSBuffer) => void): IDisposable {
const fileReader = new FileReader();
const queue: Blob[] = [];
let isReading = false;
fileReader.onload = function (event) {
isReading = false;
const buff = <ArrayBuffer>(<any>event.target).result;
try {
_listener(VSBuffer.wrap(new Uint8Array(buff)));
} catch (err) {
onUnexpectedError(err);
}
if (queue.length > 0) {
enqueue(queue.shift()!);
}
};
const enqueue = (blob: Blob) => {
if (isReading) {
queue.push(blob);
return;
}
isReading = true;
fileReader.readAsArrayBuffer(blob);
};
const listener = (e: MessageEvent) => {
enqueue(<Blob>e.data);
};
this.socket.addEventListener('message', listener);
return {
dispose: () => this.socket.removeEventListener('message', listener)
};
}
public onClose(listener: () => void): IDisposable {
this.socket.addEventListener('close', listener);
return {
dispose: () => this.socket.removeEventListener('close', listener)
};
}
public onEnd(listener: () => void): IDisposable {
return Disposable.None;
}
public write(buffer: VSBuffer): void {
this.socket.send(buffer.buffer);
}
public end(): void {
this.socket.close();
}
}
export const browserWebSocketFactory = new class implements IWebSocketFactory {
connect(host: string, port: number, query: string, callback: IConnectCallback): void {
const errorListener = (err: any) => callback(err, undefined);
const socket = new WebSocket(`ws://${host}:${port}/?${query}&skipWebSocketFrames=false`);
socket.onopen = function (event) {
socket.removeEventListener('error', errorListener);
callback(undefined, new BrowserSocket(socket));
};
socket.addEventListener('error', errorListener);
}
};

View File

@@ -57,7 +57,7 @@ interface ISimpleConnectionOptions {
port: number;
reconnectionToken: string;
reconnectionProtocol: PersistentProtocol | null;
webSocketFactory: IWebSocketFactory;
socketFactory: ISocketFactory;
signService: ISignService;
}
@@ -65,13 +65,13 @@ export interface IConnectCallback {
(err: any | undefined, socket: ISocket | undefined): void;
}
export interface IWebSocketFactory {
export interface ISocketFactory {
connect(host: string, port: number, query: string, callback: IConnectCallback): void;
}
async function connectToRemoteExtensionHostAgent(options: ISimpleConnectionOptions, connectionType: ConnectionType, args: any | undefined): Promise<PersistentProtocol> {
const protocol = await new Promise<PersistentProtocol>((c, e) => {
options.webSocketFactory.connect(
options.socketFactory.connect(
options.host,
options.port,
`reconnectionToken=${options.reconnectionToken}&reconnection=${options.reconnectionProtocol ? 'true' : 'false'}`,
@@ -202,7 +202,7 @@ async function doConnectRemoteAgentTunnel(options: ISimpleConnectionOptions, sta
export interface IConnectionOptions {
isBuilt: boolean;
commit: string | undefined;
webSocketFactory: IWebSocketFactory;
socketFactory: ISocketFactory;
addressProvider: IAddressProvider;
signService: ISignService;
}
@@ -216,7 +216,7 @@ async function resolveConnectionOptions(options: IConnectionOptions, reconnectio
port: port,
reconnectionToken: reconnectionToken,
reconnectionProtocol: reconnectionProtocol,
webSocketFactory: options.webSocketFactory,
socketFactory: options.socketFactory,
signService: options.signService
};
}

View File

@@ -10,4 +10,16 @@ export const REMOTE_HOST_SCHEME = Schemas.vscodeRemote;
export function getRemoteAuthority(uri: URI): string | undefined {
return uri.scheme === REMOTE_HOST_SCHEME ? uri.authority : undefined;
}
export function getRemoteName(authority: string | undefined): string | undefined {
if (!authority) {
return undefined;
}
const pos = authority.indexOf('+');
if (pos < 0) {
// funky? bad authority?
return authority;
}
return authority.substr(0, pos);
}

View File

@@ -5,9 +5,9 @@
import * as net from 'net';
import { NodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
import { IWebSocketFactory, IConnectCallback } from 'vs/platform/remote/common/remoteAgentConnection';
import { ISocketFactory, IConnectCallback } from 'vs/platform/remote/common/remoteAgentConnection';
export const nodeWebSocketFactory = new class implements IWebSocketFactory {
export const nodeSocketFactory = new class implements ISocketFactory {
connect(host: string, port: number, query: string, callback: IConnectCallback): void {
const errorListener = (err: any) => callback(err, undefined);

View File

@@ -90,7 +90,7 @@ Registry.as<IConfigurationRegistry>(Extensions.Configuration)
'http.proxy': {
type: 'string',
pattern: '^https?://([^:]*(:[^@]*)?@)?([^:]+)(:\\d+)?/?$|^$',
description: localize('proxy', "The proxy setting to use. If not set will be taken from the http_proxy and https_proxy environment variables.")
markdownDescription: localize('proxy', "The proxy setting to use. If not set, will be inherited from the `http_proxy` and `https_proxy` environment variables.")
},
'http.proxyStrictSSL': {
type: 'boolean',
@@ -100,7 +100,7 @@ Registry.as<IConfigurationRegistry>(Extensions.Configuration)
'http.proxyAuthorization': {
type: ['null', 'string'],
default: null,
description: localize('proxyAuthorization', "The value to send as the 'Proxy-Authorization' header for every network request.")
markdownDescription: localize('proxyAuthorization', "The value to send as the `Proxy-Authorization` header for every network request.")
},
'http.proxySupport': {
type: 'string',

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export interface IPropertyData {
classification: 'SystemMetaData' | 'CallstackOrException' | 'CustomerContent' | 'PublicNonPersonalData';
classification: 'SystemMetaData' | 'CallstackOrException' | 'CustomerContent' | 'PublicNonPersonalData' | 'EndUserPseudonymizedInformation';
purpose: 'PerformanceAndHealth' | 'FeatureInsight' | 'BusinessInsight';
endpoint?: string;
isMeasurement?: boolean;

View File

@@ -69,20 +69,16 @@ export class TelemetryService implements ITelemetryService {
this._commonProperties.then(values => {
const isHashedId = /^[a-f0-9]+$/i.test(values['common.machineId']);
/* __GDPR__
"machineIdFallback" : {
"usingFallbackGuid" : { "classification": "SystemMetaData", "purpose": "BusinessInsight", "isMeasurement": true }
}
*/
this.publicLog('machineIdFallback', { usingFallbackGuid: !isHashedId });
type MachineIdFallbackClassification = {
usingFallbackGuid: { classification: 'SystemMetaData', purpose: 'BusinessInsight', isMeasurement: true };
};
this.publicLog2<{ usingFallbackGuid: boolean }, MachineIdFallbackClassification>('machineIdFallback', { usingFallbackGuid: !isHashedId });
if (config.trueMachineId) {
/* __GDPR__
"machineIdDisambiguation" : {
"correctedMachineId" : { "endPoint": "MacAddressHash", "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" }
}
*/
this.publicLog('machineIdDisambiguation', { correctedMachineId: config.trueMachineId });
type MachineIdDisambiguationClassification = {
correctedMachineId: { endPoint: 'MacAddressHash', classification: 'EndUserPseudonymizedInformation', purpose: 'FeatureInsight' };
};
this.publicLog2<{ correctedMachineId: string }, MachineIdDisambiguationClassification>('machineIdDisambiguation', { correctedMachineId: config.trueMachineId });
}
});
}

View File

@@ -33,17 +33,17 @@ export const NullTelemetryService = new class implements ITelemetryService {
export interface ITelemetryAppender {
log(eventName: string, data: any): void;
dispose(): Promise<any> | undefined;
flush(): Promise<any>;
}
export function combinedAppender(...appenders: ITelemetryAppender[]): ITelemetryAppender {
return {
log: (e, d) => appenders.forEach(a => a.log(e, d)),
dispose: () => Promise.all(appenders.map(a => a.dispose()))
flush: () => Promise.all(appenders.map(a => a.flush()))
};
}
export const NullAppender: ITelemetryAppender = { log: () => null, dispose: () => Promise.resolve(null) };
export const NullAppender: ITelemetryAppender = { log: () => null, flush: () => Promise.resolve(null) };
export class LogAppender implements ITelemetryAppender {
@@ -51,7 +51,7 @@ export class LogAppender implements ITelemetryAppender {
private commonPropertiesRegex = /^sessionID$|^version$|^timestamp$|^commitHash$|^common\./;
constructor(@ILogService private readonly _logService: ILogService) { }
dispose(): Promise<any> {
flush(): Promise<any> {
return Promise.resolve(undefined);
}

View File

@@ -73,7 +73,7 @@ export class AppInsightsAppender implements ITelemetryAppender {
});
}
dispose(): Promise<any> | undefined {
flush(): Promise<any> | undefined {
if (this._aiClient) {
return new Promise(resolve => {
this._aiClient!.flush({

View File

@@ -37,7 +37,7 @@ export class TelemetryAppenderClient implements ITelemetryAppender {
return Promise.resolve(null);
}
dispose(): any {
flush(): any {
// TODO
}
}

View File

@@ -84,7 +84,7 @@ suite('AIAdapter', () => {
});
teardown(() => {
adapter.dispose();
adapter.flush();
});
test('Simple event', () => {

View File

@@ -30,7 +30,7 @@ class TestTelemetryAppender implements ITelemetryAppender {
return this.events.length;
}
public dispose(): Promise<any> {
public flush(): Promise<any> {
this.isDisposed = true;
return Promise.resolve(null);
}

View File

@@ -115,12 +115,7 @@ export class Win32UpdateService extends AbstractUpdateService {
const updateType = getUpdateType();
if (!update || !update.url || !update.version || !update.productVersion) {
/* __GDPR__
"update:notAvailable" : {
"explicit" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }
}
*/
this.telemetryService.publicLog('update:notAvailable', { explicit: !!context });
this.telemetryService.publicLog2<{ explicit: boolean }, UpdateNotAvailableClassification>('update:notAvailable', { explicit: !!context });
this.setState(State.Idle(updateType));
return Promise.resolve(null);