Skip to content

fix(extension-api): reject key chords with empty + segments - #912

Open
Rehan30g wants to merge 1 commit into
modem-dev:mainfrom
Rehan30g:fix/reject-empty-keychord-segments-906
Open

fix(extension-api): reject key chords with empty + segments#912
Rehan30g wants to merge 1 commit into
modem-dev:mainfrom
Rehan30g:fix/reject-empty-keychord-segments-906

Conversation

@Rehan30g

Copy link
Copy Markdown

Problem

The shared key-chord parser (parseKeyChord in src/extension-api/keys.ts) split a chord on + and filtered out any empty tokens before validating modifier/base-key structure. That let malformed bindings silently resolve to a different, valid shortcut:

s+       → s
+s       → s
ctrl++s  → ctrl+s
ctrl+s+  → ctrl+s

parseKeyChord("s+") returned the same parsed chord as parseKeyChord("s"), so a typo in a user [keybindings] entry, an extension registerCommand binding, or the public matchesKey helper could claim and fire a real shortcut instead of being rejected. This was inconsistent with the parser's existing behavior for other malformed chords like ctlr+s, f13, and ctrl+, which are already rejected.

Fix

Recognize the literal + chord (optionally whitespace-padded, e.g. " + ") before empty-segment rejection, since splitting it on + produces two empty segments that are intentional. For every other chord, split on +, trim each segment, and return a parse error if any segment is empty instead of silently dropping it. Whitespace-padded valid chords such as ctrl + s continue to parse.

The fix lives entirely in the shared grammar in src/extension-api/keys.ts, so built-in commands, user keybindings, extension registerCommand bindings, and the public matchesKey helper all inherit the stricter validation from one place.

Tests

  • src/extension-api/keys.test.ts: added table-driven coverage asserting s+, +s, ctrl++s, and ctrl+s+ are rejected, and that +, " + ", and ctrl + s still parse correctly.
  • src/ui/lib/keymap.test.ts: added a case confirming a malformed chord with an empty + segment (s+) does not claim another command's real shortcut (s) and is reported as one keybinding issue while its valid sibling chord survives.

Validation

bun test src/extension-api/keys.test.ts src/ui/lib/keymap.test.ts   # 36 pass
bun run typecheck                                                    # pass
bun run lint                                                         # 0 warnings, 0 errors
bun run format:check                                                 # pass
bun run deps:check                                                   # no violations
bun run test                                                         # 3364 pass, 35 skip, 2 fail (pre-existing, unrelated: a jujutsu test that requires the `jj` binary on PATH, and a React-internal error in an unrelated component test — both reproduce identically on main without this change)

A patch Changeset for hunkdiff is included.

Fixes #906

The shared chord parser filtered out empty tokens after splitting on
"+", so malformed bindings like "s+", "+s", "ctrl++s", and "ctrl+s+"
were silently normalized into a different valid shortcut instead of
being rejected. A typo could therefore claim and fire a real
keybinding.

Recognize the literal "+" chord before empty segments are rejected,
then treat any other empty segment around "+" as a parse error. This
keeps "+" and " + " valid while making parseKeyChord reject malformed
chords consistently with its existing handling of "ctrl+" and
"ctlr+s".

Fixes modem-dev#906
@greptile-apps

greptile-apps Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

PR author is not in the allowed authors list.

@vercel

vercel Bot commented Aug 30, 2026

Copy link
Copy Markdown

@Rehan30g is attempting to deploy a commit to the Modem Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reject malformed key chords containing empty segments

1 participant