aboutsummaryrefslogtreecommitdiff
path: root/src/content/usecases/KeymapUseCase.ts
blob: 495f6d026c79900ec434a7f97ef16683502c4fbd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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';

type KeymapEntityMap = Map<KeySequence, operations.Operation>;

const reservedKeymaps = Keymaps.fromJSON({
  '<Esc>': { type: operations.CANCEL },
  '<C-[>': { type: operations.CANCEL },
});

@injectable()
export default class KeymapUseCase {
  constructor(
    @inject('KeymapRepository')
    private repository: KeymapRepository,

    @inject('SettingRepository')
    private settingRepository: SettingRepository,

    @inject('AddonEnabledRepository')
    private addonEnabledRepository: AddonEnabledRepository,
  ) {
  }

  nextOp(key: Key): operations.Operation | null {
    let sequence = this.repository.enqueueKey(key);

    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<KeySequence, operations.Operation>(entries);
  }
}