From 8140b1fa1803f0d4269b45ec1dd01e443017325a Mon Sep 17 00:00:00 2001 From: MacDue Date: Wed, 3 Aug 2022 00:11:58 +0100 Subject: [PATCH] LibMarkdown: Implement the image size extension This implements the image size extension that's quite commonly used: https://github.com/commonmark/commonmark-spec/wiki/Deployed-Extensions#image-size This supports specifying... Both width and height: ![](foo.png =100x200) Width only: ![](foo.png =100x) Height only: ![](foo.png =x200) The size is always in pixels (relative sizing does not seem to be spec'd anywhere). --- Userland/Libraries/LibMarkdown/Text.cpp | 50 ++++++++++++++++++++++++- Userland/Libraries/LibMarkdown/Text.h | 10 ++++- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/Userland/Libraries/LibMarkdown/Text.cpp b/Userland/Libraries/LibMarkdown/Text.cpp index ec62ff40e63..1826642342c 100644 --- a/Userland/Libraries/LibMarkdown/Text.cpp +++ b/Userland/Libraries/LibMarkdown/Text.cpp @@ -140,6 +140,13 @@ void Text::LinkNode::render_to_html(StringBuilder& builder) const if (is_image) { builder.append("\""sv);render_to_html(builder); builder.append("\" >"sv); @@ -576,11 +583,52 @@ NonnullOwnPtr Text::parse_link(Vector::ConstIterator& tokens) auto separator = *tokens; VERIFY(separator == "]("sv); + Optional image_width; + Optional image_height; + + auto parse_image_dimensions = [&](StringView dimensions) -> bool { + if (!dimensions.starts_with('=')) + return false; + + ArmedScopeGuard clear_image_dimensions = [&] { + image_width = {}; + image_height = {}; + }; + + auto dimension_seperator = dimensions.find('x', 1); + if (!dimension_seperator.has_value()) + return false; + + auto width_string = dimensions.substring_view(1, *dimension_seperator - 1); + if (!width_string.is_empty()) { + auto width = width_string.to_int(); + if (!width.has_value()) + return false; + image_width = width; + } + + auto height_start = *dimension_seperator + 1; + if (height_start < dimensions.length()) { + auto height_string = dimensions.substring_view(height_start); + auto height = height_string.to_int(); + if (!height.has_value()) + return false; + image_height = height; + } + + clear_image_dimensions.disarm(); + return true; + }; + StringBuilder address; for (auto iterator = tokens + 1; !iterator.is_end(); ++iterator) { + // FIXME: What to do if there's multiple dimension tokens? + if (is_image && !address.is_empty() && parse_image_dimensions(iterator->data)) + continue; + if (*iterator == ")"sv) { tokens = iterator; - return make(is_image, move(link_text), address.build()); + return make(is_image, move(link_text), address.build().trim_whitespace(), image_width, image_height); } address.append(iterator->data); diff --git a/Userland/Libraries/LibMarkdown/Text.h b/Userland/Libraries/LibMarkdown/Text.h index 3fc6c485033..2c95ac63e9e 100644 --- a/Userland/Libraries/LibMarkdown/Text.h +++ b/Userland/Libraries/LibMarkdown/Text.h @@ -97,14 +97,22 @@ public: bool is_image; NonnullOwnPtr text; String href; + Optional image_width; + Optional image_height; - LinkNode(bool is_image, NonnullOwnPtr text, String href) + LinkNode(bool is_image, NonnullOwnPtr text, String href, Optional image_width, Optional image_height) : is_image(is_image) , text(move(text)) , href(move(href)) + , image_width(image_width) + , image_height(image_height) { } + bool has_image_dimensions() const + { + return image_width.has_value() || image_height.has_value(); + } virtual void render_to_html(StringBuilder& builder) const override; virtual void render_for_terminal(StringBuilder& builder) const override; virtual size_t terminal_length() const override;