mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2026-10-25 00:02:16 +00:00
104 lines
5.0 KiB
TypeScript
104 lines
5.0 KiB
TypeScript
import assert from "assert";
|
|
import { describe } from "mocha";
|
|
import { defaultKeymap, historyKeymap } from "@codemirror/commands";
|
|
import { searchKeymap } from "@codemirror/search";
|
|
import * as fs from "fs";
|
|
import {
|
|
CMKeyBinding, IDE_RESERVED_KEYS, effectiveCMKeySpec, isMacOS, matchesKeyBinding,
|
|
normalizeCMKeySpec, parseKeyBinding, stripCMKeymap
|
|
} from "../../src/ide/keys";
|
|
|
|
function keyEvent(key: string, mods: { mod?: boolean, shift?: boolean, alt?: boolean }): any {
|
|
var mod = !!mods.mod;
|
|
return {
|
|
key,
|
|
ctrlKey: mod && !isMacOS(), metaKey: mod && isMacOS(),
|
|
shiftKey: !!mods.shift, altKey: !!mods.alt
|
|
};
|
|
}
|
|
|
|
describe('parseKeyBinding', () => {
|
|
it('should parse mod+shift+letter', () => {
|
|
assert.deepStrictEqual(parseKeyBinding('mod+shift+k'), { mod: true, shift: true, key: 'k' });
|
|
assert.deepStrictEqual(parseKeyBinding('MOD+SHIFT+K'), { mod: true, shift: true, key: 'k' });
|
|
});
|
|
it('should map arrow aliases', () => {
|
|
assert.strictEqual(parseKeyBinding('mod+left').key, 'arrowleft');
|
|
});
|
|
it('should parse f-keys', () => {
|
|
assert.deepStrictEqual(parseKeyBinding('f8'), { mod: false, shift: false, key: 'f8' });
|
|
assert.deepStrictEqual(parseKeyBinding('F12'), { mod: false, shift: false, key: 'f12' });
|
|
assert.strictEqual(parseKeyBinding('f13'), null);
|
|
});
|
|
it('should reject layout-dependent specs', () => {
|
|
assert.strictEqual(parseKeyBinding('mod+alt+k'), null); // alt is never bound
|
|
assert.strictEqual(parseKeyBinding('mod+shift+='), null); // shift mutates punctuation
|
|
assert.strictEqual(parseKeyBinding('mod+shift+1'), null); // ...and digits
|
|
});
|
|
});
|
|
|
|
describe('matchesKeyBinding', () => {
|
|
const b = parseKeyBinding('mod+shift+k');
|
|
it('should match regardless of the reported case', () => {
|
|
assert.ok(matchesKeyBinding(b, keyEvent('K', { mod: true, shift: true })));
|
|
assert.ok(matchesKeyBinding(b, keyEvent('k', { mod: true, shift: true })));
|
|
});
|
|
it('should not match without the modifiers', () => {
|
|
assert.ok(!matchesKeyBinding(b, keyEvent('k', { mod: true })));
|
|
assert.ok(!matchesKeyBinding(b, keyEvent('k', { shift: true })));
|
|
assert.ok(!matchesKeyBinding(b, keyEvent('k', { mod: true, shift: true, alt: true })));
|
|
});
|
|
});
|
|
|
|
describe('normalizeCMKeySpec', () => {
|
|
it('should ignore modifier order and case', () => {
|
|
// the bug this test exists for: CodeMirror binds deleteLine as
|
|
// "Shift-Mod-k", which an exact string match against "Mod-Shift-k" misses
|
|
assert.strictEqual(normalizeCMKeySpec('Shift-Mod-k'), normalizeCMKeySpec('Mod-Shift-k'));
|
|
assert.strictEqual(normalizeCMKeySpec('Mod-Shift-K'), 'Mod-Shift-k');
|
|
assert.strictEqual(normalizeCMKeySpec('Cmd-Shift-k'), 'Mod-Shift-k');
|
|
});
|
|
it('should keep distinct keys distinct', () => {
|
|
assert.notStrictEqual(normalizeCMKeySpec('Mod-Shift-k'), normalizeCMKeySpec('Mod-k'));
|
|
assert.notStrictEqual(normalizeCMKeySpec('Mod-Shift-k'), normalizeCMKeySpec('Mod-Alt-k'));
|
|
});
|
|
it('should handle the minus key', () => {
|
|
assert.strictEqual(normalizeCMKeySpec('Mod--'), 'Mod--');
|
|
});
|
|
});
|
|
|
|
describe('stripCMKeymap', () => {
|
|
const keymaps: { [name: string]: readonly CMKeyBinding[] } = {
|
|
defaultKeymap, searchKeymap
|
|
};
|
|
for (const name of Object.keys(keymaps)) {
|
|
it(`should leave no IDE shortcut bound in ${name}`, () => {
|
|
const left = stripCMKeymap(keymaps[name], IDE_RESERVED_KEYS)
|
|
.map(effectiveCMKeySpec)
|
|
.filter((s) => s && IDE_RESERVED_KEYS.some((r) => normalizeCMKeySpec(r) == normalizeCMKeySpec(s)));
|
|
assert.deepStrictEqual(left, [], `${name} still binds ${left}`);
|
|
});
|
|
}
|
|
it('should actually remove the two known collisions', () => {
|
|
assert.strictEqual(stripCMKeymap(defaultKeymap, IDE_RESERVED_KEYS).length, defaultKeymap.length - 1);
|
|
assert.strictEqual(stripCMKeymap(searchKeymap, IDE_RESERVED_KEYS).length, searchKeymap.length - 1);
|
|
});
|
|
it('should not disturb bindings the IDE does not claim', () => {
|
|
// Mod-Shift-z (redo on mac) is not an IDE shortcut and must survive
|
|
assert.strictEqual(stripCMKeymap(historyKeymap, IDE_RESERVED_KEYS).length, historyKeymap.length);
|
|
});
|
|
});
|
|
|
|
describe('IDE_RESERVED_KEYS', () => {
|
|
it('should cover every mod+shift shortcut ui.ts binds', () => {
|
|
const src = fs.readFileSync(__dirname + '/../../../src/ide/ui.ts', 'utf-8');
|
|
const bound = new Set((src.match(/'mod\+shift\+[a-z]'/g) || []).map((s) => s.replace(/'/g, '')));
|
|
assert.ok(bound.size > 0, 'found no shortcuts in ui.ts -- did the spelling change?');
|
|
const reserved = new Set(IDE_RESERVED_KEYS.map(normalizeCMKeySpec));
|
|
for (const key of bound) {
|
|
const spec = normalizeCMKeySpec(key.replace(/\+/g, '-'));
|
|
assert.ok(reserved.has(spec), `ui.ts binds ${key}, missing from IDE_RESERVED_KEYS`);
|
|
}
|
|
});
|
|
});
|