Files
dbx/apps/desktop/src/lib/shortcutRegistry.ts
T
2026-06-11 11:12:05 +08:00

260 lines
6.1 KiB
TypeScript

export type ShortcutActionId =
| "executeSql"
| "formatSql"
| "saveSql"
| "acceptCompletion"
| "indentMore"
| "indentLess"
| "duplicateLine"
| "deleteLine"
| "moveLineUp"
| "moveLineDown"
| "copyLineUp"
| "copyLineDown"
| "undo"
| "redo"
| "selectAll"
| "copyCurrentRow"
| "deleteCurrentRow"
| "newQuery"
| "openSettings"
| "closeTab"
| "focusSearch"
| "zoomInUi"
| "zoomOutUi"
| "resetUiZoom"
| "find"
| "replace"
| "refreshData"
| "toggleTranspose"
| "cancelSearch"
| "toggleSidebar";
export type ShortcutScope = "global" | "editor" | "grid" | "search";
export interface ShortcutDefinition {
id: ShortcutActionId;
labelKey: string;
scope: ShortcutScope;
defaultShortcut: string;
}
export type ShortcutSettings = Record<ShortcutActionId, string>;
export const SHORTCUT_DEFINITIONS: ShortcutDefinition[] = [
{
id: "executeSql",
labelKey: "settings.shortcutExecuteSql",
scope: "editor",
defaultShortcut: "Mod+Enter",
},
{
id: "formatSql",
labelKey: "settings.shortcutFormatSql",
scope: "editor",
defaultShortcut: "Shift+Mod+F",
},
{
id: "saveSql",
labelKey: "settings.shortcutSaveSql",
scope: "editor",
defaultShortcut: "Mod+S",
},
{
id: "acceptCompletion",
labelKey: "settings.shortcutAcceptCompletion",
scope: "editor",
defaultShortcut: "Tab",
},
{
id: "indentMore",
labelKey: "settings.shortcutIndentMore",
scope: "editor",
defaultShortcut: "",
},
{
id: "indentLess",
labelKey: "settings.shortcutIndentLess",
scope: "editor",
defaultShortcut: "Shift+Tab",
},
{
id: "duplicateLine",
labelKey: "settings.shortcutDuplicateLine",
scope: "editor",
defaultShortcut: "Mod+D",
},
{
id: "deleteLine",
labelKey: "settings.shortcutDeleteLine",
scope: "editor",
defaultShortcut: "Shift+Mod+K",
},
{
id: "moveLineUp",
labelKey: "settings.shortcutMoveLineUp",
scope: "editor",
defaultShortcut: "Alt+ArrowUp",
},
{
id: "moveLineDown",
labelKey: "settings.shortcutMoveLineDown",
scope: "editor",
defaultShortcut: "Alt+ArrowDown",
},
{
id: "copyLineUp",
labelKey: "settings.shortcutCopyLineUp",
scope: "editor",
defaultShortcut: "Shift+Alt+ArrowUp",
},
{
id: "copyLineDown",
labelKey: "settings.shortcutCopyLineDown",
scope: "editor",
defaultShortcut: "Shift+Alt+ArrowDown",
},
{
id: "undo",
labelKey: "settings.shortcutUndo",
scope: "editor",
defaultShortcut: "Mod+Z",
},
{
id: "redo",
labelKey: "settings.shortcutRedo",
scope: "editor",
defaultShortcut: "Shift+Mod+Z",
},
{
id: "selectAll",
labelKey: "settings.shortcutSelectAll",
scope: "editor",
defaultShortcut: "Mod+A",
},
{
id: "copyCurrentRow",
labelKey: "settings.shortcutCopyCurrentRow",
scope: "grid",
defaultShortcut: "Mod+D",
},
{
id: "deleteCurrentRow",
labelKey: "settings.shortcutDeleteCurrentRow",
scope: "grid",
defaultShortcut: "Delete",
},
{
id: "newQuery",
labelKey: "settings.shortcutNewQuery",
scope: "global",
defaultShortcut: "Mod+T",
},
{
id: "openSettings",
labelKey: "settings.shortcutOpenSettings",
scope: "global",
defaultShortcut: "Mod+,",
},
{
id: "closeTab",
labelKey: "settings.shortcutCloseTab",
scope: "global",
defaultShortcut: "Meta+W",
},
{
id: "focusSearch",
labelKey: "settings.shortcutFocusSearch",
scope: "global",
defaultShortcut: "Mod+F",
},
{
id: "zoomInUi",
labelKey: "settings.shortcutZoomInUi",
scope: "global",
defaultShortcut: "Mod+=",
},
{
id: "zoomOutUi",
labelKey: "settings.shortcutZoomOutUi",
scope: "global",
defaultShortcut: "Mod+-",
},
{
id: "resetUiZoom",
labelKey: "settings.shortcutResetUiZoom",
scope: "global",
defaultShortcut: "Mod+0",
},
{
id: "find",
labelKey: "settings.shortcutFind",
scope: "editor",
defaultShortcut: "Mod+F",
},
{
id: "replace",
labelKey: "settings.shortcutReplace",
scope: "editor",
defaultShortcut: "Mod+R",
},
{
id: "refreshData",
labelKey: "settings.shortcutRefreshData",
scope: "global",
defaultShortcut: "F5",
},
{
id: "toggleTranspose",
labelKey: "settings.shortcutToggleTranspose",
scope: "grid",
defaultShortcut: "Tab",
},
{
id: "cancelSearch",
labelKey: "settings.shortcutCancelSearch",
scope: "search",
defaultShortcut: "Escape",
},
{
id: "toggleSidebar",
labelKey: "settings.shortcutToggleSidebar",
scope: "global",
defaultShortcut: "Mod+B",
},
];
export const DEFAULT_SHORTCUT_SETTINGS: ShortcutSettings = Object.fromEntries(SHORTCUT_DEFINITIONS.map((definition) => [definition.id, definition.defaultShortcut])) as ShortcutSettings;
export function normalizeShortcutSettings(settings?: Partial<ShortcutSettings>): ShortcutSettings {
return Object.fromEntries(SHORTCUT_DEFINITIONS.map((definition) => [definition.id, typeof settings?.[definition.id] === "string" ? settings[definition.id] : definition.defaultShortcut])) as ShortcutSettings;
}
export function shortcutToCodeMirrorKey(shortcut: string): string {
return shortcut
.split("+")
.map((part) => (part.length === 1 ? part.toLowerCase() : part))
.join("-");
}
export function formatShortcut(shortcut: string, platform = globalThis.navigator?.platform || ""): string {
const isMac = platform.toLowerCase().includes("mac");
return shortcut
.split("+")
.map((part) => {
if (part === "Mod") return isMac ? "Cmd" : "Ctrl";
if (part === "Meta") return isMac ? "Cmd" : "Meta";
return part;
})
.join("+");
}
export function findShortcutConflict(actionId: ShortcutActionId, shortcut: string, shortcuts: ShortcutSettings): ShortcutActionId | null {
if (!shortcut) return null;
const definition = SHORTCUT_DEFINITIONS.find((item) => item.id === actionId);
if (!definition) return null;
const conflict = SHORTCUT_DEFINITIONS.find((item) => item.id !== actionId && item.scope === definition.scope && shortcuts[item.id] === shortcut);
return conflict?.id ?? null;
}