Skip to content

WIP - #1

Merged
mdroidian merged 2 commits into
mainfrom
WIP
Jun 30, 2026
Merged

WIP#1
mdroidian merged 2 commits into
mainfrom
WIP

Conversation

@mdroidian

@mdroidian mdroidian commented Feb 17, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai

coderabbitai Bot commented Feb 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Free

Run ID: 6eba46b3-880e-482f-998d-51aa095da259

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This pull request introduces a new Quick Switcher feature for quickly navigating to bookmarked Roam pages via keyboard shortcuts. The implementation includes a modal dialog component for searching and opening bookmarks, a settings panel for creating and managing bookmarks with custom keyboard shortcuts, core initialization and controller logic, utility functions for shortcut normalization and URL parsing, type definitions, test coverage, and integration into the extension's main entry point. Additionally, a To Do section is added to the README documenting planned UI improvements.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes


Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands.

@mdroidian

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Feb 17, 2026

Copy link
Copy Markdown
✅ Actions performed

Full review triggered.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

View 6 additional findings in Devin Review.

Open in Devin Review

Comment thread src/utils/quickSwitcher.ts Outdated
Comment on lines +28 to +34
const normalizedToken = token.toLowerCase().trim();
if (!normalizedToken) {
return "";
}
if (normalizedToken === " ") {
return "space";
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Space key in shortcuts is silently dropped due to .trim() before space check

The normalizeKeyToken function calls .toLowerCase().trim() on the token before checking if it equals " " (space). Since .trim() removes whitespace, a single space " " becomes "", which triggers the early return at line 29 (if (!normalizedToken) return ""). The normalizedToken === " " check at line 32 is therefore unreachable.

Root Cause and Impact

When a KeyboardEvent fires for the Space key, event.key is " ". This flows through normalizeKeyboardEventKeynormalizeKeyToken({ token: " " }), where .trim() converts it to "", and the function returns empty string. As a result, keyboardEventToShortcut returns null for any shortcut involving Space.

Since the shortcut capture UI (onShortcutKeyDown in QuickSwitcherSettings.tsx:89) also uses keyboardEventToShortcut, users cannot even record a Space-based shortcut. If a stored shortcut containing "space" were loaded from settings (e.g., "ctrl+space"), it would parse correctly via normalizeShortcut (since the string token "space" survives .trim()), but the keyboard event would never match it — making the shortcut permanently non-functional.

Suggested change
const normalizedToken = token.toLowerCase().trim();
if (!normalizedToken) {
return "";
}
if (normalizedToken === " ") {
return "space";
}
const lower = token.toLowerCase();
if (lower === " " || lower.trim() === "space" || lower.trim() === "spacebar") {
return "space";
}
const normalizedToken = lower.trim();
if (!normalizedToken) {
return "";
}
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread src/quickSwitcher.tsx
Comment on lines +180 to +204
const onDocumentKeyDown = (event: KeyboardEvent): void => {
if (isDialogOpen && event.key === "Escape") {
event.preventDefault();
closeDialog();
return;
}

if (isEditableTarget({ target: event.target })) {
return;
}

const shortcut = keyboardEventToShortcut({ event });
if (!shortcut) {
return;
}

const bookmark = bookmarks.find((entry) => entry.shortcut === shortcut);
if (!bookmark) {
return;
}

event.preventDefault();
event.stopPropagation();
void openBookmark({ bookmark });
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Bookmark keyboard shortcuts fire while the Quick Switcher dialog is open

The onDocumentKeyDown handler only guards against Escape when the dialog is open (isDialogOpen && event.key === "Escape"). For all other keys, it falls through to the isEditableTarget check. If the dialog is open and focus is on a non-editable element (e.g., a MenuItem, the dialog overlay, or the dialog body), the bookmark shortcut matching proceeds and navigates away from the current page while the dialog remains open.

Detailed Explanation

When the dialog opens, focus is set on the search input via a setTimeout in QuickSwitcherDialog.tsx:52. However, the user can move focus to non-editable elements by clicking on menu items, the dialog body, or using Tab. In that state:

  1. isDialogOpen is true, but event.key is not "Escape" → line 181 doesn't match
  2. isEditableTarget({ target: event.target }) returns false → line 187 doesn't bail out
  3. keyboardEventToShortcut produces a shortcut string → line 196 finds a matching bookmark
  4. openBookmark navigates to the page while the dialog is still rendered

The fix is to return early from the handler whenever isDialogOpen is true (for any key, not just Escape), or to add if (isDialogOpen) return; after the Escape check.

Suggested change
const onDocumentKeyDown = (event: KeyboardEvent): void => {
if (isDialogOpen && event.key === "Escape") {
event.preventDefault();
closeDialog();
return;
}
if (isEditableTarget({ target: event.target })) {
return;
}
const shortcut = keyboardEventToShortcut({ event });
if (!shortcut) {
return;
}
const bookmark = bookmarks.find((entry) => entry.shortcut === shortcut);
if (!bookmark) {
return;
}
event.preventDefault();
event.stopPropagation();
void openBookmark({ bookmark });
};
const onDocumentKeyDown = (event: KeyboardEvent): void => {
if (isDialogOpen) {
if (event.key === "Escape") {
event.preventDefault();
closeDialog();
}
return;
}
if (isEditableTarget({ target: event.target })) {
return;
}
const shortcut = keyboardEventToShortcut({ event });
if (!shortcut) {
return;
}
const bookmark = bookmarks.find((entry) => entry.shortcut === shortcut);
if (!bookmark) {
return;
}
event.preventDefault();
event.stopPropagation();
void openBookmark({ bookmark });
};
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@mdroidian
mdroidian merged commit 4c5a79c into main Jun 30, 2026
2 checks passed
@mdroidian
mdroidian deleted the WIP branch June 30, 2026 22:22
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.

1 participant