Skip to content

Commit b911dea

Browse files
SaKaNa-Yantfu
andauthored
fix(hub-ui): warn about shortcut conflicts across modes (#443)
Co-authored-by: Anthony Fu <github@antfu.me>
1 parent 8673ec5 commit b911dea

3 files changed

Lines changed: 66 additions & 12 deletions

File tree

‎packages/hub-ui/src/client/components/views-builtin/SettingsShortcuts.vue‎

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { ShortcutRow } from '../../state/keybindings'
55
import DisplayKbd from '@antfu/design/components/Display/DisplayKbd.vue'
66
import { computed, nextTick, ref, watch } from 'vue'
77
import { t } from '../../i18n'
8-
import { filterCommandsByWhen, findCommandDeep, formatKeybinding, getShortcutRows, isKeybindingOverrideDifferentFromDefault, isMac, KNOWN_BROWSER_SHORTCUTS } from '../../state/keybindings'
8+
import { filterCommandsByWhen, findCommandDeep, findKeybindingConflict, formatKeybinding, getShortcutRows, isKeybindingOverrideDifferentFromDefault, isMac, KNOWN_BROWSER_SHORTCUTS } from '../../state/keybindings'
99
import { useSettings } from '../../state/settings-defaults'
1010
import DockIcon from '../dock/DockIcon.vue'
1111
@@ -157,17 +157,11 @@ const editorWarnings = computed<string[]>(() => {
157157
warnings.push(t('shortcuts.warnBrowser', { description: browserDescription, keys: formatKeybinding(key).join('+') }))
158158
}
159159
160-
// Conflict with other commands
160+
// Hidden commands can share the same mode again after the user switches modes.
161161
if (editorCommandId.value) {
162-
for (const row of shortcutRows.value) {
163-
if (row.command.id === editorCommandId.value)
164-
continue
165-
const bindings = getEffectiveKeybindings(row.command.id)
166-
if (bindings.some(b => b.key === key)) {
167-
warnings.push(t('shortcuts.warnCommand', { title: row.command.title }))
168-
break
169-
}
170-
}
162+
const conflict = findKeybindingConflict(commandsCtx.commands, editorCommandId.value, key, getEffectiveKeybindings)
163+
if (conflict)
164+
warnings.push(t('shortcuts.warnCommand', { title: conflict.title }))
171165
}
172166
173167
return warnings

‎packages/hub-ui/src/client/state/keybindings.test.ts‎

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,54 @@
11
import type { DevframeCommandEntry, DevframeCommandKeybinding } from '@devframes/hub'
22
import type { WhenContext } from 'devframe/utils/when'
33
import { describe, expect, it } from 'vitest'
4-
import { collectAllKeybindings, filterCommandsByWhen, findCommandDeep, getShortcutRows, walkCommands } from './keybindings'
4+
import { collectAllKeybindings, filterCommandsByWhen, findCommandDeep, findKeybindingConflict, getShortcutRows, walkCommands } from './keybindings'
5+
6+
describe('findKeybindingConflict', () => {
7+
const commands: DevframeCommandEntry[] = [
8+
{ id: 'settings', title: 'Open Settings', source: 'client' },
9+
{
10+
id: 'dock-mode',
11+
title: 'Dock Mode',
12+
source: 'client',
13+
when: '!popupOpen',
14+
children: [
15+
{ id: 'float', title: 'Float Mode', source: 'client', when: '!popupOpen' },
16+
],
17+
},
18+
{ id: 'hidden', title: 'Hide', source: 'client', when: 'clientType == embedded' },
19+
{ id: 'disabled', title: 'Disabled', source: 'client', allowShortcuts: false },
20+
]
21+
22+
it.each<[string, Pick<WhenContext, 'popupOpen' | 'clientType'>]>([
23+
['float', { popupOpen: true, clientType: 'embedded' }],
24+
['hidden', { popupOpen: false, clientType: 'standalone' }],
25+
])('warns about %s even when the current mode hides it', (id, context) => {
26+
const visibleRows = getShortcutRows(filterCommandsByWhen(commands, {
27+
...context,
28+
dockOpen: true,
29+
paletteOpen: false,
30+
dockSelectedId: '',
31+
}))
32+
expect(visibleRows.some(row => row.command.id === id)).toBe(false)
33+
const getKeybindings = (commandId: string) => commandId === id ? [{ key: 'Mod+Shift+J' }] : []
34+
expect(findKeybindingConflict(commands, 'settings', 'Mod+Shift+J', getKeybindings)?.id).toBe(id)
35+
})
36+
37+
it('ignores the edited command and commands that disallow shortcuts', () => {
38+
const getKeybindings = (id: string) => ['settings', 'disabled'].includes(id) ? [{ key: 'Mod+J' }] : []
39+
expect(findKeybindingConflict(commands, 'settings', 'Mod+J', getKeybindings)).toBeUndefined()
40+
})
41+
42+
it('uses effective bindings, including cleared defaults and multiple bindings', () => {
43+
const commands: DevframeCommandEntry[] = [
44+
{ id: 'cleared', title: 'Cleared', source: 'client', keybindings: [{ key: 'Mod+J' }] },
45+
{ id: 'overridden', title: 'Overridden', source: 'client', keybindings: [{ key: 'Mod+K' }] },
46+
]
47+
const getKeybindings = (id: string) => id === 'overridden' ? [{ key: 'Mod+L' }, { key: 'Mod+J' }] : []
48+
expect(findKeybindingConflict(commands, 'settings', 'Mod+J', getKeybindings)?.id).toBe('overridden')
49+
expect(findKeybindingConflict(commands, 'settings', 'Mod+K', getKeybindings)).toBeUndefined()
50+
})
51+
})
552

653
describe('getShortcutRows', () => {
754
it('omits opted-out commands while retaining their bindable descendants and palette-hidden commands', () => {

‎packages/hub-ui/src/client/state/keybindings.ts‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,19 @@ export function getShortcutRows(commands: DevframeCommandEntry[]): ShortcutRow[]
133133
return rows
134134
}
135135

136+
/** Check all bindable commands, including those hidden in the current mode. */
137+
export function findKeybindingConflict(
138+
commands: DevframeCommandEntry[],
139+
commandId: string,
140+
key: string,
141+
getKeybindings: (id: string) => DevframeCommandKeybinding[],
142+
): DevframeCommandEntry | undefined {
143+
return getShortcutRows(commands).find(({ command }) =>
144+
command.id !== commandId
145+
&& getKeybindings(command.id).some(binding => binding.key === key),
146+
)?.command
147+
}
148+
136149
/**
137150
* Drop the commands whose `when` clause does not hold in the current context,
138151
* descendants included at every depth; `when` controls palette visibility at

0 commit comments

Comments
 (0)