Skip to content

Commit e1ece5a

Browse files
committed
feat: highlight conflicting hotkeys
1 parent e3ec6f2 commit e1ece5a

18 files changed

Lines changed: 186 additions & 76 deletions

File tree

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import Lineage from 'src/main';
2+
import { App, Hotkey } from 'obsidian';
3+
import { hotkeyToString } from 'src/view/actions/keyboard-shortcuts/helpers/keyboard-events/hotkey-to-string';
4+
5+
export type HotkeyDictionary = {
6+
[commandId: string]: Hotkey[];
7+
};
8+
9+
type ExtendedApp = App & {
10+
hotkeyManager: {
11+
defaultKeys: HotkeyDictionary;
12+
customKeys: HotkeyDictionary;
13+
};
14+
};
15+
16+
const reverseDictionary = (dictionary: HotkeyDictionary) => {
17+
const entries = Object.entries(dictionary)
18+
.map(([command, hotkeys]) => {
19+
return hotkeys.map((hk) => [hotkeyToString(hk), command]);
20+
})
21+
.filter((x) => x)
22+
.flat() as [string, string][];
23+
return Object.fromEntries(entries);
24+
};
25+
26+
export const getUsedHotkeys = (plugin: Lineage) => {
27+
const hotkeyManager = (plugin.app as ExtendedApp).hotkeyManager;
28+
return {
29+
...reverseDictionary(hotkeyManager.defaultKeys),
30+
...reverseDictionary(hotkeyManager.customKeys),
31+
};
32+
};

src/view/actions/keyboard-shortcuts/helpers/create-commands.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { Hotkey } from 'obsidian';
22
import { ViewStore } from 'src/view/view';
33
import Lineage from 'src/main';
4-
import { addNodeAndSplitAtCursor } from 'src/view/actions/keyboard-shortcuts/helpers/add-node-and-split-at-cursor';
5-
import { saveNodeContent } from 'src/view/actions/keyboard-shortcuts/helpers/save-node-content';
6-
import { cancelChanges } from 'src/view/actions/keyboard-shortcuts/helpers/cancel-changes';
7-
import { saveNodeAndInsertNode } from 'src/view/actions/keyboard-shortcuts/helpers/save-node-and-insert-node';
8-
import { mergeNode } from 'src/view/actions/keyboard-shortcuts/helpers/merge-node';
4+
import { addNodeAndSplitAtCursor } from 'src/view/actions/keyboard-shortcuts/helpers/tree/add-node-and-split-at-cursor';
5+
import { saveNodeContent } from 'src/view/actions/keyboard-shortcuts/helpers/tree/save-node-content';
6+
import { cancelChanges } from 'src/view/actions/keyboard-shortcuts/helpers/tree/cancel-changes';
7+
import { saveNodeAndInsertNode } from 'src/view/actions/keyboard-shortcuts/helpers/tree/save-node-and-insert-node';
8+
import { mergeNode } from 'src/view/actions/keyboard-shortcuts/helpers/tree/merge-node';
99

