Guide
The toolbox: paths, cli, markdown
Since Sprints 372–374 the parts every command-line tool and site generator needs are in the standard library.
import cli
import markdown
import paths
import texts
fn level(line: Text) -> Int:
mut n = 0
for c in line.chars():
if c != "#":
return n
n = n + 1
return n
fn main() -> Int:
let spec = cli.spec("toc", "Prints a table of contents").option("depth", "d", "3", "deepest level").positional("file", "the Markdown file")
match cli.parse(spec, args()):
case Err(e):
eprint(e)
return 2
case Ok(opts):
let depth = opts.value("depth").to_int().unwrap_or(3)
let page = paths.with_extension(paths.name(opts.value("file")), "html")
let doc = "# Notes\n\n## Install\n\n### From source\n\n## First steps"
for line in doc.split("\n"):
let n = level(line)
if n >= 2 and n <= depth:
let title = line.slice(n + 1, line.len())
print("{texts.repeat(" ", n - 2)}- [{title}]({page}#{markdown.slug(title)})")
return 0cli declares what a program accepts in one chained expression — flag, option with a fallback, positional — and parse(spec, args()) answers with every value by name: --depth 3, --depth=3, -d 3 and -d3 all work, -h prints cli.usage(spec), and a mistake is an Err naming what was expected (missing argument <file> — usage: toc [options] <file>), here exit 2. paths works on text only — join, name, parent, stem, extension, with_extension, normalize, relative — so the same code runs in tests and in the browser. markdown.to_html renders the everyday Markdown subset with every character escaped and script links inert; title and slug give a page its name and its anchors. examples/site/ builds a whole site from the three.