Summary
Since #786, ⇧-click on a cue row toggles that single row's membership of the
selection, exactly like ⌘-click. Contiguous range selection ("click row 3,
shift-click row 9, get rows 3 through 9") is no longer reachable anywhere in the
cue list.
Background
Before #786, the cue list relied on List's native multi-selection, which gave
⇧-click range selection for free. #786 made a plain click inside the #,
Name, or Info column open that column's TextField, so the row's own tap
handlers now claim the click before List sees it, and the native behaviour is
unreachable.
CueRowTap.intent (OnlyCue/UI/CueRowTapIntent.swift:41) collapses both
modifiers into one isExtending: Bool:
case .stripe:
return isExtending ? .extendSelection : .selectAndSeek
and CueListPane implements .extendSelection as a symmetric difference —
a toggle:
onExtendSelection: {
var updated = selection
updated.formSymmetricDifference([cue.id])
lastRowTapSelection = updated
selection = updated
},
This was a conscious trade-off in #786 (⌘ and ⇧ deliberately behaved alike
to keep the truth table at eight rows), not an oversight, but it is a loss of
function on a list that routinely runs to hundreds of cues.
Proposed change
Split the two modifiers:
⌘-click keeps today's toggle behaviour.
⇧-click selects the inclusive range between the anchor and the clicked
row, replacing the current selection.
The anchor is the last row selected without ⇧ (a plain stripe click, a
⌘-click, or a click that began an edit). A ⇧-click does not move the
anchor, so repeated ⇧-clicks re-range from the same origin — matching Finder
and every spreadsheet.
This means CueRowTapIntent gains a case (extendRange) and
CueRowTap.intent gains a parameter distinguishing ⌘ from ⇧. Ordering
comes from the pane's filtered, sorted cue array, not from Cue.id — the
range must follow what the user sees.
Acceptance criteria
Files
OnlyCue/UI/CueRowTapIntent.swift — add the ⇧ case and its parameter.
OnlyCue/UI/CueRowView.swift — read NSEvent.modifierFlags for .shift
separately from .command.
OnlyCue/UI/CueListPane.swift — hold the anchor, resolve the range against
the displayed cue order, keep lastRowTapSelection in sync so the
reveal-the-row onChange still skips self-inflicted changes.
OnlyCueTests/CueRowTapIntentTests.swift, OnlyCueUITests/CueListSingleClickEditUITests.swift
Spec
docs/superpowers/specs/2026-08-28-cue-list-single-click-edit.md — modifier-click
multi-select. docs/ui-sections.md "Cue Row Interaction" needs its ⌘/⇧
sentence corrected once this lands.
Follows #786. Related: #787.
Summary
Since #786,
⇧-click on a cue row toggles that single row's membership of theselection, exactly like
⌘-click. Contiguous range selection ("click row 3,shift-click row 9, get rows 3 through 9") is no longer reachable anywhere in the
cue list.
Background
Before #786, the cue list relied on
List's native multi-selection, which gave⇧-click range selection for free. #786 made a plain click inside the#,Name, orInfocolumn open that column'sTextField, so the row's own taphandlers now claim the click before
Listsees it, and the native behaviour isunreachable.
CueRowTap.intent(OnlyCue/UI/CueRowTapIntent.swift:41) collapses bothmodifiers into one
isExtending: Bool:and
CueListPaneimplements.extendSelectionas a symmetric difference —a toggle:
This was a conscious trade-off in #786 (
⌘and⇧deliberately behaved aliketo keep the truth table at eight rows), not an oversight, but it is a loss of
function on a list that routinely runs to hundreds of cues.
Proposed change
Split the two modifiers:
⌘-click keeps today's toggle behaviour.⇧-click selects the inclusive range between the anchor and the clickedrow, replacing the current selection.
The anchor is the last row selected without
⇧(a plain stripe click, a⌘-click, or a click that began an edit). A⇧-click does not move theanchor, so repeated
⇧-clicks re-range from the same origin — matching Finderand every spreadsheet.
This means
CueRowTapIntentgains a case (extendRange) andCueRowTap.intentgains a parameter distinguishing⌘from⇧. Orderingcomes from the pane's filtered, sorted cue array, not from
Cue.id— therange must follow what the user sees.
Acceptance criteria
⇧-clicks row9, then rows 3 through 9 inclusive are selected.
⇧-clicks row 5, then rows 3 through5 are selected (the anchor stayed at 3, it did not move to 9).
⇧-click range, when the user⌘-clicks a row inside it, thenonly that row is removed and the rest of the range stays selected.
⇧-clicking backwards (anchor below the target) selects the sameinclusive range.
⇧-click range covers only rows visible underthe filter, in displayed order.
⇧-click never opens aTextFieldand never moves the playhead.⇧-click on the stripe stillranges.
CueRowTap.intenttruth table; a UI testin
CueListSingleClickEditUITestscovers the range-select path.Files
OnlyCue/UI/CueRowTapIntent.swift— add the⇧case and its parameter.OnlyCue/UI/CueRowView.swift— readNSEvent.modifierFlagsfor.shiftseparately from
.command.OnlyCue/UI/CueListPane.swift— hold the anchor, resolve the range againstthe displayed cue order, keep
lastRowTapSelectionin sync so thereveal-the-row
onChangestill skips self-inflicted changes.OnlyCueTests/CueRowTapIntentTests.swift,OnlyCueUITests/CueListSingleClickEditUITests.swiftSpec
docs/superpowers/specs/2026-08-28-cue-list-single-click-edit.md— modifier-clickmulti-select.
docs/ui-sections.md"Cue Row Interaction" needs its⌘/⇧sentence corrected once this lands.
Follows #786. Related: #787.