1010
export const hotkeysLang = {
1111
save_changes_and_exit_card: 'Save changes and exit card',
@@ -39,6 +39,8 @@ export type PluginCommand = {
3939
hotkeys: Hotkey[];
4040
};
4141

42+
export type LineageCommandName = keyof typeof hotkeysLang;
43+
export type LineageCommands = Record<LineageCommandName, PluginCommand>;
4244
export const createCommands = (plugin: Lineage) => {
4345
const isEditing = (store: ViewStore) => {
4446
return !!store.getValue().ui.state.editing.activeNodeId;
@@ -297,5 +299,5 @@ export const createCommands = (plugin: Lineage) => {
297299
{ key: 'ArrowDown', modifiers: ['Ctrl', 'Shift'] },
298300
],
299301
},
300-
} satisfies Record<keyof typeof hotkeysLang, PluginCommand>;
302+
} satisfies LineageCommands;
301303
};
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { eventToString } from 'src/view/actions/keyboard-shortcuts/helpers/keyboard-events/event-to-string';
2+
import { PluginCommand } from 'src/view/actions/keyboard-shortcuts/helpers/create-commands';
3+
import { hotkeyToString } from 'src/view/actions/keyboard-shortcuts/helpers/keyboard-events/hotkey-to-string';
4+
import { getUsedHotkeys } from 'src/obsidian/helpers/get-used-hotkeys';
5+
import Lineage from 'src/main';
6+
7+
export const detectConflictingHotkeys = (
8+
plugin: Lineage,
9+
commands: PluginCommand[],
10+
container: HTMLElement,
11+
) => {
12+
const free = new Set();
13+
const all = [];
14+
const listener = (event: KeyboardEvent) => {
15+
const hotkey = eventToString(event);
16+
free.add(hotkey);
17+
};
18+
const el = document.createElement('div');
19+
el.addEventListener('keydown', listener);
20+
container.append(el);
21+
22+
for (const command of commands) {
23+
for (const hotkey of command.hotkeys) {
24+
all.push(hotkeyToString(hotkey));
25+
const modifiers = new Set(hotkey.modifiers);
26+
const event = new KeyboardEvent('keydown', {
27+
key: hotkey.key,
28+
shiftKey: modifiers.has('Shift'),
29+
altKey: modifiers.has('Alt'),
30+
ctrlKey: modifiers.has('Ctrl'),
31+
});
32+
el.dispatchEvent(event);
33+
}
34+
}
35+
el.removeEventListener('keydown', listener);
36+
container.removeChild(el);
37+
const used = getUsedHotkeys(plugin);
38+
return new Map(all.filter((h) => !free.has(h)).map((hk) => [hk, used[hk]]));
39+
};
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Modifiers } from 'src/view/actions/keyboard-shortcuts/keyboard-shortcuts';
2+
3+
export const eventToString = (event: KeyboardEvent) => {
4+
let string = event.key.toUpperCase();
5+
if (event.altKey) string += Modifiers.Alt;
6+
if (event.ctrlKey) string += Modifiers.Ctrl;
7+
if (event.shiftKey) string += Modifiers.Shift;
8+
return string;
9+
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { Hotkey } from 'obsidian';
2+
3+
export const hotkeyToString = (hotkey: Hotkey) =>
4+
hotkey.key.toUpperCase() +
5+
hotkey.modifiers
6+
.sort()
7+
.map((x) => (x === 'Mod' ? 'Ctrl' : x))
8+
.join('');

src/view/actions/keyboard-shortcuts/helpers/add-node-and-split-at-cursor.ts renamed to src/view/actions/keyboard-shortcuts/helpers/tree/add-node-and-split-at-cursor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ViewStore } from 'src/view/view';
22
import Lineage from 'src/main';
33
import { Direction } from 'src/stores/view/view-reducer';
44

5-
import { saveNodeAndInsertNode } from 'src/view/actions/keyboard-shortcuts/helpers/save-node-and-insert-node';
5+
import { saveNodeAndInsertNode } from 'src/view/actions/keyboard-shortcuts/helpers/tree/save-node-and-insert-node';
66
import { activeTextArea } from 'src/view/components/container/column/components/group/components/card/actions/save-node-content-action';
77

88
export const addNodeAndSplitAtCursor = (

src/view/actions/keyboard-shortcuts/helpers/cancel-changes.ts renamed to src/view/actions/keyboard-shortcuts/helpers/tree/cancel-changes.ts

File renamed without changes.

src/view/actions/keyboard-shortcuts/helpers/merge-node.ts renamed to src/view/actions/keyboard-shortcuts/helpers/tree/merge-node.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ViewStore } from 'src/view/view';
22
import { VerticalDirection } from 'src/stores/view/view-reducer';
3-
import { saveNodeContent } from 'src/view/actions/keyboard-shortcuts/helpers/save-node-content';
3+
import { saveNodeContent } from 'src/view/actions/keyboard-shortcuts/helpers/tree/save-node-content';
44

55
export const mergeNode = (store: ViewStore, direction: VerticalDirection) => {
66
saveNodeContent(store);

src/view/actions/keyboard-shortcuts/helpers/save-node-and-insert-node.ts renamed to src/view/actions/keyboard-shortcuts/helpers/tree/save-node-and-insert-node.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ViewStore } from 'src/view/view';
22
import { Direction } from 'src/stores/view/view-reducer';
3-
import { saveNodeContent } from 'src/view/actions/keyboard-shortcuts/helpers/save-node-content';
3+
import { saveNodeContent } from 'src/view/actions/keyboard-shortcuts/helpers/tree/save-node-content';
44

55
export const saveNodeAndInsertNode = (
66
store: ViewStore,

src/view/actions/keyboard-shortcuts/helpers/save-node-content.ts renamed to src/view/actions/keyboard-shortcuts/helpers/tree/save-node-content.ts

File renamed without changes.

0 commit comments

Comments
 (0)