@@ -270,6 +270,7 @@ impl Command {
270
270
// TODO: different description ?
271
271
goto_line_end_newline, "Goto line end" ,
272
272
goto_first_nonwhitespace, "Goto first non-blank in line" ,
273
+ trim_selections, "Trim whitespace from selections" ,
273
274
extend_to_line_start, "Extend to line start" ,
274
275
extend_to_line_end, "Extend to line end" ,
275
276
extend_to_line_end_newline, "Extend to line end" ,
@@ -582,6 +583,42 @@ fn goto_first_nonwhitespace(cx: &mut Context) {
582
583
doc. set_selection ( view. id , selection) ;
583
584
}
584
585
586
+ fn trim_selections ( cx : & mut Context ) {
587
+ let ( view, doc) = current ! ( cx. editor) ;
588
+ let text = doc. text ( ) . slice ( ..) ;
589
+
590
+ let ranges: SmallVec < [ Range ; 1 ] > = doc
591
+ . selection ( view. id )
592
+ . iter ( )
593
+ . filter_map ( |range| {
594
+ if range. is_empty ( ) || range. fragment ( text) . chars ( ) . all ( |ch| ch. is_whitespace ( ) ) {
595
+ return None ;
596
+ }
597
+ let mut start = range. from ( ) ;
598
+ let mut end = range. to ( ) ;
599
+ start = movement:: skip_while ( text, start, |x| x. is_whitespace ( ) ) . unwrap_or ( start) ;
600
+ end = movement:: backwards_skip_while ( text, end, |x| x. is_whitespace ( ) ) . unwrap_or ( end) ;
601
+ if range. anchor < range. head {
602
+ Some ( Range :: new ( start, end) )
603
+ } else {
604
+ Some ( Range :: new ( end, start) )
605
+ }
606
+ } )
607
+ . collect ( ) ;
608
+
609
+ if !ranges. is_empty ( ) {
610
+ let primary = doc. selection ( view. id ) . primary ( ) ;
611
+ let idx = ranges
612
+ . iter ( )
613
+ . position ( |range| range. overlaps ( & primary) )
614
+ . unwrap_or ( ranges. len ( ) - 1 ) ;
615
+ doc. set_selection ( view. id , Selection :: new ( ranges, idx) ) ;
616
+ } else {
617
+ collapse_selection ( cx) ;
618
+ keep_primary_selection ( cx) ;
619
+ } ;
620
+ }
621
+
585
622
fn goto_window ( cx : & mut Context , align : Align ) {
586
623
let ( view, doc) = current ! ( cx. editor) ;
587
624
0 commit comments