Repository: jugglerchris/rust-html2text (rust)

Issue:
Imbricated tables in HTML emails and --css --ignore-css-colour
I updated my patched version of the html2text script with the new 0.13 release, I tested it on a few emails and **found one email that did not output anything.**

I'm using `--colour --css --ignore-css-colour` to get custom text formats but still hide some elements that should not appear.

There is no zero height element or any reference to display or overflow in the email sources, but ater some tests **I found that if I remove the top 'tr' and 'td' opening and closing tags in the parent table, it works then, every other element is inside imbricated tables inside this one.**

The concerned html email:

- I patched html2text.rs with `config = config.raw_mode(true);` and some changes in `match annotation {}`, then I build with `cargo build --features css --example html2text`
- I run with `html2text --width 80 --wrap-width 80 --colour --ignore-css-colour --css email.html`
- Removing lines 9, 10, 82 and 83 in the email fixes the issue.

``` html
<html>
<head>
<meta content="width=device-width" name="onboarding-uptimerobot"/>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<title>📲 SMS/Voice calls: Stay updated anytime, anywhere!</title>
</head>
<body style="font-family: 'Roboto', Arial, sans-serif; color: #131a26; background: #fefefe;">
<table border="0" cellpadding="0" cellspacing="0" style="max-width: 600px; margin: 0px auto 0 auto; padding: 0 10px;">
<tr style="font-family: 'Roboto', Arial, sans-serif; color: #131a26; background: #fefefe;">
<td style="font-family: 'Roboto', Arial, sans-serif; color: #131a26; background: #fefefe;">
<table border="0" cellpadding="0" cellspacing="0" style="max-width: 600px; margin: 0px auto 0 auto; padding: 0 10px;">
<tr style="max-width: 600px; margin: 0px auto 0 auto; padding: 0 10px;">
<td style="max-width: 600px; margin: 0px auto 0 auto; padding: 0 10px;">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td style="color: #ffffff; background:#131a26; border-radius: 6px 6px 0 0; box-shadow: 0 20px 40px 0 rgba(0,0,0,0.1); padding: 6px 0 0 0; font-size: 14px;">
<a href="https://uptimerobot.user.com/emails/c/eM9oWZX0/?to=https%3A%2F%2Fapp.uptimerobot.com%2Fbilling%2Fcheckout%2Fextra-credits%2F%3Futm_source%3Duser_com%26utm_medium%3Demail%26utm_campaign%3Dsms-calls-promo-free">
<img alt="" src="https://uptimerobot.user.com/uploads/su5k6k-uptimerobot/email-enable-sms-promo_DfAjPuj.png" style="width: 100%;"/>
</a>
</td>
</tr>
</table>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td style="color: #ffffff; background:#131a26; border-radius: 0 0 6px 6px; box-shadow: 0 20px 20px 0 rgba(0,0,0,0.1); padding: 1px 35px; font-size: 14px;">
<p style="line-height: 22px; margin-bottom: 30px; padding-left: 30px; padding-right: 30px;">
                        Hey there!
                      </p>
<p style="line-height: 22px; margin-bottom: 30px; padding-left: 30px; padding-right: 30px;">
                        Did you know we can notify you about incidents via SMS or voice calls? 📲
                      </p>
<h3 style="line-height: 22px; padding-left: 30px; padding-right: 20px; color: #3bd771">
                        Why use SMS/Voice call alerts?
                      </h3>
<ul style="line-height: 22px; margin-bottom: 30px; padding-left: 50px; padding-right: 30px;">
<li>SMS/Voice calls work without an internet connection.</li>
<li>They won't get lost in tons of emails or push notifications.</li>
<li>Try it out with our special entry package: <b style="color: #3bd771">Get 10 SMS/voice call credits for only $3!</b>
</li>
</ul>
<p style="line-height: 22px; margin-bottom: 40px; margin-top: 30px">
<a href="https://uptimerobot.user.com/emails/c/eM9QO1ZX0/?to=https%3A%2F%2Fapp.uptimerobot.com%2Fbilling%2Fcheckout%2Fextra-credits%2F%3Futm_source%3Duser_com%26utm_medium%3Demail%26utm_campaign%3Dsms-calls-promo-free" style="width: 220px; max-width: 90%; line-height: 48px; background-color:#3bd771; color: #fff; display: block; margin: 0 auto; text-decoration: none; border-radius: 28px; font-size: 16px; text-align: center; font-weight: bold; vertical-align: middle;">Buy SMS/Call credits</a></p>
<p style="line-height: 22px; margin-bottom: 30px; padding-left: 30px; padding-right: 30px;">Have a great (up)time!<br/>
                        Lucia from UptimeRobot</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
<table style="width: 100%">
<tr>
<td style="font-size: 12px; color: #687790; text-align: center; padding: 15px 0; font-family: 'Roboto',sans-serif;">
<p style="font-size: 16px; text-align: center; color: #131a26;"><b>Join our <a href="https://uptimerobot.user.com/emails/c/9kvRxzDWeM0/?to=https%3A%2F%2Fdiscord.com%2Finvite%2FJRBar2vA5N" style="font-size: 16px; text-align: center; color:#3bd771;">Discord</a>. Stay updated<span style="color:#3bd771;">.</span> Earn rewards<span style="color:#3bd771;">.</span></b></p>
<p style="box-sizing: border-box; font-size: 12px; line-height: 130%;">
<a href="https://uptimerobot.user.com/emails/c/axoKy6PXQ92d/?to=https%3A%2F%2Fwww.facebook.com%2FUptimeRobot%2F">
<img alt="uptimerobot-facebook" height="auto" src="http://cdn.mcauto-images-production.sendgrid.net/3e8054f26aace367/ab7d7dc4-d774-407a-a021-359470531d13/64x64.png" width="32"/></a>
<a href="https://uptimerobot.user.com/emails/c/05mR0X861Rk1A/?to=https%3A%2F%2Ftwitter.com%2Fuptimerobot">
<img alt="uptimerobot-twitter" height="auto" src="http://cdn.mcauto-images-production.sendgrid.net/b0f7060ce6d5fe3b/2852c673-3641-4439-a082-7b8a02f11784/64x64.png" width="32"/></a>
<a href="https://uptimerobot.user.com/emails/c/5woQzn5QJpn/?to=https%3A%2F%2Fwww.linkedin.com%2Fcompany%2Fuptime-robot%2F">
<img alt="uptimerobot-linkedin" height="auto" src="http://cdn.mcauto-images-production.sendgrid.net/3e8054f26aace367/bec4a5fa-247f-480f-8e75-d9edc9fdcb29/64x64.png" width="32"/></a>
<a href="https://uptimerobot.user.com/emails/c/A98WXkKv2l/?to=https%3A%2F%2Fdiscord.gg%2FJRBar2vA5N">
<img alt="uptimerobot-discord" height="auto" src="http://cdn.mcauto-images-production.sendgrid.net/b0f7060ce6d5fe3b/30a85fbe-fbe8-4148-92f8-63b7cfc8bdb3/64x64.png" width="32"/></a>
</p>
<p style="font-size: 12px; text-align: center; color: #999;">
<a href="https://uptimerobot.user.com/emails/c/OVPR3/?to=https%3A%2F%2Fuptimerobot.com%2Fpricing%2F" style="font-size: 12px; text-align: center; color: #999;">Pricing</a> | <a href="https://uptimerobot.user.com/emails/c/oPDK44J0vKg0j/?to=https%3A%2F%2Fblog.uptimerobot.com%2F" style="font-size: 12px; text-align: center; color: #999;">Blog</a> | <a href="https://uptimerobot.user.com/emails/c/axo2MrQ92d/?to=https%3A%2F%2Fuptimerobot.com%2Faffiliate%2F" style="font-size: 12px; text-align: center; color: #999;">Affiliate</a></p>
<br/>
<p>
<span style="color: #999; font-size: 10px;">
                    Uptime Robot Service Provider Ltd.<br/>
                    Regent House, Office 21, Bisazza Street,
                    Sliema SLM1640,
                    Malta</span>
</p>
<p style="font-size: 10px;">
<span style="color: #999; font-size: 10px;">
<a href="https://uptimerobot.user.com/emails/unsubscribe/4uwjdp/173087/">Unsubscribe</a></span>
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
<img alt="" src="https://uptimerobot.user.com/emails/open/187/"/></body>
</html>

```

