diff --git a/output_multiple_nodes.svg b/output_multiple_nodes.svg
index ef9e6e0..8ad8a2e 100644
--- a/output_multiple_nodes.svg
+++ b/output_multiple_nodes.svg
@@ -1,5 +1,5 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index c88079b..b3b4889 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,6 +1,7 @@
pub mod parse;
pub mod render;
+use crate::Element::{Edge, Node};
use parse::tokens::TokenType;
use std::collections::HashMap;
@@ -10,7 +11,7 @@ pub struct Vis {
pub styles: Vec,
}
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub enum Element {
Node(String, Option, Vec),
Edge(String, String, TokenType, Option),
@@ -28,6 +29,33 @@ impl Element {
) -> Element {
Element::Edge(id, source, token, label)
}
+
+ pub fn to_string(&self) -> String {
+ match self {
+ Node(id, label, children) => {
+ let mut s = String::new();
+ s.push_str(&format!(
+ "Node {{{}: {}",
+ id,
+ label.as_ref().unwrap_or(&"".to_string())
+ ));
+ for child in children {
+ s.push_str(&format!(" {}", child.to_string()));
+ }
+ s.push_str("}");
+ s
+ }
+ Edge(id, source, token, label) => {
+ let mut s = "Edge {{".to_string();
+ s.push_str(&format!("{} {} {:?}", id, source, token));
+ if let Some(label) = label {
+ s.push_str(&format!(" {}", label));
+ }
+ s.push_str("}");
+ s
+ }
+ }
+ }
}
#[derive(Debug, Clone)]
@@ -39,6 +67,6 @@ pub struct StyleNode {
#[derive(Debug, Clone)]
pub enum ContainerType {
- Node,
+ NonGroup, // needs thinking about
Group,
}
diff --git a/src/main.rs b/src/main.rs
index 560b1d6..cd48301 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,15 +1,24 @@
use anyhow::anyhow;
use std::env::args;
use std::fs;
+use std::fs::File;
+use std::io::Write;
+use std::process::exit;
+use vis::render::svgrender2::SvgRender;
+use vis::render::Renderer;
fn main() -> anyhow::Result<()> {
let args: Vec = args().collect();
if args.len() != 2 {
- return Err(anyhow!("Usage: vis vis-file"));
+ eprintln!("Usage: vis vis-file");
+ exit(-64);
} else {
let vis_file = read_file(&args[1])?;
let vis = vis::parse::parse_vis(vis_file.as_str())?;
println!("{:?}", vis);
+ let svg_bytes = SvgRender {}.render(vis)?;
+ let mut file = File::create("bank.svg").expect("Unable to create file");
+ file.write_all(&svg_bytes).expect("Unable to write data");
}
Ok(())
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index 937394c..f595361 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -10,7 +10,7 @@ use std::collections::HashMap;
pub fn parse_vis(contents: &str) -> anyhow::Result {
let tokens = crate::parse::scanner::scan(contents)?;
- println!("{:?}", tokens);
+ // println!("{:?}", tokens);
let mut parser = Parser::new(tokens);
Ok(Vis {
@@ -93,8 +93,9 @@ impl Parser {
fn string(&mut self) -> anyhow::Result {
let text = self.peek().clone();
+ let text = text.lexeme[1..text.lexeme.len() - 1].to_owned();
self.consume(Str, "Expected quoted string")?;
- Ok(text.lexeme.to_owned())
+ Ok(text)
}
fn text(&mut self) -> anyhow::Result {
@@ -164,10 +165,10 @@ impl Parser {
if self.match_token(Group) {
ContainerType::Group
} else {
- ContainerType::Node
+ ContainerType::NonGroup
}
} else {
- ContainerType::Node
+ ContainerType::NonGroup
})
}
@@ -231,3 +232,54 @@ impl Parser {
&self.tokens[self.current]
}
}
+
+#[cfg(test)]
+mod tests {
+ use crate::Element;
+
+ #[test]
+ fn test_parse() {
+ let contents = r#"structure {
+ top: "top-node" {
+ child: "child-node" {
+ }
+ }
+ }"#;
+ let vis = crate::parse::parser::parse_vis(contents).ok();
+
+ assert!(vis.is_some(), "Parsed structure should not be None");
+
+ if let Some(vis) = vis {
+ // Validate the parsed structure by asserting its elements
+ assert_eq!(
+ vis.structure.len(),
+ 1,
+ "The structure should contain one top-level element"
+ );
+
+ if let Element::Node(id, title, children) = &vis.structure[0] {
+ assert_eq!(id, "top", "The ID of the first node should be 'top'");
+ assert_eq!(
+ title.as_ref().unwrap(),
+ &"top-node".to_owned(),
+ "The title of the first node should be 'top-node'"
+ );
+ assert_eq!(children.len(), 1);
+ let child = &children[0];
+ if let Element::Node(id, title, children) = child {
+ assert_eq!(id, "child", "The ID of the second node should be 'child'");
+ assert_eq!(
+ title.as_ref().unwrap(),
+ &"child-node".to_owned(),
+ "The title of the second node should be 'child-node'"
+ );
+ assert_eq!(children.len(), 0);
+ }
+ } else {
+ panic!("The top-level element should be a Node");
+ }
+ } else {
+ panic!("Parsed structure was unexpectedly None");
+ }
+ }
+}
diff --git a/src/render/mod.rs b/src/render/mod.rs
index d1cb3f0..1ceabaa 100644
--- a/src/render/mod.rs
+++ b/src/render/mod.rs
@@ -4,7 +4,7 @@ pub mod html;
mod rendering_svg_elements;
mod svg_renderer;
pub mod svglib;
-mod svgrender2;
+pub mod svgrender2;
/// trait for turning the object model into a byte representation
pub trait Renderer {
diff --git a/src/render/rendering_svg_elements.rs b/src/render/rendering_svg_elements.rs
index 22f31ce..d28e6b2 100644
--- a/src/render/rendering_svg_elements.rs
+++ b/src/render/rendering_svg_elements.rs
@@ -1,7 +1,7 @@
use crate::render::svglib::rect::rect;
use crate::render::svglib::svg::{svg, Svg};
use crate::render::svglib::text::text;
-use crate::{Element, StyleNode, Vis};
+use crate::{Element, Vis};
pub fn render_vis_with_grid_layout(
vis: &Vis,
@@ -54,7 +54,7 @@ fn layout_box(
let child_y = current_y + row as f32 * (grid_cell_size + spacing);
match element {
- Element::Node(id, label, children) => {
+ Element::Node(_, label, children) => {
let (_, _) = layout_box(
svg,
children,
@@ -128,7 +128,7 @@ mod tests {
// Create a mock StyleNode
let style_node = StyleNode {
id_ref: "node_1".to_string(),
- containertype: ContainerType::Node,
+ containertype: ContainerType::NonGroup,
attributes: [("fill".to_string(), "white".to_string())]
.iter()
.cloned()
diff --git a/src/render/svg_node.css b/src/render/svg_node.css
index 7325bd8..e8e53c6 100644
--- a/src/render/svg_node.css
+++ b/src/render/svg_node.css
@@ -1,5 +1,5 @@
svg {
- background-color: white;
+ background-color: gray;
}
.node {
diff --git a/src/render/svglib/circle.rs b/src/render/svglib/circle.rs
index ca1e9dd..37a4c91 100644
--- a/src/render/svglib/circle.rs
+++ b/src/render/svglib/circle.rs
@@ -1,4 +1,4 @@
-use crate::render::svglib::{att, att_str3, Att, Element, ElementType, Shape, Value};
+use crate::render::svglib::{att, att_to_string, Att, Element, ElementType, Shape, Value};
pub fn circle() -> Circle {
Circle::new()
@@ -7,23 +7,23 @@ pub fn circle() -> Circle {
pub struct Circle(Vec);
impl Circle {
- fn new() -> Self {
+ pub fn new() -> Self {
Self(vec![])
}
- fn id>(mut self, id: V) -> Self {
+ pub fn id>(mut self, id: V) -> Self {
self.0.push(att("id", id));
self
}
- fn cx>(mut self, cx: V) -> Self {
+ pub fn cx>(mut self, cx: V) -> Self {
self.0.push(att("cx", cx));
self
}
- fn cy>(mut self, cy: V) -> Self {
+ pub fn cy>(mut self, cy: V) -> Self {
self.0.push(att("cy", cy));
self
}
- fn r>(mut self, r: V) -> Self {
+ pub fn r>(mut self, r: V) -> Self {
self.0.push(att("r", r));
self
}
@@ -51,16 +51,16 @@ impl Element for Circle {
ElementType::Circle
}
- fn atts(&self) -> &[Att] {
- &self.0
- }
-
fn to_string(&self) -> String {
format!(
r#""#,
- self.0.iter().map(att_str3).collect::()
+ self.0.iter().map(att_to_string).collect::()
)
}
+
+ fn atts(&self) -> &[Att] {
+ &self.0
+ }
}
#[cfg(test)]
diff --git a/src/render/svglib/div.rs b/src/render/svglib/div.rs
index 02c31fa..f11bbfc 100644
--- a/src/render/svglib/div.rs
+++ b/src/render/svglib/div.rs
@@ -1,4 +1,4 @@
-use crate::render::svglib::{att, att_str3, Att, Value};
+use crate::render::svglib::{att, att_to_string, Att, Value};
pub fn div() -> Div {
Div::new()
@@ -17,10 +17,7 @@ impl Div {
}
}
- pub fn id(&mut self, id: V)
- where
- V: Into,
- {
+ pub fn id>(&mut self, id: V) {
self.atts.push(att("id", id));
}
@@ -32,7 +29,7 @@ impl Div {
self
}
- pub fn innerHTML>(mut self, html: V) -> Self {
+ pub fn inner_html>(mut self, html: V) -> Self {
self.child = html.into();
self
}
@@ -40,7 +37,7 @@ impl Div {
pub fn to_string(&self) -> String {
format!(
r#"{}
"#,
- self.atts.iter().map(att_str3).collect::(),
+ self.atts.iter().map(att_to_string).collect::(),
self.child
)
}
diff --git a/src/render/svglib/ellipse.rs b/src/render/svglib/ellipse.rs
index 4271395..94a8a6f 100644
--- a/src/render/svglib/ellipse.rs
+++ b/src/render/svglib/ellipse.rs
@@ -1,4 +1,4 @@
-use crate::render::svglib::{att, att_str3, Att, Element, ElementType, Shape, Value};
+use crate::render::svglib::{att, att_to_string, Att, Element, ElementType, Shape, Value};
pub fn ellipse() -> Ellipse {
Ellipse(vec![])
@@ -8,45 +8,39 @@ pub fn ellipse() -> Ellipse {
pub struct Ellipse(Vec);
impl Ellipse {
- fn cx>(mut self, cx: V) -> Self {
+ pub fn id>(&mut self, id: V) {
+ self.0.push(att("id", id));
+ }
+ pub fn cx>(mut self, cx: V) -> Self {
self.0.push(att("cx", cx));
self
}
- fn cy>(mut self, cy: V) -> Self {
+ pub fn cy>(mut self, cy: V) -> Self {
self.0.push(att("cy", cy));
self
}
- fn rx>(mut self, rx: V) -> Self {
+ pub fn rx>(mut self, rx: V) -> Self {
self.0.push(att("rx", rx));
self
}
- fn ry>(mut self, ry: V) -> Self {
+ pub fn ry>(mut self, ry: V) -> Self {
self.0.push(att("ry", ry));
self
}
}
impl Shape for Ellipse {
- fn fill(mut self, value: V) -> Self
- where
- V: Into,
- {
+ fn fill>(mut self, value: V) -> Self {
self.0.push(att("fill", value));
self
}
- fn stroke(mut self, value: V) -> Self
- where
- V: Into,
- {
+ fn stroke>(mut self, value: V) -> Self {
self.0.push(att("stroke", value));
self
}
- fn transform(mut self, value: V) -> Self
- where
- V: Into,
- {
+ fn transform>(mut self, value: V) -> Self {
self.0.push(att("transform", value));
self
}
@@ -64,7 +58,7 @@ impl Element for Ellipse {
fn to_string(&self) -> String {
format!(
r#""#,
- self.0.iter().map(att_str3).collect::()
+ self.0.iter().map(att_to_string).collect::()
)
}
}
diff --git a/src/render/svglib/foreign_object.rs b/src/render/svglib/foreign_object.rs
index 922e06b..34e809f 100644
--- a/src/render/svglib/foreign_object.rs
+++ b/src/render/svglib/foreign_object.rs
@@ -1,5 +1,5 @@
use crate::render::svglib::div::Div;
-use crate::render::svglib::{att, att_str3, Att, Element, ElementType, Value};
+use crate::render::svglib::{att, att_to_string, Att, Element, ElementType, Value};
pub fn foreign_object() -> ForeignObject {
ForeignObject::new()
@@ -65,7 +65,10 @@ impl Element for ForeignObject {
fn to_string(&self) -> String {
format!(
r#"{}"#,
- self.atts.iter().map(|a| att_str3(a)).collect::(),
+ self.atts
+ .iter()
+ .map(|a| att_to_string(a))
+ .collect::(),
self.child
.as_ref()
.map(|c| c.to_string())
diff --git a/src/render/svglib/group.rs b/src/render/svglib/group.rs
index 498c084..ad1b16e 100644
--- a/src/render/svglib/group.rs
+++ b/src/render/svglib/group.rs
@@ -1,4 +1,4 @@
-use crate::render::svglib::{att, att_str3, Att, Element, ElementType, Value};
+use crate::render::svglib::{att, att_to_string, Att, Element, ElementType, Value};
pub fn group() -> Group {
Group {
@@ -17,17 +17,11 @@ impl Group {
self.children.push(Box::new(child));
}
- pub fn id(&mut self, id: V)
- where
- V: Into,
- {
+ pub fn id>(&mut self, id: V) {
self.atts.push(att("id", id));
}
- pub fn transform(&mut self, value: V)
- where
- V: Into,
- {
+ pub fn transform>(&mut self, value: V) {
self.atts.push(att("transform", value));
}
}
@@ -42,7 +36,10 @@ impl Element for Group {
}
fn to_string(&self) -> String {
- let mut svg = format!("", self.atts.iter().map(att_str3).collect::());
+ let mut svg = format!(
+ "",
+ self.atts.iter().map(att_to_string).collect::()
+ );
for e in &self.children {
svg.push_str(e.to_string().as_str());
diff --git a/src/render/svglib/image.rs b/src/render/svglib/image.rs
index 6f9da1f..9fbf1ad 100644
--- a/src/render/svglib/image.rs
+++ b/src/render/svglib/image.rs
@@ -1,48 +1,42 @@
-use crate::render::svglib::{att, att_str3, Att, Element, ElementType, Value};
+use crate::render::svglib::{att, att_to_string, Att, Element, ElementType, Value};
pub fn image() -> Image {
Image::new()
}
-struct Image {
+pub struct Image {
atts: Vec,
}
impl Image {
- fn new() -> Self {
+ pub fn new() -> Self {
Self { atts: vec![] }
}
- fn id(&mut self, id: V)
- where
- V: Into,
- {
+ pub fn id>(&mut self, id: V) {
self.atts.push(att("id", id));
}
- fn transform(&mut self, value: V)
- where
- V: Into,
- {
+ pub fn transform>(&mut self, value: V) {
self.atts.push(att("transform", value));
}
- fn x>(mut self, x: V) -> Self {
+ pub fn x>(mut self, x: V) -> Self {
self.atts.push(att("x", x));
self
}
- fn y>(mut self, y: V) -> Self {
+ pub fn y>(mut self, y: V) -> Self {
self.atts.push(att("y", y));
self
}
- fn width>(mut self, width: V) -> Self {
+ pub fn width>(mut self, width: V) -> Self {
self.atts.push(att("width", width));
self
}
- fn height>(mut self, height: V) -> Self {
+ pub fn height>(mut self, height: V) -> Self {
self.atts.push(att("height", height));
self
}
- fn href>(mut self, href: V) -> Self {
+ pub fn href>(mut self, href: V) -> Self {
self.atts.push(att("href", href));
self
}
@@ -53,16 +47,16 @@ impl Element for Image {
ElementType::Image
}
- fn atts(&self) -> &[Att] {
- &self.atts
- }
-
fn to_string(&self) -> String {
format!(
r#""#,
- self.atts.iter().map(att_str3).collect::()
+ self.atts.iter().map(att_to_string).collect::()
)
}
+
+ fn atts(&self) -> &[Att] {
+ &self.atts
+ }
}
#[cfg(test)]
diff --git a/src/render/svglib/line.rs b/src/render/svglib/line.rs
index 1f5e030..3f0ddf1 100644
--- a/src/render/svglib/line.rs
+++ b/src/render/svglib/line.rs
@@ -1,4 +1,4 @@
-use crate::render::svglib::{att, att_str3, Att, Element, ElementType, Shape, Value};
+use crate::render::svglib::{att, att_to_string, Att, Element, ElementType, Shape, Value};
pub fn line() -> Line {
Line(vec![])
@@ -7,11 +7,9 @@ pub fn line() -> Line {
pub struct Line(Vec);
impl Line {
- fn id(&mut self, id: V)
- where
- V: Into,
- {
+ pub fn id>(mut self, id: V) -> Self {
self.0.push(att("id", id));
+ self
}
pub fn x1>(mut self, x: V) -> Self {
@@ -48,7 +46,7 @@ impl Element for Line {
fn to_string(&self) -> String {
format!(
r#" "#,
- self.0.iter().map(att_str3).collect::()
+ self.0.iter().map(att_to_string).collect::()
)
}
}
diff --git a/src/render/svglib/link.rs b/src/render/svglib/link.rs
index c12840d..58f3522 100644
--- a/src/render/svglib/link.rs
+++ b/src/render/svglib/link.rs
@@ -1,21 +1,16 @@
-use crate::render::svglib::{att, Att, Element, ElementType, Value};
+use crate::render::svglib::{att, att_to_string, Att, Element, ElementType, Value};
pub fn link(href: &str) -> Link {
let mut atts = vec![];
atts.push(att("href", href));
- Link { atts }
+ Link(atts)
}
-struct Link {
- atts: Vec,
-}
+pub struct Link(Vec);
impl Link {
- fn id(&mut self, id: V)
- where
- V: Into,
- {
- self.atts.push(att("id", id));
+ pub fn id>(&mut self, id: V) {
+ self.0.push(att("id", id));
}
}
@@ -24,11 +19,14 @@ impl Element for Link {
ElementType::Link
}
- fn atts(&self) -> &[Att] {
- &self.atts
+ fn to_string(&self) -> String {
+ format!(
+ r#""#,
+ self.0.iter().map(att_to_string).collect::()
+ )
}
- fn to_string(&self) -> String {
- todo!()
+ fn atts(&self) -> &[Att] {
+ &self.0
}
}
diff --git a/src/render/svglib/mod.rs b/src/render/svglib/mod.rs
index ab86762..7f025cf 100644
--- a/src/render/svglib/mod.rs
+++ b/src/render/svglib/mod.rs
@@ -11,7 +11,7 @@ pub mod rect;
pub mod svg;
pub mod text;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct Value(String);
impl From<&str> for Value {
@@ -116,10 +116,8 @@ where
Att::new(name, value.into())
}
-fn att_str(att: &Option) -> String {
- att.as_ref()
- .map(|a| format!(r#" {}="{}""#, a.name, a.value.to_string()))
- .unwrap_or("".to_string())
+fn att_to_string(att: &Att) -> String {
+ format!(r#" {}="{}""#, att.name, att.value.to_string())
}
fn att_str2(att_name: &str, att_val: &Option) -> String {
@@ -128,7 +126,3 @@ fn att_str2(att_name: &str, att_val: &Option) -> String {
.map(|val| format!(r#" {}="{}""#, att_name, val))
.unwrap_or("".to_string())
}
-
-fn att_str3(att: &Att) -> String {
- format!(r#" {}="{}""#, att.name, att.value.to_string())
-}
diff --git a/src/render/svglib/path.rs b/src/render/svglib/path.rs
index a2ab851..f5361c0 100644
--- a/src/render/svglib/path.rs
+++ b/src/render/svglib/path.rs
@@ -14,13 +14,13 @@ impl Element for Path {
ElementType::Path
}
- fn atts(&self) -> &[Att] {
- &self.atts
- }
-
fn to_string(&self) -> String {
todo!()
}
+
+ fn atts(&self) -> &[Att] {
+ &self.atts
+ }
}
impl Path {
@@ -98,26 +98,17 @@ impl Path {
}
impl Shape for Path {
- fn fill(mut self, value: V) -> Self
- where
- V: Into,
- {
+ fn fill>(mut self, value: V) -> Self {
self.atts.push(att("fill", value));
self
}
- fn stroke(mut self, value: V) -> Self
- where
- V: Into,
- {
+ fn stroke>(mut self, value: V) -> Self {
self.atts.push(att("stroke", value));
self
}
- fn transform(mut self, value: V) -> Self
- where
- V: Into,
- {
+ fn transform>(mut self, value: V) -> Self {
self.atts.push(att("transform", value));
self
}
diff --git a/src/render/svglib/rect.rs b/src/render/svglib/rect.rs
index e9d0949..077214c 100644
--- a/src/render/svglib/rect.rs
+++ b/src/render/svglib/rect.rs
@@ -1,4 +1,4 @@
-use crate::render::svglib::{att, att_str3, Att, Element, ElementType, Value};
+use crate::render::svglib::{att, att_to_string, Att, Element, ElementType, Value};
pub fn rect() -> Rect {
Rect::new()
@@ -10,8 +10,11 @@ pub struct Rect {
impl Rect {
pub fn new() -> Self {
- let mut atts = vec![];
- Self { atts }
+ Self { atts: vec![] }
+ }
+ pub fn id>(mut self, id: V) -> Self {
+ self.atts.push(att("id", id));
+ self
}
pub fn rounded() -> Self {
Self { atts: vec![] }
@@ -71,7 +74,7 @@ impl Element for Rect {
fn to_string(&self) -> String {
format!(
r#""#,
- self.atts.iter().map(att_str3).collect::()
+ self.atts.iter().map(att_to_string).collect::()
)
}
}
diff --git a/src/render/svglib/svg.rs b/src/render/svglib/svg.rs
index 39ad8a7..e7744f7 100644
--- a/src/render/svglib/svg.rs
+++ b/src/render/svglib/svg.rs
@@ -1,4 +1,4 @@
-use crate::render::svglib::{att_str2, Att, Element, Value};
+use crate::render::svglib::{att, att_to_string, Att, Element, Value};
pub fn svg() -> Svg {
Svg::new()
@@ -7,11 +7,6 @@ pub fn svg() -> Svg {
pub struct Svg {
style: Option,
elements: Vec>,
- width: Option,
- height: Option,
- viewbox: Option,
- preserveaspectratio: Option,
- transform: Option,
atts: Vec,
}
@@ -19,12 +14,7 @@ impl Svg {
pub fn new() -> Self {
Self {
style: None,
- elements: Vec::new(),
- width: None,
- height: None,
- viewbox: None,
- preserveaspectratio: None,
- transform: None,
+ elements: vec![],
atts: vec![],
}
}
@@ -38,35 +28,32 @@ impl Svg {
}
pub fn width>(&mut self, width: V) {
- self.width = Some(width.into().to_string());
+ self.atts.push(att("width", width.into().to_string()));
}
pub fn height>(&mut self, height: V) {
- self.height = Some(height.into().to_string());
+ self.atts.push(att("height", height.into().to_string()));
}
- pub fn viewbox(&mut self, viewbox: &str) {
- self.viewbox = Some(viewbox.to_string());
+ pub fn viewbox>(&mut self, viewbox: V) {
+ self.atts.push(att("viewBox", viewbox));
}
- pub fn preserveaspectratio(&mut self, preserveaspectratio: &str) {
- self.preserveaspectratio = Some(preserveaspectratio.to_string());
+ pub fn preserveaspectratio>(&mut self, preserveaspectratio: V) {
+ self.atts
+ .push(att("preserveaspectratio", preserveaspectratio));
}
- fn transform>(&mut self, value: V) {
- self.transform = Some(value.into().to_string());
+ pub fn transform>(&mut self, transform: V) {
+ self.atts.push(att("transform", transform));
}
pub fn to_string(&self) -> String {
let mut svg = String::new();
svg.push_str(
format!(
- r#"