Repository: osa1/tiny (language: rust)

Issue:
Weird Highlighting
my nick is znschaffer yet tiny keeps on highlighting YouTube links bizarrely.

<img width="1014" alt="image" src="https://github.com/user-attachments/assets/ecc15fe4-f703-437a-a564-625322bc5ed0">

I'm not sure what in the regex for nick's would cause this but it's mighty annoying


Discussion / hints:
This is probably an IRC color code to show the "Tube" part in red background, similar to the old logos here: https://logos-world.net/youtube-logo/ (scroll to "Meaning and History").

It looks like either the colored part is not terminated, or it is terminated but we don't handle the termination code properly.

Have you checked if these messages look as expected in other clients?

Which server/channel is this? Maybe I (or someone else) can join and debug this.

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8947b961..ab1b2e1e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,8 @@
 # Unreleased
 
 - Improve nick matching to avoid highlighting message incorrectly. (#430)
+- Fix resetting message color when a color prefix (0x03) is not followed by a
+  color code. (#434)
 
 # 2024/01/01: 0.12.0
 
diff --git a/crates/libtiny_tui/src/msg_area/line.rs b/crates/libtiny_tui/src/msg_area/line.rs
index 30bc2f1c..bedde36b 100644
--- a/crates/libtiny_tui/src/msg_area/line.rs
+++ b/crates/libtiny_tui/src/msg_area/line.rs
@@ -156,7 +156,11 @@ impl Line {
                         self.set_message_style(SegStyle::Fixed(Style { fg: bg, bg: fg }));
                     }
                 }
-                IrcFormatEvent::Reset => {
+                // TODO: ResetColors should only reset the colors and not the formatting.
+                // However we don't store the current formatting and we can't apply formatting to
+                // a color from the current color scheme (e.g. `SegStyle::UserMsg`). For now reset
+                // the colors and formatting.
+                IrcFormatEvent::ResetColors | IrcFormatEvent::Reset => {
                     self.set_message_style(SegStyle::UserMsg);
                 }
             }
diff --git a/crates/libtiny_wire/src/formatting.rs b/crates/libtiny_wire/src/formatting.rs
index 753a928a..cec8c1bd 100644
--- a/crates/libtiny_wire/src/formatting.rs
+++ b/crates/libtiny_wire/src/formatting.rs
@@ -30,10 +30,13 @@ pub enum IrcFormatEvent<'a> {
         bg: Option<Color>,
     },
 
-    /// Reverse current background and foreground
+    /// Reverse current background and foreground colors.
     ReverseColor,
 
-    /// Reset formatting to the default
+    /// Reset background and foreground colors to the defaults.
+    ResetColors,
+
+    /// Reset formatting to the default.
     Reset,
 }
 
@@ -325,12 +328,10 @@ impl<'a> Iterator for FormatEventParser<'a> {
 
                 CHAR_COLOR => {
                     self.bump(1);
-                    match self.parse_color() {
-                        Some((fg, bg)) => return Some(IrcFormatEvent::Color { fg, bg }),
-                        None => {
-                            // Just skip the control char
-                        }
-                    }
+                    return match self.parse_color() {
+                        Some((fg, bg)) => Some(IrcFormatEvent::Color { fg, bg }),
+                        None => Some(IrcFormatEvent::ResetColors),
+                    };
                 }
 
                 CHAR_HEX_COLOR => {
@@ -389,6 +390,7 @@ pub fn remove_irc_control_chars(str: &str) -> String {
             | IrcFormatEvent::Monospace
             | IrcFormatEvent::Color { .. }
             | IrcFormatEvent::ReverseColor
+            | IrcFormatEvent::ResetColors
             | IrcFormatEvent::Reset => {}
             IrcFormatEvent::Text(text) => s.push_str(text),
         }
@@ -431,6 +433,7 @@ fn test_parse_text_2() {
     let s = "a\x03";
     let mut parser = parse_irc_formatting(s);
     assert_eq!(parser.next(), Some(IrcFormatEvent::Text("a")));
+    assert_eq!(parser.next(), Some(IrcFormatEvent::ResetColors));
     assert_eq!(parser.next(), None);
 }
 
@@ -439,6 +442,7 @@ fn test_parse_text_3() {
     let s = "a\x03b";
     let mut parser = parse_irc_formatting(s);
     assert_eq!(parser.next(), Some(IrcFormatEvent::Text("a")));
+    assert_eq!(parser.next(), Some(IrcFormatEvent::ResetColors));
     assert_eq!(parser.next(), Some(IrcFormatEvent::Text("b")));
     assert_eq!(parser.next(), None);
 }
@@ -511,6 +515,7 @@ fn test_parse_text_5() {
 
     let s = "\x03,a";
     let mut parser = parse_irc_formatting(s);
+    assert_eq!(parser.next(), Some(IrcFormatEvent::ResetColors));
     assert_eq!(parser.next(), Some(IrcFormatEvent::Text(",a")));
     assert_eq!(parser.next(), None);
 }


Test patch: