summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2019-09-23 10:45:45 +0300
committerLars Wirzenius <liw@liw.fi>2019-09-23 10:45:45 +0300
commit804c418bbfba696020957f5f22aa30660302b744 (patch)
treeba296e779b1ba65faab49b9cce13cb7b10baff15 /src
parent2936f3cf609bff77ef0851ebf55b35c74d31a67a (diff)
downloadroadmap-804c418bbfba696020957f5f22aa30660302b744.tar.gz
Add: support for color and shape for steps
These must currently be specified in the YAML directly.
Diffstat (limited to 'src')
-rw-r--r--src/bin/roadmap2dot.rs7
-rw-r--r--src/lib.rs69
2 files changed, 71 insertions, 5 deletions
diff --git a/src/bin/roadmap2dot.rs b/src/bin/roadmap2dot.rs
index 16ec0f0..2526555 100644
--- a/src/bin/roadmap2dot.rs
+++ b/src/bin/roadmap2dot.rs
@@ -33,8 +33,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut text = String::new();
let mut f = File::open(opt.filename)?;
f.read_to_string(&mut text)?;
+// eprintln!("text:\n{}\n", text);
let r = Roadmap::from_yaml(&text)?;
+// eprintln!("");
+ for name in r.step_names() {
+ let step = r.get_step(name).unwrap();
+ eprintln!("step {} ({}) status {}", name, step.name(), step.status());
+ }
+ eprintln!("");
println!("{}", r.as_dot(LABEL_WIDTH).unwrap());
Ok(())
diff --git a/src/lib.rs b/src/lib.rs
index 3058373..91938b4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -38,6 +38,7 @@ use textwrap::fill;
#[derive(Clone)]
pub struct Step {
name: String,
+ status: String,
label: String,
depends: Vec<String>,
}
@@ -47,6 +48,7 @@ impl Step {
pub fn new(name: &str, label: &str) -> Step {
Step {
name: name.to_string(),
+ status: "".to_string(),
label: label.to_string(),
depends: vec![],
}
@@ -62,6 +64,17 @@ impl Step {
&self.label
}
+ /// Return the status of a step.
+ pub fn status<'a>(&'a self) -> &'a str {
+ &self.status
+ }
+
+ /// Set the status of a step.
+ pub fn set_status(&mut self, status: &str) {
+ eprintln!("xxx setting status to {} for {}", status, self.label());
+ self.status = String::from(status);
+ }
+
/// Return vector of names of dependencies for a step.
pub fn dependencies(&self) -> impl Iterator<Item = &String> {
self.depends.iter()
@@ -69,7 +82,7 @@ impl Step {
/// Add the name of a dependency to step.
pub fn add_dependency(&mut self, name: &str) {
- self.depends.push(name.to_string());
+ self.depends.push(String::from(name));
}
}
@@ -94,18 +107,30 @@ impl Roadmap {
roadmap.add_step(&step)?;
}
+ for name in roadmap.step_names() {
+ let step = roadmap.get_step(name).unwrap();
+ eprintln!("roadmap step {} ({}) status {}", name, step.name(), step.status());
+ }
+
Ok(roadmap)
}
// Convert a Value into a Step, if possible.
fn step_from_value(name: &str, value: &Value) -> Result<Step, &'static str> {
let label_key = Value::String("label".to_string());
+ let status_key = Value::String("status".to_string());
let deps_key = Value::String("depends".to_string());
+ eprintln!("=====\nstep_from_value: {:?}", value);
match value {
Value::Mapping(map) => {
if let Some(Value::String(label)) = map.get(&label_key) {
let mut step = Step::new(name, label);
+ if let Some(Value::String(status)) = map.get(&status_key) {
+ eprintln!("step_from_value: status: {:?}", status);
+ step.set_status(&status);
+ eprintln!("status from step: {:?}", step.status());
+ }
if let Some(Value::Sequence(deps)) = map.get(&deps_key) {
for depname in deps.iter() {
if let Value::String(depname) = depname {
@@ -163,9 +188,11 @@ impl Roadmap {
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",
+ "{} [label=\"{}\" style=filled fillcolor=\"{}\" shape=\"{}\"];\n",
step.name(),
- fill(&step.label(), label_width).replace("\n", "\\n")
+ fill(&step.label(), label_width).replace("\n", "\\n"),
+ Roadmap::get_status_color(step),
+ Roadmap::get_status_shape(step),
)
});
@@ -186,6 +213,30 @@ impl Roadmap {
Ok(dot)
}
+
+ fn get_status_color(step: &Step) -> &str {
+// eprintln!("color for {}: {}", step.status(), step.label());
+ match step.status() {
+ "blocked" => "#f4bada",
+ "finished" => "#eeeeee",
+ "ready" => "#ffffff",
+ "next" => "#0cc00",
+ "goal" => "#00eeee",
+ _ => "unknownstatus",
+ }
+ }
+
+ fn get_status_shape(step: &Step) -> &str {
+// eprintln!("shape for {}", step.status());
+ match step.status() {
+ "blocked" => "rectangle",
+ "finished" => "circle",
+ "ready" => "ellipse",
+ "next" => "ellipse",
+ "goal" => "diamond",
+ _ => "unknownshape",
+ }
+ }
}
#[cfg(test)]
@@ -196,11 +247,19 @@ mod tests {
fn new_step() {
let step = Step::new("myname", "my label");
assert_eq!(step.name(), "myname");
+ assert_eq!(step.status(), "goal");
assert_eq!(step.label(), "my label");
assert_eq!(step.dependencies().count(), 0);
}
#[test]
+ fn set_status() {
+ let mut step = Step::new("myname", "my label");
+ step.set_status("next");
+ assert_eq!(step.status(), "next");
+ }
+
+ #[test]
fn add_step_dependency() {
let mut second = Step::new("second", "the second step");
second.add_dependency("first");
@@ -255,8 +314,8 @@ mod tests {
assert_eq!(
roadmap.as_dot(999).unwrap(),
"digraph \"roadmap\" {
-first [label=\"\"];
-second [label=\"\"];
+first [label=\"\" fillcolor=\"#ffffff\" shape=\"ellipse\"];
+second [label=\"\" fillcolor=\"#00eeeeee\" shape=\"diamond\"];
first -> second;
}
"