Chord-click selects one note or the whole strum, per profile - #297
Conversation
📝 WalkthroughWalkthroughChord-click selection now follows shortcut-profile defaults or a persisted override. Alt-click reverses the mode, sustain resizing uses the same grouping decision, and keys-data clicks remain ungrouped. The shortcut panel, global API, documentation, changelog, and helper tests are updated. ChangesChord selection behavior
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant ShortcutPanel
participant Main as src/main.js
participant Shortcuts as src/shortcuts.js
participant Mouse as src/mouse.js
participant Notes as NoteSelection
ShortcutPanel->>Main: Set chord-click behavior
Main->>Shortcuts: Persist and synchronize behavior
Mouse->>Shortcuts: Resolve profile, override, and Alt state
Shortcuts-->>Mouse: Return groupChord
Mouse->>Notes: Select note or same-time chord siblings
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/mouse.js (1)
184-207: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winMake Alt-click isolate an already-selected chord note.
When a whole chord is selected, Alt-clicking one of its selected notes sets
groupChordto false, but Line 204 still skips reselection becauseidxis already selected. The subsequent move drag therefore still contains the entire chord, violating the documented inversion behavior.Preserve the Keys DATA exemption, but collapse non-keys multi-selection to
idxwhengroupChordis false.Suggested fix
- const groupChord = _editorChordGrabsStrumPure(_chordSel, e.altKey, isKeysArr()); + const keysData = isKeysArr(); + const groupChord = _editorChordGrabsStrumPure(_chordSel, e.altKey, keysData); ... - } else if (!S.sel.has(idx)) { + } else if (!S.sel.has(idx) || (!groupChord && !keysData && S.sel.size > 1)) {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/mouse.js` around lines 184 - 207, Update the click-selection logic around groupChord and the `!S.sel.has(idx)` branch so that non-Keys DATA Alt-clicks with `groupChord` false collapse the selection to `idx` even when that note is already selected. Preserve the existing whole-chord toggle and selection behavior when `groupChord` is true, along with the Keys DATA exemption.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/mouse.js`:
- Around line 184-207: Update the click-selection logic around groupChord and
the `!S.sel.has(idx)` branch so that non-Keys DATA Alt-clicks with `groupChord`
false collapse the selection to `idx` even when that note is already selected.
Preserve the existing whole-chord toggle and selection behavior when
`groupChord` is true, along with the Keys DATA exemption.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 16c4ae12-78b4-4eda-8333-c02c47832e7b
📒 Files selected for processing (7)
CHANGELOG.mddocs/USER-GUIDE.mdscreen.htmlsrc/main.jssrc/mouse.jssrc/shortcuts.jstests/chord_select_behavior.test.mjs
62fc462 to
408d8b6
Compare
Why
Clicking one note of a chord in a guitar/bass part selected the whole strum — every same-time note — which is a genuine "wait, what?" moment in a piano-roll-style editor. Notably the editor already selects a single note in piano-roll (keys) parts; only the fretted parts force-grouped.
Rather than pick a universal winner, this makes chord-click selection profile-driven, exactly like the existing right-click behaviour (
_editorDefaultRightClickBehaviorPure→ EOF vs context). So the DAW-flavoured profiles feel like a DAW, and Legacy (EOF) stays EOF-faithful.What
_editorChordGrabsStrumPure), so a click and an edge-drag can never disagree about what a grab means. (This flips resize in the DAW profiles from its old chord-default to single-default — the intended consistency win.)?) pins it regardless of profile, persisted tolocalStorage(editor.chordSelect) the same wayeditor.rightClickBehavioris.Design notes
The profile default → explicit override → Alt inversion → keys-DATA exemption all fold into one pure helper (
_editorChordGrabsStrumPure) that both grab paths inmouse.jscall, so there's a single source of truth for "does this grab act on the strum?"Tests
tests/chord_select_behavior.test.mjs— new.test.mjsunit suite over the three pure resolvers (default, effective-with-override, and the grab decision incl. Alt inversion + keys exemption + boolean coercion). Fails on main (the resolvers don't exist there). Full JS suite (186) + pytest-free (noroutes.pychange) +npm run lint(0 errors) all green.Docs
CHANGELOG
[Unreleased]+ USER-GUIDE §4 (Edit notes) updated.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Tests