import { injectable, inject } from 'tsyringe'; import KeymapRepository from '../repositories/KeymapRepository'; import SettingRepository from '../repositories/SettingRepository'; import AddonEnabledRepository from '../repositories/AddonEnabledRepository'; import * as operations from '../../shared/operations'; import Keymaps from '../../shared/settings/Keymaps'; import Key from '../../shared/settings/Key'; import KeySequence from '../../shared/settings/KeySequence'; import AddressRepository from '../repositories/AddressRepository'; type KeymapEntityMap = Map; const reservedKeymaps = Keymaps.fromJSON({ '': { type: operations.CANCEL }, '': { type: operations.CANCEL }, }); @injectable() export default class KeymapUseCase { constructor( @inject('KeymapRepository') private repository: KeymapRepository, @inject('SettingRepository') private settingRepository: SettingRepository, @inject('AddonEnabledRepository') private addonEnabledRepository: AddonEnabledRepository, @inject('AddressRepository') private addressRepository: AddressRepository, ) { } nextOp(key: Key): operations.Operation | null { let sequence = this.repository.enqueueKey(key); if (sequence.length() === 1 && this.blacklistKey(key)) { // ignore if the input starts with black list keys this.repository.clear(); return null; } let keymaps = this.keymapEntityMap(); let matched = Array.from(keymaps.keys()).filter( (mapping: KeySequence) => { return mapping.startsWith(sequence); }); if (!this.addonEnabledRepository.get()) { // available keymaps are only ADDON_ENABLE and ADDON_TOGGLE_ENABLED if // the addon disabled matched = matched.filter((keymap) => { let type = (keymaps.get(keymap) as operations.Operation).type; return type === operations.ADDON_ENABLE || type === operations.ADDON_TOGGLE_ENABLED; }); } if (matched.length === 0) { // No operations to match with inputs this.repository.clear(); return null; } else if (matched.length > 1 || matched.length === 1 && sequence.length() < matched[0].length()) { // More than one operations are matched return null; } // Exactly one operation is matched let operation = keymaps.get(matched[0]) as operations.Operation; this.repository.clear(); return operation; } clear(): void { this.repository.clear(); } private keymapEntityMap(): KeymapEntityMap { let keymaps = this.settingRepository.get().keymaps.combine(reservedKeymaps); let entries = keymaps.entries().map( ([keys, op]) => [KeySequence.fromMapKeys(keys), op] ) as [KeySequence, operations.Operation][]; return new Map(entries); } private blacklistKey(key: Key): boolean { let url = this.addressRepository.getCurrentURL(); let blacklist = this.settingRepository.get().blacklist; return blacklist.includeKey(url, key); } }