diff options
author | Minijackson <minijackson@riseup.net> | 2021-11-28 00:19:12 +0100 |
---|---|---|
committer | Minijackson <minijackson@riseup.net> | 2021-11-28 00:21:46 +0100 |
commit | 17b10fab16bc5df3a969826150e92f50e88a99b9 (patch) | |
tree | 12a0c721e89ef17f07a9ede593d82a4c95bc7937 /src/build.rs | |
parent | 517cabe8ec54d0bf5f5f9cc9089d76a1fad7bb6a (diff) | |
download | pandoc-docbook-17b10fab16bc5df3a969826150e92f50e88a99b9.tar.gz pandoc-docbook-17b10fab16bc5df3a969826150e92f50e88a99b9.zip |
add css and html template, refactor build
Diffstat (limited to 'src/build.rs')
-rw-r--r-- | src/build.rs | 411 |
1 files changed, 161 insertions, 250 deletions
diff --git a/src/build.rs b/src/build.rs index 0b0c646..1c12476 100644 --- a/src/build.rs +++ b/src/build.rs | |||
@@ -1,20 +1,29 @@ | |||
1 | use std::path::{Path, PathBuf}; | 1 | use std::path::{Path, PathBuf}; |
2 | 2 | ||
3 | use eyre::{eyre, ContextCompat, Result, WrapErr}; | 3 | use eyre::{eyre, Result, WrapErr}; |
4 | use log::{debug, error, log_enabled, trace, warn}; | 4 | use log::{debug, error, log_enabled, trace, warn}; |
5 | use pandoc_ast::MutVisitor; | 5 | use pandoc_ast::MutVisitor; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | filters, | 8 | filters::{self, relativize_summary}, |
9 | utils::{AutoIdentifier, PandocMeta, PandocOutputExt}, | 9 | utils::{AutoIdentifier, PandocMeta, PandocOutputExt, PathExt}, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | const CSS: &str = include_str!("../res/style.css"); | ||
13 | const HTML_TEMPLATE: &str = include_str!("../res/template.html"); | ||
14 | |||
12 | pub fn do_build(config: &crate::config::Config) -> Result<()> { | 15 | pub fn do_build(config: &crate::config::Config) -> Result<()> { |
13 | let summary = Summary::try_from_file(&config.book.summary)?; | 16 | let tmpdir = tempfile::tempdir().wrap_err("Could not create temporary directory")?; |
17 | debug!("Created temporary directory at: '{}'", tmpdir.path().display()); | ||
18 | let template_path = tmpdir.path().join("template.html"); | ||
19 | trace!("Writing HTML template to: '{}'", template_path.display()); | ||
20 | std::fs::write(&template_path, HTML_TEMPLATE) | ||
21 | .wrap_err("Could not save HTML template in temporary directory")?; | ||
22 | |||
14 | let source_root = Path::new(&config.book.summary) | 23 | let source_root = Path::new(&config.book.summary) |
15 | .parent() | 24 | .parent() |
16 | .expect("Summary has no parent"); | 25 | .expect("Summary has no parent"); |
17 | let files = summary.collect_source_files(source_root)?; | 26 | let (summary, files) = process_summary(&config.book.summary, source_root)?; |
18 | 27 | ||
19 | let build_dir = Path::new(&config.build.build_dir); | 28 | let build_dir = Path::new(&config.build.build_dir); |
20 | trace!("Creating build directory: '{}'", build_dir.display()); | 29 | trace!("Creating build directory: '{}'", build_dir.display()); |
@@ -25,6 +34,10 @@ pub fn do_build(config: &crate::config::Config) -> Result<()> { | |||
25 | ) | 34 | ) |
26 | })?; | 35 | })?; |
27 | 36 | ||
37 | let style_path = build_dir.join("style.css"); | ||
38 | debug!("Generating file: '{}'", style_path.display()); | ||
39 | std::fs::write(&style_path, CSS).wrap_err("Could not create style.css")?; | ||
40 | |||
28 | // Pre-create files so that we know which links to relativize | 41 | // Pre-create files so that we know which links to relativize |
29 | for SourceFile { path, .. } in &files { | 42 | for SourceFile { path, .. } in &files { |
30 | let output_file = build_dir.join(path.with_extension("html")); | 43 | let output_file = build_dir.join(path.with_extension("html")); |
@@ -47,7 +60,7 @@ pub fn do_build(config: &crate::config::Config) -> Result<()> { | |||
47 | })?; | 60 | })?; |
48 | } | 61 | } |
49 | 62 | ||
50 | for SourceFile { path, source } in &files { | 63 | for SourceFile { path, source, .. } in &files { |
51 | let mut pandoc_command = pandoc::new(); | 64 | let mut pandoc_command = pandoc::new(); |
52 | 65 | ||
53 | let output_file = build_dir.join(path.with_extension("html")); | 66 | let output_file = build_dir.join(path.with_extension("html")); |
@@ -61,25 +74,36 @@ pub fn do_build(config: &crate::config::Config) -> Result<()> { | |||
61 | .expect("Source file has no parent") | 74 | .expect("Source file has no parent") |
62 | .to_path_buf(); | 75 | .to_path_buf(); |
63 | let build_dir_clone = build_dir.to_path_buf(); | 76 | let build_dir_clone = build_dir.to_path_buf(); |
64 | let summary_clone = summary.source.clone(); | 77 | |
78 | let level = source_dir | ||
79 | .components() | ||
80 | .skip_while(|c| matches!(c, std::path::Component::CurDir)) | ||
81 | .count(); | ||
82 | |||
83 | let summary = relativize_summary(&summary.source, level); | ||
84 | let mut source = source.clone(); | ||
85 | source.meta.insert( | ||
86 | "summary".to_string(), | ||
87 | pandoc_ast::MetaValue::MetaBlocks(summary.blocks), | ||
88 | ); | ||
89 | |||
90 | let style_path = std::iter::repeat(std::path::Component::ParentDir) | ||
91 | .take(level) | ||
92 | .collect::<PathBuf>() | ||
93 | .join("style.css"); | ||
65 | 94 | ||
66 | pandoc_command | 95 | pandoc_command |
67 | .set_input(pandoc::InputKind::Pipe(source.to_json())) | 96 | .set_input(pandoc::InputKind::Pipe(source.to_json())) |
68 | .set_input_format(pandoc::InputFormat::Json, vec![]) | 97 | .set_input_format(pandoc::InputFormat::Json, vec![]) |
69 | .set_output(pandoc::OutputKind::File(output_file)) | 98 | .set_output(pandoc::OutputKind::File(output_file)) |
70 | .set_output_format(pandoc::OutputFormat::Html5, vec![]) | 99 | .set_output_format(pandoc::OutputFormat::Html5, vec![]) |
71 | .add_options(&[pandoc::PandocOption::SelfContained]) | 100 | .add_options(&[ |
101 | pandoc::PandocOption::Css(style_path.to_string()), | ||
102 | pandoc::PandocOption::SectionDivs, | ||
103 | pandoc::PandocOption::Standalone, | ||
104 | pandoc::PandocOption::Template(template_path.clone()), | ||
105 | ]) | ||
72 | .add_filter(move |source| { | 106 | .add_filter(move |source| { |
73 | let level = source_dir | ||
74 | .components() | ||
75 | .skip_while(|c| matches!(c, std::path::Component::CurDir)) | ||
76 | .count(); | ||
77 | |||
78 | let mut insert_summary_filter = filters::InsertSummary { | ||
79 | level, | ||
80 | summary: &summary_clone, | ||
81 | }; | ||
82 | |||
83 | let mut relativize_urls_filter = filters::RelativizeUrls { | 107 | let mut relativize_urls_filter = filters::RelativizeUrls { |
84 | config: &config_clone, | 108 | config: &config_clone, |
85 | // TODO: other output formats | 109 | // TODO: other output formats |
@@ -89,7 +113,6 @@ pub fn do_build(config: &crate::config::Config) -> Result<()> { | |||
89 | }; | 113 | }; |
90 | 114 | ||
91 | let mut source = pandoc_ast::Pandoc::from_json(&source); | 115 | let mut source = pandoc_ast::Pandoc::from_json(&source); |
92 | insert_summary_filter.walk_pandoc(&mut source); | ||
93 | relativize_urls_filter.walk_pandoc(&mut source); | 116 | relativize_urls_filter.walk_pandoc(&mut source); |
94 | source.to_json() | 117 | source.to_json() |
95 | }); | 118 | }); |
@@ -109,7 +132,7 @@ pub fn do_build(config: &crate::config::Config) -> Result<()> { | |||
109 | // TODO: move that into generated.rs | 132 | // TODO: move that into generated.rs |
110 | fn generate_source( | 133 | fn generate_source( |
111 | title: Vec<pandoc_ast::Inline>, | 134 | title: Vec<pandoc_ast::Inline>, |
112 | children: Vec<(PandocMeta, PathBuf)>, | 135 | children: &[(&PandocMeta, &Path)], |
113 | level: usize, | 136 | level: usize, |
114 | ) -> Result<pandoc_ast::Pandoc> { | 137 | ) -> Result<pandoc_ast::Pandoc> { |
115 | // TODO: make that text configurable | 138 | // TODO: make that text configurable |
@@ -117,8 +140,8 @@ fn generate_source( | |||
117 | "Here are the articles in this section:".to_string(), | 140 | "Here are the articles in this section:".to_string(), |
118 | )])]; | 141 | )])]; |
119 | 142 | ||
120 | for (mut child, file) in children { | 143 | for (child, file) in children { |
121 | let title = match child.remove("title") { | 144 | let title = match child.get("title").cloned() { |
122 | None => { | 145 | None => { |
123 | warn!("Missing title for file: '{}'", file.display()); | 146 | warn!("Missing title for file: '{}'", file.display()); |
124 | vec![pandoc_ast::Inline::Str("Untitled page".to_string())] | 147 | vec![pandoc_ast::Inline::Str("Untitled page".to_string())] |
@@ -174,17 +197,13 @@ fn list_content(block: &mut pandoc_ast::Block) -> Result<&mut Vec<Vec<pandoc_ast | |||
174 | } | 197 | } |
175 | } | 198 | } |
176 | 199 | ||
177 | fn try_into_node_vec(vec: &mut Vec<Vec<pandoc_ast::Block>>) -> Result<Vec<Node>> { | ||
178 | vec.iter_mut().map(Node::try_from_vec_block).collect() | ||
179 | } | ||
180 | |||
181 | // TODO: support separators like these: | 200 | // TODO: support separators like these: |
182 | // --------- | 201 | // --------- |
183 | 202 | ||
184 | #[derive(Debug)] | 203 | #[derive(Debug)] |
185 | pub struct Summary { | 204 | pub struct Summary { |
186 | source: pandoc_ast::Pandoc, | 205 | source: pandoc_ast::Pandoc, |
187 | nodes: Vec<Node>, | 206 | //nodes: Vec<Node>, |
188 | } | 207 | } |
189 | 208 | ||
190 | #[derive(Debug)] | 209 | #[derive(Debug)] |
@@ -194,258 +213,150 @@ struct SourceFile { | |||
194 | } | 213 | } |
195 | 214 | ||
196 | // TODO: move that into summary.rs | 215 | // TODO: move that into summary.rs |
197 | impl Summary { | 216 | fn process_summary(file: &str, source_root: &Path) -> Result<(Summary, Vec<SourceFile>)> { |
198 | fn try_from_file(file: &str) -> Result<Self> { | 217 | debug!("Parsing summary"); |
199 | debug!("Parsing summary"); | 218 | let mut pandoc_command = pandoc::new(); |
200 | let mut pandoc_command = pandoc::new(); | 219 | pandoc_command |
201 | pandoc_command | 220 | .add_input(file) |
202 | .add_input(file) | 221 | .set_output_format(pandoc::OutputFormat::Json, vec![]) |
203 | .set_output_format(pandoc::OutputFormat::Json, vec![]) | 222 | .set_output(pandoc::OutputKind::Pipe); |
204 | .set_output(pandoc::OutputKind::Pipe); | 223 | |
224 | if log_enabled!(log::Level::Trace) { | ||
225 | pandoc_command.set_show_cmdline(true); | ||
226 | } | ||
205 | 227 | ||
206 | trace!("Launching pandoc command"); | 228 | let output = pandoc_command |
229 | .execute() | ||
230 | .wrap_err("Could not execute pandoc")? | ||
231 | .buffer(); | ||
207 | 232 | ||
208 | if log_enabled!(log::Level::Trace) { | 233 | let mut document = pandoc_ast::Pandoc::from_json(&output); |
209 | pandoc_command.set_show_cmdline(true); | ||
210 | } | ||
211 | |||
212 | let output = pandoc_command | ||
213 | .execute() | ||
214 | .wrap_err("Could not execute pandoc")? | ||
215 | .buffer(); | ||
216 | |||
217 | let document = pandoc_ast::Pandoc::from_json(&output); | ||
218 | |||
219 | let summary: Self = document.try_into()?; | ||
220 | if summary.has_files_missing( | ||
221 | Path::new(file) | ||
222 | .parent() | ||
223 | .expect("Summary file has no parent"), | ||
224 | ) { | ||
225 | return Err(eyre!("Files from the summary are missing, aborting")); | ||
226 | } | ||
227 | 234 | ||
228 | Ok(summary) | 235 | if document.blocks.len() != 1 { |
236 | return Err(eyre!("Summary does not contain a single list")); | ||
229 | } | 237 | } |
230 | 238 | ||
231 | fn has_files_missing(&self, root: &Path) -> bool { | 239 | let root = &mut document.blocks[0]; |
232 | // Do not use `.any()` to prevent short-circuiting, we want to report all missing files | ||
233 | self.nodes.iter().fold(false, |acc, node| { | ||
234 | let missing = node.has_files_missing(root); | ||
235 | acc || missing | ||
236 | }) | ||
237 | } | ||
238 | 240 | ||
239 | /// Get a list of source files. | 241 | let list = list_content(root)?; |
240 | /// | ||
241 | /// If a file is a generated file, generate it and store it in memory. | ||
242 | fn collect_source_files(&self, root: &Path) -> Result<Vec<SourceFile>> { | ||
243 | let mut result = Vec::new(); | ||
244 | 242 | ||
245 | for node in &self.nodes { | 243 | let mut source_files = Vec::new(); |
246 | node.collect_source_files(&mut result, root, Path::new("."), 0)?; | ||
247 | } | ||
248 | 244 | ||
249 | Ok(result) | 245 | for element in list.iter_mut() { |
246 | process_summary_element(element, Path::new("./"), source_root, &mut source_files)?; | ||
250 | } | 247 | } |
251 | } | ||
252 | |||
253 | impl TryFrom<pandoc_ast::Pandoc> for Summary { | ||
254 | type Error = eyre::Error; | ||
255 | 248 | ||
256 | fn try_from(mut document: pandoc_ast::Pandoc) -> Result<Self, Self::Error> { | 249 | Ok((Summary { source: document }, source_files)) |
257 | if document.blocks.len() != 1 { | 250 | } |
258 | return Err(eyre!("Summary does not contain a single list")); | ||
259 | } | ||
260 | 251 | ||
261 | let root = &mut document.blocks[0]; | 252 | fn process_summary_element( |
253 | element: &mut Vec<pandoc_ast::Block>, | ||
254 | parent: &Path, | ||
255 | source_root: &Path, | ||
256 | source_files: &mut Vec<SourceFile>, | ||
257 | ) -> Result<()> { | ||
258 | if element.len() != 1 && element.len() != 2 { | ||
259 | // TODO: better error message? | ||
260 | return Err(eyre!("Summary element does not contain a single list")); | ||
261 | } | ||
262 | 262 | ||
263 | let list = list_content(root)?; | 263 | trace!("Parsing summary element"); |
264 | let mut value = element.iter_mut(); | ||
264 | 265 | ||
265 | let nodes = list | 266 | let item = match value.next().unwrap() { |
266 | .iter_mut() | 267 | pandoc_ast::Block::Plain(inlines) => inlines, |
267 | .map(Node::try_from_vec_block) | 268 | pandoc_ast::Block::Para(inlines) => inlines, |
268 | .collect::<Result<_>>()?; | 269 | _ => return Err(eyre!("List item is not a link or plain text")), |
270 | }; | ||
269 | 271 | ||
270 | Ok(Summary { | 272 | if item.is_empty() { |
271 | source: document, | 273 | return Err(eyre!("Summary list items cannot be empty")); |
272 | nodes, | ||
273 | }) | ||
274 | } | 274 | } |
275 | } | ||
276 | 275 | ||
277 | #[derive(Debug)] | 276 | let child_parent = match &item[0] { |
278 | pub enum Node { | 277 | pandoc_ast::Inline::Link(_, _, target) => { |
279 | Provided { | 278 | let file = &target.0; |
280 | file: String, | 279 | Path::new(&file).with_extension("") |
281 | children: Vec<Node>, | ||
282 | }, | ||
283 | Generated { | ||
284 | file: String, | ||
285 | title: Vec<pandoc_ast::Inline>, | ||
286 | children: Vec<Node>, | ||
287 | }, | ||
288 | } | ||
289 | |||
290 | impl Node { | ||
291 | fn children(&self) -> &[Node] { | ||
292 | match self { | ||
293 | Node::Provided { children, .. } => children, | ||
294 | Node::Generated { children, .. } => children, | ||
295 | } | 280 | } |
296 | } | 281 | _ => { |
297 | 282 | let title = item.clone(); | |
298 | fn has_files_missing(&self, root: &Path) -> bool { | 283 | let id = AutoIdentifier::from(title.as_slice()); |
299 | if let Node::Provided { file, .. } = self { | 284 | parent.join(&id.0) |
300 | if !root.join(file).exists() { | ||
301 | error!("File '{}' specified in summary does not exists", file); | ||
302 | return true; | ||
303 | } | ||
304 | } | 285 | } |
286 | }; | ||
287 | trace!("Summary element is {:?}", child_parent); | ||
305 | 288 | ||
306 | // Do not use `.any()` to prevent short-circuiting, we want to report all missing files | 289 | let previous_source_len = source_files.len(); |
307 | self.children().iter().fold(false, |acc, node| { | 290 | if let Some(children) = value.next() { |
308 | let missing = node.has_files_missing(root); | 291 | for child in list_content(children)? { |
309 | acc || missing | 292 | process_summary_element(child, &child_parent, source_root, source_files)?; |
310 | }) | 293 | } |
311 | } | 294 | } |
312 | 295 | ||
313 | fn collect_source_files( | 296 | match &item[0] { |
314 | &self, | 297 | pandoc_ast::Inline::Link(_, _, target) => { |
315 | result: &mut Vec<SourceFile>, | 298 | if item.len() != 1 { |
316 | root: &Path, | 299 | return Err(eyre!("Summary list item not a single link or plain text")); |
317 | parent: &Path, | ||
318 | level: usize, | ||
319 | ) -> Result<()> { | ||
320 | let new_parent; | ||
321 | let children_; | ||
322 | let path; | ||
323 | let source: Box<dyn FnOnce(_) -> _>; | ||
324 | |||
325 | match self { | ||
326 | Node::Provided { file, children } => { | ||
327 | trace!("Parsing file: '{}'", file); | ||
328 | |||
329 | // TODO: some filters here? not all filters, since we may want to filter generated | ||
330 | // files too | ||
331 | let mut pandoc_command = pandoc::new(); | ||
332 | pandoc_command | ||
333 | .add_input(&root.join(file)) | ||
334 | .set_output(pandoc::OutputKind::Pipe) | ||
335 | .set_output_format(pandoc::OutputFormat::Json, vec![]); | ||
336 | |||
337 | if log_enabled!(log::Level::Trace) { | ||
338 | pandoc_command.set_show_cmdline(true); | ||
339 | } | ||
340 | |||
341 | let raw_source = pandoc_command | ||
342 | .execute() | ||
343 | .wrap_err_with(|| format!("Failed to parse '{}'", file))? | ||
344 | .buffer(); | ||
345 | source = Box::new(move |_| Ok(pandoc_ast::Pandoc::from_json(&raw_source))); | ||
346 | |||
347 | let file = Path::new(&file); | ||
348 | let stem = file.file_stem().expect("No file name"); | ||
349 | let id = | ||
350 | AutoIdentifier::from(stem.to_str().wrap_err("Invalid unicode in file name")?); | ||
351 | |||
352 | path = file.into(); | ||
353 | new_parent = file.parent().expect("Source file has no parent").join(&*id); | ||
354 | children_ = children; | ||
355 | } | 300 | } |
356 | 301 | ||
357 | Self::Generated { | 302 | let file = target.0.clone(); |
358 | file, | 303 | source_files.push(parse_file(&file, source_root)?); |
359 | title, | ||
360 | children, | ||
361 | } => { | ||
362 | trace!("Found file to generate: '{}'", file); | ||
363 | |||
364 | path = file.into(); | ||
365 | |||
366 | source = Box::new(move |direct_children| { | ||
367 | generate_source(title.clone(), direct_children, level) | ||
368 | }); | ||
369 | new_parent = Path::new(file).with_extension(""); | ||
370 | children_ = children; | ||
371 | } | ||
372 | }; | ||
373 | |||
374 | let mut direct_children = Vec::with_capacity(children_.len()); | ||
375 | |||
376 | for child in children_ { | ||
377 | child.collect_source_files(result, root, &new_parent, level + 1)?; | ||
378 | let direct_child = result.last().unwrap(); | ||
379 | direct_children.push((direct_child.source.meta.clone(), direct_child.path.clone())); | ||
380 | } | 304 | } |
381 | 305 | _ => { | |
382 | result.push(SourceFile { | 306 | let title = item.clone(); |
383 | path, | 307 | |
384 | source: source(direct_children)?, | 308 | let id = AutoIdentifier::from(title.as_slice()); |
385 | }); | 309 | |
386 | 310 | *item = vec![pandoc_ast::Inline::Link( | |
387 | Ok(()) | 311 | (String::new(), vec!["generated".to_string()], vec![]), |
388 | } | 312 | item.clone(), |
389 | 313 | ( | |
390 | // Wil also modify the block to linkify generated pages | 314 | parent.join(&id.0).with_extension("html").to_string(), |
391 | fn try_from_vec_block(value: &mut Vec<pandoc_ast::Block>) -> Result<Self> { | 315 | String::new(), |
392 | if value.len() != 1 && value.len() != 2 { | 316 | ), |
393 | // TODO: better error message? | 317 | )]; |
394 | return Err(eyre!("Summary does not contain a single list")); | 318 | |
395 | } | 319 | // TODO: this shows children recursively (and has a bug when in a subdirectory) |
396 | 320 | let children_metadata = source_files[previous_source_len..source_files.len()] | |
397 | let mut value = value.iter_mut(); | 321 | .iter() |
398 | 322 | .map(|source| (&source.source.meta, source.path.as_ref())) | |
399 | let item = match value.next().unwrap() { | 323 | .collect::<Vec<_>>(); |
400 | pandoc_ast::Block::Plain(inlines) => inlines, | 324 | |
401 | pandoc_ast::Block::Para(inlines) => inlines, | 325 | let source = generate_source(title, &children_metadata, 0)?; |
402 | _ => return Err(eyre!("List item is not a link or plain text")), | 326 | |
403 | }; | 327 | source_files.push(SourceFile { |
404 | 328 | path: child_parent.with_extension("html"), | |
405 | if item.is_empty() { | 329 | source, |
406 | return Err(eyre!("Summary list items cannot be empty")); | 330 | }); |
407 | } | 331 | } |
332 | } | ||
408 | 333 | ||
409 | let children = if let Some(children) = value.next() { | 334 | Ok(()) |
410 | try_into_node_vec(list_content(children)?)? | 335 | } |
411 | } else { | ||
412 | vec![] | ||
413 | }; | ||
414 | |||
415 | match &item[0] { | ||
416 | pandoc_ast::Inline::Link(_, _, target) => { | ||
417 | if item.len() != 1 { | ||
418 | return Err(eyre!("Summary list item not a single link or plain text")); | ||
419 | } | ||
420 | |||
421 | let file = target.0.clone(); | ||
422 | |||
423 | Ok(Node::Provided { file, children }) | ||
424 | } | ||
425 | _ => { | ||
426 | let title = item.clone(); | ||
427 | 336 | ||
428 | let id = AutoIdentifier::from(title.as_slice()); | 337 | fn parse_file(file: &str, source_root: &Path) -> Result<SourceFile> { |
338 | trace!("Parsing file: '{}'", file); | ||
429 | 339 | ||
430 | // TODO: missing parent | 340 | // TODO: some filters here? not all filters, since we may want to filter generated |
341 | // files too | ||
342 | let mut pandoc_command = pandoc::new(); | ||
343 | pandoc_command | ||
344 | .add_input(&source_root.join(file)) | ||
345 | .set_output(pandoc::OutputKind::Pipe) | ||
346 | .set_output_format(pandoc::OutputFormat::Json, vec![]); | ||
431 | 347 | ||
432 | // Move generate page into this pass | 348 | if log_enabled!(log::Level::Trace) { |
433 | //let mut file = parent.join(&*id); | 349 | pandoc_command.set_show_cmdline(true); |
434 | //file.set_extension("md"); | 350 | } |
435 | 351 | ||
436 | // TODO: Attribute to style them differently | 352 | let raw_source = pandoc_command |
437 | *item = vec![pandoc_ast::Inline::Link( | 353 | .execute() |
438 | (String::new(), vec!["generated".to_string()], vec![]), | 354 | .wrap_err_with(|| format!("Failed to parse '{}'", file))? |
439 | item.clone(), | 355 | .buffer(); |
440 | (id.0.clone(), String::new()), | 356 | let source = pandoc_ast::Pandoc::from_json(&raw_source); |
441 | )]; | ||
442 | 357 | ||
443 | Ok(Node::Generated { | 358 | Ok(SourceFile { |
444 | file: id.0, | 359 | path: file.into(), |
445 | title, | 360 | source, |
446 | children, | 361 | }) |
447 | }) | ||
448 | } | ||
449 | } | ||
450 | } | ||
451 | } | 362 | } |