1use std::fmt;
23use std::path::PathBuf;
24use std::str::FromStr;
25
26use serde::{Deserialize, Serialize};
27
28pub mod doc;
29pub mod markdown;
30pub mod render;
31pub mod scaffold;
32pub mod source;
33pub mod template;
34pub mod typst_emit;
35
36pub use doc::WispDoc;
37pub use scaffold::init;
38pub use source::export;
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
43#[serde(rename_all = "lowercase")]
44pub enum Format {
45 Typst,
46 Html,
47}
48
49impl Format {
50 pub fn required_partials(self) -> &'static [&'static str] {
53 match self {
54 Format::Typst => &[
55 "theme.typ",
56 "header.typ",
57 "footer.typ",
58 "cover.typ",
59 "toc.typ",
60 ],
61 Format::Html => &[
62 "theme.css",
63 "header.html",
64 "footer.html",
65 "cover.html",
66 "toc.html",
67 ],
68 }
69 }
70}
71
72impl fmt::Display for Format {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 f.write_str(match self {
75 Format::Typst => "typst",
76 Format::Html => "html",
77 })
78 }
79}
80
81impl FromStr for Format {
82 type Err = String;
83 fn from_str(s: &str) -> Result<Self, Self::Err> {
84 match s.trim().to_ascii_lowercase().as_str() {
85 "typst" | "typ" => Ok(Format::Typst),
86 "html" => Ok(Format::Html),
87 other => Err(format!(
88 "unknown partial format `{other}` (expected `typst` or `html`)"
89 )),
90 }
91 }
92}
93
94#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
97#[serde(rename_all = "lowercase")]
98pub enum Renderer {
99 #[default]
100 Typst,
101 Weasyprint,
102 Chromium,
103}
104
105impl Renderer {
106 pub fn format(self) -> Format {
108 match self {
109 Renderer::Typst => Format::Typst,
110 Renderer::Weasyprint | Renderer::Chromium => Format::Html,
111 }
112 }
113}
114
115impl fmt::Display for Renderer {
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 f.write_str(match self {
118 Renderer::Typst => "typst",
119 Renderer::Weasyprint => "weasyprint",
120 Renderer::Chromium => "chromium",
121 })
122 }
123}
124
125impl FromStr for Renderer {
126 type Err = String;
127 fn from_str(s: &str) -> Result<Self, Self::Err> {
128 match s.trim().to_ascii_lowercase().as_str() {
129 "typst" => Ok(Renderer::Typst),
130 "weasyprint" => Ok(Renderer::Weasyprint),
131 "chromium" | "chrome" => Ok(Renderer::Chromium),
132 other => Err(format!(
133 "unknown renderer `{other}` (expected `typst`, `weasyprint`, or `chromium`)"
134 )),
135 }
136 }
137}
138
139#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
141#[serde(rename_all = "UPPERCASE")]
142pub enum Status {
143 Approved,
144 Draft,
145}
146
147impl fmt::Display for Status {
148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149 f.write_str(match self {
150 Status::Approved => "APPROVED",
151 Status::Draft => "DRAFT",
152 })
153 }
154}
155
156#[derive(Debug, Clone)]
158pub struct InitOptions {
159 pub dir: PathBuf,
160 pub format: Format,
161 pub logo: Option<PathBuf>,
163 pub force: bool,
165}
166
167#[derive(Debug, Clone, Serialize)]
169pub struct InitReport {
170 pub dir: PathBuf,
171 pub format: Format,
172 pub written: Vec<String>,
173 pub skipped: Vec<String>,
174}
175
176#[derive(Debug, Clone)]
179pub struct ExportOptions {
180 pub root: PathBuf,
182 pub today: chrono::NaiveDate,
184 pub source: Option<PathBuf>,
186 pub template: Option<PathBuf>,
188 pub output: Option<PathBuf>,
190 pub toc: Option<bool>,
192 pub page_numbers: Option<bool>,
194 pub draft: bool,
196 pub allow_dirty: bool,
197 pub renderer: Option<Renderer>,
199}
200
201#[derive(Debug, Clone, Serialize)]
203pub struct ExportReport {
204 pub output: PathBuf,
205 pub version: String,
206 pub effective_date: String,
207 pub commit: String,
208 pub content_hash: String,
209 pub status: Status,
210 pub renderer: Renderer,
211 pub sections: Vec<String>,
213 pub pages: Option<u32>,
215}