chiark / gitweb /
Editor: fix handling of abutting scan matches.
authorSimon Tatham <anakin@pobox.com>
Fri, 5 Jan 2024 22:26:37 +0000 (22:26 +0000)
committerSimon Tatham <anakin@pobox.com>
Fri, 5 Jan 2024 22:26:37 +0000 (22:26 +0000)
My example test of '#hashtag@mention' _shouldn't_ have highlighted the
mention, because the word character before the @ disqualifies it. But
I was doing the matching on a slice of the string, instead of giving
get_span the whole string and telling it where to start from.

That in turn was because I hadn't bothered to give get_span that
argument. But it's really easy to add! Now done.

src/editor.rs
src/scan_re.rs

index aac14baf0740f358fa8b6a1f6e5d1e902436227e..d357d967d389cf08f4603a28f20e04df22603453 100644 (file)
@@ -893,8 +893,8 @@ impl Composer {
             // something starting soonest (out of those that pick up
             // anything at all).
             let next_match = scanners.iter().filter_map(|(colour, scanner)| {
-                scanner.get_span(&core.text[pos..])
-                    .map(|(start, end)| (pos + start, pos + end, colour))
+                scanner.get_span(&core.text, pos)
+                    .map(|(start, end)| (start, end, colour))
             }).min();
 
             match next_match {
@@ -1216,14 +1216,22 @@ fn test_regions() {
         ComposeBufferRegion { start: 90, end: 91, colour: ' ' },
     });
 
-    // Scan a shorter piece of text in which a hashtag and a mention
-    // directly abut. FIXME: actually, surely we _shouldn't_ match
-    // this?
+    // When a hashtag and a mention directly abut, it should
+    // disqualify the hashtag.
     let composer = Composer::test_new(
         standard_conf.clone(), "#hashtag@mention");
     assert_eq!(composer.make_regions(&composer.core), vec! {
         ComposeBufferRegion { start: 0, end: 8, colour: '#' },
-        ComposeBufferRegion { start: 8, end: 16, colour: '@' },
+        ComposeBufferRegion { start: 8, end: 16, colour: ' ' },
+    });
+
+    // But a space between them is enough to make them work.
+    let composer = Composer::test_new(
+        standard_conf.clone(), "#hashtag @mention");
+    assert_eq!(composer.make_regions(&composer.core), vec! {
+        ComposeBufferRegion { start: 0, end: 8, colour: '#' },
+        ComposeBufferRegion { start: 8, end: 9, colour: ' ' },
+        ComposeBufferRegion { start: 9, end: 17, colour: '@' },
     });
 
     // The total cost of main_sample_text is 61 (counting the mention
index 43c9a20b085f8a83ea15cad3423011bf6b3a9bb3..adc38446c61d3505bbf48ccd159cdcfa7986386d 100644 (file)
@@ -8,8 +8,8 @@ pub struct Findable {
 }
 
 impl Findable {
-    pub fn get_span(&self, text: &str) -> Option<(usize, usize)> {
-        let mut start: usize = 0;
+    pub fn get_span(&self, text: &str, start: usize) -> Option<(usize, usize)> {
+        let mut start = start;
         loop {
             match self.text.find_at(&text, start) {
                 None => break None,
@@ -159,68 +159,68 @@ impl Scan {
 #[test]
 fn test_mention() {
     let scan = Scan::get();
-    assert_eq!(scan.mention.get_span("hello @user"),
+    assert_eq!(scan.mention.get_span("hello @user", 0),
                Some((6, 11)));
-    assert_eq!(scan.mention.get_span("hello @user@domain.foo"),
+    assert_eq!(scan.mention.get_span("hello @user@domain.foo", 0),
                Some((6, 22)));
 
-    assert_eq!(scan.mention.get_span("hello a@user"), None);
-    assert_eq!(scan.mention.get_span("hello =@user"), None);
-    assert_eq!(scan.mention.get_span("hello /@user"), None);
-    assert_eq!(scan.mention.get_span("hello )@user"),
+    assert_eq!(scan.mention.get_span("hello a@user", 0), None);
+    assert_eq!(scan.mention.get_span("hello =@user", 0), None);
+    assert_eq!(scan.mention.get_span("hello /@user", 0), None);
+    assert_eq!(scan.mention.get_span("hello )@user", 0),
                Some((7, 12)));
 
-    assert_eq!(scan.mention.get_span("hello @user.name"),
+    assert_eq!(scan.mention.get_span("hello @user.name", 0),
                Some((6, 16)));
-    assert_eq!(scan.mention.get_span("hello @user.name."),
+    assert_eq!(scan.mention.get_span("hello @user.name.", 0),
                Some((6, 16)));
-    assert_eq!(scan.mention.get_span("hello @user-name"),
+    assert_eq!(scan.mention.get_span("hello @user-name", 0),
                Some((6, 16)));
-    assert_eq!(scan.mention.get_span("hello @user-name-"),
+    assert_eq!(scan.mention.get_span("hello @user-name-", 0),
                Some((6, 16)));
 }
 
 #[test]
 fn test_hashtag() {
     let scan = Scan::get();
-    assert_eq!(scan.hashtag.get_span("some #text here"),
+    assert_eq!(scan.hashtag.get_span("some #text here", 0),
                Some((5, 10)));
-    assert_eq!(scan.hashtag.get_span("some # here"), None);
-    assert_eq!(scan.hashtag.get_span("some #__a__ here"),
+    assert_eq!(scan.hashtag.get_span("some # here", 0), None);
+    assert_eq!(scan.hashtag.get_span("some #__a__ here", 0),
                Some((5, 11)));
-    assert_eq!(scan.hashtag.get_span("some #_____ here"),
+    assert_eq!(scan.hashtag.get_span("some #_____ here", 0),
                Some((5, 11)));
-    assert_eq!(scan.hashtag.get_span("some #_0_0_ here"),
+    assert_eq!(scan.hashtag.get_span("some #_0_0_ here", 0),
                Some((5, 11)));
 
-    assert_eq!(scan.hashtag.get_span("some a#text here"), None);
-    assert_eq!(scan.hashtag.get_span("some )#text here"), None);
-    assert_eq!(scan.hashtag.get_span("some (#text here"),
+    assert_eq!(scan.hashtag.get_span("some a#text here", 0), None);
+    assert_eq!(scan.hashtag.get_span("some )#text here", 0), None);
+    assert_eq!(scan.hashtag.get_span("some (#text here", 0),
                Some((6,11)));
 }
 
 #[test]
 fn test_domain() {
     let scan = Scan::get();
-    assert_eq!(scan.domain.get_span("foo.bar.baz"),
+    assert_eq!(scan.domain.get_span("foo.bar.baz", 0),
                Some((0, 11)));
-    assert_eq!(scan.domain.get_span("foo.bar.baz."),
+    assert_eq!(scan.domain.get_span("foo.bar.baz.", 0),
                Some((0, 11)));
-    assert_eq!(scan.domain.get_span("foo.b-r.baz"),
+    assert_eq!(scan.domain.get_span("foo.b-r.baz", 0),
                Some((0, 11)));
-    assert_eq!(scan.domain.get_span("foo.-br.baz"),
+    assert_eq!(scan.domain.get_span("foo.-br.baz", 0),
                Some((0, 3)));
-    assert_eq!(scan.domain.get_span("foo.br-.baz"),
+    assert_eq!(scan.domain.get_span("foo.br-.baz", 0),
                Some((0, 6))); // matches foo.br
 }
 
 #[test]
 fn test_url() {
     let scan = Scan::get();
-    assert_eq!(scan.url.get_span("Look at https://example.com."),
+    assert_eq!(scan.url.get_span("Look at https://example.com.", 0),
                Some((8, 27)));
-    assert_eq!(scan.url.get_span("Or https://en.wikipedia.org/wiki/Panda_(disambiguation)."),
+    assert_eq!(scan.url.get_span("Or https://en.wikipedia.org/wiki/Panda_(disambiguation).", 0),
                Some((3, 55)));
-    assert_eq!(scan.url.get_span("Or https://example.com/music/Track_(Thing_(Edited))."),
+    assert_eq!(scan.url.get_span("Or https://example.com/music/Track_(Thing_(Edited)).", 0),
                Some((3, 51)));
 }