@tooee/commands 0.1.16 → 0.1.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/context.d.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import { type ReactNode } from "react";
2
- import type { Command, CommandContext, CommandRegistry } from "./types.js";
2
+ import type { Command, CommandContext, CommandGroup, CommandRegistry, CommandSequenceState, RegisteredCommandGroup } from "./types.js";
3
3
  import type { Mode } from "./mode.js";
4
4
  type ContextGetter = () => Partial<CommandContext>;
5
5
  interface CommandContextValue {
6
6
  registry: CommandRegistry;
7
7
  leaderKey?: string;
8
8
  contextSources: Map<string, ContextGetter>;
9
+ groups: Map<string, RegisteredCommandGroup>;
9
10
  }
10
11
  declare const CommandContext: import("react").Context<CommandContextValue | null>;
11
12
  export interface CommandProviderProps {
@@ -20,6 +21,8 @@ export declare function useCommandContext(): {
20
21
  invoke: (id: string) => void;
21
22
  };
22
23
  export declare function useCommandRegistry(): CommandContextValue;
24
+ export declare function useCommandSequenceState(): CommandSequenceState | null;
25
+ export declare function useCommandGroup(group: CommandGroup): void;
23
26
  export declare function useProvideCommandContext(getter: () => Partial<CommandContext>): void;
24
27
  export {};
25
28
  //# sourceMappingURL=context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AAEd,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAgB,MAAM,YAAY,CAAA;AACxF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAQrC,KAAK,aAAa,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,CAAA;AAElD,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,eAAe,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;CAC3C;AAED,QAAA,MAAM,cAAc,qDAAkD,CAAA;AAEtE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,SAAS,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,WAAW,CAAC,EAAE,IAAI,CAAA;CACnB;AAED,wBAAgB,eAAe,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,oBAAoB,aAQ9F;AAuID,wBAAgB,iBAAiB,IAAI;IAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAAC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,CAazF;AAED,wBAAgB,kBAAkB,IAAI,mBAAmB,CAMxD;AAID,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,CAuBpF"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AAEd,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,YAAY,EACZ,eAAe,EACf,oBAAoB,EAGpB,sBAAsB,EACvB,MAAM,YAAY,CAAA;AACnB,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAQrC,KAAK,aAAa,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,CAAA;AAElD,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,eAAe,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;IAC1C,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAA;CAC5C;AAED,QAAA,MAAM,cAAc,qDAAkD,CAAA;AAGtE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,SAAS,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,WAAW,CAAC,EAAE,IAAI,CAAA;CACnB;AAED,wBAAgB,eAAe,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,oBAAoB,aAQ9F;AA8KD,wBAAgB,iBAAiB,IAAI;IAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAAC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,CAazF;AAED,wBAAgB,kBAAkB,IAAI,mBAAmB,CAMxD;AAED,wBAAgB,uBAAuB,IAAI,oBAAoB,GAAG,IAAI,CAErE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CA8BzD;AAkBD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,CAuBpF"}
package/dist/context.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "@opentui/react/jsx-runtime";
2
- import { createContext, useContext, useRef, useCallback, useEffect, useMemo, } from "react";
2
+ import { createContext, useContext, useRef, useCallback, useEffect, useMemo, useState, } from "react";
3
3
  import { useKeyboard } from "@opentui/react";
4
4
  import { ModeProvider, useMode, useSetMode } from "./mode.js";
5
5
  import { parseHotkey } from "./parse.js";
@@ -7,16 +7,21 @@ import { matchStep } from "./match.js";
7
7
  import { SequenceTracker } from "./sequence.js";
8
8
  const DEFAULT_MODES = ["cursor"];
9
9
  const CommandContext = createContext(null);
10
+ const CommandSequenceContext = createContext(null);
10
11
  export function CommandProvider({ children, leader, keymap, initialMode }) {
11
12
  return (_jsx(ModeProvider, { initialMode: initialMode, children: _jsx(CommandDispatcher, { leader: leader, keymap: keymap, children: children }) }));
12
13
  }
13
14
  function CommandDispatcher({ children, leader, keymap, }) {
14
15
  const registryRef = useRef(null);
15
16
  const contextSourcesRef = useRef(new Map());
17
+ const groupsRef = useRef(new Map());
16
18
  const mode = useMode();
17
19
  const modeRef = useRef(mode);
18
20
  modeRef.current = mode;
19
21
  const setMode = useSetMode();
22
+ const [sequenceState, setSequenceState] = useState(null);
23
+ const clearSequenceStateRef = useRef(() => setSequenceState(null));
24
+ clearSequenceStateRef.current = () => setSequenceState(null);
20
25
  const buildCtx = useCallback(() => {
21
26
  const ctx = {
22
27
  mode: modeRef.current,
@@ -51,7 +56,7 @@ function CommandDispatcher({ children, leader, keymap, }) {
51
56
  },
52
57
  };
53
58
  }
54
- const trackerRef = useRef(new SequenceTracker());
59
+ const trackerRef = useRef(new SequenceTracker({ onReset: () => clearSequenceStateRef.current() }));
55
60
  const parseCacheRef = useRef(new Map());
56
61
  const getParsedHotkey = useCallback((hotkey) => {
57
62
  const cache = parseCacheRef.current;
@@ -73,8 +78,7 @@ function CommandDispatcher({ children, leader, keymap, }) {
73
78
  const ctx = buildCtx();
74
79
  // Collect eligible commands with their parsed hotkeys
75
80
  const singleStepCandidates = [];
76
- const multiStepHotkeys = [];
77
- const multiStepCommands = [];
81
+ const multiStepCandidates = [];
78
82
  for (const command of registry.commands.values()) {
79
83
  const commandModes = command.modes ?? DEFAULT_MODES;
80
84
  if (!commandModes.includes(currentMode))
@@ -89,34 +93,61 @@ function CommandDispatcher({ children, leader, keymap, }) {
89
93
  singleStepCandidates.push({ command, parsed });
90
94
  }
91
95
  else {
92
- multiStepHotkeys.push(parsed);
93
- multiStepCommands.push(command);
96
+ multiStepCandidates.push({ command, hotkey, parsed });
94
97
  }
95
98
  }
96
99
  // Check multi-step sequences first (they consume buffer state)
97
- if (multiStepHotkeys.length > 0) {
98
- const idx = trackerRef.current.feed(event, multiStepHotkeys);
99
- if (idx >= 0) {
100
+ if (multiStepCandidates.length > 0) {
101
+ const multiStepHotkeys = multiStepCandidates.map((candidate) => candidate.parsed);
102
+ const result = trackerRef.current.feedWithState(event, multiStepHotkeys);
103
+ if (result.matchedIndex >= 0) {
100
104
  event.preventDefault();
101
- multiStepCommands[idx].handler(ctx);
105
+ setSequenceState(null);
106
+ multiStepCandidates[result.matchedIndex].command.handler(ctx);
102
107
  return;
103
108
  }
109
+ if (result.pending) {
110
+ const firstCandidate = multiStepCandidates[result.pending.indexes[0]];
111
+ setSequenceState({
112
+ prefix: firstCandidate.parsed.steps.slice(0, result.pending.prefixLength),
113
+ candidates: result.pending.indexes
114
+ .map((idx) => multiStepCandidates[idx])
115
+ .filter(({ command }) => !command.hidden)
116
+ .map(({ command, hotkey, parsed }) => ({
117
+ command,
118
+ hotkey,
119
+ steps: parsed.steps,
120
+ remainingSteps: parsed.steps.slice(result.pending.prefixLength),
121
+ nextStep: parsed.steps[result.pending.prefixLength],
122
+ group: groupsRef.current.get(stepsKey(parsed.steps.slice(0, result.pending.prefixLength + 1))),
123
+ })),
124
+ });
125
+ event.preventDefault();
126
+ return;
127
+ }
128
+ setSequenceState(null);
104
129
  }
105
130
  // Check single-step matches
106
131
  for (const { command, parsed } of singleStepCandidates) {
107
132
  if (matchStep(event, parsed.steps[0])) {
108
133
  event.preventDefault();
134
+ setSequenceState(null);
109
135
  command.handler(ctx);
110
136
  return;
111
137
  }
112
138
  }
113
139
  });
140
+ useEffect(() => {
141
+ trackerRef.current.reset();
142
+ setSequenceState(null);
143
+ }, [mode]);
114
144
  const ctxValue = useMemo(() => ({
115
145
  registry: registryRef.current,
116
146
  leaderKey: leader,
117
147
  contextSources: contextSourcesRef.current,
148
+ groups: groupsRef.current,
118
149
  }), [leader]);
119
- return _jsx(CommandContext.Provider, { value: ctxValue, children: children });
150
+ return (_jsx(CommandContext.Provider, { value: ctxValue, children: _jsx(CommandSequenceContext, { value: sequenceState, children: children }) }));
120
151
  }
121
152
  export function useCommandContext() {
122
153
  const ctx = useContext(CommandContext);
@@ -138,6 +169,54 @@ export function useCommandRegistry() {
138
169
  }
139
170
  return ctx;
140
171
  }
172
+ export function useCommandSequenceState() {
173
+ return useContext(CommandSequenceContext);
174
+ }
175
+ export function useCommandGroup(group) {
176
+ const ctx = useContext(CommandContext);
177
+ if (!ctx) {
178
+ throw new Error("useCommandGroup must be used within a CommandProvider");
179
+ }
180
+ const groupRef = useRef(group);
181
+ groupRef.current = group;
182
+ const { groups, leaderKey } = ctx;
183
+ useEffect(() => {
184
+ const parsed = parseHotkey(groupRef.current.prefix, leaderKey);
185
+ const registered = {
186
+ ...groupRef.current,
187
+ prefixKey: stepsKey(parsed.steps),
188
+ };
189
+ groups.set(registered.prefixKey, registered);
190
+ return () => {
191
+ groups.delete(registered.prefixKey);
192
+ };
193
+ }, [
194
+ group.id,
195
+ group.prefix,
196
+ group.title,
197
+ group.description,
198
+ group.icon,
199
+ group.order,
200
+ groups,
201
+ leaderKey,
202
+ ]);
203
+ }
204
+ function stepsKey(steps) {
205
+ return steps.map(formatStepKey).join(" ");
206
+ }
207
+ function formatStepKey(step) {
208
+ const modifiers = [];
209
+ if (step.ctrl)
210
+ modifiers.push("ctrl");
211
+ if (step.meta)
212
+ modifiers.push("meta");
213
+ if (step.option)
214
+ modifiers.push("option");
215
+ if (step.shift)
216
+ modifiers.push("shift");
217
+ modifiers.push(step.key);
218
+ return modifiers.join("+");
219
+ }
141
220
  let nextContextSourceId = 0;
142
221
  export function useProvideCommandContext(getter) {
143
222
  const ctx = useContext(CommandContext);
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.tsx"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
- export type { Command, CommandContext, CommandContextBase, CommandHandler, CommandWhen, ParsedHotkey, ParsedStep, } from "./types.js";
1
+ export type { Command, CommandContext, CommandContextBase, CommandGroup, CommandHandler, CommandSequenceCandidate, CommandSequenceState, CommandWhen, ParsedHotkey, ParsedStep, RegisteredCommandGroup, } from "./types.js";
2
2
  export type { Mode } from "./mode.js";
3
3
  export { ModeProvider, useMode, useSetMode } from "./mode.js";
4
4
  export type { ModeProviderProps } from "./mode.js";
5
5
  export { parseHotkey } from "./parse.js";
6
6
  export { matchStep } from "./match.js";
7
7
  export { SequenceTracker } from "./sequence.js";
8
- export type { SequenceTrackerOptions } from "./sequence.js";
9
- export { CommandProvider, useCommandContext, useProvideCommandContext } from "./context.js";
8
+ export type { SequenceFeedResult, SequencePendingMatch, SequenceTrackerOptions, } from "./sequence.js";
9
+ export { CommandProvider, useCommandContext, useCommandGroup, useCommandRegistry, useCommandSequenceState, useProvideCommandContext, } from "./context.js";
10
10
  export type { CommandProviderProps } from "./context.js";
11
11
  export { useCommand } from "./use-command.js";
12
12
  export type { UseCommandOptions } from "./use-command.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,OAAO,EACP,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,WAAW,EACX,YAAY,EACZ,UAAU,GACX,MAAM,YAAY,CAAA;AACnB,YAAY,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC7D,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAC/C,YAAY,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAA;AAC3D,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAA;AAC3F,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,OAAO,EACP,cAAc,EACd,kBAAkB,EAClB,YAAY,EACZ,cAAc,EACd,wBAAwB,EACxB,oBAAoB,EACpB,WAAW,EACX,YAAY,EACZ,UAAU,EACV,sBAAsB,GACvB,MAAM,YAAY,CAAA;AACnB,YAAY,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC7D,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAC/C,YAAY,EACV,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,cAAc,CAAA;AACrB,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA"}
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ export { ModeProvider, useMode, useSetMode } from "./mode.js";
2
2
  export { parseHotkey } from "./parse.js";
3
3
  export { matchStep } from "./match.js";
4
4
  export { SequenceTracker } from "./sequence.js";
5
- export { CommandProvider, useCommandContext, useProvideCommandContext } from "./context.js";
5
+ export { CommandProvider, useCommandContext, useCommandGroup, useCommandRegistry, useCommandSequenceState, useProvideCommandContext, } from "./context.js";
6
6
  export { useCommand } from "./use-command.js";
7
7
  export { useActions } from "./use-actions.js";
8
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE7D,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAE/C,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAA;AAE3F,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE7D,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAM/C,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA"}
@@ -2,18 +2,34 @@ import type { KeyEvent } from "@opentui/core";
2
2
  import type { ParsedHotkey } from "./types.js";
3
3
  export interface SequenceTrackerOptions {
4
4
  timeout?: number;
5
+ onReset?: () => void;
6
+ }
7
+ export interface SequencePendingMatch {
8
+ prefixLength: number;
9
+ indexes: number[];
10
+ }
11
+ export interface SequenceFeedResult {
12
+ matchedIndex: number;
13
+ pending: SequencePendingMatch | null;
5
14
  }
6
15
  export declare class SequenceTracker {
7
16
  private buffer;
8
17
  private timer;
9
18
  private timeout;
19
+ private onReset?;
10
20
  constructor(options?: SequenceTrackerOptions);
11
21
  /**
12
22
  * Feed a key event and check against registered hotkeys.
13
- * Returns the index of the matched hotkey, or -1 if no match.
23
+ * Returns the index of the matched hotkey, or -1 if no full match.
14
24
  */
15
25
  feed(event: KeyEvent, hotkeys: ParsedHotkey[]): number;
26
+ /**
27
+ * Feed a key event and return both full-match and pending-prefix state.
28
+ */
29
+ feedWithState(event: KeyEvent, hotkeys: ParsedHotkey[]): SequenceFeedResult;
30
+ getPendingMatch(hotkeys: ParsedHotkey[]): SequencePendingMatch | null;
16
31
  private matchesBuffer;
32
+ private findPendingMatch;
17
33
  reset(): void;
18
34
  private resetTimer;
19
35
  private clearTimer;
@@ -1 +1 @@
1
- {"version":3,"file":"sequence.d.ts","sourceRoot":"","sources":["../src/sequence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAG9C,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,OAAO,CAAQ;gBAEX,OAAO,CAAC,EAAE,sBAAsB;IAI5C;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM;IAqBtD,OAAO,CAAC,aAAa;IAWrB,KAAK,IAAI,IAAI;IAKb,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,UAAU;CAMnB"}
1
+ {"version":3,"file":"sequence.d.ts","sourceRoot":"","sources":["../src/sequence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAG9C,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAAA;CACrC;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,OAAO,CAAC,CAAY;gBAEhB,OAAO,CAAC,EAAE,sBAAsB;IAK5C;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM;IAItD;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,kBAAkB;IAuB3E,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,oBAAoB,GAAG,IAAI;IAIrE,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,gBAAgB;IA+BxB,KAAK,IAAI,IAAI;IAOb,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,UAAU;CAMnB"}
package/dist/sequence.js CHANGED
@@ -3,29 +3,42 @@ export class SequenceTracker {
3
3
  buffer = [];
4
4
  timer = null;
5
5
  timeout;
6
+ onReset;
6
7
  constructor(options) {
7
8
  this.timeout = options?.timeout ?? 500;
9
+ this.onReset = options?.onReset;
8
10
  }
9
11
  /**
10
12
  * Feed a key event and check against registered hotkeys.
11
- * Returns the index of the matched hotkey, or -1 if no match.
13
+ * Returns the index of the matched hotkey, or -1 if no full match.
12
14
  */
13
15
  feed(event, hotkeys) {
16
+ return this.feedWithState(event, hotkeys).matchedIndex;
17
+ }
18
+ /**
19
+ * Feed a key event and return both full-match and pending-prefix state.
20
+ */
21
+ feedWithState(event, hotkeys) {
14
22
  this.buffer.push(event);
15
23
  this.resetTimer();
16
24
  for (let i = 0; i < hotkeys.length; i++) {
17
25
  const hotkey = hotkeys[i];
18
26
  if (this.matchesBuffer(hotkey)) {
19
27
  this.reset();
20
- return i;
28
+ return { matchedIndex: i, pending: null };
21
29
  }
22
30
  }
23
31
  // Prune buffer if no hotkey could possibly match
24
- const maxLen = Math.max(...hotkeys.map((h) => h.steps.length));
25
- if (this.buffer.length > maxLen) {
26
- this.buffer.shift();
32
+ const maxLen = Math.max(0, ...hotkeys.map((h) => h.steps.length));
33
+ if (maxLen > 0) {
34
+ while (this.buffer.length > maxLen) {
35
+ this.buffer.shift();
36
+ }
27
37
  }
28
- return -1;
38
+ return { matchedIndex: -1, pending: this.findPendingMatch(hotkeys) };
39
+ }
40
+ getPendingMatch(hotkeys) {
41
+ return this.findPendingMatch(hotkeys);
29
42
  }
30
43
  matchesBuffer(hotkey) {
31
44
  const { steps } = hotkey;
@@ -38,9 +51,36 @@ export class SequenceTracker {
38
51
  }
39
52
  return true;
40
53
  }
54
+ findPendingMatch(hotkeys) {
55
+ const maxPrefixLength = Math.min(this.buffer.length, Math.max(0, ...hotkeys.map((h) => h.steps.length - 1)));
56
+ for (let prefixLength = maxPrefixLength; prefixLength > 0; prefixLength--) {
57
+ const start = this.buffer.length - prefixLength;
58
+ const indexes = [];
59
+ for (let hotkeyIndex = 0; hotkeyIndex < hotkeys.length; hotkeyIndex++) {
60
+ const hotkey = hotkeys[hotkeyIndex];
61
+ if (hotkey.steps.length <= prefixLength)
62
+ continue;
63
+ let matches = true;
64
+ for (let i = 0; i < prefixLength; i++) {
65
+ if (!matchStep(this.buffer[start + i], hotkey.steps[i])) {
66
+ matches = false;
67
+ break;
68
+ }
69
+ }
70
+ if (matches)
71
+ indexes.push(hotkeyIndex);
72
+ }
73
+ if (indexes.length > 0)
74
+ return { prefixLength, indexes };
75
+ }
76
+ return null;
77
+ }
41
78
  reset() {
79
+ const hadBuffer = this.buffer.length > 0;
42
80
  this.buffer = [];
43
81
  this.clearTimer();
82
+ if (hadBuffer)
83
+ this.onReset?.();
44
84
  }
45
85
  resetTimer() {
46
86
  this.clearTimer();
@@ -1 +1 @@
1
- {"version":3,"file":"sequence.js","sourceRoot":"","sources":["../src/sequence.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAMtC,MAAM,OAAO,eAAe;IAClB,MAAM,GAAe,EAAE,CAAA;IACvB,KAAK,GAAyC,IAAI,CAAA;IAClD,OAAO,CAAQ;IAEvB,YAAY,OAAgC;QAC1C,IAAI,CAAC,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,GAAG,CAAA;IACxC,CAAC;IAED;;;OAGG;IACH,IAAI,CAAC,KAAe,EAAE,OAAuB;QAC3C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACvB,IAAI,CAAC,UAAU,EAAE,CAAA;QAEjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAE,CAAA;YAC1B,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC/B,IAAI,CAAC,KAAK,EAAE,CAAA;gBACZ,OAAO,CAAC,CAAA;YACV,CAAC;QACH,CAAC;QAED,iDAAiD;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;QAC9D,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC;YAChC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAA;QACrB,CAAC;QAED,OAAO,CAAC,CAAC,CAAA;IACX,CAAC;IAEO,aAAa,CAAC,MAAoB;QACxC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAA;QACxB,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM;YAAE,OAAO,KAAK,CAAA;QAEnD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAA;QAC/C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAE,EAAE,KAAK,CAAC,CAAC,CAAE,CAAC;gBAAE,OAAO,KAAK,CAAA;QAClE,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,EAAE,CAAA;QAChB,IAAI,CAAC,UAAU,EAAE,CAAA;IACnB,CAAC;IAEO,UAAU;QAChB,IAAI,CAAC,UAAU,EAAE,CAAA;QACjB,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;IAC3D,CAAC;IAEO,UAAU;QAChB,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACxB,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACxB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;QACnB,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"sequence.js","sourceRoot":"","sources":["../src/sequence.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -40,4 +40,27 @@ export interface CommandRegistry {
40
40
  register: (command: Command) => () => void;
41
41
  invoke: (id: string) => void;
42
42
  }
43
+ export interface CommandGroup {
44
+ id: string;
45
+ title: string;
46
+ prefix: string;
47
+ description?: string;
48
+ icon?: string;
49
+ order?: number;
50
+ }
51
+ export interface RegisteredCommandGroup extends CommandGroup {
52
+ prefixKey: string;
53
+ }
54
+ export interface CommandSequenceCandidate {
55
+ command: Command;
56
+ hotkey: string;
57
+ steps: ParsedStep[];
58
+ remainingSteps: ParsedStep[];
59
+ nextStep: ParsedStep;
60
+ group?: CommandGroup;
61
+ }
62
+ export interface CommandSequenceState {
63
+ prefix: ParsedStep[];
64
+ candidates: CommandSequenceCandidate[];
65
+ }
43
66
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAErC,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,IAAI,CAAA;IACV,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IAC7B,QAAQ,EAAE;QAAE,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,OAAO,EAAE,CAAA;KAAE,CAAA;IACjE,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB;AAED,MAAM,WAAW,cAAe,SAAQ,kBAAkB;IACxD,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAC1E,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAA;AAE1D,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,cAAc,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,KAAK,CAAC,EAAE,IAAI,EAAE,CAAA;IACd,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,UAAU,EAAE,CAAA;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,OAAO,CAAA;IACb,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,IAAI,CAAA;IAC1C,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAErC,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,IAAI,CAAA;IACV,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IAC7B,QAAQ,EAAE;QAAE,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,OAAO,EAAE,CAAA;KAAE,CAAA;IACjE,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB;AAED,MAAM,WAAW,cAAe,SAAQ,kBAAkB;IACxD,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAC1E,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAA;AAE1D,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,cAAc,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,KAAK,CAAC,EAAE,IAAI,EAAE,CAAA;IACd,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,UAAU,EAAE,CAAA;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,OAAO,CAAA;IACb,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,IAAI,CAAA;IAC1C,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,sBAAuB,SAAQ,YAAY;IAC1D,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,UAAU,EAAE,CAAA;IACnB,cAAc,EAAE,UAAU,EAAE,CAAA;IAC5B,QAAQ,EAAE,UAAU,CAAA;IACpB,KAAK,CAAC,EAAE,YAAY,CAAA;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,UAAU,EAAE,CAAA;IACpB,UAAU,EAAE,wBAAwB,EAAE,CAAA;CACvC"}
@@ -7,6 +7,10 @@ export interface ActionDefinition {
7
7
  modes?: Mode[];
8
8
  handler: CommandHandler;
9
9
  when?: CommandWhen;
10
+ category?: string;
11
+ group?: string;
12
+ icon?: string;
13
+ hidden?: boolean;
10
14
  }
11
15
  export declare function useActions(actions: ActionDefinition[] | undefined): void;
12
16
  //# sourceMappingURL=use-actions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-actions.d.ts","sourceRoot":"","sources":["../src/use-actions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAW,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACtE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAErC,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,IAAI,EAAE,CAAA;IACd,OAAO,EAAE,cAAc,CAAA;IACvB,IAAI,CAAC,EAAE,WAAW,CAAA;CACnB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,SAAS,GAAG,IAAI,CAgCxE"}
1
+ {"version":3,"file":"use-actions.d.ts","sourceRoot":"","sources":["../src/use-actions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAW,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACtE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAErC,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,IAAI,EAAE,CAAA;IACd,OAAO,EAAE,cAAc,CAAA;IACvB,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,SAAS,GAAG,IAAI,CA0CxE"}
@@ -4,7 +4,9 @@ export function useActions(actions) {
4
4
  const { registry } = useCommandRegistry();
5
5
  const actionsRef = useRef(actions);
6
6
  actionsRef.current = actions;
7
- const key = useMemo(() => actions?.map((a) => `${a.id}:${a.hotkey ?? ""}`).join(",") ?? "", [actions]);
7
+ const key = useMemo(() => actions
8
+ ?.map((a) => `${a.id}:${a.title}:${a.hotkey ?? ""}:${a.category ?? ""}:${a.group ?? ""}:${a.icon ?? ""}:${a.hidden ?? false}`)
9
+ .join(",") ?? "", [actions]);
8
10
  useEffect(() => {
9
11
  const current = actionsRef.current;
10
12
  if (!current || current.length === 0)
@@ -17,6 +19,10 @@ export function useActions(actions) {
17
19
  modes: action.modes,
18
20
  handler: (ctx) => actionsRef.current?.[i]?.handler(ctx),
19
21
  when: action.when ? (ctx) => actionsRef.current?.[i]?.when?.(ctx) ?? false : undefined,
22
+ category: action.category,
23
+ group: action.group,
24
+ icon: action.icon,
25
+ hidden: action.hidden,
20
26
  };
21
27
  return registry.register(command);
22
28
  });
@@ -1 +1 @@
1
- {"version":3,"file":"use-actions.js","sourceRoot":"","sources":["../src/use-actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAajD,MAAM,UAAU,UAAU,CAAC,OAAuC;IAChE,MAAM,EAAE,QAAQ,EAAE,GAAG,kBAAkB,EAAE,CAAA;IACzC,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAA;IAClC,UAAU,CAAC,OAAO,GAAG,OAAO,CAAA;IAE5B,MAAM,GAAG,GAAG,OAAO,CACjB,GAAG,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EACtE,CAAC,OAAO,CAAC,CACV,CAAA;IAED,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAA;QAClC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QAE5C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YAC5C,MAAM,OAAO,GAAY;gBACvB,EAAE,EAAE,MAAM,CAAC,EAAE;gBACb,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,aAAa,EAAE,MAAM,CAAC,MAAM;gBAC5B,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC;gBACvD,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,SAAS;aACvF,CAAA;YACD,OAAO,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;QACnC,CAAC,CAAC,CAAA;QAEF,OAAO,GAAG,EAAE;YACV,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;gBACrC,UAAU,EAAE,CAAA;YACd,CAAC;QACH,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAA;AACrB,CAAC"}
1
+ {"version":3,"file":"use-actions.js","sourceRoot":"","sources":["../src/use-actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAiBjD,MAAM,UAAU,UAAU,CAAC,OAAuC;IAChE,MAAM,EAAE,QAAQ,EAAE,GAAG,kBAAkB,EAAE,CAAA;IACzC,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAA;IAClC,UAAU,CAAC,OAAO,GAAG,OAAO,CAAA;IAE5B,MAAM,GAAG,GAAG,OAAO,CACjB,GAAG,EAAE,CACH,OAAO;QACL,EAAE,GAAG,CACH,CAAC,CAAC,EAAE,EAAE,CACJ,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,IAAI,EAAE,IAAI,CAAC,CAAC,QAAQ,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC,CAAC,MAAM,IAAI,KAAK,EAAE,CACnH;SACA,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EACpB,CAAC,OAAO,CAAC,CACV,CAAA;IAED,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAA;QAClC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QAE5C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YAC5C,MAAM,OAAO,GAAY;gBACvB,EAAE,EAAE,MAAM,CAAC,EAAE;gBACb,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,aAAa,EAAE,MAAM,CAAC,MAAM;gBAC5B,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC;gBACvD,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,SAAS;gBACtF,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAA;YACD,OAAO,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;QACnC,CAAC,CAAC,CAAA;QAEF,OAAO,GAAG,EAAE;YACV,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;gBACrC,UAAU,EAAE,CAAA;YACd,CAAC;QACH,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAA;AACrB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tooee/commands",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "description": "Vim-inspired modal command system for Tooee",
5
5
  "keywords": [
6
6
  "cli",
package/src/context.tsx CHANGED
@@ -5,10 +5,20 @@ import {
5
5
  useCallback,
6
6
  useEffect,
7
7
  useMemo,
8
+ useState,
8
9
  type ReactNode,
9
10
  } from "react"
10
11
  import { useKeyboard } from "@opentui/react"
11
- import type { Command, CommandContext, CommandRegistry, ParsedHotkey } from "./types.js"
12
+ import type {
13
+ Command,
14
+ CommandContext,
15
+ CommandGroup,
16
+ CommandRegistry,
17
+ CommandSequenceState,
18
+ ParsedHotkey,
19
+ ParsedStep,
20
+ RegisteredCommandGroup,
21
+ } from "./types.js"
12
22
  import type { Mode } from "./mode.js"
13
23
  import { ModeProvider, useMode, useSetMode } from "./mode.js"
14
24
  import { parseHotkey } from "./parse.js"
@@ -23,9 +33,11 @@ interface CommandContextValue {
23
33
  registry: CommandRegistry
24
34
  leaderKey?: string
25
35
  contextSources: Map<string, ContextGetter>
36
+ groups: Map<string, RegisteredCommandGroup>
26
37
  }
27
38
 
28
39
  const CommandContext = createContext<CommandContextValue | null>(null)
40
+ const CommandSequenceContext = createContext<CommandSequenceState | null>(null)
29
41
 
30
42
  export interface CommandProviderProps {
31
43
  children: ReactNode
@@ -55,10 +67,14 @@ function CommandDispatcher({
55
67
  }) {
56
68
  const registryRef = useRef<CommandRegistry | null>(null)
57
69
  const contextSourcesRef = useRef(new Map<string, ContextGetter>())
70
+ const groupsRef = useRef(new Map<string, RegisteredCommandGroup>())
58
71
  const mode = useMode()
59
72
  const modeRef = useRef(mode)
60
73
  modeRef.current = mode
61
74
  const setMode = useSetMode()
75
+ const [sequenceState, setSequenceState] = useState<CommandSequenceState | null>(null)
76
+ const clearSequenceStateRef = useRef(() => setSequenceState(null))
77
+ clearSequenceStateRef.current = () => setSequenceState(null)
62
78
 
63
79
  const buildCtx = useCallback((): CommandContext => {
64
80
  const ctx: Record<string, any> = {
@@ -96,7 +112,7 @@ function CommandDispatcher({
96
112
  }
97
113
  }
98
114
 
99
- const trackerRef = useRef(new SequenceTracker())
115
+ const trackerRef = useRef(new SequenceTracker({ onReset: () => clearSequenceStateRef.current() }))
100
116
  const parseCacheRef = useRef(new Map<string, ParsedHotkey>())
101
117
 
102
118
  const getParsedHotkey = useCallback(
@@ -124,8 +140,7 @@ function CommandDispatcher({
124
140
 
125
141
  // Collect eligible commands with their parsed hotkeys
126
142
  const singleStepCandidates: { command: Command; parsed: ParsedHotkey }[] = []
127
- const multiStepHotkeys: ParsedHotkey[] = []
128
- const multiStepCommands: Command[] = []
143
+ const multiStepCandidates: { command: Command; hotkey: string; parsed: ParsedHotkey }[] = []
129
144
 
130
145
  for (const command of registry.commands.values()) {
131
146
  const commandModes = command.modes ?? DEFAULT_MODES
@@ -140,41 +155,77 @@ function CommandDispatcher({
140
155
  if (parsed.steps.length === 1) {
141
156
  singleStepCandidates.push({ command, parsed })
142
157
  } else {
143
- multiStepHotkeys.push(parsed)
144
- multiStepCommands.push(command)
158
+ multiStepCandidates.push({ command, hotkey, parsed })
145
159
  }
146
160
  }
147
161
 
148
162
  // Check multi-step sequences first (they consume buffer state)
149
- if (multiStepHotkeys.length > 0) {
150
- const idx = trackerRef.current.feed(event, multiStepHotkeys)
151
- if (idx >= 0) {
163
+ if (multiStepCandidates.length > 0) {
164
+ const multiStepHotkeys = multiStepCandidates.map((candidate) => candidate.parsed)
165
+ const result = trackerRef.current.feedWithState(event, multiStepHotkeys)
166
+ if (result.matchedIndex >= 0) {
152
167
  event.preventDefault()
153
- multiStepCommands[idx]!.handler(ctx)
168
+ setSequenceState(null)
169
+ multiStepCandidates[result.matchedIndex]!.command.handler(ctx)
154
170
  return
155
171
  }
172
+
173
+ if (result.pending) {
174
+ const firstCandidate = multiStepCandidates[result.pending.indexes[0]!]!
175
+ setSequenceState({
176
+ prefix: firstCandidate.parsed.steps.slice(0, result.pending.prefixLength),
177
+ candidates: result.pending.indexes
178
+ .map((idx) => multiStepCandidates[idx]!)
179
+ .filter(({ command }) => !command.hidden)
180
+ .map(({ command, hotkey, parsed }) => ({
181
+ command,
182
+ hotkey,
183
+ steps: parsed.steps,
184
+ remainingSteps: parsed.steps.slice(result.pending!.prefixLength),
185
+ nextStep: parsed.steps[result.pending!.prefixLength]!,
186
+ group: groupsRef.current.get(
187
+ stepsKey(parsed.steps.slice(0, result.pending!.prefixLength + 1)),
188
+ ),
189
+ })),
190
+ })
191
+ event.preventDefault()
192
+ return
193
+ }
194
+
195
+ setSequenceState(null)
156
196
  }
157
197
 
158
198
  // Check single-step matches
159
199
  for (const { command, parsed } of singleStepCandidates) {
160
200
  if (matchStep(event, parsed.steps[0]!)) {
161
201
  event.preventDefault()
202
+ setSequenceState(null)
162
203
  command.handler(ctx)
163
204
  return
164
205
  }
165
206
  }
166
207
  })
167
208
 
209
+ useEffect(() => {
210
+ trackerRef.current.reset()
211
+ setSequenceState(null)
212
+ }, [mode])
213
+
168
214
  const ctxValue = useMemo(
169
215
  () => ({
170
216
  registry: registryRef.current!,
171
217
  leaderKey: leader,
172
218
  contextSources: contextSourcesRef.current,
219
+ groups: groupsRef.current,
173
220
  }),
174
221
  [leader],
175
222
  )
176
223
 
177
- return <CommandContext.Provider value={ctxValue}>{children}</CommandContext.Provider>
224
+ return (
225
+ <CommandContext.Provider value={ctxValue}>
226
+ <CommandSequenceContext value={sequenceState}>{children}</CommandSequenceContext>
227
+ </CommandContext.Provider>
228
+ )
178
229
  }
179
230
 
180
231
  export function useCommandContext(): { commands: Command[]; invoke: (id: string) => void } {
@@ -200,6 +251,56 @@ export function useCommandRegistry(): CommandContextValue {
200
251
  return ctx
201
252
  }
202
253
 
254
+ export function useCommandSequenceState(): CommandSequenceState | null {
255
+ return useContext(CommandSequenceContext)
256
+ }
257
+
258
+ export function useCommandGroup(group: CommandGroup): void {
259
+ const ctx = useContext(CommandContext)
260
+ if (!ctx) {
261
+ throw new Error("useCommandGroup must be used within a CommandProvider")
262
+ }
263
+
264
+ const groupRef = useRef(group)
265
+ groupRef.current = group
266
+ const { groups, leaderKey } = ctx
267
+
268
+ useEffect(() => {
269
+ const parsed = parseHotkey(groupRef.current.prefix, leaderKey)
270
+ const registered: RegisteredCommandGroup = {
271
+ ...groupRef.current,
272
+ prefixKey: stepsKey(parsed.steps),
273
+ }
274
+ groups.set(registered.prefixKey, registered)
275
+ return () => {
276
+ groups.delete(registered.prefixKey)
277
+ }
278
+ }, [
279
+ group.id,
280
+ group.prefix,
281
+ group.title,
282
+ group.description,
283
+ group.icon,
284
+ group.order,
285
+ groups,
286
+ leaderKey,
287
+ ])
288
+ }
289
+
290
+ function stepsKey(steps: ParsedStep[]): string {
291
+ return steps.map(formatStepKey).join(" ")
292
+ }
293
+
294
+ function formatStepKey(step: ParsedStep): string {
295
+ const modifiers = []
296
+ if (step.ctrl) modifiers.push("ctrl")
297
+ if (step.meta) modifiers.push("meta")
298
+ if (step.option) modifiers.push("option")
299
+ if (step.shift) modifiers.push("shift")
300
+ modifiers.push(step.key)
301
+ return modifiers.join("+")
302
+ }
303
+
203
304
  let nextContextSourceId = 0
204
305
 
205
306
  export function useProvideCommandContext(getter: () => Partial<CommandContext>): void {
package/src/index.ts CHANGED
@@ -2,10 +2,14 @@ export type {
2
2
  Command,
3
3
  CommandContext,
4
4
  CommandContextBase,
5
+ CommandGroup,
5
6
  CommandHandler,
7
+ CommandSequenceCandidate,
8
+ CommandSequenceState,
6
9
  CommandWhen,
7
10
  ParsedHotkey,
8
11
  ParsedStep,
12
+ RegisteredCommandGroup,
9
13
  } from "./types.js"
10
14
  export type { Mode } from "./mode.js"
11
15
  export { ModeProvider, useMode, useSetMode } from "./mode.js"
@@ -13,8 +17,19 @@ export type { ModeProviderProps } from "./mode.js"
13
17
  export { parseHotkey } from "./parse.js"
14
18
  export { matchStep } from "./match.js"
15
19
  export { SequenceTracker } from "./sequence.js"
16
- export type { SequenceTrackerOptions } from "./sequence.js"
17
- export { CommandProvider, useCommandContext, useProvideCommandContext } from "./context.js"
20
+ export type {
21
+ SequenceFeedResult,
22
+ SequencePendingMatch,
23
+ SequenceTrackerOptions,
24
+ } from "./sequence.js"
25
+ export {
26
+ CommandProvider,
27
+ useCommandContext,
28
+ useCommandGroup,
29
+ useCommandRegistry,
30
+ useCommandSequenceState,
31
+ useProvideCommandContext,
32
+ } from "./context.js"
18
33
  export type { CommandProviderProps } from "./context.js"
19
34
  export { useCommand } from "./use-command.js"
20
35
  export type { UseCommandOptions } from "./use-command.js"
package/src/sequence.ts CHANGED
@@ -4,22 +4,42 @@ import { matchStep } from "./match.js"
4
4
 
5
5
  export interface SequenceTrackerOptions {
6
6
  timeout?: number // ms, default 500
7
+ onReset?: () => void
8
+ }
9
+
10
+ export interface SequencePendingMatch {
11
+ prefixLength: number
12
+ indexes: number[]
13
+ }
14
+
15
+ export interface SequenceFeedResult {
16
+ matchedIndex: number
17
+ pending: SequencePendingMatch | null
7
18
  }
8
19
 
9
20
  export class SequenceTracker {
10
21
  private buffer: KeyEvent[] = []
11
22
  private timer: ReturnType<typeof setTimeout> | null = null
12
23
  private timeout: number
24
+ private onReset?: () => void
13
25
 
14
26
  constructor(options?: SequenceTrackerOptions) {
15
27
  this.timeout = options?.timeout ?? 500
28
+ this.onReset = options?.onReset
16
29
  }
17
30
 
18
31
  /**
19
32
  * Feed a key event and check against registered hotkeys.
20
- * Returns the index of the matched hotkey, or -1 if no match.
33
+ * Returns the index of the matched hotkey, or -1 if no full match.
21
34
  */
22
35
  feed(event: KeyEvent, hotkeys: ParsedHotkey[]): number {
36
+ return this.feedWithState(event, hotkeys).matchedIndex
37
+ }
38
+
39
+ /**
40
+ * Feed a key event and return both full-match and pending-prefix state.
41
+ */
42
+ feedWithState(event: KeyEvent, hotkeys: ParsedHotkey[]): SequenceFeedResult {
23
43
  this.buffer.push(event)
24
44
  this.resetTimer()
25
45
 
@@ -27,17 +47,23 @@ export class SequenceTracker {
27
47
  const hotkey = hotkeys[i]!
28
48
  if (this.matchesBuffer(hotkey)) {
29
49
  this.reset()
30
- return i
50
+ return { matchedIndex: i, pending: null }
31
51
  }
32
52
  }
33
53
 
34
54
  // Prune buffer if no hotkey could possibly match
35
- const maxLen = Math.max(...hotkeys.map((h) => h.steps.length))
36
- if (this.buffer.length > maxLen) {
37
- this.buffer.shift()
55
+ const maxLen = Math.max(0, ...hotkeys.map((h) => h.steps.length))
56
+ if (maxLen > 0) {
57
+ while (this.buffer.length > maxLen) {
58
+ this.buffer.shift()
59
+ }
38
60
  }
39
61
 
40
- return -1
62
+ return { matchedIndex: -1, pending: this.findPendingMatch(hotkeys) }
63
+ }
64
+
65
+ getPendingMatch(hotkeys: ParsedHotkey[]): SequencePendingMatch | null {
66
+ return this.findPendingMatch(hotkeys)
41
67
  }
42
68
 
43
69
  private matchesBuffer(hotkey: ParsedHotkey): boolean {
@@ -51,9 +77,42 @@ export class SequenceTracker {
51
77
  return true
52
78
  }
53
79
 
80
+ private findPendingMatch(hotkeys: ParsedHotkey[]): SequencePendingMatch | null {
81
+ const maxPrefixLength = Math.min(
82
+ this.buffer.length,
83
+ Math.max(0, ...hotkeys.map((h) => h.steps.length - 1)),
84
+ )
85
+
86
+ for (let prefixLength = maxPrefixLength; prefixLength > 0; prefixLength--) {
87
+ const start = this.buffer.length - prefixLength
88
+ const indexes: number[] = []
89
+
90
+ for (let hotkeyIndex = 0; hotkeyIndex < hotkeys.length; hotkeyIndex++) {
91
+ const hotkey = hotkeys[hotkeyIndex]!
92
+ if (hotkey.steps.length <= prefixLength) continue
93
+
94
+ let matches = true
95
+ for (let i = 0; i < prefixLength; i++) {
96
+ if (!matchStep(this.buffer[start + i]!, hotkey.steps[i]!)) {
97
+ matches = false
98
+ break
99
+ }
100
+ }
101
+
102
+ if (matches) indexes.push(hotkeyIndex)
103
+ }
104
+
105
+ if (indexes.length > 0) return { prefixLength, indexes }
106
+ }
107
+
108
+ return null
109
+ }
110
+
54
111
  reset(): void {
112
+ const hadBuffer = this.buffer.length > 0
55
113
  this.buffer = []
56
114
  this.clearTimer()
115
+ if (hadBuffer) this.onReset?.()
57
116
  }
58
117
 
59
118
  private resetTimer(): void {
package/src/types.ts CHANGED
@@ -44,3 +44,30 @@ export interface CommandRegistry {
44
44
  register: (command: Command) => () => void
45
45
  invoke: (id: string) => void
46
46
  }
47
+
48
+ export interface CommandGroup {
49
+ id: string
50
+ title: string
51
+ prefix: string
52
+ description?: string
53
+ icon?: string
54
+ order?: number
55
+ }
56
+
57
+ export interface RegisteredCommandGroup extends CommandGroup {
58
+ prefixKey: string
59
+ }
60
+
61
+ export interface CommandSequenceCandidate {
62
+ command: Command
63
+ hotkey: string
64
+ steps: ParsedStep[]
65
+ remainingSteps: ParsedStep[]
66
+ nextStep: ParsedStep
67
+ group?: CommandGroup
68
+ }
69
+
70
+ export interface CommandSequenceState {
71
+ prefix: ParsedStep[]
72
+ candidates: CommandSequenceCandidate[]
73
+ }
@@ -10,6 +10,10 @@ export interface ActionDefinition {
10
10
  modes?: Mode[]
11
11
  handler: CommandHandler
12
12
  when?: CommandWhen
13
+ category?: string
14
+ group?: string
15
+ icon?: string
16
+ hidden?: boolean
13
17
  }
14
18
 
15
19
  export function useActions(actions: ActionDefinition[] | undefined): void {
@@ -18,7 +22,13 @@ export function useActions(actions: ActionDefinition[] | undefined): void {
18
22
  actionsRef.current = actions
19
23
 
20
24
  const key = useMemo(
21
- () => actions?.map((a) => `${a.id}:${a.hotkey ?? ""}`).join(",") ?? "",
25
+ () =>
26
+ actions
27
+ ?.map(
28
+ (a) =>
29
+ `${a.id}:${a.title}:${a.hotkey ?? ""}:${a.category ?? ""}:${a.group ?? ""}:${a.icon ?? ""}:${a.hidden ?? false}`,
30
+ )
31
+ .join(",") ?? "",
22
32
  [actions],
23
33
  )
24
34
 
@@ -34,6 +44,10 @@ export function useActions(actions: ActionDefinition[] | undefined): void {
34
44
  modes: action.modes,
35
45
  handler: (ctx) => actionsRef.current?.[i]?.handler(ctx),
36
46
  when: action.when ? (ctx) => actionsRef.current?.[i]?.when?.(ctx) ?? false : undefined,
47
+ category: action.category,
48
+ group: action.group,
49
+ icon: action.icon,
50
+ hidden: action.hidden,
37
51
  }
38
52
  return registry.register(command)
39
53
  })