supertext 0.0.2

html document tools
Documentation
# supertext

hypertext, a bit less hyper

i want to construct HTML documents in some Rust code. i don't want a full
templating solution. i just want to append some tags and not forget to escape
user-provided input.

you probably don't want to use this, but if you do it should work. public
interfaces are basically expected to break. it is 0.0.1 for a reason.

## example

```rust
pub fn example(items: &[(String, String)]) -> Result<String, std::fmt::Error> {
    let mut out = String::new();
    let mut writer = HtmlWriter::new(&mut out);

    let mut html = HtmlSink::root(&mut writer);

    {
        let mut style = html.open_tag(style());
        style.rule(".table { font-family: monospace; border: 1px solid black; }")?;
        style.rule(".row-item { padding-left: 4px; padding-right: 4px; border-right: 1px solid black; }")?;
        style.rule(".odd-row { background: #eee; }")?;
        style.rule(".even-row { background: #ddd; }")?;
    }

    {
        let mut header = html.open_tag(h1());
        header.text("an example page that is super cool")?;
    }

    {
        let mut description = html.open_tag(p());
        match items.len() {
            0 => description.text("no items")?,
            1 => description.text("one item")?,
            o => description.text(&format!("{} items", o))?,
        };
    }

    let mut table = html.open_tag(table().class("table"));
    {
        let mut header = table.header();
        let th = th().class("row-item");
        let mut add_cell = |name: &'static str| header.open_tag(th.clone()).text(name);
        add_cell("key")?;
        add_cell("value")?;
    }

    let td = td().class("row-item");

    for (i, item) in items.iter().enumerate() {
        let mut row = table.row(tr().class(["even-row", "odd-row"][i % 2]));

        {
            let mut elem = row.open_tag(td.clone());
            elem.open_tag(a().href(&format!("/{}", item.0))).text(&item.0)?;
        }
        {
            row.open_tag(td.clone()).text(&item.1)?;
        }
    }

    table.close();

    html.close();

    Ok(out)
}
```

## non-goals

this crate is intended to avoid trivially injectable HTML document
construction. it is not intended to prevent semantically incoherent HTML
documents. yet?

for example, this crate allows creating a table with twelve columns in its
header, but varying (and not-twelve) rows afterwards. this crate allows
tags to reference styles that are undefined. this crate allows intra-page
links that are invalid. this crate allows syntactically invalid CSS.

## TODO

- [ ] really want to fuzz document construction and ensure no inputs produce
      different trees when parsed than when constructed
- [ ] really want to be able to check if strings need escaping at compile time
      rather than runtime
- [ ] for strings that need runtime escaping, would really like to not reallocate
      for replaced strings - retaining borrows of original data and not
      producing interim replaced copies would be nice. maybe something like a
      rope instead? or views on the underlying string with buffers of
      replacements to be evaluated when rendered out.
- [ ] what to do with css rules? each rule gets a newline currently, is that ok?
- [ ] controlling indentation for paragraphs? `p.text()` lines always just
      appends escaped text to the writer, maybe those should be spaced with
      newlines? should `text()` automatically append a line break?

## related work (and things this is not)

[build\_html](https://docs.rs/build_html/latest/build_html/) looks good,
almost is what i want! unfortunately: 

> Note that escaping strings is also not automatic. You should use the
> escape\_html function if you are displaying untrusted text.

the API was already wanted more ceremony than i was happy with, but this moves
it out of the running.

[html](https://docs.rs/html/latest/html/) is comprehensive, but perhaps too
much so.

the docs surface area is roughly the product of all kinds of tags by all kinds
of tags, to the point i have a bit of a difficult time with navigation. it
includes lots of HTML spec that is probably interesting and meaningful if
i was doing interesting things with HTML, but i'm not.

needing to set `#![recursion_limit = "512"]` when depending on this crate is
another papercut; between that and its idleness, i'm OK passing here.

[maud](https://docs.rs/maud/latest/maud/) ([book](https://maud.lambda.xyz/))
seems good, but i don't want a template engine, i just want to put a few divs
and spans together. more importantly, i want to be able to render elements of
a page potentially independently. having to construct an entire HTML document
in one go is not great, and having to learn a new syntax for control flow in
the document is the opposite direction of what i want.