From 2d89dd43f29450b20d164c1622d695e78b0c59ea Mon Sep 17 00:00:00 2001 From: sudacode Date: Fri, 20 Feb 2026 03:18:22 -0800 Subject: [PATCH] refactor: extract global shortcuts runtime wiring --- docs/subagents/INDEX.md | 2 +- .../codex-task85-20260219T233711Z-46hc.md | 4 ++ src/main.ts | 62 +++++-------------- .../global-shortcuts-runtime-handlers.test.ts | 57 +++++++++++++++++ .../global-shortcuts-runtime-handlers.ts | 60 ++++++++++++++++++ 5 files changed, 136 insertions(+), 49 deletions(-) create mode 100644 src/main/runtime/global-shortcuts-runtime-handlers.test.ts create mode 100644 src/main/runtime/global-shortcuts-runtime-handlers.ts diff --git a/docs/subagents/INDEX.md b/docs/subagents/INDEX.md index fe6e30b..5417c32 100644 --- a/docs/subagents/INDEX.md +++ b/docs/subagents/INDEX.md @@ -6,7 +6,7 @@ Read first. Keep concise. | ------------ | -------------- | ---------------------------------------------------- | --------- | ------------------------------------- | ---------------------- | | `codex-generate-minecard-image-20260220T112900Z-vsxr` | `codex-generate-minecard-image` | `Generate media fallbacks (GIF) from assets/minecard.webm and wire README/docs fallback markup` | `done` | `docs/subagents/agents/codex-generate-minecard-image-20260220T112900Z-vsxr.md` | `2026-02-20T11:35:30Z` | | `codex-main` | `planner-exec` | `Fix frequency/N+1 regression in plugin --start flow` | `in_progress` | `docs/subagents/agents/codex-main.md` | `2026-02-19T19:36:46Z` | -| `codex-task85-20260219T233711Z-46hc` | `codex-task85` | `Resume TASK-85 maintainability refactor from latest handoff point` | `in_progress` | `docs/subagents/agents/codex-task85-20260219T233711Z-46hc.md` | `2026-02-20T11:15:54Z` | +| `codex-task85-20260219T233711Z-46hc` | `codex-task85` | `Resume TASK-85 maintainability refactor from latest handoff point` | `in_progress` | `docs/subagents/agents/codex-task85-20260219T233711Z-46hc.md` | `2026-02-20T11:18:02Z` | | `codex-config-validation-20260219T172015Z-iiyf` | `codex-config-validation` | `Find root cause of config validation error for ~/.config/SubMiner/config.jsonc` | `completed` | `docs/subagents/agents/codex-config-validation-20260219T172015Z-iiyf.md` | `2026-02-19T17:26:17Z` | | `codex-task85-20260219T233711Z-46hc` | `codex-task85` | `Resume TASK-85 maintainability refactor from latest handoff point` | `in_progress` | `docs/subagents/agents/codex-task85-20260219T233711Z-46hc.md` | `2026-02-20T02:56:34Z` | | `codex-anilist-deeplink-20260219T233926Z` | `anilist-deeplink` | `Fix external subminer:// AniList callback handling from browser` | `done` | `docs/subagents/agents/codex-anilist-deeplink-20260219T233926Z.md` | `2026-02-19T23:59:21Z` | diff --git a/docs/subagents/agents/codex-task85-20260219T233711Z-46hc.md b/docs/subagents/agents/codex-task85-20260219T233711Z-46hc.md index 6a03979..4c6002b 100644 --- a/docs/subagents/agents/codex-task85-20260219T233711Z-46hc.md +++ b/docs/subagents/agents/codex-task85-20260219T233711Z-46hc.md @@ -9,6 +9,10 @@ ## Current Work (newest first) +- [2026-02-20T11:18:02Z] progress: extracted global shortcuts composition from `src/main.ts` into `src/main/runtime/global-shortcuts-runtime-handlers.ts`; `main.ts` now obtains `getConfiguredShortcuts`/`registerGlobalShortcuts`/`refreshGlobalAndOverlayShortcuts` from one runtime factory. +- [2026-02-20T11:18:02Z] progress: added parity coverage in `src/main/runtime/global-shortcuts-runtime-handlers.test.ts` for get/register/refresh wiring. +- [2026-02-20T11:18:02Z] test: `bun run build` pass (expected macOS helper Swift cache fallback) + focused suites pass for `global-shortcuts-runtime-handlers*`, `global-shortcuts*`, `global-shortcuts-main-deps*`, `cli-command-runtime-handler*`, and `startup-runtime-handlers*` (9/9). +- [2026-02-20T11:18:02Z] scope: staging `src/main.ts`, new global-shortcuts runtime handlers module/test, and subagent bookkeeping only. - [2026-02-20T11:15:54Z] progress: extracted CLI command composition from `src/main.ts` into `src/main/runtime/cli-command-runtime-handler.ts`; `main.ts` now creates `handleCliCommand` via one runtime factory (precheck + context + runtime dispatch wiring). - [2026-02-20T11:15:54Z] progress: added `src/main/runtime/cli-command-runtime-handler.test.ts` to lock composed behavior around texthooker precheck, context creation, and `'initial'` source forwarding. - [2026-02-20T11:15:54Z] test: `bun run build` pass (expected macOS helper Swift cache fallback) + focused suites pass for `cli-command-runtime-handler*`, `cli-command-prechecks*`, `cli-command-context-factory*`, `initial-args-runtime-handler*`, and `startup-runtime-handlers*` (7/7). diff --git a/src/main.ts b/src/main.ts index 26833ca..09deea7 100644 --- a/src/main.ts +++ b/src/main.ts @@ -287,16 +287,7 @@ import { createBuildUpdateVisibleOverlayBoundsMainDepsHandler, } from './main/runtime/overlay-window-layout-main-deps'; import { buildTrayMenuTemplateRuntime, resolveTrayIconPathRuntime } from './main/runtime/tray-runtime'; -import { - createGetConfiguredShortcutsHandler, - createRefreshGlobalAndOverlayShortcutsHandler, - createRegisterGlobalShortcutsHandler, -} from './main/runtime/global-shortcuts'; -import { - createBuildGetConfiguredShortcutsMainDepsHandler, - createBuildRefreshGlobalAndOverlayShortcutsMainDepsHandler, - createBuildRegisterGlobalShortcutsMainDepsHandler, -} from './main/runtime/global-shortcuts-main-deps'; +import { createGlobalShortcutsRuntimeHandlers } from './main/runtime/global-shortcuts-runtime-handlers'; import { createAppendToMpvLogHandler, createShowMpvOsdHandler } from './main/runtime/mpv-osd-log'; import { createBuildAppendToMpvLogMainDepsHandler, @@ -2505,56 +2496,31 @@ function openYomitanSettings(): void { openYomitanSettingsHandler(); } -const buildGetConfiguredShortcutsMainDepsHandler = createBuildGetConfiguredShortcutsMainDepsHandler( - { +const { + getConfiguredShortcuts, + registerGlobalShortcuts, + refreshGlobalAndOverlayShortcuts, +} = createGlobalShortcutsRuntimeHandlers({ + getConfiguredShortcutsMainDeps: { getResolvedConfig: () => getResolvedConfig(), defaultConfig: DEFAULT_CONFIG, resolveConfiguredShortcuts, }, -); -const getConfiguredShortcutsMainDeps = buildGetConfiguredShortcutsMainDepsHandler(); -const getConfiguredShortcutsHandler = createGetConfiguredShortcutsHandler( - getConfiguredShortcutsMainDeps, -); - -const buildRegisterGlobalShortcutsMainDepsHandler = - createBuildRegisterGlobalShortcutsMainDepsHandler({ - getConfiguredShortcuts: () => getConfiguredShortcuts(), + buildRegisterGlobalShortcutsMainDeps: (getConfiguredShortcutsHandler) => ({ + getConfiguredShortcuts: () => getConfiguredShortcutsHandler(), registerGlobalShortcutsCore, toggleVisibleOverlay: () => toggleVisibleOverlay(), toggleInvisibleOverlay: () => toggleInvisibleOverlay(), openYomitanSettings: () => openYomitanSettings(), isDev, getMainWindow: () => overlayManager.getMainWindow(), - }); -const registerGlobalShortcutsMainDeps = buildRegisterGlobalShortcutsMainDepsHandler(); -const registerGlobalShortcutsHandler = createRegisterGlobalShortcutsHandler( - registerGlobalShortcutsMainDeps, -); - -const buildRefreshGlobalAndOverlayShortcutsMainDepsHandler = - createBuildRefreshGlobalAndOverlayShortcutsMainDepsHandler({ + }), + buildRefreshGlobalAndOverlayShortcutsMainDeps: (registerGlobalShortcutsHandler) => ({ unregisterAllGlobalShortcuts: () => globalShortcut.unregisterAll(), - registerGlobalShortcuts: () => registerGlobalShortcuts(), + registerGlobalShortcuts: () => registerGlobalShortcutsHandler(), syncOverlayShortcuts: () => syncOverlayShortcuts(), - }); -const refreshGlobalAndOverlayShortcutsMainDeps = - buildRefreshGlobalAndOverlayShortcutsMainDepsHandler(); -const refreshGlobalAndOverlayShortcutsHandler = createRefreshGlobalAndOverlayShortcutsHandler( - refreshGlobalAndOverlayShortcutsMainDeps, -); - -function registerGlobalShortcuts(): void { - registerGlobalShortcutsHandler(); -} - -function refreshGlobalAndOverlayShortcuts(): void { - refreshGlobalAndOverlayShortcutsHandler(); -} - -function getConfiguredShortcuts() { - return getConfiguredShortcutsHandler(); -} + }), +}); const buildCycleSecondarySubModeMainDepsHandler = createBuildCycleSecondarySubModeMainDepsHandler( { diff --git a/src/main/runtime/global-shortcuts-runtime-handlers.test.ts b/src/main/runtime/global-shortcuts-runtime-handlers.test.ts new file mode 100644 index 0000000..2665177 --- /dev/null +++ b/src/main/runtime/global-shortcuts-runtime-handlers.test.ts @@ -0,0 +1,57 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import type { ConfiguredShortcuts } from '../../core/utils/shortcut-config'; +import { createGlobalShortcutsRuntimeHandlers } from './global-shortcuts-runtime-handlers'; + +function createShortcuts(): ConfiguredShortcuts { + return { + toggleVisibleOverlayGlobal: 'CommandOrControl+Shift+O', + toggleInvisibleOverlayGlobal: 'CommandOrControl+Shift+I', + copySubtitle: 's', + copySubtitleMultiple: 'CommandOrControl+s', + updateLastCardFromClipboard: 'c', + triggerFieldGrouping: null, + triggerSubsync: null, + mineSentence: 'q', + mineSentenceMultiple: 'w', + multiCopyTimeoutMs: 5000, + toggleSecondarySub: null, + markAudioCard: null, + openRuntimeOptions: null, + openJimaku: null, + }; +} + +test('global shortcuts runtime handlers compose get/register/refresh flow', () => { + const calls: string[] = []; + const shortcuts = createShortcuts(); + const runtime = createGlobalShortcutsRuntimeHandlers({ + getConfiguredShortcutsMainDeps: { + getResolvedConfig: () => ({}) as never, + defaultConfig: {} as never, + resolveConfiguredShortcuts: () => shortcuts, + }, + buildRegisterGlobalShortcutsMainDeps: (getConfiguredShortcuts) => ({ + getConfiguredShortcuts, + registerGlobalShortcutsCore: (options) => { + calls.push('register'); + assert.equal(options.shortcuts, shortcuts); + }, + toggleVisibleOverlay: () => calls.push('toggle-visible'), + toggleInvisibleOverlay: () => calls.push('toggle-invisible'), + openYomitanSettings: () => calls.push('open-yomitan'), + isDev: false, + getMainWindow: () => null, + }), + buildRefreshGlobalAndOverlayShortcutsMainDeps: (registerGlobalShortcuts) => ({ + unregisterAllGlobalShortcuts: () => calls.push('unregister'), + registerGlobalShortcuts: () => registerGlobalShortcuts(), + syncOverlayShortcuts: () => calls.push('sync-overlay'), + }), + }); + + assert.equal(runtime.getConfiguredShortcuts(), shortcuts); + runtime.registerGlobalShortcuts(); + runtime.refreshGlobalAndOverlayShortcuts(); + assert.deepEqual(calls, ['register', 'unregister', 'register', 'sync-overlay']); +}); diff --git a/src/main/runtime/global-shortcuts-runtime-handlers.ts b/src/main/runtime/global-shortcuts-runtime-handlers.ts new file mode 100644 index 0000000..00d6013 --- /dev/null +++ b/src/main/runtime/global-shortcuts-runtime-handlers.ts @@ -0,0 +1,60 @@ +import type { ConfiguredShortcuts } from '../../core/utils/shortcut-config'; +import { + createGetConfiguredShortcutsHandler, + createRefreshGlobalAndOverlayShortcutsHandler, + createRegisterGlobalShortcutsHandler, +} from './global-shortcuts'; +import { + createBuildGetConfiguredShortcutsMainDepsHandler, + createBuildRefreshGlobalAndOverlayShortcutsMainDepsHandler, + createBuildRegisterGlobalShortcutsMainDepsHandler, +} from './global-shortcuts-main-deps'; + +type GetConfiguredShortcutsMainDeps = Parameters< + typeof createBuildGetConfiguredShortcutsMainDepsHandler +>[0]; +type RegisterGlobalShortcutsMainDeps = Parameters< + typeof createBuildRegisterGlobalShortcutsMainDepsHandler +>[0]; +type RefreshGlobalAndOverlayShortcutsMainDeps = Parameters< + typeof createBuildRefreshGlobalAndOverlayShortcutsMainDepsHandler +>[0]; + +export function createGlobalShortcutsRuntimeHandlers(deps: { + getConfiguredShortcutsMainDeps: GetConfiguredShortcutsMainDeps; + buildRegisterGlobalShortcutsMainDeps: ( + getConfiguredShortcuts: () => ConfiguredShortcuts, + ) => RegisterGlobalShortcutsMainDeps; + buildRefreshGlobalAndOverlayShortcutsMainDeps: ( + registerGlobalShortcuts: () => void, + ) => RefreshGlobalAndOverlayShortcutsMainDeps; +}) { + const getConfiguredShortcutsMainDeps = createBuildGetConfiguredShortcutsMainDepsHandler( + deps.getConfiguredShortcutsMainDeps, + )(); + const getConfiguredShortcutsHandler = + createGetConfiguredShortcutsHandler(getConfiguredShortcutsMainDeps); + const getConfiguredShortcuts = () => getConfiguredShortcutsHandler(); + + const registerGlobalShortcutsMainDeps = createBuildRegisterGlobalShortcutsMainDepsHandler( + deps.buildRegisterGlobalShortcutsMainDeps(getConfiguredShortcuts), + )(); + const registerGlobalShortcutsHandler = + createRegisterGlobalShortcutsHandler(registerGlobalShortcutsMainDeps); + const registerGlobalShortcuts = () => registerGlobalShortcutsHandler(); + + const refreshGlobalAndOverlayShortcutsMainDeps = + createBuildRefreshGlobalAndOverlayShortcutsMainDepsHandler( + deps.buildRefreshGlobalAndOverlayShortcutsMainDeps(registerGlobalShortcuts), + )(); + const refreshGlobalAndOverlayShortcutsHandler = createRefreshGlobalAndOverlayShortcutsHandler( + refreshGlobalAndOverlayShortcutsMainDeps, + ); + const refreshGlobalAndOverlayShortcuts = () => refreshGlobalAndOverlayShortcutsHandler(); + + return { + getConfiguredShortcuts, + registerGlobalShortcuts, + refreshGlobalAndOverlayShortcuts, + }; +}