summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2019-09-22 21:39:38 +0300
committerLars Wirzenius <liw@liw.fi>2019-09-22 21:39:38 +0300
commit2936f3cf609bff77ef0851ebf55b35c74d31a67a (patch)
tree638667b1b383c69d4b434a00ea60d00efc520687
parent2e87edb1382f8e00f52b0ca3e11c3aff39c57a7f (diff)
downloadroadmap-2936f3cf609bff77ef0851ebf55b35c74d31a67a.tar.gz
Change: wrap long labels to 30 chars
-rw-r--r--Cargo.toml1
-rw-r--r--legend.svg96
-rw-r--r--src/bin/roadmap2dot.rs4
-rw-r--r--src/lib.rs49
4 files changed, 83 insertions, 67 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 191e6ba..7fc7fd8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,3 +9,4 @@ edition = "2018"
[dependencies]
serde_yaml = "0.8.9"
structopt = "0.3"
+textwrap = "0.11.0"
diff --git a/legend.svg b/legend.svg
index 5e31cca..cbd540f 100644
--- a/legend.svg
+++ b/legend.svg
@@ -9,70 +9,70 @@
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 343.2864)">
<title>roadmap</title>
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-343.2864 521.5757,-343.2864 521.5757,4 -4,4"/>
-<!-- ready -->
+<!-- goal -->
<g id="node1" class="node">
-<title>ready</title>
-<ellipse fill="none" stroke="#000000" cx="90.5097" cy="-301.8097" rx="90.5193" ry="37.4533"/>
-<text text-anchor="middle" x="90.5097" y="-313.1097" font-family="Times,serif" font-size="14.00" fill="#000000">This task is ready </text>
-<text text-anchor="middle" x="90.5097" y="-298.1097" font-family="Times,serif" font-size="14.00" fill="#000000">to be done: it is not</text>
-<text text-anchor="middle" x="90.5097" y="-283.1097" font-family="Times,serif" font-size="14.00" fill="#000000">blocked by anything</text>
-</g>
-<!-- blocked -->
-<g id="node4" class="node">
-<title>blocked</title>
-<ellipse fill="none" stroke="#000000" cx="188.5097" cy="-180.2498" rx="98.9899" ry="37.4533"/>
-<text text-anchor="middle" x="188.5097" y="-191.5498" font-family="Times,serif" font-size="14.00" fill="#000000">This task is blocked</text>
-<text text-anchor="middle" x="188.5097" y="-176.5498" font-family="Times,serif" font-size="14.00" fill="#000000">and can&#39;t be done until</text>
-<text text-anchor="middle" x="188.5097" y="-161.5498" font-family="Times,serif" font-size="14.00" fill="#000000">something happens</text>
-</g>
-<!-- ready&#45;&gt;blocked -->
-<g id="edge3" class="edge">
-<title>ready&#45;&gt;blocked</title>
-<path fill="none" stroke="#000000" d="M119.3829,-265.9952C129.955,-252.8814 142.0401,-237.8909 153.1175,-224.1505"/>
-<polygon fill="#000000" stroke="#000000" points="155.9527,-226.2102 159.5042,-216.2284 150.5031,-221.8168 155.9527,-226.2102"/>
+<title>goal</title>
+<ellipse fill="none" stroke="#000000" cx="217.066" cy="-48.0833" rx="98.0761" ry="48.1667"/>
+<text text-anchor="middle" x="217.066" y="-66.8833" font-family="Times,serif" font-size="14.00" fill="#000000">This is the end goal:</text>
+<text text-anchor="middle" x="217.066" y="-51.8833" font-family="Times,serif" font-size="14.00" fill="#000000">if we reach here, there</text>
+<text text-anchor="middle" x="217.066" y="-36.8833" font-family="Times,serif" font-size="14.00" fill="#000000">is nothing more to be</text>
+<text text-anchor="middle" x="217.066" y="-21.8833" font-family="Times,serif" font-size="14.00" fill="#000000">done in the project</text>
</g>
<!-- finished -->
<g id="node2" class="node">
<title>finished</title>
-<ellipse fill="none" stroke="#000000" cx="411.5097" cy="-180.2498" rx="106.1321" ry="48.1667"/>
-<text text-anchor="middle" x="411.5097" y="-199.0498" font-family="Times,serif" font-size="14.00" fill="#000000">This task is finished;</text>
-<text text-anchor="middle" x="411.5097" y="-184.0498" font-family="Times,serif" font-size="14.00" fill="#000000">the arrow indicates what</text>
-<text text-anchor="middle" x="411.5097" y="-169.0498" font-family="Times,serif" font-size="14.00" fill="#000000">follows this task (unless</text>
-<text text-anchor="middle" x="411.5097" y="-154.0498" font-family="Times,serif" font-size="14.00" fill="#000000">it&#39;s blocked)</text>
-</g>
-<!-- goal -->
-<g id="node3" class="node">
-<title>goal</title>
-<ellipse fill="none" stroke="#000000" cx="299.5097" cy="-48.0833" rx="98.0761" ry="48.1667"/>
-<text text-anchor="middle" x="299.5097" y="-66.8833" font-family="Times,serif" font-size="14.00" fill="#000000">This is the end goal:</text>
-<text text-anchor="middle" x="299.5097" y="-51.8833" font-family="Times,serif" font-size="14.00" fill="#000000">if we reach here, there</text>
-<text text-anchor="middle" x="299.5097" y="-36.8833" font-family="Times,serif" font-size="14.00" fill="#000000">is nothing more to be</text>
-<text text-anchor="middle" x="299.5097" y="-21.8833" font-family="Times,serif" font-size="14.00" fill="#000000">done in the project</text>
+<ellipse fill="none" stroke="#000000" cx="106.066" cy="-180.2498" rx="106.1321" ry="48.1667"/>
+<text text-anchor="middle" x="106.066" y="-199.0498" font-family="Times,serif" font-size="14.00" fill="#000000">This task is finished;</text>
+<text text-anchor="middle" x="106.066" y="-184.0498" font-family="Times,serif" font-size="14.00" fill="#000000">the arrow indicates what</text>
+<text text-anchor="middle" x="106.066" y="-169.0498" font-family="Times,serif" font-size="14.00" fill="#000000">follows this task (unless</text>
+<text text-anchor="middle" x="106.066" y="-154.0498" font-family="Times,serif" font-size="14.00" fill="#000000">it&#39;s blocked)</text>
</g>
<!-- finished&#45;&gt;goal -->
<g id="edge1" class="edge">
<title>finished&#45;&gt;goal</title>
-<path fill="none" stroke="#000000" d="M373.2789,-135.1352C363.805,-123.9555 353.5742,-111.8826 343.8363,-100.3913"/>
-<polygon fill="#000000" stroke="#000000" points="346.324,-97.9131 337.1887,-92.5467 340.9836,-102.4387 346.324,-97.9131"/>
-</g>
-<!-- blocked&#45;&gt;goal -->
-<g id="edge2" class="edge">
-<title>blocked&#45;&gt;goal</title>
-<path fill="none" stroke="#000000" d="M218.5479,-144.4836C229.8159,-131.0669 242.8717,-115.5215 255.1657,-100.8832"/>
-<polygon fill="#000000" stroke="#000000" points="258.15,-102.772 261.9011,-92.8634 252.7896,-98.2701 258.15,-102.772"/>
+<path fill="none" stroke="#000000" d="M143.9555,-135.1352C153.2427,-124.0771 163.2638,-112.145 172.8203,-100.7662"/>
+<polygon fill="#000000" stroke="#000000" points="175.5962,-102.9031 179.3473,-92.9945 170.2359,-98.4012 175.5962,-102.9031"/>
</g>
<!-- next -->
-<g id="node5" class="node">
+<g id="node3" class="node">
<title>next</title>
-<ellipse fill="none" stroke="#000000" cx="286.5097" cy="-301.8097" rx="87.8629" ry="26.7407"/>
-<text text-anchor="middle" x="286.5097" y="-305.6097" font-family="Times,serif" font-size="14.00" fill="#000000">This task is chosen </text>
-<text text-anchor="middle" x="286.5097" y="-290.6097" font-family="Times,serif" font-size="14.00" fill="#000000">to be done next</text>
+<ellipse fill="none" stroke="#000000" cx="231.066" cy="-301.8097" rx="87.8629" ry="26.7407"/>
+<text text-anchor="middle" x="231.066" y="-305.6097" font-family="Times,serif" font-size="14.00" fill="#000000">This task is chosen </text>
+<text text-anchor="middle" x="231.066" y="-290.6097" font-family="Times,serif" font-size="14.00" fill="#000000">to be done next</text>
+</g>
+<!-- blocked -->
+<g id="node4" class="node">
+<title>blocked</title>
+<ellipse fill="none" stroke="#000000" cx="329.066" cy="-180.2498" rx="98.9899" ry="37.4533"/>
+<text text-anchor="middle" x="329.066" y="-191.5498" font-family="Times,serif" font-size="14.00" fill="#000000">This task is blocked</text>
+<text text-anchor="middle" x="329.066" y="-176.5498" font-family="Times,serif" font-size="14.00" fill="#000000">and can&#39;t be done until</text>
+<text text-anchor="middle" x="329.066" y="-161.5498" font-family="Times,serif" font-size="14.00" fill="#000000">something happens</text>
</g>
<!-- next&#45;&gt;blocked -->
<g id="edge4" class="edge">
<title>next&#45;&gt;blocked</title>
-<path fill="none" stroke="#000000" d="M265.2451,-275.433C253.2474,-260.551 237.9419,-241.5659 224.1613,-224.4724"/>
-<polygon fill="#000000" stroke="#000000" points="226.5411,-221.8476 217.5399,-216.2592 221.0915,-226.241 226.5411,-221.8476"/>
+<path fill="none" stroke="#000000" d="M252.3306,-275.433C264.3282,-260.551 279.6337,-241.5659 293.4144,-224.4724"/>
+<polygon fill="#000000" stroke="#000000" points="296.4842,-226.241 300.0357,-216.2592 291.0346,-221.8476 296.4842,-226.241"/>
+</g>
+<!-- blocked&#45;&gt;goal -->
+<g id="edge2" class="edge">
+<title>blocked&#45;&gt;goal</title>
+<path fill="none" stroke="#000000" d="M298.7572,-144.4836C287.3877,-131.0669 274.2143,-115.5215 261.8095,-100.8832"/>
+<polygon fill="#000000" stroke="#000000" points="264.1487,-98.2297 255.0134,-92.8634 258.8083,-102.7553 264.1487,-98.2297"/>
+</g>
+<!-- ready -->
+<g id="node5" class="node">
+<title>ready</title>
+<ellipse fill="none" stroke="#000000" cx="427.066" cy="-301.8097" rx="90.5193" ry="37.4533"/>
+<text text-anchor="middle" x="427.066" y="-313.1097" font-family="Times,serif" font-size="14.00" fill="#000000">This task is ready </text>
+<text text-anchor="middle" x="427.066" y="-298.1097" font-family="Times,serif" font-size="14.00" fill="#000000">to be done: it is not</text>
+<text text-anchor="middle" x="427.066" y="-283.1097" font-family="Times,serif" font-size="14.00" fill="#000000">blocked by anything</text>
+</g>
+<!-- ready&#45;&gt;blocked -->
+<g id="edge3" class="edge">
+<title>ready&#45;&gt;blocked</title>
+<path fill="none" stroke="#000000" d="M398.1928,-265.9952C387.6207,-252.8814 375.5356,-237.8909 364.4582,-224.1505"/>
+<polygon fill="#000000" stroke="#000000" points="367.0726,-221.8168 358.0715,-216.2284 361.623,-226.2102 367.0726,-221.8168"/>
</g>
</g>
</svg>
diff --git a/src/bin/roadmap2dot.rs b/src/bin/roadmap2dot.rs
index 4e40bc6..16ec0f0 100644
--- a/src/bin/roadmap2dot.rs
+++ b/src/bin/roadmap2dot.rs
@@ -17,6 +17,8 @@ use std::path::PathBuf;
use std::fs::File;
use std::io::Read;
+const LABEL_WIDTH: usize = 30;
+
#[derive(Debug, StructOpt)]
#[structopt(name = "roadmap2dot", about = "Create a dot graph of a roadmap in YAML")]
struct Opt {
@@ -33,7 +35,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
f.read_to_string(&mut text)?;
let r = Roadmap::from_yaml(&text)?;
- println!("{}", r.as_dot().unwrap());
+ println!("{}", r.as_dot(LABEL_WIDTH).unwrap());
Ok(())
}
diff --git a/src/lib.rs b/src/lib.rs
index 4b146f2..3058373 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -24,14 +24,15 @@
//! assert_eq!(n.len(), 2);
//! assert!(n.contains(&"first"));
//! assert!(n.contains(&"endgoal"));
-//!
+//!
//! # Ok(())
//! # }
//! ```
-use std::collections::HashMap;
use serde_yaml;
use serde_yaml::Value;
+use std::collections::HashMap;
+use textwrap::fill;
/// A step in a roadmap.
#[derive(Clone)]
@@ -62,7 +63,7 @@ impl Step {
}
/// Return vector of names of dependencies for a step.
- pub fn dependencies(&self) -> impl Iterator<Item=&String> {
+ pub fn dependencies(&self) -> impl Iterator<Item = &String> {
self.depends.iter()
}
@@ -115,7 +116,7 @@ impl Roadmap {
return Ok(step);
}
Ok(Step::new(name, ""))
- },
+ }
_ => Err("step is not a mapping"),
}
}
@@ -147,22 +148,26 @@ impl Roadmap {
}
// Get iterator over refs to steps.
- pub fn iter(&self) -> impl Iterator<Item=&Step> {
+ pub fn iter(&self) -> impl Iterator<Item = &Step> {
self.steps.iter()
}
// Get iterator over mut refs to steps.
- pub fn iter_mut(&mut self) -> impl Iterator<Item=&mut Step> {
+ pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Step> {
self.steps.iter_mut()
}
/// Get a Graphviz dot language representation of a roadmap. This
/// is the textual representation, and the caller needs to use the
/// Graphviz dot(1) tool to create an image from it.
- pub fn as_dot(self) -> Result<String, Box<dyn std::error::Error>> {
- let labels = self.steps.iter().map(|step|
- format!("{} [label=\"{}\"];\n", step.name(), step.label())
- );
+ pub fn as_dot(self, label_width: usize) -> Result<String, Box<dyn std::error::Error>> {
+ let labels = self.steps.iter().map(|step| {
+ format!(
+ "{} [label=\"{}\"];\n",
+ step.name(),
+ fill(&step.label(), label_width).replace("\n", "\\n")
+ )
+ });
let mut dot = String::new();
dot.push_str("digraph \"roadmap\" {\n");
@@ -183,10 +188,9 @@ impl Roadmap {
}
}
-
#[cfg(test)]
mod tests {
- use super::{Roadmap,Step};
+ use super::{Roadmap, Step};
#[test]
fn new_step() {
@@ -232,9 +236,12 @@ mod tests {
#[test]
fn empty_dot() {
let roadmap = Roadmap::new();
- assert_eq!(roadmap.as_dot().unwrap(), "digraph \"roadmap\" {
+ assert_eq!(
+ roadmap.as_dot(999).unwrap(),
+ "digraph \"roadmap\" {
}
-");
+"
+ );
}
#[test]
@@ -245,12 +252,15 @@ mod tests {
second.add_dependency("first");
roadmap.add_step(&first).unwrap();
roadmap.add_step(&second).unwrap();
- assert_eq!(roadmap.as_dot().unwrap(), "digraph \"roadmap\" {
+ assert_eq!(
+ roadmap.as_dot(999).unwrap(),
+ "digraph \"roadmap\" {
first [label=\"\"];
second [label=\"\"];
first -> second;
}
-");
+"
+ );
}
#[test]
@@ -261,14 +271,17 @@ first -> second;
#[test]
fn from_nonempty_yaml() {
- let roadmap = Roadmap::from_yaml("
+ let roadmap = Roadmap::from_yaml(
+ "
first:
label: the first step
second:
label: the second step
depends:
- first
-").unwrap();
+",
+ )
+ .unwrap();
let names = roadmap.step_names();
assert_eq!(names.len(), 2);