2020-09-06 14:00:25 +02:00
|
|
|
import { useState, useEffect } from 'react';
|
2020-10-25 19:46:41 +02:00
|
|
|
import KeymapService, { KeymapItem } from 'lib/services/KeymapService';
|
2020-09-06 14:00:25 +02:00
|
|
|
|
|
|
|
const keymapService = KeymapService.instance();
|
|
|
|
|
|
|
|
// This custom hook provides a synchronized snapshot of the keymap residing at KeymapService
|
|
|
|
// All the logic regarding altering and interacting with the keymap is isolated from the components
|
|
|
|
|
|
|
|
const useKeymap = (): [
|
|
|
|
KeymapItem[],
|
|
|
|
Error,
|
|
|
|
(keymapItems: KeymapItem[]) => void,
|
|
|
|
(commandName: string, accelerator: string) => void,
|
|
|
|
(commandName: string) => void
|
|
|
|
] => {
|
|
|
|
const [keymapItems, setKeymapItems] = useState<KeymapItem[]>(() => keymapService.getKeymapItems());
|
|
|
|
const [keymapError, setKeymapError] = useState<Error>(null);
|
2020-10-09 19:35:46 +02:00
|
|
|
const [mustSave, setMustSave] = useState(false);
|
2020-09-06 14:00:25 +02:00
|
|
|
|
|
|
|
const setAccelerator = (commandName: string, accelerator: string) => {
|
|
|
|
setKeymapItems(prevKeymap => {
|
|
|
|
const newKeymap = [...prevKeymap];
|
|
|
|
|
|
|
|
newKeymap.find(item => item.command === commandName).accelerator = accelerator || null /* Disabled */;
|
|
|
|
return newKeymap;
|
|
|
|
});
|
2020-10-09 19:35:46 +02:00
|
|
|
|
|
|
|
setMustSave(true);
|
2020-09-06 14:00:25 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
const resetAccelerator = (commandName: string) => {
|
|
|
|
const defaultAccelerator = keymapService.getDefaultAccelerator(commandName);
|
|
|
|
setKeymapItems(prevKeymap => {
|
|
|
|
const newKeymap = [...prevKeymap];
|
|
|
|
|
|
|
|
newKeymap.find(item => item.command === commandName).accelerator = defaultAccelerator;
|
|
|
|
return newKeymap;
|
|
|
|
});
|
2020-10-09 19:35:46 +02:00
|
|
|
|
|
|
|
setMustSave(true);
|
2020-09-06 14:00:25 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
const overrideKeymapItems = (customKeymapItems: KeymapItem[]) => {
|
|
|
|
const oldKeymapItems = [...customKeymapItems];
|
|
|
|
keymapService.initialize(); // Start with a fresh keymap
|
|
|
|
|
|
|
|
try {
|
|
|
|
// First, try to update the in-memory keymap of KeymapService
|
|
|
|
// This function will throw if there are any issues with the new custom keymap
|
|
|
|
keymapService.overrideKeymap(customKeymapItems);
|
|
|
|
// Then, update the state with the data from KeymapService
|
|
|
|
// Side-effect: Changes will also be saved to the disk
|
|
|
|
setKeymapItems(keymapService.getKeymapItems());
|
|
|
|
} catch (err) {
|
|
|
|
// oldKeymapItems includes even the unchanged keymap items
|
|
|
|
// However, it is not an issue because the logic accounts for such scenarios
|
|
|
|
keymapService.overrideKeymap(oldKeymapItems);
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
useEffect(() => {
|
2020-10-09 19:35:46 +02:00
|
|
|
if (!mustSave) return;
|
|
|
|
|
|
|
|
setMustSave(false);
|
|
|
|
|
|
|
|
async function saveKeymap() {
|
|
|
|
try {
|
|
|
|
keymapService.overrideKeymap(keymapItems);
|
|
|
|
await keymapService.saveCustomKeymap();
|
|
|
|
setKeymapError(null);
|
|
|
|
} catch (err) {
|
2020-10-25 19:46:41 +02:00
|
|
|
const error = new Error(`Could not save file: ${err.message}`);
|
|
|
|
setKeymapError(error);
|
2020-10-09 19:35:46 +02:00
|
|
|
}
|
2020-09-06 14:00:25 +02:00
|
|
|
}
|
2020-10-09 19:35:46 +02:00
|
|
|
|
|
|
|
saveKeymap();
|
|
|
|
}, [keymapItems, mustSave]);
|
2020-09-06 14:00:25 +02:00
|
|
|
|
|
|
|
return [keymapItems, keymapError, overrideKeymapItems, setAccelerator, resetAccelerator];
|
|
|
|
};
|
|
|
|
|
|
|
|
export default useKeymap;
|