Radish alpha
r
rad:z3qg5TKmN83afz2fj9z3fQjU8vaYE
Radicle CI adapter for native CI
Radicle
Git
feat: add a table of contents to the run log
Lars Wirzenius committed 2 years ago
commit 2fa62ab846ae1116757e3a3a77ae4c0ca89bcaa1
parent 7746b37
2 files changed +67 -24
modified src/bin/run_log.rs
@@ -17,6 +17,13 @@ fn main() {
        "This is stdout".as_bytes(),
        "Error messages go here".as_bytes(),
    );
+
    run_log.runcmd(
+
        &["cargo", "check", "--all-targets", "--workspace"],
+
        Path::new("/tmp"),
+
        0,
+
        "This is stdout".as_bytes(),
+
        "Error messages go here".as_bytes(),
+
    );

    run_log.write().expect("write html log");
}
modified src/runlog.rs
@@ -67,7 +67,6 @@ impl RunLog {
        let mut doc = Document::default();

        doc.push_to_head(&Element::new(Tag::Title).with_text(title));
-

        doc.push_to_body(&Element::new(Tag::H1).with_text(title));

        let mut ul = Element::new(Tag::Ul);
@@ -95,15 +94,20 @@ impl RunLog {
            doc.push_to_body(&error);
        }

-
        for cmd in self.commands.iter() {
-
            cmd.format(&mut doc);
-
        }
-

        if self.timeout {
            let timeout = Element::new(Tag::P).with_text("Last command timed out");
            doc.push_to_body(&timeout);
        }

+
        let mut toc = ToC::default();
+
        let mut body = Element::new(Tag::Div);
+
        for cmd in self.commands.iter() {
+
            cmd.format(&mut body, &mut toc);
+
        }
+

+
        doc.push_to_body(&toc.as_html());
+
        doc.push_to_body(&body);
+

        let html = format!("{}", doc);
        std::fs::write(&self.filename, html.as_bytes())
            .map_err(|e| RunLogError::Write(self.filename.clone(), e))?;
@@ -134,14 +138,16 @@ impl Command {
        self.argv.as_slice().join(" ")
    }

-
    fn format(&self, doc: &mut Document) {
-
        doc.push_to_body(
-
            &Element::new(Tag::H2)
-
                .with_text("Run: ")
-
                .with_child(Element::new(Tag::Code).with_text(&self.command())),
+
    fn format(&self, body: &mut Element, toc: &mut ToC) {
+
        body.push_child(
+
            &toc.push(
+
                Element::new(Tag::Span)
+
                    .with_text("Run: ")
+
                    .with_child(Element::new(Tag::Code).with_text(&self.command())),
+
            ),
        );

-
        doc.push_to_body(&Element::new(Tag::P).with_text("Command arguments:"));
+
        body.push_child(&Element::new(Tag::P).with_text("Command arguments:"));
        let mut ul = Element::new(Tag::Ul);
        for arg in self.argv.iter() {
            ul.push_child(
@@ -149,31 +155,61 @@ impl Command {
                    .with_child(Element::new(Tag::Code).with_text(&format!("{:?}", arg))),
            );
        }
-
        doc.push_to_body(&ul);
+
        body.push_child(&ul);

-
        doc.push_to_body(
+
        body.push_child(
            &Element::new(Tag::P)
                .with_text("In directory: ")
                .with_child(Element::new(Tag::Code).with_text(&format!("{}", self.cwd.display()))),
        );

-
        doc.push_to_body(&Element::new(Tag::P).with_text(&format!("Exit code: {}", self.exit)));
+
        body.push_child(&Element::new(Tag::P).with_text(&format!("Exit code: {}", self.exit)));

-
        self.output(doc, "Stdout:", &self.stdout);
-
        self.output(doc, "Stderr:", &self.stderr);
+
        self.output(body, "Stdout:", &self.stdout);
+
        self.output(body, "Stderr:", &self.stderr);
    }

-
    fn output(&self, doc: &mut Document, stream: &str, data: &[u8]) {
+
    fn output(&self, body: &mut Element, stream: &str, data: &[u8]) {
        if !data.is_empty() {
-
            doc.push_to_body(&Element::new(Tag::P).with_text(stream));
-
            doc.push_to_body(
-
                &Element::new(Tag::P).with_child(
-
                    Element::new(Tag::Blockquote).with_child(
-
                        Element::new(Tag::Pre).with_text(&String::from_utf8_lossy(data)),
-
                    ),
-
                ),
+
            body.push_child(&Element::new(Tag::P).with_text(stream));
+
            body.push_child(
+
                &Element::new(Tag::Blockquote)
+
                    .with_child(Element::new(Tag::Pre).with_text(&String::from_utf8_lossy(data))),
+
            );
+
        }
+
    }
+
}
+

+
#[derive(Debug, Default)]
+
struct ToC {
+
    counter: usize,
+
    headings: Vec<(String, Element)>,
+
}
+

+
impl ToC {
+
    fn push(&mut self, content: Element) -> Element {
+
        self.counter += 1;
+
        let anchor = format!("h{}", self.counter);
+
        self.headings.push((anchor.clone(), content.clone()));
+
        Element::new(Tag::H2)
+
            .with_attribute("id", &format!("h{}", self.counter))
+
            .with_child(content)
+
    }
+

+
    fn as_html(&self) -> Element {
+
        let mut toc =
+
            Element::new(Tag::Div).with_child(Element::new(Tag::H2).with_text("Table of contents"));
+
        let mut list = Element::new(Tag::Ul);
+
        for (anchor, content) in self.headings.iter() {
+
            let entry = Element::new(Tag::Li).with_child(
+
                Element::new(Tag::A)
+
                    .with_attribute("href", &format!("#{anchor}"))
+
                    .with_child(content.clone()),
            );
+
            list.push_child(&entry);
        }
+
        toc.push_child(&list);
+
        toc
    }
}