/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ 'use strict'; import {TPromise} from 'vs/base/common/winjs.base'; import {TypeConstraint} from 'vs/base/common/types'; import {createDecorator, ServiceIdentifier, ServicesAccessor} from 'vs/platform/instantiation/common/instantiation'; import {Keybinding} from 'vs/base/common/keyCodes'; import {IHTMLContentElement} from 'vs/base/common/htmlContent'; export interface IUserFriendlyKeybinding { key: string; command: string; when?: string; } export interface IKeybindings { primary: number; secondary?: number[]; win?: { primary: number; secondary?: number[]; }; linux?: { primary: number; secondary?: number[]; }; mac?: { primary: number; secondary?: number[]; }; } export interface KbExpr { equals(other:KbExpr): boolean; evaluate(context:any): boolean; normalize(): KbExpr; serialize(): string; } export class KbDefinedExpression implements KbExpr { constructor(private key:string) { } public equals(other:KbExpr): boolean { if (other instanceof KbDefinedExpression) { return (this.key === other.key); } return false; } public evaluate(context:any): boolean { return (!!context[this.key]); } public normalize(): KbExpr { return this; } public serialize(): string { return this.key; } } export class KbEqualsExpression implements KbExpr { constructor(private key:string, private value:any) { } public equals(other:KbExpr): boolean { if (other instanceof KbEqualsExpression) { return (this.key === other.key && this.value === other.value); } return false; } public evaluate(context:any): boolean { // Intentional == return (context[this.key] == this.value); } public normalize(): KbExpr { if (typeof this.value === 'boolean') { if (this.value) { return new KbDefinedExpression(this.key); } return new KbNotExpression(this.key); } return this; } public serialize(): string { if (typeof this.value === 'boolean') { return this.normalize().serialize(); } return this.key + ' == \'' + this.value + '\''; } } export class KbNotEqualsExpression implements KbExpr { constructor(private key:string, private value:any) { } public equals(other:KbExpr): boolean { if (other instanceof KbNotEqualsExpression) { return (this.key === other.key && this.value === other.value); } return false; } public evaluate(context:any): boolean { // Intentional != return (context[this.key] != this.value); } public normalize(): KbExpr { if (typeof this.value === 'boolean') { if (this.value) { return new KbNotExpression(this.key); } return new KbDefinedExpression(this.key); } return this; } public serialize(): string { if (typeof this.value === 'boolean') { return this.normalize().serialize(); } return this.key + ' != \'' + this.value + '\''; } } export class KbNotExpression implements KbExpr { constructor(private key:string) { } public equals(other:KbExpr): boolean { if (other instanceof KbNotExpression) { return (this.key === other.key); } return false; } public evaluate(context:any): boolean { return (!context[this.key]); } public normalize(): KbExpr { return this; } public serialize(): string { return '!' + this.key; } } export class KbAndExpression implements KbExpr { private expr:KbExpr[]; constructor(expr:KbExpr[]) { this.expr = expr || []; } public equals(other:KbExpr): boolean { return this === other; } public evaluate(context:any): boolean { for (let i = 0, len = this.expr.length; i < len; i++) { if (!this.expr[i].evaluate(context)) { return false; } } return true; } public normalize(): KbExpr { let expr:KbExpr[] = []; for (let i = 0, len = this.expr.length; i < len; i++) { let e = this.expr[i]; if (!e) { continue; } e = e.normalize(); if (!e) { continue; } if (e instanceof KbAndExpression) { expr = expr.concat(e.expr); continue; } expr.push(e); } if (expr.length === 0) { return null; } if (expr.length === 1) { return expr[0]; } return new KbAndExpression(expr); } public serialize(): string { if (this.expr.length === 0) { return ''; } if (this.expr.length === 1) { return this.normalize().serialize(); } return this.expr.map(e => e.serialize()).join(' && '); } } export let KbExpr = { has: (key:string) => new KbDefinedExpression(key), equals: (key:string, value:any) => new KbEqualsExpression(key, value), notEquals: (key:string, value:any) => new KbNotEqualsExpression(key, value), not: (key:string) => new KbNotExpression(key), and: (...expr:KbExpr[]) => new KbAndExpression(expr), deserialize: (serialized:string): KbExpr => { if (!serialized) { return null; } let pieces = serialized.split('&&'); let result = new KbAndExpression(pieces.map(p => KbExpr._deserializeOne(p))); return result.normalize(); }, _deserializeOne: (serializedOne:string): KbExpr => { serializedOne = serializedOne.trim(); if (serializedOne.indexOf('!=') >= 0) { let pieces = serializedOne.split('!='); return new KbNotEqualsExpression(pieces[0].trim(), KbExpr._deserializeValue(pieces[1])); } if (serializedOne.indexOf('==') >= 0) { let pieces = serializedOne.split('=='); return new KbEqualsExpression(pieces[0].trim(), KbExpr._deserializeValue(pieces[1])); } if (/^\!\s*/.test(serializedOne)) { return new KbNotExpression(serializedOne.substr(1).trim()); } return new KbDefinedExpression(serializedOne); }, _deserializeValue: (serializedValue:string): any => { serializedValue = serializedValue.trim(); if (serializedValue === 'true') { return true; } if (serializedValue === 'false') { return false; } let m = /^'([^']*)'$/.exec(serializedValue); if (m) { return m[1].trim(); } return serializedValue; } }; export interface IKeybindingItem { keybinding: number; command: string; context: KbExpr; weight1: number; weight2: number; } export interface ICommandHandler { (accessor: ServicesAccessor, args: any): void; description?: string | ICommandHandlerDescription; } export interface ICommandHandlerDescription { description: string; args: { name: string; description?: string; constraint?: TypeConstraint; }[]; returns?: string; } export interface ICommandsMap { [id: string]: ICommandHandler; } export interface IKeybindingContextKey { set(value: T): void; reset(): void; } export let IKeybindingService = createDecorator('keybindingService'); export interface IKeybindingScopeLocation { setAttribute(attr:string, value:string): void; removeAttribute(attr:string): void; } export interface IKeybindingService { serviceId : ServiceIdentifier; dispose(): void; createKey(key: string, defaultValue: T): IKeybindingContextKey; createScoped(domNode: IKeybindingScopeLocation): IKeybindingService; getDefaultKeybindings(): string; lookupKeybindings(commandId: string): Keybinding[]; customKeybindingsCount(): number; getLabelFor(keybinding:Keybinding): string; getHTMLLabelFor(keybinding:Keybinding): IHTMLContentElement[]; getElectronAcceleratorFor(keybinding:Keybinding): string; executeCommand(commandId: string, args?: any): TPromise; executeCommand(commandId: string, args?: any): TPromise; }