Pull request description:
Fix issue 155: table rows with styling going missing.
There was a missing case in `wrap_render_nodes()`; table row nodes need to wrap the nested contents so that the TableRow nodes are still direct children of the TableBody.

Fixes #155 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 15303a9..49829eb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,10 @@ Possible log types:
 - `[fixed]` for any bug fixes.
 - `[security]` to invite users to upgrade in case of vulnerabilities.
 
+### 0.13.0-alpha.1
+
+- [fixed] Table rows with colours would disappear. (thanks tkapias)
+
 ### 0.13.0-alpha.0
 
 - [changed] Replaced LightningCSS with a smaller CSS parser.  There is a chance
diff --git a/Cargo.toml b/Cargo.toml
index 540282c..90bab61 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "html2text"
-version = "0.13.0-alpha.0"
+version = "0.13.0-alpha.1"
 authors = ["Chris Emerson <github@mail.nosreme.org>"]
 description = "Render HTML as plain text."
 repository = "https://github.com/jugglerchris/rust-html2text/"
diff --git a/src/lib.rs b/src/lib.rs
index c42156b..7786b58 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -892,6 +892,20 @@ impl<'a, C: 'a, N> TreeMapResult<'a, C, N, RenderNode> {
                                     cellinfo.content = vec![wrapped];
                                     RenderNode::new(RenderNodeInfo::TableCell(cellinfo))
                                 }
