diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a1a2600..0b058e9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,11 @@ Use `cargo release` to create a new release. ### Changed - Release builds no longer use fat LTO, which significantly reduces compilation time. +### Fixed +- mdcat no longer panics on markups in descriptions of rendered images (see [GH-287]). + +[GH-287]: https://github.com/swsnr/mdcat/pull/287 + ## [2.3.0] – 2024-07-28 ### Added diff --git a/pulldown-cmark-mdcat/src/render.rs b/pulldown-cmark-mdcat/src/render.rs index 5f7e55f6..151e106b 100644 --- a/pulldown-cmark-mdcat/src/render.rs +++ b/pulldown-cmark-mdcat/src/render.rs @@ -726,10 +726,22 @@ pub fn write_event<'a, W: Write>( .and_data(data) .ok() } - (Stacked(stack, RenderedImage), Text(_)) => { - Stacked(stack, RenderedImage).and_data(data).ok() - } + // To correctly handle nested images in the image description, we push a dummy rendered + // image state so to maintain a correct state stack at the end of image event, where the + // tail of the stack gets popped. + (Stacked(stack, RenderedImage), Start(Image(_, _, _))) => stack + .push(RenderedImage) + .current(RenderedImage) + .and_data(data) + .ok(), (Stacked(stack, RenderedImage), End(Image(_, _, _))) => stack.pop().and_data(data).ok(), + // Immediately after the start of image event comes the alt text, which we do not support + // for rendered images. So we just ignore all events other than image events, which are + // handled above. + // + // See also https://docs.rs/pulldown-cmark/0.9.6/src/pulldown_cmark/html.rs.html#280-290 for + // how the upstream handles images. + (Stacked(stack, RenderedImage), _) => Stacked(stack, RenderedImage).and_data(data).ok(), (Stacked(stack, Inline(state, attrs)), End(Image(_, target, title))) => { if let InlineLink = state { clear_link(writer)?; diff --git a/pulldown-cmark-mdcat/tests/render/golden/ansi-only/samples/images b/pulldown-cmark-mdcat/tests/render/golden/ansi-only/samples/images index ce1ee909..645a6895 100644 --- a/pulldown-cmark-mdcat/tests/render/golden/ansi-only/samples/images +++ b/pulldown-cmark-mdcat/tests/render/golden/ansi-only/samples/images @@ -6,6 +6,8 @@ An inline ]8;;https://example.com/\linked image[2] An inline ]8;;https://example.com/\linked image[3]]8;;\ with nested formatting. +An inline]8;;file://HOSTNAME/WORKING_DIRECTORY/tests/render/md/samples/image.png\ image with a nested image[4] and markups in description]8;;\. + Or as block: ]8;;file://HOSTNAME/WORKING_DIRECTORY/tests/render/md/samples/image.png\image]8;;\ @@ -13,3 +15,4 @@ Or as block: [1]: ]8;;file://HOSTNAME/WORKING_DIRECTORY/tests/render/md/samples/image.png\./image.png]8;;\ [2]: ]8;;file://HOSTNAME/WORKING_DIRECTORY/tests/render/md/samples/image.png\./image.png]8;;\ [3]: ]8;;file://HOSTNAME/WORKING_DIRECTORY/tests/render/md/samples/image.png\./image.png]8;;\ +[4]: ]8;;file://HOSTNAME/WORKING_DIRECTORY/tests/render/md/samples/image.png\./image.png]8;;\ diff --git a/pulldown-cmark-mdcat/tests/render/golden/dump/samples/images b/pulldown-cmark-mdcat/tests/render/golden/dump/samples/images index d3bafefe..88a38465 100644 --- a/pulldown-cmark-mdcat/tests/render/golden/dump/samples/images +++ b/pulldown-cmark-mdcat/tests/render/golden/dump/samples/images @@ -6,9 +6,11 @@ An inline linked image[4][5] with some extra text. An inline linked image[6][7] with nested formatting. +An inline image with a nested image[8] and markups in description[9]. + Or as block: -image[8] +image[10] [1]: ./image.png [2]: ./image.png @@ -18,3 +20,5 @@ image[8] [6]: ./image.png [7]: https://example.com [8]: ./image.png +[9]: ./image.png +[10]: ./image.png diff --git a/pulldown-cmark-mdcat/tests/render/golden/iterm2/samples/images b/pulldown-cmark-mdcat/tests/render/golden/iterm2/samples/images index 2652b335..ab7a1b13 100644 --- a/pulldown-cmark-mdcat/tests/render/golden/iterm2/samples/images +++ b/pulldown-cmark-mdcat/tests/render/golden/iterm2/samples/images @@ -6,6 +6,8 @@ An inline ]8;;https://example.com/\linked]1337;File=name=aW1hZ2UucG5 An inline ]8;;https://example.com/\linked]1337;File=name=aW1hZ2UucG5n;size=1371;inline=1:iVBORw0KGgoAAAANSUhEUgAAACgAAAAUCAYAAAD/Rn+7AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAC4jAAAuIwF4pT92AAAE+0lEQVRIx62WTWgTaxSGnyTDmKKNNqOMxpoW02AbDHUK7gKV6kJxYfEHcacLXTRQdKsRKrhQXCnBhS5F/EcXioK0ILqQQqmhkmKDOIkQOi0ziZMqpaWdu5D5blISrL33wPD9M+93vnPe93gcx3H4C7MsC9u2sW2bUqkk5oLBIC0tLQQCAdrb2+ue1XUd27b5+vUrpmliGAaqqqIoCqZpMj4+DsDt27fFGYm/tGAwKPqBQACAtrY2AoFAzVqji7mXcs0wjJq2GtyaAK4EVw/4n14gm82KcbFYpFgsNtwvuc/zXzy5lku5oFyPDQwM1Af4tz+xLGtNHncvFIlExFwqlRL9lU8rzGlgpmnWnfv27VvdtdWYe840TSeTyTgDAwMOINp6n6dRFjfylG3bf0yI1Ziu64yPj4t4LBaLdb0oYtBtnz59yokTJwC4fPkyx48fBxDUEI1GaWtrW3McVsejpmkAmKZZkyjV8Si53pqYmABg8+bNgpdisRilUqkm8xRFEXz3f1gwGCSbzdZ4LxQKoaoqhmEg2bZd86yRSITt27djmiZbtmzh06dPnD9/nl27drF7927u3btHb28vfX19DA8P4/P5uHr1KouLi9y6dYu5uTkKhQKDg4P09fVRLpe5efMmhUKBJ0+eEI1GuXTpEolEghcvXjAyMoJlWSSTSbZt21YDPhaLId2/fx9VVevSh2VZhMNhwuEwX7584ejRo6xfv547d+6wf/9+kskke/bs4ciRI3R1dZHNZnn+/DmpVIr+/n6mp6cZHh5maGiIQqFAd3c3N27c4NChQ7x9+5YLFy7w6tUr8vk86XSadDqN1+sVL2YYBtJKkjQMgx8/fojYcKXI6/Vy8uRJnj17BkBHRwd+vx+AX79+sXXrVs6dO8e1a9cYGxujUqnw8+dPZFkGYH5+Hq/XiyzLeDwe8vk8AA8ePGB5eZmenh42btxIpVIhm82KmJRCoVANcQJCjpaWlpidncUwDJqammhubsbd39zczNzcnNj38OFDTp8+TaFQ4Pv372J+37597N27l3Q6jaIovHz5Er/fT2dnJwCHDx8mFoshyzILCwt8+PCBVColEsV36tSpoQ0bNjA9PQ1ALpdjcnLyN3pJQtd1RkdHKZVK+P1+Ll68KELh8+fPvH//Hl3XOXbsGFNTU5TLZYLBICMjI8TjcTweD1euXKG7u5vl5WXK5TLRaJSOjg7a29t5/Pgxs7OzTExM0NnZiW3b7NixQySL5+7duw4gKonqTEokEgC0tLTgOI6oVDweD47j4PF4XLIXfXe8tLSEJElMTk7S398PwNTUFACvX7/m4MGDYv+7d+/I5XKiYABQVZVoNIqkKIoAVE+04/F4Xb6rBlTdd8eS9FtF37x5QzKZZHBwkJmZGVRVFTzqErZlWZw9e1ZwoKZpRKNR4vE4UiOyLRaL5HI54vE4ay0oAHp7e7l+/TqmaeLz+fj48SNdXV0C3EpyPnDgAJFIhNbW1n+VpFqwq1lcURQhbW4916gYbWQ9PT08evSo4bpt20IEQqEQmqYJKdV1Hck0zZpbaJomlKQ6Nl05zOfzqypQV2ujo6MitBKJhFAo1yG+M2fODLW2thIOh5FlGUVR0DSNnTt3srCwwNjYGJlMhlKpRCaTQZZlfD4fTU1NbNq0ac3ALMti3bp1zMzMMD8/T6VSEUyxuLhIIBDAtm3+Ach61YAcN+PJAAAAAElFTkSuQmCC\]8;;\ with nested formatting. +An inline]1337;File=name=aW1hZ2UucG5n;size=1371;inline=1:iVBORw0KGgoAAAANSUhEUgAAACgAAAAUCAYAAAD/Rn+7AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAC4jAAAuIwF4pT92AAAE+0lEQVRIx62WTWgTaxSGnyTDmKKNNqOMxpoW02AbDHUK7gKV6kJxYfEHcacLXTRQdKsRKrhQXCnBhS5F/EcXioK0ILqQQqmhkmKDOIkQOi0ziZMqpaWdu5D5blISrL33wPD9M+93vnPe93gcx3H4C7MsC9u2sW2bUqkk5oLBIC0tLQQCAdrb2+ue1XUd27b5+vUrpmliGAaqqqIoCqZpMj4+DsDt27fFGYm/tGAwKPqBQACAtrY2AoFAzVqji7mXcs0wjJq2GtyaAK4EVw/4n14gm82KcbFYpFgsNtwvuc/zXzy5lku5oFyPDQwM1Af4tz+xLGtNHncvFIlExFwqlRL9lU8rzGlgpmnWnfv27VvdtdWYe840TSeTyTgDAwMOINp6n6dRFjfylG3bf0yI1Ziu64yPj4t4LBaLdb0oYtBtnz59yokTJwC4fPkyx48fBxDUEI1GaWtrW3McVsejpmkAmKZZkyjV8Si53pqYmABg8+bNgpdisRilUqkm8xRFEXz3f1gwGCSbzdZ4LxQKoaoqhmEg2bZd86yRSITt27djmiZbtmzh06dPnD9/nl27drF7927u3btHb28vfX19DA8P4/P5uHr1KouLi9y6dYu5uTkKhQKDg4P09fVRLpe5efMmhUKBJ0+eEI1GuXTpEolEghcvXjAyMoJlWSSTSbZt21YDPhaLId2/fx9VVevSh2VZhMNhwuEwX7584ejRo6xfv547d+6wf/9+kskke/bs4ciRI3R1dZHNZnn+/DmpVIr+/n6mp6cZHh5maGiIQqFAd3c3N27c4NChQ7x9+5YLFy7w6tUr8vk86XSadDqN1+sVL2YYBtJKkjQMgx8/fojYcKXI6/Vy8uRJnj17BkBHRwd+vx+AX79+sXXrVs6dO8e1a9cYGxujUqnw8+dPZFkGYH5+Hq/XiyzLeDwe8vk8AA8ePGB5eZmenh42btxIpVIhm82KmJRCoVANcQJCjpaWlpidncUwDJqammhubsbd39zczNzcnNj38OFDTp8+TaFQ4Pv372J+37597N27l3Q6jaIovHz5Er/fT2dnJwCHDx8mFoshyzILCwt8+PCBVColEsV36tSpoQ0bNjA9PQ1ALpdjcnLyN3pJQtd1RkdHKZVK+P1+Ll68KELh8+fPvH//Hl3XOXbsGFNTU5TLZYLBICMjI8TjcTweD1euXKG7u5vl5WXK5TLRaJSOjg7a29t5/Pgxs7OzTExM0NnZiW3b7NixQySL5+7duw4gKonqTEokEgC0tLTgOI6oVDweD47j4PF4XLIXfXe8tLSEJElMTk7S398PwNTUFACvX7/m4MGDYv+7d+/I5XKiYABQVZVoNIqkKIoAVE+04/F4Xb6rBlTdd8eS9FtF37x5QzKZZHBwkJmZGVRVFTzqErZlWZw9e1ZwoKZpRKNR4vE4UiOyLRaL5HI54vE4ay0oAHp7e7l+/TqmaeLz+fj48SNdXV0C3EpyPnDgAJFIhNbW1n+VpFqwq1lcURQhbW4916gYbWQ9PT08evSo4bpt20IEQqEQmqYJKdV1Hck0zZpbaJomlKQ6Nl05zOfzqypQV2ujo6MitBKJhFAo1yG+M2fODLW2thIOh5FlGUVR0DSNnTt3srCwwNjYGJlMhlKpRCaTQZZlfD4fTU1NbNq0ac3ALMti3bp1zMzMMD8/T6VSEUyxuLhIIBDAtm3+Ach61YAcN+PJAAAAAElFTkSuQmCC\ . + Or as block: ]1337;File=name=aW1hZ2UucG5n;size=1371;inline=1:iVBORw0KGgoAAAANSUhEUgAAACgAAAAUCAYAAAD/Rn+7AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAC4jAAAuIwF4pT92AAAE+0lEQVRIx62WTWgTaxSGnyTDmKKNNqOMxpoW02AbDHUK7gKV6kJxYfEHcacLXTRQdKsRKrhQXCnBhS5F/EcXioK0ILqQQqmhkmKDOIkQOi0ziZMqpaWdu5D5blISrL33wPD9M+93vnPe93gcx3H4C7MsC9u2sW2bUqkk5oLBIC0tLQQCAdrb2+ue1XUd27b5+vUrpmliGAaqqqIoCqZpMj4+DsDt27fFGYm/tGAwKPqBQACAtrY2AoFAzVqji7mXcs0wjJq2GtyaAK4EVw/4n14gm82KcbFYpFgsNtwvuc/zXzy5lku5oFyPDQwM1Af4tz+xLGtNHncvFIlExFwqlRL9lU8rzGlgpmnWnfv27VvdtdWYe840TSeTyTgDAwMOINp6n6dRFjfylG3bf0yI1Ziu64yPj4t4LBaLdb0oYtBtnz59yokTJwC4fPkyx48fBxDUEI1GaWtrW3McVsejpmkAmKZZkyjV8Si53pqYmABg8+bNgpdisRilUqkm8xRFEXz3f1gwGCSbzdZ4LxQKoaoqhmEg2bZd86yRSITt27djmiZbtmzh06dPnD9/nl27drF7927u3btHb28vfX19DA8P4/P5uHr1KouLi9y6dYu5uTkKhQKDg4P09fVRLpe5efMmhUKBJ0+eEI1GuXTpEolEghcvXjAyMoJlWSSTSbZt21YDPhaLId2/fx9VVevSh2VZhMNhwuEwX7584ejRo6xfv547d+6wf/9+kskke/bs4ciRI3R1dZHNZnn+/DmpVIr+/n6mp6cZHh5maGiIQqFAd3c3N27c4NChQ7x9+5YLFy7w6tUr8vk86XSadDqN1+sVL2YYBtJKkjQMgx8/fojYcKXI6/Vy8uRJnj17BkBHRwd+vx+AX79+sXXrVs6dO8e1a9cYGxujUqnw8+dPZFkGYH5+Hq/XiyzLeDwe8vk8AA8ePGB5eZmenh42btxIpVIhm82KmJRCoVANcQJCjpaWlpidncUwDJqammhubsbd39zczNzcnNj38OFDTp8+TaFQ4Pv372J+37597N27l3Q6jaIovHz5Er/fT2dnJwCHDx8mFoshyzILCwt8+PCBVColEsV36tSpoQ0bNjA9PQ1ALpdjcnLyN3pJQtd1RkdHKZVK+P1+Ll68KELh8+fPvH//Hl3XOXbsGFNTU5TLZYLBICMjI8TjcTweD1euXKG7u5vl5WXK5TLRaJSOjg7a29t5/Pgxs7OzTExM0NnZiW3b7NixQySL5+7duw4gKonqTEokEgC0tLTgOI6oVDweD47j4PF4XLIXfXe8tLSEJElMTk7S398PwNTUFACvX7/m4MGDYv+7d+/I5XKiYABQVZVoNIqkKIoAVE+04/F4Xb6rBlTdd8eS9FtF37x5QzKZZHBwkJmZGVRVFTzqErZlWZw9e1ZwoKZpRKNR4vE4UiOyLRaL5HI54vE4ay0oAHp7e7l+/TqmaeLz+fj48SNdXV0C3EpyPnDgAJFIhNbW1n+VpFqwq1lcURQhbW4916gYbWQ9PT08evSo4bpt20IEQqEQmqYJKdV1Hck0zZpbaJomlKQ6Nl05zOfzqypQV2ujo6MitBKJhFAo1yG+M2fODLW2thIOh5FlGUVR0DSNnTt3srCwwNjYGJlMhlKpRCaTQZZlfD4fTU1NbNq0ac3ALMti3bp1zMzMMD8/T6VSEUyxuLhIIBDAtm3+Ach61YAcN+PJAAAAAElFTkSuQmCC\ diff --git a/pulldown-cmark-mdcat/tests/render/md/samples/images.md b/pulldown-cmark-mdcat/tests/render/md/samples/images.md index b8c14f79..4513670d 100644 --- a/pulldown-cmark-mdcat/tests/render/md/samples/images.md +++ b/pulldown-cmark-mdcat/tests/render/md/samples/images.md @@ -6,6 +6,8 @@ An inline [linked ![image](./image.png)](https://example.com) with some extra te An inline [**linked ![image](./image.png)**](https://example.com) with nested formatting. +An inline ![image with a nested ![image](./image.png) and *markups* in description](./image.png). + Or as block: ![image](./image.png)