From 501938e71dd1705fd77597a71b3c3940d46ffd05 Mon Sep 17 00:00:00 2001 From: Ivan Ukhov Date: Fri, 23 Feb 2024 10:27:21 +0100 Subject: [PATCH 1/6] =?UTF-8?q?Introduce=20=E2=80=9Cbare=E2=80=9D=20nodes?= =?UTF-8?q?=20with=20no=20surrounding=20new=20lines?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/node/element/mod.rs | 22 ++++++++++++++-------- src/node/mod.rs | 26 +++++++++++++++++++++++++- src/node/text.rs | 7 ++++++- 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/src/node/element/mod.rs b/src/node/element/mod.rs index dcb75d8..bb321a3 100644 --- a/src/node/element/mod.rs +++ b/src/node/element/mod.rs @@ -76,10 +76,18 @@ impl fmt::Display for Element { return write!(formatter, "/>"); } write!(formatter, ">")?; + let mut bare = false; for child in self.children.iter() { - write!(formatter, "\n{}", child)?; + bare = child.is_bare() && !formatter.alternate(); + if !bare { + write!(formatter, "\n")?; + } + write!(formatter, "{}", child)?; + } + if !bare { + write!(formatter, "\n")?; } - write!(formatter, "\n", self.name) + write!(formatter, "", self.name) } } @@ -361,7 +369,7 @@ macro_rules! implement { } } - node! { $struct_name::inner } + node! { $struct_name::inner [is_bareable] } )*); } @@ -405,11 +413,11 @@ mod tests { assert_eq!( one.to_string(), - "\n\nfoo\n\n\nbar\n\n", + "\nfoo\nbar\n", ); assert_eq!( two.to_string(), - "\n\nfoo\n\n\nbuz\n\n", + "\nfoo\nbuz\n", ); } @@ -446,9 +454,7 @@ mod tests { element.to_string().lines().collect::>(), &[ r###""###, - "", - "widgets >=3.0.9, <3.1.dev0", - "", + "widgets >=3.0.9, <3.1.dev0", "", ], ); diff --git a/src/node/mod.rs b/src/node/mod.rs index 98fced6..6f127c2 100644 --- a/src/node/mod.rs +++ b/src/node/mod.rs @@ -42,6 +42,16 @@ pub trait Node: U: Into, { } + + #[doc(hidden)] + fn is_bare(&self) -> bool { + false + } + + #[doc(hidden)] + fn is_bareable(&self) -> bool { + false + } } #[doc(hidden)] @@ -90,6 +100,9 @@ impl NodeDefaultHash for Box { macro_rules! node( ($struct_name:ident::$field_name:ident) => ( + node!($struct_name::$field_name []); + ); + ($struct_name:ident::$field_name:ident [$($indicator_name:ident),*]) => ( impl $struct_name { /// Append a node. pub fn add(mut self, node: T) -> Self @@ -129,6 +142,13 @@ macro_rules! node( { self.$field_name.assign(name, value); } + + $( + #[inline] + fn $indicator_name(&self) -> bool { + true + } + )* } impl ::std::ops::Deref for $struct_name { @@ -150,7 +170,11 @@ macro_rules! node( impl ::std::fmt::Display for $struct_name { #[inline] fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - self.$field_name.fmt(formatter) + if self.is_bareable() { + write!(formatter, "{:#}", self.$field_name) + } else { + self.$field_name.fmt(formatter) + } } } diff --git a/src/node/text.rs b/src/node/text.rs index f5ecda4..0a47a41 100644 --- a/src/node/text.rs +++ b/src/node/text.rs @@ -30,7 +30,12 @@ impl fmt::Display for Text { } } -impl Node for Text {} +impl Node for Text { + #[inline] + fn is_bare(&self) -> bool { + true + } +} impl super::NodeDefaultHash for Text { #[inline] From 3d6f56ad6b20aabdfedad8c80c76db3d315819a3 Mon Sep 17 00:00:00 2001 From: Ivan Ukhov Date: Fri, 23 Feb 2024 10:33:32 +0100 Subject: [PATCH 2/6] Add an argument to Title --- src/node/element/mod.rs | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/node/element/mod.rs b/src/node/element/mod.rs index bb321a3..afece53 100644 --- a/src/node/element/mod.rs +++ b/src/node/element/mod.rs @@ -324,9 +324,6 @@ implement! { #[doc = "A [`textPath`](https://www.w3.org/TR/SVG/text.html#TextPathElement) element."] struct TextPath - #[doc = "A [`title`](https://www.w3.org/TR/SVG/struct.html#TitleElement) element."] - struct Title - #[doc = "A [`tspan`](https://www.w3.org/TR/SVG/text.html#TextElement) element."] struct TSpan @@ -339,7 +336,9 @@ macro_rules! implement { ($( #[$doc:meta] struct $struct_name:ident - [$($pn:ident: $($pt:tt)*),*] [$inner:ident $(,$an:ident: $at:ty)*] $body:block + [$($indicator_name:ident),*] + [$($trait_name:ident: $($trait_type:tt)*),*] + [$inner:ident $(,$argument_name:ident: $argument_type:ty)*] $body:block )*) => ($( #[$doc] #[derive(Clone, Debug)] @@ -351,11 +350,13 @@ macro_rules! implement { impl $struct_name { /// Create a node. #[inline] - pub fn new<$($pn: $($pt)*),*>($($an: $at),*) -> Self { + pub fn new<$($trait_name: $($trait_type)*),*>($($argument_name: $argument_type),*) -> Self { #[inline(always)] - fn initialize<$($pn: $($pt)*),*>($inner: &mut Element $(, $an: $at)*) $body + fn initialize<$($trait_name: $($trait_type)*),*>( + $inner: &mut Element $(, $argument_name: $argument_type)* + ) $body let mut inner = Element::new(tag::$struct_name); - initialize(&mut inner $(, $an)*); + initialize(&mut inner $(, $argument_name)*); $struct_name { inner, } @@ -369,23 +370,28 @@ macro_rules! implement { } } - node! { $struct_name::inner [is_bareable] } + node! { $struct_name::inner [$($indicator_name),*] } )*); } implement! { + #[doc = "A [`title`](https://www.w3.org/TR/SVG/struct.html#TitleElement) element."] + struct Title [] [T: Into] [inner, content: T] { + inner.append(crate::node::Text::new(content)); + } + #[doc = "An [`svg`](https://www.w3.org/TR/SVG/struct.html#SVGElement) element."] - struct SVG [] [inner] { + struct SVG [is_bareable] [] [inner] { inner.assign("xmlns", "http://www.w3.org/2000/svg"); } #[doc = "A [`script`](https://www.w3.org/TR/SVG/script.html#ScriptElement) element."] - struct Script [T: Into] [inner, content: T] { + struct Script [is_bareable] [T: Into] [inner, content: T] { inner.append(crate::node::Text::new(content)); } #[doc = "A [`style`](https://www.w3.org/TR/SVG/styling.html#StyleElement) element."] - struct Style [T: Into] [inner, content: T] { + struct Style [is_bareable] [T: Into] [inner, content: T] { inner.append(crate::node::Text::new(content)); } } @@ -448,7 +454,7 @@ mod tests { .set("width", 0.3088995) .set("x", 328.0725) .set("y", 120) - .add(Title::new().add(node::Text::new("widgets >=3.0.9, <3.1.dev0"))); + .add(Title::new("widgets >=3.0.9, <3.1.dev0")); assert_eq!( element.to_string().lines().collect::>(), From 73333f91895fe7a29f59c94590f3e7007512b4cc Mon Sep 17 00:00:00 2001 From: Ivan Ukhov Date: Fri, 23 Feb 2024 10:34:37 +0100 Subject: [PATCH 3/6] Add an argument to Text --- src/node/element/mod.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/node/element/mod.rs b/src/node/element/mod.rs index afece53..919a940 100644 --- a/src/node/element/mod.rs +++ b/src/node/element/mod.rs @@ -318,9 +318,6 @@ implement! { #[doc = "A [`symbol`](https://www.w3.org/TR/SVG/struct.html#SymbolElement) element."] struct Symbol - #[doc = "A [`text`](https://www.w3.org/TR/SVG/text.html#TextElement) element."] - struct Text - #[doc = "A [`textPath`](https://www.w3.org/TR/SVG/text.html#TextPathElement) element."] struct TextPath @@ -375,6 +372,11 @@ macro_rules! implement { } implement! { + #[doc = "A [`text`](https://www.w3.org/TR/SVG/text.html#TextElement) element."] + struct Text [] [T: Into] [inner, content: T] { + inner.append(crate::node::Text::new(content)); + } + #[doc = "A [`title`](https://www.w3.org/TR/SVG/struct.html#TitleElement) element."] struct Title [] [T: Into] [inner, content: T] { inner.append(crate::node::Text::new(content)); @@ -405,14 +407,14 @@ fn escape(value: &str) -> String { #[cfg(test)] mod tests { use super::{Element, Rectangle, Style, Title}; - use crate::node::{self, element, Node}; + use crate::node::{element, Node}; #[test] fn element_children() { let mut one = element::Group::new() - .add(element::Text::new().add(node::Text::new("foo"))) - .add(element::Text::new().add(node::Text::new("bar"))) - .add(element::Text::new().add(node::Text::new("buz"))); + .add(element::Text::new("foo")) + .add(element::Text::new("bar")) + .add(element::Text::new("buz")); let two = element::Group::new() .add(one.get_children()[0].clone()) .add(one.get_children_mut().pop().unwrap()); From d22509627a6c77a927a6f8f713e75fa897c73c0c Mon Sep 17 00:00:00 2001 From: Ivan Ukhov Date: Fri, 23 Feb 2024 10:37:22 +0100 Subject: [PATCH 4/6] Add an argument to TSpan --- src/node/element/mod.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/node/element/mod.rs b/src/node/element/mod.rs index 919a940..2cccaea 100644 --- a/src/node/element/mod.rs +++ b/src/node/element/mod.rs @@ -321,9 +321,6 @@ implement! { #[doc = "A [`textPath`](https://www.w3.org/TR/SVG/text.html#TextPathElement) element."] struct TextPath - #[doc = "A [`tspan`](https://www.w3.org/TR/SVG/text.html#TextElement) element."] - struct TSpan - #[doc = "A [`use`](https://www.w3.org/TR/SVG/struct.html#UseElement) element."] struct Use } @@ -373,7 +370,7 @@ macro_rules! implement { implement! { #[doc = "A [`text`](https://www.w3.org/TR/SVG/text.html#TextElement) element."] - struct Text [] [T: Into] [inner, content: T] { + struct Text [is_bareable] [T: Into] [inner, content: T] { inner.append(crate::node::Text::new(content)); } @@ -382,6 +379,11 @@ implement! { inner.append(crate::node::Text::new(content)); } + #[doc = "A [`tspan`](https://www.w3.org/TR/SVG/text.html#TextElement) element."] + struct TSpan [] [T: Into] [inner, content: T] { + inner.append(crate::node::Text::new(content)); + } + #[doc = "An [`svg`](https://www.w3.org/TR/SVG/struct.html#SVGElement) element."] struct SVG [is_bareable] [] [inner] { inner.assign("xmlns", "http://www.w3.org/2000/svg"); @@ -421,11 +423,11 @@ mod tests { assert_eq!( one.to_string(), - "\nfoo\nbar\n", + "\n\nfoo\n\n\nbar\n\n", ); assert_eq!( two.to_string(), - "\nfoo\nbuz\n", + "\n\nfoo\n\n\nbuz\n\n", ); } From 15e002b04a740edd9d4a629d9b15e4cc21ec54fb Mon Sep 17 00:00:00 2001 From: Ivan Ukhov Date: Fri, 23 Feb 2024 10:37:34 +0100 Subject: [PATCH 5/6] Bump the version number --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bc76153..34b73c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "svg" -version = "0.15.1" +version = "0.16.0" edition = "2021" license = "Apache-2.0/MIT" authors = [ From 765e9cdac90d9cc1913dcf5088ad2e2b423025c0 Mon Sep 17 00:00:00 2001 From: Ivan Ukhov Date: Fri, 23 Feb 2024 10:39:58 +0100 Subject: [PATCH 6/6] Address a lint --- src/node/element/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node/element/mod.rs b/src/node/element/mod.rs index 2cccaea..08a58c0 100644 --- a/src/node/element/mod.rs +++ b/src/node/element/mod.rs @@ -80,12 +80,12 @@ impl fmt::Display for Element { for child in self.children.iter() { bare = child.is_bare() && !formatter.alternate(); if !bare { - write!(formatter, "\n")?; + writeln!(formatter)?; } write!(formatter, "{}", child)?; } if !bare { - write!(formatter, "\n")?; + writeln!(formatter)?; } write!(formatter, "", self.name) }