+                                RenderNodeInfo::TableRow(mut row, vert) => {
+                                    let cells = row.cells;
+                                    let cells = cells
+                                        .into_iter()
+                                        .map(|mut child| {
+                                            let children = child.content;
+                                            let wrapped = RenderNode::new(f(children));
+                                            child.content = vec![wrapped];
+                                            child
+                                        })
+                                        .collect();
+                                    row.cells = cells;
+                                    RenderNode::new(RenderNodeInfo::TableRow(row, vert))
+                                }
                                 ni => RenderNode::new(f(vec![RenderNode::new(ni)])),
                             }
                         }))
diff --git a/src/render/mod.rs b/src/render/mod.rs
index 3637c18..e0955cc 100644
--- a/src/render/mod.rs
+++ b/src/render/mod.rs
@@ -58,9 +58,6 @@ pub(crate) trait Renderer {
     /// Return the current width in character cells
     fn width(&self) -> usize;
 
-    /// Add a line to the current block without starting a new one.
-    fn add_block_line(&mut self, line: &str);
-
     /// Add a new block from a sub renderer, and prefix every line by the
     /// corresponding text from each iteration of prefixes.
     fn append_subrender<'a, I>(&mut self, other: Self, prefixes: I) -> Result<(), Error>
@@ -86,9 +83,6 @@ pub(crate) trait Renderer {
     /// Returns true if this renderer has no content.
     fn empty(&self) -> bool;
 
-    /// Return the length of the contained text.
-    fn text_len(&self) -> usize;
-
     /// Start a hyperlink
     /// TODO: return sub-builder or similar to make misuse
     /// of start/link harder?
diff --git a/src/render/text_renderer.rs b/src/render/text_renderer.rs
index 4c1cee9..43a94c8 100644
--- a/src/render/text_renderer.rs
+++ b/src/render/text_renderer.rs
@@ -993,22 +993,6 @@ impl<D: TextDecorator> SubRenderer<D> {
         }
     }
 
-    /// Add a prerendered (multiline) string with the current annotations.
-    fn add_subblock(&mut self, s: &str) {
-        use self::TaggedLineElement::Str;
-
-        html_trace!("add_subblock({}, {})", self.width, s);
-        let tag = self.ann_stack.clone();
-        self.lines.extend(s.lines().map(|l| {
-            let mut line = TaggedLine::new();
-            line.push(Str(TaggedString {
-                s: l.into(),
-                tag: tag.clone(),
-            }));
-            RenderLine::Text(line)
-        }));
-    }
-
     /// Flushes the current wrapped block into the lines.
     fn flush_wrapping(&mut self) -> Result<(), Error> {
         if let Some(w) = self.wrapping.take() {
@@ -1249,10 +1233,6 @@ impl<D: TextDecorator> Renderer for SubRenderer<D> {
         self.width
     }
 
-    fn add_block_line(&mut self, line: &str) {
-        self.add_subblock(line);
-    }
-
     fn append_subrender<'a, I>(&mut self, other: Self, prefixes: I) -> Result<(), Error>
     where
         I: Iterator<Item = &'a str>,
@@ -1478,20 +1458,6 @@ impl<D: TextDecorator> Renderer for SubRenderer<D> {
             }
     }
 
-    fn text_len(&self) -> usize {
-        let mut result = 0;
-        for line in &self.lines {
-            result += match *line {
-                RenderLine::Text(ref tline) => tline.width(),
-                RenderLine::Line(_) => 0, // FIXME: should borders count?
-            };
-        }
-        if let Some(ref w) = self.wrapping {
-            result += w.text_len();
-        }
-        result
-    }
-
     fn start_link(&mut self, target: &str) -> crate::Result<()> {
         let (s, annotation) = self.decorator.decorate_link_start(target);
         self.ann_stack.push(annotation);


Test patch:
diff --git a/src/tests.rs b/src/tests.rs
index 46a7e4d..44e2c6c 100644
--- a/src/tests.rs
+++ b/src/tests.rs
@@ -2388,6 +2388,38 @@ Baz
             r#"X<R>CD</R>Y
 
 <G>C</G>D
+"#,
+            20,
+        );
+    }
+
+    #[test]
+    fn test_colour_row() {
+        test_html_coloured(
+            br#"<head><style>
+        tr.r {
+            color: #f00;
+        }
+        </style></head><body>
+        <table>
+         <tr>
+           <td>Row</td><td>One</td>
+         </tr>
+         <tr class="r">
+           <td>Row</td><td>Two</td>
+         </tr>
+         <tr>
+           <td>Row</td><td>Three</td>
+         </tr>
+        </table>
+        "#,
+            r#"───┬─────
+Row│One  
+───┼─────
+<R>Row</R>│<R>Two</R>  
+───┼─────
+Row│Three
+───┴─────
 "#,
             20,
         );