Repository: osa1/tiny (language: rust)

Issue:
Join/Part messages overflow
Saw this randomly when a bunch of people all joined/parted at the same time. It somehow corrected itself eventually, but still worth some investigation.

![image](https://user-images.githubusercontent.com/5448324/86273168-83653700-bbd8-11ea-9fb0-11a24f314d6b.png)



Discussion / hints:
![image](https://user-images.githubusercontent.com/5448324/86273622-3d5ca300-bbd9-11ea-8151-f79708c8d5d4.png)
This time it panicked! :fearful: 

Fix patch:
diff --git a/libtiny_tui/src/msg_area/line.rs b/libtiny_tui/src/msg_area/line.rs
index 2d70605b..2346be45 100644
--- a/libtiny_tui/src/msg_area/line.rs
+++ b/libtiny_tui/src/msg_area/line.rs
@@ -149,8 +149,12 @@ impl Line {
         self.len_chars += 1;
     }
 
-    /// How many lines does this take when rendered? O(n) where n = number of
-    /// split positions in the line (i.e. whitespaces).
+    pub(crate) fn force_recalculation(&mut self) {
+        self.line_data.set_dirty()
+    }
+
+    /// Calculates the number of lines that this line will be.
+    /// The calculation is only done if the line_data is dirty or the window is resized.
     pub(crate) fn rendered_height(&mut self, width: i32) -> i32 {
         if self.line_data.is_dirty() || self.line_data.needs_resize(width, 0) {
             self.line_data.reset(width, 0);
diff --git a/libtiny_tui/src/msg_area/mod.rs b/libtiny_tui/src/msg_area/mod.rs
index 187a14e5..3f5e66cc 100644
--- a/libtiny_tui/src/msg_area/mod.rs
+++ b/libtiny_tui/src/msg_area/mod.rs
@@ -180,6 +180,8 @@ impl MsgArea {
         F: Fn(&mut Line),
     {
         f(&mut self.lines[idx]);
+        // Line was modified so we need to invalidate its height
+        self.lines[idx].force_recalculation();
     }
 
     pub(crate) fn clear(&mut self) {


Test patch:
diff --git a/libtiny_tui/src/tests/mod.rs b/libtiny_tui/src/tests/mod.rs
index 9fb6485b..f97ed4c2 100644
--- a/libtiny_tui/src/tests/mod.rs
+++ b/libtiny_tui/src/tests/mod.rs
@@ -439,3 +439,31 @@ fn test_text_field_wrap() {
     // TODO: Test changing nick (osa: I don't understand how nick length is taken into account when
     // falling back to scrolling)
 }
+
+#[test]
+fn test_join_part_overflow() {
+    let mut tui = TUI::new_test(21, 4);
+    let serv = "irc.server_1.org";
+    let chan = "#chan";
+    tui.new_server_tab(serv, None);
+    tui.set_nick(serv, "osa1");
+    tui.new_chan_tab(serv, chan);
+    tui.next_tab();
+    tui.next_tab();
+
+    let target = MsgTarget::Chan { serv, chan };
+    let ts = time::at_utc(time::Timespec::new(0, 0));
+    tui.add_nick("123456", Some(ts), &target);
+    tui.add_nick("abcdef", Some(ts), &target);
+    tui.add_nick("hijklm", Some(ts), &target);
+    tui.draw();
+
+    #[rustfmt::skip]
+    let screen =
+        "|00:00 +123456 +abcdef|
+         |+hijklm              |
+         |osa1:                |
+         |< #chan              |";
+
+    expect_screen(screen, &tui, 21, 4, Location::caller());
+}