"Fossies" - the Fresh Open Source Software Archive

Member "vscode-1.49.1/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts" (16 Sep 2020, 14985 Bytes) of package /linux/misc/vscode-1.49.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) TypeScript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "abstractKeybindingService.test.ts": 1.48.2_vs_1.49.0.

    1 /*---------------------------------------------------------------------------------------------
    2  *  Copyright (c) Microsoft Corporation. All rights reserved.
    3  *  Licensed under the MIT License. See License.txt in the project root for license information.
    4  *--------------------------------------------------------------------------------------------*/
    5 import * as assert from 'assert';
    6 import { KeyChord, KeyCode, KeyMod, Keybinding, ResolvedKeybinding, SimpleKeybinding, createKeybinding, createSimpleKeybinding } from 'vs/base/common/keyCodes';
    7 import { OS } from 'vs/base/common/platform';
    8 import Severity from 'vs/base/common/severity';
    9 import { ICommandService } from 'vs/platform/commands/common/commands';
   10 import { ContextKeyExpr, IContext, IContextKeyService, IContextKeyServiceTarget, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
   11 import { AbstractKeybindingService } from 'vs/platform/keybinding/common/abstractKeybindingService';
   12 import { IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding';
   13 import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver';
   14 import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
   15 import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding';
   16 import { INotification, INotificationService, IPromptChoice, IPromptOptions, NoOpNotification, IStatusMessageOptions } from 'vs/platform/notification/common/notification';
   17 import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
   18 import { Disposable } from 'vs/base/common/lifecycle';
   19 import { NullLogService } from 'vs/platform/log/common/log';
   20 
   21 function createContext(ctx: any) {
   22     return {
   23         getValue: (key: string) => {
   24             return ctx[key];
   25         }
   26     };
   27 }
   28 
   29 suite('AbstractKeybindingService', () => {
   30 
   31     class TestKeybindingService extends AbstractKeybindingService {
   32         private _resolver: KeybindingResolver;
   33 
   34         constructor(
   35             resolver: KeybindingResolver,
   36             contextKeyService: IContextKeyService,
   37             commandService: ICommandService,
   38             notificationService: INotificationService
   39         ) {
   40             super(contextKeyService, commandService, NullTelemetryService, notificationService, new NullLogService());
   41             this._resolver = resolver;
   42         }
   43 
   44         protected _getResolver(): KeybindingResolver {
   45             return this._resolver;
   46         }
   47 
   48         protected _documentHasFocus(): boolean {
   49             return true;
   50         }
   51 
   52         public resolveKeybinding(kb: Keybinding): ResolvedKeybinding[] {
   53             return [new USLayoutResolvedKeybinding(kb, OS)];
   54         }
   55 
   56         public resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding {
   57             let keybinding = new SimpleKeybinding(
   58                 keyboardEvent.ctrlKey,
   59                 keyboardEvent.shiftKey,
   60                 keyboardEvent.altKey,
   61                 keyboardEvent.metaKey,
   62                 keyboardEvent.keyCode
   63             ).toChord();
   64             return this.resolveKeybinding(keybinding)[0];
   65         }
   66 
   67         public resolveUserBinding(userBinding: string): ResolvedKeybinding[] {
   68             return [];
   69         }
   70 
   71         public testDispatch(kb: number): boolean {
   72             const keybinding = createSimpleKeybinding(kb, OS);
   73             return this._dispatch({
   74                 _standardKeyboardEventBrand: true,
   75                 ctrlKey: keybinding.ctrlKey,
   76                 shiftKey: keybinding.shiftKey,
   77                 altKey: keybinding.altKey,
   78                 metaKey: keybinding.metaKey,
   79                 keyCode: keybinding.keyCode,
   80                 code: null!
   81             }, null!);
   82         }
   83 
   84         public _dumpDebugInfo(): string {
   85             return '';
   86         }
   87 
   88         public _dumpDebugInfoJSON(): string {
   89             return '';
   90         }
   91 
   92         public registerSchemaContribution() {
   93             // noop
   94         }
   95     }
   96 
   97     let createTestKeybindingService: (items: ResolvedKeybindingItem[], contextValue?: any) => TestKeybindingService = null!;
   98     let currentContextValue: IContext | null = null;
   99     let executeCommandCalls: { commandId: string; args: any[]; }[] = null!;
  100     let showMessageCalls: { sev: Severity, message: any; }[] = null!;
  101     let statusMessageCalls: string[] | null = null;
  102     let statusMessageCallsDisposed: string[] | null = null;
  103 
  104     setup(() => {
  105         executeCommandCalls = [];
  106         showMessageCalls = [];
  107         statusMessageCalls = [];
  108         statusMessageCallsDisposed = [];
  109 
  110         createTestKeybindingService = (items: ResolvedKeybindingItem[]): TestKeybindingService => {
  111 
  112             let contextKeyService: IContextKeyService = {
  113                 _serviceBrand: undefined,
  114                 dispose: undefined!,
  115                 onDidChangeContext: undefined!,
  116                 bufferChangeEvents() { },
  117                 createKey: undefined!,
  118                 contextMatchesRules: undefined!,
  119                 getContextKeyValue: undefined!,
  120                 createScoped: undefined!,
  121                 getContext: (target: IContextKeyServiceTarget): any => {
  122                     return currentContextValue;
  123                 }
  124             };
  125 
  126             let commandService: ICommandService = {
  127                 _serviceBrand: undefined,
  128                 onWillExecuteCommand: () => Disposable.None,
  129                 onDidExecuteCommand: () => Disposable.None,
  130                 executeCommand: (commandId: string, ...args: any[]): Promise<any> => {
  131                     executeCommandCalls.push({
  132                         commandId: commandId,
  133                         args: args
  134                     });
  135                     return Promise.resolve(undefined);
  136                 }
  137             };
  138 
  139             let notificationService: INotificationService = {
  140                 _serviceBrand: undefined,
  141                 notify: (notification: INotification) => {
  142                     showMessageCalls.push({ sev: notification.severity, message: notification.message });
  143                     return new NoOpNotification();
  144                 },
  145                 info: (message: any) => {
  146                     showMessageCalls.push({ sev: Severity.Info, message });
  147                     return new NoOpNotification();
  148                 },
  149                 warn: (message: any) => {
  150                     showMessageCalls.push({ sev: Severity.Warning, message });
  151                     return new NoOpNotification();
  152                 },
  153                 error: (message: any) => {
  154                     showMessageCalls.push({ sev: Severity.Error, message });
  155                     return new NoOpNotification();
  156                 },
  157                 prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions) {
  158                     throw new Error('not implemented');
  159                 },
  160                 status(message: string, options?: IStatusMessageOptions) {
  161                     statusMessageCalls!.push(message);
  162                     return {
  163                         dispose: () => {
  164                             statusMessageCallsDisposed!.push(message);
  165                         }
  166                     };
  167                 },
  168                 setFilter() { }
  169             };
  170 
  171             let resolver = new KeybindingResolver(items, [], () => { });
  172 
  173             return new TestKeybindingService(resolver, contextKeyService, commandService, notificationService);
  174         };
  175     });
  176 
  177     teardown(() => {
  178         currentContextValue = null;
  179         executeCommandCalls = null!;
  180         showMessageCalls = null!;
  181         createTestKeybindingService = null!;
  182         statusMessageCalls = null;
  183         statusMessageCallsDisposed = null;
  184     });
  185 
  186     function kbItem(keybinding: number, command: string, when?: ContextKeyExpression): ResolvedKeybindingItem {
  187         const resolvedKeybinding = (keybinding !== 0 ? new USLayoutResolvedKeybinding(createKeybinding(keybinding, OS)!, OS) : undefined);
  188         return new ResolvedKeybindingItem(
  189             resolvedKeybinding,
  190             command,
  191             null,
  192             when,
  193             true,
  194             null
  195         );
  196     }
  197 
  198     function toUsLabel(keybinding: number): string {
  199         const usResolvedKeybinding = new USLayoutResolvedKeybinding(createKeybinding(keybinding, OS)!, OS);
  200         return usResolvedKeybinding.getLabel()!;
  201     }
  202 
  203     test('issue #16498: chord mode is quit for invalid chords', () => {
  204 
  205         let kbService = createTestKeybindingService([
  206             kbItem(KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_X), 'chordCommand'),
  207             kbItem(KeyCode.Backspace, 'simpleCommand'),
  208         ]);
  209 
  210         // send Ctrl/Cmd + K
  211         let shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KEY_K);
  212         assert.equal(shouldPreventDefault, true);
  213         assert.deepEqual(executeCommandCalls, []);
  214         assert.deepEqual(showMessageCalls, []);
  215         assert.deepEqual(statusMessageCalls, [
  216             `(${toUsLabel(KeyMod.CtrlCmd | KeyCode.KEY_K)}) was pressed. Waiting for second key of chord...`
  217         ]);
  218         assert.deepEqual(statusMessageCallsDisposed, []);
  219         executeCommandCalls = [];
  220         showMessageCalls = [];
  221         statusMessageCalls = [];
  222         statusMessageCallsDisposed = [];
  223 
  224         // send backspace
  225         shouldPreventDefault = kbService.testDispatch(KeyCode.Backspace);
  226         assert.equal(shouldPreventDefault, true);
  227         assert.deepEqual(executeCommandCalls, []);
  228         assert.deepEqual(showMessageCalls, []);
  229         assert.deepEqual(statusMessageCalls, [
  230             `The key combination (${toUsLabel(KeyMod.CtrlCmd | KeyCode.KEY_K)}, ${toUsLabel(KeyCode.Backspace)}) is not a command.`
  231         ]);
  232         assert.deepEqual(statusMessageCallsDisposed, [
  233             `(${toUsLabel(KeyMod.CtrlCmd | KeyCode.KEY_K)}) was pressed. Waiting for second key of chord...`
  234         ]);
  235         executeCommandCalls = [];
  236         showMessageCalls = [];
  237         statusMessageCalls = [];
  238         statusMessageCallsDisposed = [];
  239 
  240         // send backspace
  241         shouldPreventDefault = kbService.testDispatch(KeyCode.Backspace);
  242         assert.equal(shouldPreventDefault, true);
  243         assert.deepEqual(executeCommandCalls, [{
  244             commandId: 'simpleCommand',
  245             args: [null]
  246         }]);
  247         assert.deepEqual(showMessageCalls, []);
  248         assert.deepEqual(statusMessageCalls, []);
  249         assert.deepEqual(statusMessageCallsDisposed, []);
  250         executeCommandCalls = [];
  251         showMessageCalls = [];
  252         statusMessageCalls = [];
  253         statusMessageCallsDisposed = [];
  254 
  255         kbService.dispose();
  256     });
  257 
  258     test('issue #16833: Keybinding service should not testDispatch on modifier keys', () => {
  259 
  260         let kbService = createTestKeybindingService([
  261             kbItem(KeyCode.Ctrl, 'nope'),
  262             kbItem(KeyCode.Meta, 'nope'),
  263             kbItem(KeyCode.Alt, 'nope'),
  264             kbItem(KeyCode.Shift, 'nope'),
  265 
  266             kbItem(KeyMod.CtrlCmd, 'nope'),
  267             kbItem(KeyMod.WinCtrl, 'nope'),
  268             kbItem(KeyMod.Alt, 'nope'),
  269             kbItem(KeyMod.Shift, 'nope'),
  270         ]);
  271 
  272         function assertIsIgnored(keybinding: number): void {
  273             let shouldPreventDefault = kbService.testDispatch(keybinding);
  274             assert.equal(shouldPreventDefault, false);
  275             assert.deepEqual(executeCommandCalls, []);
  276             assert.deepEqual(showMessageCalls, []);
  277             assert.deepEqual(statusMessageCalls, []);
  278             assert.deepEqual(statusMessageCallsDisposed, []);
  279             executeCommandCalls = [];
  280             showMessageCalls = [];
  281             statusMessageCalls = [];
  282             statusMessageCallsDisposed = [];
  283         }
  284 
  285         assertIsIgnored(KeyCode.Ctrl);
  286         assertIsIgnored(KeyCode.Meta);
  287         assertIsIgnored(KeyCode.Alt);
  288         assertIsIgnored(KeyCode.Shift);
  289 
  290         assertIsIgnored(KeyMod.CtrlCmd);
  291         assertIsIgnored(KeyMod.WinCtrl);
  292         assertIsIgnored(KeyMod.Alt);
  293         assertIsIgnored(KeyMod.Shift);
  294 
  295         kbService.dispose();
  296     });
  297 
  298     test('can trigger command that is sharing keybinding with chord', () => {
  299 
  300         let kbService = createTestKeybindingService([
  301             kbItem(KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_X), 'chordCommand'),
  302             kbItem(KeyMod.CtrlCmd | KeyCode.KEY_K, 'simpleCommand', ContextKeyExpr.has('key1')),
  303         ]);
  304 
  305 
  306         // send Ctrl/Cmd + K
  307         currentContextValue = createContext({
  308             key1: true
  309         });
  310         let shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KEY_K);
  311         assert.equal(shouldPreventDefault, true);
  312         assert.deepEqual(executeCommandCalls, [{
  313             commandId: 'simpleCommand',
  314             args: [null]
  315         }]);
  316         assert.deepEqual(showMessageCalls, []);
  317         assert.deepEqual(statusMessageCalls, []);
  318         assert.deepEqual(statusMessageCallsDisposed, []);
  319         executeCommandCalls = [];
  320         showMessageCalls = [];
  321         statusMessageCalls = [];
  322         statusMessageCallsDisposed = [];
  323 
  324         // send Ctrl/Cmd + K
  325         currentContextValue = createContext({});
  326         shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KEY_K);
  327         assert.equal(shouldPreventDefault, true);
  328         assert.deepEqual(executeCommandCalls, []);
  329         assert.deepEqual(showMessageCalls, []);
  330         assert.deepEqual(statusMessageCalls, [
  331             `(${toUsLabel(KeyMod.CtrlCmd | KeyCode.KEY_K)}) was pressed. Waiting for second key of chord...`
  332         ]);
  333         assert.deepEqual(statusMessageCallsDisposed, []);
  334         executeCommandCalls = [];
  335         showMessageCalls = [];
  336         statusMessageCalls = [];
  337         statusMessageCallsDisposed = [];
  338 
  339         // send Ctrl/Cmd + X
  340         currentContextValue = createContext({});
  341         shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KEY_X);
  342         assert.equal(shouldPreventDefault, true);
  343         assert.deepEqual(executeCommandCalls, [{
  344             commandId: 'chordCommand',
  345             args: [null]
  346         }]);
  347         assert.deepEqual(showMessageCalls, []);
  348         assert.deepEqual(statusMessageCalls, []);
  349         assert.deepEqual(statusMessageCallsDisposed, [
  350             `(${toUsLabel(KeyMod.CtrlCmd | KeyCode.KEY_K)}) was pressed. Waiting for second key of chord...`
  351         ]);
  352         executeCommandCalls = [];
  353         showMessageCalls = [];
  354         statusMessageCalls = [];
  355         statusMessageCallsDisposed = [];
  356 
  357         kbService.dispose();
  358     });
  359 
  360     test('cannot trigger chord if command is overwriting', () => {
  361 
  362         let kbService = createTestKeybindingService([
  363             kbItem(KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_X), 'chordCommand', ContextKeyExpr.has('key1')),
  364             kbItem(KeyMod.CtrlCmd | KeyCode.KEY_K, 'simpleCommand'),
  365         ]);
  366 
  367 
  368         // send Ctrl/Cmd + K
  369         currentContextValue = createContext({});
  370         let shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KEY_K);
  371         assert.equal(shouldPreventDefault, true);
  372         assert.deepEqual(executeCommandCalls, [{
  373             commandId: 'simpleCommand',
  374             args: [null]
  375         }]);
  376         assert.deepEqual(showMessageCalls, []);
  377         assert.deepEqual(statusMessageCalls, []);
  378         assert.deepEqual(statusMessageCallsDisposed, []);
  379         executeCommandCalls = [];
  380         showMessageCalls = [];
  381         statusMessageCalls = [];
  382         statusMessageCallsDisposed = [];
  383 
  384         // send Ctrl/Cmd + K
  385         currentContextValue = createContext({
  386             key1: true
  387         });
  388         shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KEY_K);
  389         assert.equal(shouldPreventDefault, true);
  390         assert.deepEqual(executeCommandCalls, [{
  391             commandId: 'simpleCommand',
  392             args: [null]
  393         }]);
  394         assert.deepEqual(showMessageCalls, []);
  395         assert.deepEqual(statusMessageCalls, []);
  396         assert.deepEqual(statusMessageCallsDisposed, []);
  397         executeCommandCalls = [];
  398         showMessageCalls = [];
  399         statusMessageCalls = [];
  400         statusMessageCallsDisposed = [];
  401 
  402         // send Ctrl/Cmd + X
  403         currentContextValue = createContext({
  404             key1: true
  405         });
  406         shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KEY_X);
  407         assert.equal(shouldPreventDefault, false);
  408         assert.deepEqual(executeCommandCalls, []);
  409         assert.deepEqual(showMessageCalls, []);
  410         assert.deepEqual(statusMessageCalls, []);
  411         assert.deepEqual(statusMessageCallsDisposed, []);
  412         executeCommandCalls = [];
  413         showMessageCalls = [];
  414         statusMessageCalls = [];
  415         statusMessageCallsDisposed = [];
  416 
  417         kbService.dispose();
  418     });
  419 
  420     test('can have spying command', () => {
  421 
  422         let kbService = createTestKeybindingService([
  423             kbItem(KeyMod.CtrlCmd | KeyCode.KEY_K, '^simpleCommand'),
  424         ]);
  425 
  426         // send Ctrl/Cmd + K
  427         currentContextValue = createContext({});
  428         let shouldPreventDefault = kbService.testDispatch(KeyMod.CtrlCmd | KeyCode.KEY_K);
  429         assert.equal(shouldPreventDefault, false);
  430         assert.deepEqual(executeCommandCalls, [{
  431             commandId: 'simpleCommand',
  432             args: [null]
  433         }]);
  434         assert.deepEqual(showMessageCalls, []);
  435         assert.deepEqual(statusMessageCalls, []);
  436         assert.deepEqual(statusMessageCallsDisposed, []);
  437         executeCommandCalls = [];
  438         showMessageCalls = [];
  439         statusMessageCalls = [];
  440         statusMessageCallsDisposed = [];
  441 
  442         kbService.dispose();
  443     });
  444 });