diff --git a/src/typstgen.nim b/src/typstgen.nim index 372b6c7..3e8b818 100644 --- a/src/typstgen.nim +++ b/src/typstgen.nim @@ -1,39 +1,90 @@ -import std/[streams, tables, strutils, os] +import std/[os, sequtils, streams, strutils, tables] import yaml, hwylterm - type + Component = Table[string, string] + TypstTemplate = object + keys: seq[string] + src: string Config = object - components {.defaultVal: @[]}: seq[Table[string, string]] - templates {.defaultVal: initTable[string, string]()}: Table[string, string] + components {.defaultVal: @[]}: seq[Component] + templates {.defaultVal: initTable[string, TypstTemplate]()}: Table[string, TypstTemplate] + +func `%`(t: TypstTemplate, a: openArray[string]): string = + t.src % a + +proc checkTemplates(templates: Table[string, TypstTemplate]) = + ## quit if any templates have the same keys + var keyTable: Table[string, seq[string]] + + for name, templ in templates.pairs(): + let k = templ.keys.join(";") + if k in keyTable: + keyTable[k].add name + else: + keyTable[k] = @[name] + + for keys, names in keyTable.pairs(): + if names.len > 1: + quit("non-unique key combos in templates: " & names.join(",")) -proc typstGen(configPath: string) = +proc addDefaultTemplates(c: var Config) = + # TODO: more default templates? + if "raw" notin c.templates: + c.templates["raw"] = TypstTemplate(keys: @["raw"], src: "$raw") + + if "image" notin c.templates: + c.templates["image"] = TypstTemplate(keys: @["image"], src: """ +#figure( + image("$image"), + caption: [$image] +) +""" + ) + + if "figure" notin c.templates: + c.templates["figure"] = TypstTemplate(keys: @["image", "caption"], src: """ +#align(center)[ + #figure( + image("$image"), + caption: [ + $image + ] + ) + $caption +] +""" + ) + + +proc loadConfig(configPath: string): Config = - var config: Config var s = newFileStream(configPath) - load(s, config) - s.close() + load(s, result) + close s - var output: string + addDefaultTemplates result + checkTemplates result.templates - if not config.templates.hasKey("raw"): - config.templates["raw"] = "$text" +proc getTemplate(c: Config, component: Component): TypstTemplate = + let k = component.keys().toSeq() + for _, templ in c.templates.pairs(): + if templ.keys == k: + return templ + quit($bb("[red]error[/] failed to find template for component:\n") & $component) - func componentToFmtArgs(t: Table[string, string]): seq[string] = - for k, v in t.pairs: - result.add k - result.add v +func toFmtArgs(comp: Component): seq[string] = + for k, v in comp.pairs: result.add k; result.add v - for component in config.components: - var kind = "figure" - var component = component - discard component.pop("kind", kind) - output &= config.templates[kind] % componentToFmtArgs(component) - - echo output +proc applyTemplate(c: Config, component: Component): string = + let templ = c.getTemplate(component) + result = templ % component.toFmtArgs() +proc typstGen(c: Config): string = + for component in c.components: + result &= c.applyTemplate(component) when isMainModule: import hwylterm/[cli, parseopt3] @@ -45,10 +96,13 @@ when isMainModule: [ ("h", "help", "show this help"), ("c","config", "path to config file"), + ("","check", "load config and exit"), ] ) - var p = initOptParser() - var configPath = "typstgen.yml" + var + p = initOptParser(longNoVal= @["check"]) + configPath = "typstgen.yml" + check: bool for kind, key, val in p.getopt(): case kind of cmdError: quit($bb"[red]cli error[/]: " & p.message) @@ -60,9 +114,14 @@ when isMainModule: writeHelp(); quit 0 of "config", "c": configPath = val + of "check": + check = true if not fileExists(configPath): quit($bbfmt("file: [b]{configPath}[/] does not exist")) - typstGen(configPath) + + let config = loadConfig(configPath) + if check: quit 0 + echo typstGen(config)