Current section
Files
Jump to
Current section
Files
src/arctic/plugin/diagram.gleam
import arctic/parse
import gleam/bool
import gleam/dict
import gleam/int
import gleam/result.{map_error}
import lustre/attribute
import lustre/element/html
import shellout
import simplifile
import snag
pub fn parse(dir: String, get_id: fn(a) -> Int, to_state: fn(Int) -> a) {
fn(_args: List(String), body: String, data: parse.ParseData(a)) {
// TODO: use pos for error messages
let counter = get_id(parse.get_state(data))
let assert Ok(id) = dict.get(parse.get_metadata(data), "id")
let img_filename = "image-" <> int.to_string(counter) <> "-" <> id <> ".svg"
let out = #(
html.div([attribute.class("diagram")], [
html.img([
attribute.src("/" <> img_filename),
attribute.attribute("onload", "this.width *= 2.25;"),
]),
]),
to_state(counter + 1),
)
use exists <- result.try(
simplifile.is_file(dir <> "/" <> img_filename)
|> map_error(fn(err) {
snag.new(
"couldn't check `"
<> dir
<> "/"
<> img_filename
<> "` ("
<> simplifile.describe_error(err)
<> ")",
)
}),
)
// very simple caching: if we've generated an image with this name before, don't do it again
// this works for now because I can always just delete an image file.
// But in the future I want an actual caching system that detects updates.
// Perhaps a sqlite db?
use <- bool.guard(when: exists, return: Ok(out))
let latex_code = "
\\documentclass[margin=0pt]{standalone}
\\usepackage{tikz-cd}
\\begin{document}
\\begin{tikzcd}\n" <> body <> "\\end{tikzcd}
\\end{document}"
use _ <- result.try(
simplifile.write(latex_code, to: "./diagram-work/diagram.tex")
|> map_error(fn(err) {
snag.new(
"couldn't write to `diagram-work/diagram.tex` ("
<> simplifile.describe_error(err)
<> ")",
)
}),
)
use _ <- result.try(
shellout.command(
run: "pdflatex",
with: ["-interaction", "nonstopmode", "diagram.tex"],
in: "diagram-work",
opt: [],
)
|> map_error(fn(err) {
snag.new(
"couldn't execute `pdflatex -interaction nonstopmode diagram.tex` in `diagram-work` (Code "
<> int.to_string(err.0)
<> ": "
<> err.1,
)
}),
)
use _ <- result.try(
shellout.command(
run: "inkscape",
with: [
"-l",
"--export-filename",
"../" <> dir <> "/" <> img_filename,
"diagram.pdf",
],
in: "diagram-work",
opt: [shellout.LetBeStdout],
)
|> map_error(fn(err) {
snag.new(
"couldn't execute `inkscape -l --export-filename ../"
<> dir
<> "/"
<> img_filename
<> " diagram.pdf` in `diagram-work` (Code "
<> int.to_string(err.0)
<> ": "
<> err.1
<> ")",
)
}),
)
Ok(out)
}
}