on master help sign in
Fix extra selection with regex anchors (^,$) (#3598)
78189ddA-Walrus
helix-core/src/selection.rs+77−1
@@ -659,7 +659,13 @@ pub fn select_on_matches(
659
659
660 let start = text.byte_to_char(start_byte + mat.start());
660 let start = text.byte_to_char(start_byte + mat.start());
661 let end = text.byte_to_char(start_byte + mat.end());
661 let end = text.byte_to_char(start_byte + mat.end());
662+
662− result.push(Range::new(start, end));
663+ let range = Range::new(start, end);
664+ // Make sure the match is not right outside of the selection.
665+ // These invalid matches can come from using RegEx anchors like `^`, `$`
666+ if range != Range::point(sel.to()) {
667+ result.push(range);
668+ }
663 }
669 }
664 }
670 }
665
671
@@ -929,6 +935,76 @@ mod test {
929 assert_eq!(Range::new(6, 5).min_width_1(s), Range::new(6, 5));
935 assert_eq!(Range::new(6, 5).min_width_1(s), Range::new(6, 5));
930 }
936 }
931
937
938+ #[test]
939+ fn test_select_on_matches() {
940+ use crate::regex::{Regex, RegexBuilder};
941+
942+ let r = Rope::from_str("Nobody expects the Spanish inquisition");
943+ let s = r.slice(..);
944+
945+ let selection = Selection::single(0, r.len_chars());
946+ assert_eq!(
947+ select_on_matches(s, &selection, &Regex::new(r"[A-Z][a-z]*").unwrap()),
948+ Some(Selection::new(
949+ smallvec![Range::new(0, 6), Range::new(19, 26)],
950+ 0
951+ ))
952+ );
953+
954+ let r = Rope::from_str("This\nString\n\ncontains multiple\nlines");
955+ let s = r.slice(..);
956+
957+ let start_of_line = RegexBuilder::new(r"^").multi_line(true).build().unwrap();
958+ let end_of_line = RegexBuilder::new(r"$").multi_line(true).build().unwrap();
959+
960+ // line without ending
961+ assert_eq!(
962+ select_on_matches(s, &Selection::single(0, 4), &start_of_line),
963+ Some(Selection::single(0, 0))
964+ );
965+ assert_eq!(
966+ select_on_matches(s, &Selection::single(0, 4), &end_of_line),
967+ None
968+ );
969+ // line with ending
970+ assert_eq!(
971+ select_on_matches(s, &Selection::single(0, 5), &start_of_line),
972+ Some(Selection::single(0, 0))
973+ );
974+ assert_eq!(
975+ select_on_matches(s, &Selection::single(0, 5), &end_of_line),
976+ Some(Selection::single(4, 4))
977+ );
978+ // line with start of next line
979+ assert_eq!(
980+ select_on_matches(s, &Selection::single(0, 6), &start_of_line),
981+ Some(Selection::new(
982+ smallvec![Range::point(0), Range::point(5)],
983+ 0
984+ ))
985+ );
986+ assert_eq!(
987+ select_on_matches(s, &Selection::single(0, 6), &end_of_line),
988+ Some(Selection::single(4, 4))
989+ );
990+
991+ // multiple lines
992+ assert_eq!(
993+ select_on_matches(
994+ s,
995+ &Selection::single(0, s.len_chars()),
996+ &RegexBuilder::new(r"^[a-z ]*$")
997+ .multi_line(true)
998+ .build()
999+ .unwrap()
1000+ ),
1001+ Some(Selection::new(
1002+ smallvec![Range::point(12), Range::new(13, 30), Range::new(31, 36)],
1003+ 0
1004+ ))
1005+ );
1006+ }
1007+
932 #[test]
1008 #[test]
933 fn test_line_range() {
1009 fn test_line_range() {
934 let r = Rope::from_str("\r\nHi\r\nthere!");
1010 let r = Rope::from_str("\r\nHi\r\nthere!");