Skip to content

Fix BLOCKMENTIONSDATED parsing, hotkey add behavior, and FORM focus handling#149

Open
salmonumbrella wants to merge 8 commits intoRoamJS:mainfrom
salmonumbrella:fix/blockmentionsdated-date-parsing
Open

Fix BLOCKMENTIONSDATED parsing, hotkey add behavior, and FORM focus handling#149
salmonumbrella wants to merge 8 commits intoRoamJS:mainfrom
salmonumbrella:fix/blockmentionsdated-date-parsing

Conversation

@salmonumbrella
Copy link
Contributor

@salmonumbrella salmonumbrella commented Feb 14, 2026

Summary

  • fix BLOCKMENTIONSDATED date argument parsing for comma-containing dates and normalize first of ... date phrases
  • add shared SmartBlock arg splitter with handling for nested commands and page refs
  • fix Hot Key panel add behavior by picking the next available default hotkey instead of overwriting existing control+o
  • improve hotkey state updates with functional state setters to avoid stale updates
  • force %FORM% dialog focus to reduce keyboard-input method issues in form workflows
  • add opt-in streamed output mode (Stream Output + Stream Delay) and thread it through trigger paths
  • document BREADCRUMBS page-only/parents-only prefixes in command help
  • add tests for arg splitting and next-hotkey selection
  • include consolidated investigation notes in research.md

Issue Links

Validation

  • npm test (12 passed)

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced hot key management with automatic duplicate prevention and availability checking.
    • Improved date argument parsing for block mention-based calculations.
    • Better keyboard focus control in dialogs and forms to prevent unintended input.
  • Improvements

    • Refined command argument parsing logic.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 14, 2026

Walkthrough

The PR addresses issues with BLOCKMENTIONSDATED command date handling and hotkey entry creation. Two new utility modules are introduced: getNextAvailableHotKey computes the next available hotkey combination from predefined modifier and suffix sequences, and splitSmartBlockArgs parses smartblock command arguments with special handling for block mention nesting and date token coalescing. The HotKeyPanel component is refactored to use functional state updates with automatic hotkey generation instead of accepting external keys. The core.ts utility is updated to use splitSmartBlockArgs for argument parsing and includes a new parseBlockMentionsDatedArg helper for date processing in BLOCKMENTIONSDATED commands. Additional changes enforce focus in FORM and BREADCRUMBS UI flows and adjust block text insertion logic. Corresponding tests are added for both new utilities.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~40 minutes

🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly describes the three main fixes in the changeset: BLOCKMENTIONSDATED parsing, hotkey add behavior, and FORM focus handling.
Linked Issues check ✅ Passed The PR addresses both linked issues: #54 with parseBlockMentionsDatedArg for date parsing and #142 with getNextAvailableHotKey for hotkey addition, plus FORM focus enforcement.
Out of Scope Changes check ✅ Passed All changes align with stated objectives: argument parsing utilities, hotkey utilities, FORM focus handling, and BLOCKMENTIONSDATED fixes; minor formatting in index.ts is consistent.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/HotKeyPanel.tsx`:
- Around line 160-169: The callback passed to setKeys calls
getNextAvailableHotKey which can throw and crash React; wrap the call to
getNextAvailableHotKey in a try/catch inside the setKeys updater (the function
that currently builds newKeys and calls extensionAPI.settings.set) and on error
do not throw—show a user-friendly notification (or toast) and return currentKeys
unchanged so state and settings are not mutated; only call
extensionAPI.settings.set("hot-keys", newKeys) when getNextAvailableHotKey
succeeds. Ensure you reference getNextAvailableHotKey, setKeys,
extensionAPI.settings.set, and randomWorkflow.uid when locating the code.
🧹 Nitpick comments (2)
src/HotKeyPanel.tsx (1)

55-69: Side effects inside React state updaters.

Calling extensionAPI.settings.set(...) inside setKeys(currentKeys => {...}) is a side effect inside a state updater, which React expects to be pure. This pattern is repeated in onKeyDown (Line 67), onItemSelect (Line 86), delete (Line 104), and Add Hot Key (Line 167). While it works correctly in practice, if React ever double-invokes the updater (e.g., StrictMode), the settings call would fire twice. If this isn't a concern today, it's fine to leave as-is.

src/utils/core.ts (1)

2805-2818: Verify the finalText insertion logic handles the suffix correctly through textPostProcess.

The new approach implicitly preserves the suffix (from the original block text) because textPostProcess = getTextByBlockUid(uid) already contains prefix + suffix from the earlier updateBlock on Line 2770–2773. The insertion point (indexDiffered) naturally splits around where the suffix begins. This is correct but subtler than the previous approach.

Note: props.suffix (set at Line 2776) appears to be unused now — it can be cleaned up.

Comment on lines +160 to +169
setKeys((currentKeys) => {
const nextHotkey = getNextAvailableHotKey(currentKeys);
const newKeys = Object.fromEntries(
Object.entries(currentKeys).concat([
[nextHotkey, randomWorkflow.uid],
])
);
extensionAPI.settings.set("hot-keys", newKeys);
return newKeys;
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

getNextAvailableHotKey can throw inside a state updater, which may crash the component.

If all 144 hotkey combinations are exhausted, getNextAvailableHotKey throws. Since this throw occurs inside the setKeys callback (a React state updater), React will propagate it as an unhandled error, potentially unmounting the component tree. Consider catching the error and showing a user-friendly notification instead.

🛡️ Proposed fix
          setKeys((currentKeys) => {
+            let nextHotkey: string;
+            try {
+              nextHotkey = getNextAvailableHotKey(currentKeys);
+            } catch {
+              // All combinations exhausted — return state unchanged
+              return currentKeys;
+            }
-            const nextHotkey = getNextAvailableHotKey(currentKeys);
             const newKeys = Object.fromEntries(
               Object.entries(currentKeys).concat([
                 [nextHotkey, randomWorkflow.uid],
               ])
             );
             extensionAPI.settings.set("hot-keys", newKeys);
             return newKeys;
           });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
setKeys((currentKeys) => {
const nextHotkey = getNextAvailableHotKey(currentKeys);
const newKeys = Object.fromEntries(
Object.entries(currentKeys).concat([
[nextHotkey, randomWorkflow.uid],
])
);
extensionAPI.settings.set("hot-keys", newKeys);
return newKeys;
});
setKeys((currentKeys) => {
let nextHotkey: string;
try {
nextHotkey = getNextAvailableHotKey(currentKeys);
} catch {
// All combinations exhausted — return state unchanged
return currentKeys;
}
const newKeys = Object.fromEntries(
Object.entries(currentKeys).concat([
[nextHotkey, randomWorkflow.uid],
])
);
extensionAPI.settings.set("hot-keys", newKeys);
return newKeys;
});
🤖 Prompt for AI Agents
In `@src/HotKeyPanel.tsx` around lines 160 - 169, The callback passed to setKeys
calls getNextAvailableHotKey which can throw and crash React; wrap the call to
getNextAvailableHotKey in a try/catch inside the setKeys updater (the function
that currently builds newKeys and calls extensionAPI.settings.set) and on error
do not throw—show a user-friendly notification (or toast) and return currentKeys
unchanged so state and settings are not mutated; only call
extensionAPI.settings.set("hot-keys", newKeys) when getNextAvailableHotKey
succeeds. Ensure you reference getNextAvailableHotKey, setKeys,
extensionAPI.settings.set, and randomWorkflow.uid when locating the code.

@mdroidian
Copy link
Collaborator

Hi — thank you for putting this together. I appreciate the effort here.

We just added a formal contributing guide, so this likely wasn’t visible when you started the PR. Going forward, we’re trying to standardize reviews around it to keep things manageable:

https://github.com/RoamJS/contributing/blob/main/contributing.md

A couple adjustments are needed before this can move forward:

  • One PR = One Issue — this PR currently spans multiple issues. Please split it into separate PRs (one per issue).
  • Keep PRs small and tightly scoped per the size guidelines.
  • Include a short (2–3 min) Loom walkthrough showing what changed and how you verified it.

PRs that touch multiple concerns are significantly harder to review, and I have limited bandwidth right now. Following the guide helps ensure contributions can be reviewed and merged much more quickly.

Once this is split up and the Loom is added, I’ll be happy to take a look.

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

Labels

None yet

Projects

None yet

2 participants