Keymaps as a clean architecture [WIP]
This commit is contained in:
parent
a88324acd9
commit
efc48dc742
15 changed files with 620 additions and 88 deletions
20
src/content/usecases/FindSlaveUseCase.ts
Normal file
20
src/content/usecases/FindSlaveUseCase.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import FindMasterClient, { FindMasterClientImpl }
|
||||
from '../client/FindMasterClient';
|
||||
|
||||
export default class FindSlaveUseCase {
|
||||
private findMasterClient: FindMasterClient;
|
||||
|
||||
constructor({
|
||||
findMasterClient = new FindMasterClientImpl(),
|
||||
} = {}) {
|
||||
this.findMasterClient = findMasterClient;
|
||||
}
|
||||
|
||||
findNext() {
|
||||
this.findMasterClient.findNext();
|
||||
}
|
||||
|
||||
findPrev() {
|
||||
this.findMasterClient.findPrev();
|
||||
}
|
||||
}
|
15
src/content/usecases/FocusUseCase.ts
Normal file
15
src/content/usecases/FocusUseCase.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import FocusPresenter, { FocusPresenterImpl }
|
||||
from '../presenters/FocusPresenter';
|
||||
export default class FocusUseCases {
|
||||
private presenter: FocusPresenter;
|
||||
|
||||
constructor({
|
||||
presenter = new FocusPresenterImpl(),
|
||||
} = {}) {
|
||||
this.presenter = presenter;
|
||||
}
|
||||
|
||||
focusFirstInput() {
|
||||
this.presenter.focusFirstElement();
|
||||
}
|
||||
}
|
100
src/content/usecases/KeymapUseCase.ts
Normal file
100
src/content/usecases/KeymapUseCase.ts
Normal file
|
@ -0,0 +1,100 @@
|
|||
import KeymapRepository, { KeymapRepositoryImpl }
|
||||
from '../repositories/KeymapRepository';
|
||||
import SettingRepository, { SettingRepositoryImpl }
|
||||
from '../repositories/SettingRepository';
|
||||
import AddonEnabledRepository, { AddonEnabledRepositoryImpl }
|
||||
from '../repositories/AddonEnabledRepository';
|
||||
|
||||
import * as operations from '../../shared/operations';
|
||||
import { Keymaps } from '../../shared/Settings';
|
||||
import * as keyUtils from '../../shared/utils/keys';
|
||||
|
||||
type KeymapEntityMap = Map<keyUtils.Key[], operations.Operation>;
|
||||
|
||||
const reservedKeymaps: Keymaps = {
|
||||
'<Esc>': { type: operations.CANCEL },
|
||||
'<C-[>': { type: operations.CANCEL },
|
||||
};
|
||||
|
||||
const mapStartsWith = (
|
||||
mapping: keyUtils.Key[],
|
||||
keys: keyUtils.Key[],
|
||||
): boolean => {
|
||||
if (mapping.length < keys.length) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
if (!keyUtils.equals(mapping[i], keys[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
export default class KeymapUseCase {
|
||||
private repository: KeymapRepository;
|
||||
|
||||
private settingRepository: SettingRepository;
|
||||
|
||||
private addonEnabledRepository: AddonEnabledRepository;
|
||||
|
||||
constructor({
|
||||
repository = new KeymapRepositoryImpl(),
|
||||
settingRepository = new SettingRepositoryImpl(),
|
||||
addonEnabledRepository = new AddonEnabledRepositoryImpl(),
|
||||
} = {}) {
|
||||
this.repository = repository;
|
||||
this.settingRepository = settingRepository;
|
||||
this.addonEnabledRepository = addonEnabledRepository;
|
||||
}
|
||||
|
||||
nextOp(key: keyUtils.Key): operations.Operation | null {
|
||||
let keys = this.repository.enqueueKey(key);
|
||||
|
||||
let keymaps = this.keymapEntityMap();
|
||||
let matched = Array.from(keymaps.keys()).filter(
|
||||
(mapping: keyUtils.Key[]) => {
|
||||
return mapStartsWith(mapping, keys);
|
||||
});
|
||||
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 && keys.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,
|
||||
...reservedKeymaps,
|
||||
};
|
||||
let entries = Object.entries(keymaps).map((entry) => {
|
||||
return [
|
||||
keyUtils.fromMapKeys(entry[0]),
|
||||
entry[1],
|
||||
];
|
||||
}) as [keyUtils.Key[], operations.Operation][];
|
||||
return new Map<keyUtils.Key[], operations.Operation>(entries);
|
||||
}
|
||||
}
|
27
src/content/usecases/NavigateUseCase.ts
Normal file
27
src/content/usecases/NavigateUseCase.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import * as navigates from '../navigates';
|
||||
|
||||
export default class NavigateClass {
|
||||
openHistoryPrev(): void {
|
||||
navigates.historyPrev(window);
|
||||
}
|
||||
|
||||
openHistoryNext(): void {
|
||||
navigates.historyNext(window);
|
||||
}
|
||||
|
||||
openLinkPrev(): void {
|
||||
navigates.linkPrev(window);
|
||||
}
|
||||
|
||||
openLinkNext(): void {
|
||||
navigates.linkNext(window);
|
||||
}
|
||||
|
||||
openParent(): void {
|
||||
navigates.parent(window);
|
||||
}
|
||||
|
||||
openRoot(): void {
|
||||
navigates.root(window);
|
||||
}
|
||||
}
|
58
src/content/usecases/ScrollUseCase.ts
Normal file
58
src/content/usecases/ScrollUseCase.ts
Normal file
|
@ -0,0 +1,58 @@
|
|||
import ScrollPresenter, { ScrollPresenterImpl }
|
||||
from '../presenters/ScrollPresenter';
|
||||
import SettingRepository, { SettingRepositoryImpl }
|
||||
from '../repositories/SettingRepository';
|
||||
|
||||
export default class ScrollUseCase {
|
||||
private presenter: ScrollPresenter;
|
||||
|
||||
private settingRepository: SettingRepository;
|
||||
|
||||
constructor({
|
||||
presenter = new ScrollPresenterImpl(),
|
||||
settingRepository = new SettingRepositoryImpl(),
|
||||
} = {}) {
|
||||
this.presenter = presenter;
|
||||
this.settingRepository = settingRepository;
|
||||
}
|
||||
|
||||
scrollVertically(count: number): void {
|
||||
let smooth = this.getSmoothScroll();
|
||||
this.presenter.scrollVertically(count, smooth);
|
||||
}
|
||||
|
||||
scrollHorizonally(count: number): void {
|
||||
let smooth = this.getSmoothScroll();
|
||||
this.presenter.scrollHorizonally(count, smooth);
|
||||
}
|
||||
|
||||
scrollPages(count: number): void {
|
||||
let smooth = this.getSmoothScroll();
|
||||
this.presenter.scrollPages(count, smooth);
|
||||
}
|
||||
|
||||
scrollToTop(): void {
|
||||
let smooth = this.getSmoothScroll();
|
||||
this.presenter.scrollToTop(smooth);
|
||||
}
|
||||
|
||||
scrollToBottom(): void {
|
||||
let smooth = this.getSmoothScroll();
|
||||
this.presenter.scrollToBottom(smooth);
|
||||
}
|
||||
|
||||
scrollToHome(): void {
|
||||
let smooth = this.getSmoothScroll();
|
||||
this.presenter.scrollToHome(smooth);
|
||||
}
|
||||
|
||||
scrollToEnd(): void {
|
||||
let smooth = this.getSmoothScroll();
|
||||
this.presenter.scrollToEnd(smooth);
|
||||
}
|
||||
|
||||
private getSmoothScroll(): boolean {
|
||||
let settings = this.settingRepository.get();
|
||||
return settings.properties.smoothscroll;
|
||||
}
|
||||
}
|
Reference in a new issue