authorclover caruso <git@paperclover.net> 2026-10-15 14:14:45-07:00
committerclover caruso <git@paperclover.net> 2026-10-15 14:23:02-07:00
logc780bc064c84cc299b01189b7b225c335dd00da7
tree5bc95f8d3a11e329842d46ce50d00321bf3c2e3f
parent1dcb0343511f2ace03aa4f29c9c7a1b39716096b
signature Signed by SSH key SHA256:52mNGHRsVFBDED9IAX5pe+LRWUefqTbxEReunq21QvU (~clover)

feat: move lines and list items with Alt+Up and Alt+Down, as in VS Code

Alt+Up and Alt+Down now move the selected paragraphs, list items included, past their sibling on Windows and Linux, alongside OneNote's Alt+Shift+Up and Down. On macOS, Option+Up and Down do the same, as VS Code binds them there, taking over from plain Option's jump to the paragraph start or end; Option-Shift still extends the selection to the paragraph ends, and Option-Command keeps moving paragraphs as OneNote for Mac does. Fixes #151 Assisted-by: claude-opus-5.5

1 files changed, 54 insertions(+), 13 deletions(-)

crates/draw/src/edit.rs+54-13
......@@ -88,7 +88,8 @@ pub enum Command {
8888 /// Moves the caret a page and the view with it, extending the selection with Shift.
8989 MovePage { up: bool },
9090 /// Moves the selected paragraphs past their sibling above or below: OneNote's Alt+Shift+Up
91 /// and Down, Option-Command on macOS as OneNote for Mac binds them.
91 /// and Down, Option-Command on macOS as OneNote for Mac binds them, and VS Code's Alt or
92 /// Option with Up and Down.
9293 MoveParagraphs { up: bool },
9394}
9495
......@@ -289,7 +290,7 @@ fn mac_command(key: &Key, modifiers: Modifiers) -> Option<Command> {
289290 };
290291 match key {
291292 Key::Named(arrow @ (NamedKey::ArrowUp | NamedKey::ArrowDown))
292 if command && option && !shift && !control =>
293 if option && !shift && !control =>
293294 {
294295 Some(Command::MoveParagraphs {
295296 up: *arrow == NamedKey::ArrowUp,
......@@ -351,14 +352,11 @@ fn mac_command(key: &Key, modifiers: Modifiers) -> Option<Command> {
351352/// and End reaches the document's ends; Control with Up and Down moves by paragraphs.
352353fn pc_command(key: &Key, modifiers: Modifiers) -> Option<Command> {
353354 let Modifiers {
354 shift,
355 control,
356 option,
357 ..
355 control, option, ..
358356 } = modifiers;
359357 if option {
360358 return match key {
361 _ if !shift || control => None,
359 _ if control => None,
362360 Key::Named(NamedKey::ArrowUp) => Some(Command::MoveParagraphs { up: true }),
363361 Key::Named(NamedKey::ArrowDown) => Some(Command::MoveParagraphs { up: false }),
364362 _ => None,
......@@ -605,11 +603,6 @@ mod tests {
605603 with(|m| (m.command, m.option) = (true, true)),
606604 Some(Command::Move(Movement::LineEnd)),
607605 ),
608 (
609 named(NamedKey::ArrowUp),
610 with(|m| m.option = true),
611 Some(Command::Move(Movement::ParagraphStart)),
612 ),
613606 (named(NamedKey::Home), Modifiers::default(), None),
614607 (
615608 named(NamedKey::End),
......@@ -652,11 +645,36 @@ mod tests {
652645 with(|m| (m.command, m.option) = (true, true)),
653646 Some(Command::MoveParagraphs { up: false }),
654647 ),
648 (
649 named(NamedKey::ArrowUp),
650 with(|m| (m.command, m.option) = (true, true)),
651 Some(Command::MoveParagraphs { up: true }),
652 ),
653 (
654 named(NamedKey::ArrowUp),
655 with(|m| m.option = true),
656 Some(Command::MoveParagraphs { up: true }),
657 ),
658 (
659 named(NamedKey::ArrowDown),
660 with(|m| m.option = true),
661 Some(Command::MoveParagraphs { up: false }),
662 ),
655663 (
656664 named(NamedKey::ArrowUp),
657665 with(|m| (m.shift, m.option) = (true, true)),
658666 Some(Command::Move(Movement::ParagraphStart)),
659667 ),
668 (
669 named(NamedKey::ArrowDown),
670 with(|m| (m.shift, m.option) = (true, true)),
671 Some(Command::Move(Movement::ParagraphEnd)),
672 ),
673 (
674 named(NamedKey::ArrowUp),
675 with(|m| (m.control, m.option) = (true, true)),
676 Some(Command::Move(Movement::ParagraphStart)),
677 ),
660678 ];
661679 for (key, modifiers, command) in cases {
662680 assert_eq!(
......@@ -688,7 +706,30 @@ mod tests {
688706 alt_shift,
689707 Some(Command::MoveParagraphs { up: true }),
690708 ),
691 (named(NamedKey::ArrowUp), alt, None),
709 (
710 named(NamedKey::ArrowDown),
711 alt_shift,
712 Some(Command::MoveParagraphs { up: false }),
713 ),
714 (
715 named(NamedKey::ArrowUp),
716 alt,
717 Some(Command::MoveParagraphs { up: true }),
718 ),
719 (
720 named(NamedKey::ArrowDown),
721 alt,
722 Some(Command::MoveParagraphs { up: false }),
723 ),
724 (
725 named(NamedKey::ArrowUp),
726 Modifiers {
727 control: true,
728 command: true,
729 ..alt
730 },
731 None,
732 ),
692733 (
693734 named(NamedKey::ArrowLeft),
694735 control,