1
0
Fork 0
mirror of https://github.com/lise-henry/crowbook synced 2024-05-10 08:36:12 +02:00

Compare commits

...

16 Commits

Author SHA1 Message Date
Lise Henry 1596c2b4f4 Fix latex template 2023-08-10 02:25:11 +02:00
Lise Henry de2d9fd8fa Fix html dir template 2023-08-10 01:49:40 +02:00
Lise Henry 3e40d5f483 Tiny refactoring 2023-08-10 01:33:40 +02:00
Lise Henry f45ecd003f Fix html_single template 2023-08-10 01:05:15 +02:00
Lise Henry 8ecc5f52b1 Fix EPUB and Html single rendering 2023-08-10 00:59:50 +02:00
Lise Henry cf281db90f Delete ODT template 2023-08-09 20:26:16 +02:00
Lise Henry 4d3757b6d5 Update template.tex 2023-08-09 20:25:50 +02:00
Lise Henry b462d1607e Update html_single templates 2023-08-09 20:13:21 +02:00
Lise Henry a7747800d5 Fix html_if template 2023-08-09 20:08:56 +02:00
Lise Henry 801fad056b Fix html_dir/ templates 2023-08-09 20:07:53 +02:00
Lise Henry 7acb19b467 Fix epub3 titlepage template 2023-08-09 20:03:45 +02:00
Lise Henry 5c03c6d3d7 Update epub3/ templates 2023-08-09 20:01:32 +02:00
Lise Henry 6e211925e8 Update epub/ templates 2023-08-09 19:59:18 +02:00
Lise Henry ee8f84d13b Fix template for html single 2023-08-09 13:48:37 +02:00
Lise Henry 0fb81d8740 Start fixing some templates 2023-08-09 13:36:15 +02:00
Lise Henry fe8d98ccd7 Replace mustache with upon (wip)
This compiles but probably wrecks everything since the template syntax
is a bit different
2023-08-09 13:30:07 +02:00
30 changed files with 569 additions and 717 deletions

13
Cargo.lock generated
View File

@ -353,7 +353,6 @@ dependencies = [
"lazy_static 1.4.0",
"log 0.4.19",
"mime_guess",
"mustache",
"numerals",
"punkt",
"rayon",
@ -361,6 +360,7 @@ dependencies = [
"syntect",
"tempfile",
"textwrap",
"upon",
"uuid",
"walkdir 2.3.3",
"yaml-rust",
@ -1642,6 +1642,17 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
[[package]]
name = "upon"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21a9260fe394dfd8ab204a8eab40f88eb9a331bb852147d24fc0aff6b30daa02"
dependencies = [
"serde",
"unicode-ident",
"unicode-width",
]
[[package]]
name = "utf8-ranges"
version = "1.0.5"

View File

@ -51,7 +51,7 @@ html-escape = "0.2"
mime_guess = "2"
comrak = "0.18"
yaml-rust = "0.4"
mustache = "0.9"
upon = "0.7"
uuid = { version = "1", features = ["v4"] }
walkdir = "2"
base64 = "0.21"

View File

@ -41,7 +41,7 @@ proofread.languagetool: true
rendering.num_depth: 4
rendering.initials: false
rendering.inline_toc: true
rendering.chapter.template: "{{{number}}}. {{{chapter_title}}}"
rendering.chapter.template: "{{number}}. {{chapter_title}}"
rendering.chapter.roman_numerals: false
rendering.part.reset_counter: true
rendering.highlight: syntect
@ -50,8 +50,8 @@ html.highlight.theme: "Solarized (dark)"
# Html options
html.icon: crowbook.svg
html.header: "{{{title}}} {{{version}}}"
html.footer: "Generated by [Crowbook](https://github.com/lise-henry/crowbook) {{{crowbook_version}}}"
html.header: "{{title}} {{version}}"
html.footer: "Generated by [Crowbook](https://github.com/lise-henry/crowbook) {{crowbook_version}}"
html.side_notes: false
html.standalone.one_chapter: false

View File

@ -22,11 +22,11 @@ use crate::chapter::Chapter;
use crate::cleaner::{Cleaner, CleanerParams, Default, French, Off};
use crate::epub::Epub;
use crate::error::{Error, Result, Source};
use crate::html_dir::{HtmlDir, ProofHtmlDir};
use crate::html_dir::HtmlDir;
use crate::html_if::HtmlIf;
use crate::html_single::{HtmlSingle, ProofHtmlSingle};
use crate::html_single::HtmlSingle;
use crate::lang;
use crate::latex::{Latex, Pdf, ProofLatex, ProofPdf};
use crate::latex::{Latex, Pdf};
use crate::misc;
use crate::number::Number;
use crate::parser::Features;
@ -38,14 +38,13 @@ use crate::token::Token;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::collections::{HashMap, BTreeMap};
use std::fmt;
use std::fs::File;
use std::io::{Read, Write};
use std::iter::IntoIterator;
use std::path::{Path, PathBuf};
use mustache::{MapBuilder, Template};
use numerals::roman::Roman;
use rayon::prelude::*;
use yaml_rust::{Yaml, YamlLoader};
@ -120,7 +119,7 @@ impl fmt::Display for HeaderData {
/// // Render the book as html to stdout
/// book.render_format_to("html", &mut std::io::stdout()).unwrap();
/// ```
pub struct Book {
pub struct Book<'a> {
/// Internal structure. You should not accesss this directly except if
/// you are writing a new renderer.
pub chapters: Vec<Chapter>,
@ -141,69 +140,52 @@ pub struct Book {
pub features: Features,
cleaner: Box<dyn Cleaner>,
chapter_template: Option<Template>,
part_template: Option<Template>,
formats: HashMap<&'static str, (String, Box<dyn BookRenderer>)>,
#[doc(hidden)]
pub bars: Bars,
/// Store the templates registry
pub registry: upon::Engine<'a>,
}
impl Book {
impl<'a> Book<'a> {
/// Creates a new, empty `Book`
pub fn new() -> Book {
pub fn new() -> Book<'a> {
let mut book = Book {
source: Source::empty(),
chapters: vec![],
cleaner: Box::new(Off),
root: PathBuf::new(),
options: BookOptions::new(),
chapter_template: None,
part_template: None,
formats: HashMap::new(),
features: Features::new(),
bars: Bars::new(),
registry: upon::Engine::new(),
};
// Add some filters to registry that are useful for some templates
book.registry.add_filter("eq", str::eq);
book.registry.add_filter("starts", |a: &str, b: &str| a.starts_with(b));
book.add_format(
"html",
lformat!("HTML (standalone page)"),
Box::new(HtmlSingle {}),
)
.add_format(
"proofread.html",
lformat!("HTML (standalone page/proofreading)"),
Box::new(ProofHtmlSingle {}),
)
.add_format(
"html.dir",
lformat!("HTML (multiple pages)"),
Box::new(HtmlDir {}),
)
.add_format(
"proofread.html.dir",
lformat!("HTML (multiple pages/proofreading)"),
Box::new(ProofHtmlDir {}),
)
.add_format("tex", lformat!("LaTeX"), Box::new(Latex {}))
.add_format(
"proofread.tex",
lformat!("LaTeX (proofreading)"),
Box::new(ProofLatex {}),
)
.add_format("pdf", lformat!("PDF"), Box::new(Pdf {}))
.add_format(
"proofread.pdf",
lformat!("PDF (proofreading)"),
Box::new(ProofPdf {}),
)
.add_format("epub", lformat!("EPUB"), Box::new(Epub {}))
.add_format(
"html.if",
lformat!("HTML (interactive fiction)"),
Box::new(HtmlIf {}),
);
#[cfg(feature = "odt")]
book.add_format("odt", lformat!("ODT"), Box::new(Odt {}));
book
}
@ -265,9 +247,9 @@ impl Book {
/// assert_eq!(book.options.get_str("author").unwrap(), "Foo");
/// assert_eq!(book.options.get_str("title").unwrap(), "Bar");
/// ```
pub fn set_options<'a, I>(&mut self, options: I) -> &mut Book
pub fn set_options<'b, I>(&mut self, options: I) -> &mut Self
where
I: IntoIterator<Item = &'a (&'a str, &'a str)>,
I: IntoIterator<Item = &'b (&'b str, &'b str)>,
{
// set options
for (key, value) in options {
@ -302,7 +284,7 @@ impl Book {
/// let mut book = Book::new();
/// let result = book.load_file("some.book");
/// ```
pub fn load_file<P: AsRef<Path>>(&mut self, path: P) -> Result<&mut Book> {
pub fn load_file<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
let filename = format!("{}", path.as_ref().display());
self.source = Source::new(filename.as_str());
self.options.source = Source::new(filename.as_str());
@ -316,9 +298,8 @@ impl Book {
self.options.root = self.root.clone();
}
let result = self.read_config(&f);
match result {
Ok(book) => Ok(book),
match self.read_config(&f) {
Ok(_) => Ok(()),
Err(err) => {
if err.is_config_parser() && path.as_ref().ends_with(".md") {
let err = Error::default(
@ -353,7 +334,7 @@ impl Book {
/// let mut book = Book::new();
/// book.load_markdown_file("foo.md"); // not unwraping since foo.md doesn't exist
/// ```
pub fn load_markdown_file<P: AsRef<Path>>(&mut self, path: P) -> Result<&mut Self> {
pub fn load_markdown_file<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
let filename = format!("{}", path.as_ref().display());
self.source = Source::new(filename.as_str());
@ -372,7 +353,7 @@ impl Book {
// Update grammar checker according to options
self.add_chapter(Number::Hidden, &relative_path.to_string_lossy(), false)?;
Ok(self)
Ok(())
}
/// Reads a single markdown config from a `Read`able object.
@ -397,18 +378,18 @@ impl Book {
/// book.read_markdown_config(content.as_bytes()).unwrap();
/// assert_eq!(book.options.get_str("title").unwrap(), "Bar");
/// ```
pub fn read_markdown_config<R: Read>(&mut self, source: R) -> Result<&mut Self> {
pub fn read_markdown_config<R: Read>(&mut self, source: R) -> Result<()> {
self.options.set("tex.class", "article").unwrap();
self.options.set("input.yaml_blocks", "true").unwrap();
// Update grammar checker according to options
self.add_chapter_from_source(Number::Hidden, source, false)?;
Ok(self)
Ok(())
}
/// Sets options from a YAML block
fn set_options_from_yaml(&mut self, yaml: &str) -> Result<&mut Book> {
fn set_options_from_yaml(&mut self, yaml: &str) -> Result<&mut Self> {
self.options.source = self.source.clone();
match YamlLoader::load_from_str(yaml) {
Err(err) => {
@ -471,8 +452,8 @@ impl Book {
/// let mut book = Book::new();
/// book.read_config(content.as_bytes()); // no unwraping as `intro.md` and `chapter_01.md` don't exist
/// ```
pub fn read_config<R: Read>(&mut self, mut source: R) -> Result<&mut Book> {
fn get_filename<'a>(source: &Source, s: &'a str) -> Result<&'a str> {
pub fn read_config<R: Read>(&mut self, mut source: R) -> Result<()> {
fn get_filename<'b>(source: &Source, s: &'b str) -> Result<&'b str> {
let words: Vec<&str> = (s[1..]).split_whitespace().collect();
if words.len() > 1 {
return Err(Error::config_parser(
@ -691,7 +672,7 @@ impl Book {
self.source.unset_line();
self.set_chapter_template()?;
Ok(self)
Ok(())
}
/// Determine whether proofreading is activated or not
@ -1179,12 +1160,16 @@ impl Book {
/// Sets the chapter_template once and for all
fn set_chapter_template(&mut self) -> Result<()> {
let template = compile_str(
self.options.get_str("rendering.chapter.template").unwrap(),
&self.source,
"rendering.chapter.template",
)?;
self.chapter_template = Some(template);
self.registry.add_template("rendering.chapter.template",
self.options.get_str("rendering.chapter.template").unwrap().to_owned())
.map_err(|e| Error::template(
&self.source,
lformat!(
"could not compile '{template}': {error}",
template = "rendering.chapter.template",
error = e
))
)?;
Ok(())
}
@ -1236,7 +1221,7 @@ impl Book {
};
let mut data = self.get_metadata(&mut f)?;
if !title.is_empty() {
data = data.insert_bool(format!("has_{header_type}_title"), true);
data.insert(format!("has_{header_type}_title"), true.into());
}
let number = self.get_header_number(header, n)?;
let header_name = self
@ -1245,43 +1230,20 @@ impl Book {
.map(|s| s.to_owned())
.unwrap_or_else(|_| lang::get_str(self.options.get_str("lang").unwrap(), header_type));
data = data
.insert_str(format!("{header_type}_title"), title.clone())
.insert_str(header_type, header_name.clone())
.insert_str("number", number.clone());
let data = data.build();
let mut res: Vec<u8> = vec![];
data.insert(format!("{header_type}_title"), title.clone().into());
data.insert(header_type.into(), header_name.clone().into());
data.insert("number".into(), number.clone().into());
let opt_template = match header {
Header::Part => &self.part_template,
Header::Chapter => &self.chapter_template,
};
if let Some(ref template) = *opt_template {
template.render_data(&mut res, &data)?;
} else {
let template = compile_str(
self.options
.get_str(&format!("rendering.{header_type}.template"))
.unwrap(),
&self.source,
&format!("rendering.{header_type}.template"),
)?;
template.render_data(&mut res, &data)?;
}
match String::from_utf8(res) {
Err(_) => panic!(
"{}",
lformat!("header generated by mustache was not valid utf-8")
),
Ok(res) => Ok(HeaderData {
text: res,
number,
header: header_name,
title,
}),
}
let res = self.registry.get_template(&format!("rendering.{header_type}.template"))
.expect("Error accessing template rendering.{header_type}.template")
.render(&data)
.to_string()?;
Ok(HeaderData {
text: res,
number,
header: header_name,
title,
})
}
/// Returns the string corresponding to a number, title, and the numbering template for chapter
@ -1302,26 +1264,24 @@ impl Book {
self.get_header(Header::Part, n, title, f)
}
/// Returns a `MapBuilder` (used by `Mustache` for templating), to be used (and completed)
/// Returns a `Map of Key/Value` (used by `Upon` for templating), to be used (and completed)
/// by renderers. It fills it with the metadata options.
///
/// It also uses the lang/xx.yaml file corresponding to the language and fills
/// `loc_xxx` fiels with it that corresponds to translated versions.
///
/// This method treats the metadata as Markdown and thus calls `f` to render it.
/// This is why we cant really cache this as it will depend on the renderer.
#[doc(hidden)]
pub fn get_metadata<F>(&self, mut f: F) -> Result<MapBuilder>
pub fn get_metadata<F>(&self, mut f: F) -> Result<BTreeMap<String, upon::Value>>
where
F: FnMut(&str) -> Result<String>,
{
let mut mapbuilder = MapBuilder::new();
mapbuilder = mapbuilder.insert_str("crowbook_version", env!("CARGO_PKG_VERSION"));
mapbuilder = mapbuilder.insert_bool(
format!("lang_{}", self.options.get_str("lang").unwrap()),
true,
);
let mut m: BTreeMap<String, upon::Value> = BTreeMap::new();
m.insert("crowbook_version".into(), env!("CARGO_PKG_VERSION").into());
m.insert(format!("lang_{}", self.options.get_str("lang").unwrap()), true.into());
// Add metadata to mapbuilder
// Add metadata to map
for key in self.options.get_metadata() {
if let Ok(s) = self.options.get_str(key) {
let key = key.replace('.', "_");
@ -1335,12 +1295,13 @@ impl Book {
match content {
Ok(content) => {
if !content.is_empty() {
mapbuilder = mapbuilder.insert_str(format!("{key}_raw"), raw);
mapbuilder = mapbuilder.insert_str(key.clone(), content);
m.insert(format!("{key}_raw"), raw.into());
m.insert(key.clone(), content.into());
mapbuilder = mapbuilder.insert_bool(format!("has_{key}"), true);
m.insert(format!("has_{key}"), true.into());
} else {
mapbuilder = mapbuilder.insert_bool(format!("has_{key}"), false);
m.insert(key.clone(), "".into());
m.insert(format!("has_{key}"), false.into());
}
}
Err(err) => {
@ -1356,7 +1317,8 @@ impl Book {
}
}
} else {
mapbuilder = mapbuilder.insert_bool(format!("has_{key}"), false);
m.insert(key.clone(), "".into());
m.insert(format!("has_{key}"), false.into());
}
}
@ -1365,11 +1327,31 @@ impl Book {
for (key, value) in hash {
let key = format!("loc_{}", key.as_str().unwrap());
let value = value.as_str().unwrap();
mapbuilder = mapbuilder.insert_str(key, value);
m.insert(key, value.into());
}
Ok(mapbuilder)
Ok(m)
}
/// Calls upon::engine::compile, does NOT registre the complete
pub fn compile_str<'s, O>(&self, template: &'s str, source: O, template_name: &str) -> Result<upon::Template<'_, 's>>
where
O: Into<Source>,
{
let input: String = template.to_owned();
let result = self.registry.compile(template);
match result {
Ok(result) => Ok(result),
Err(err) => Err(Error::template(
source,
lformat!(
"could not compile '{template_name}': {:#}",
err
),
)),
}
}
/// Remove YAML blocks from a string and try to parse them to set options
///
/// YAML blocks start with
@ -1495,28 +1477,9 @@ impl Book {
}
}
impl std::default::Default for Book {
impl std::default::Default for Book<'_> {
fn default() -> Self {
Self::new()
}
}
/// Calls mustache::compile_str but catches panics and returns a result
pub fn compile_str<O>(template: &str, source: O, template_name: &str) -> Result<mustache::Template>
where
O: Into<Source>,
{
let input: String = template.to_owned();
let result = mustache::compile_str(&input);
match result {
Ok(result) => Ok(result),
Err(err) => Err(Error::template(
source,
lformat!(
"could not compile '{template}': {error}",
template = template_name,
error = err
),
)),
}
}

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017-2022 Élisabeth HENRY.
// Copyright (C) 2017-2023 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
@ -63,7 +63,7 @@ impl Default for Bars {
/// Return the style of a bar
impl Book {
impl Book<'_> {
/// Adds a progress bar where where info should be written.
///
/// See [indicatif doc](https://docs.rs/indicatif) for more information.
@ -270,7 +270,7 @@ impl Book {
}
}
impl Drop for Book {
impl Drop for Book<'_> {
fn drop(&mut self) {
if let Some(ref bar) = self.bars.secondbar {
bar.finish_and_clear();

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 Élisabeth HENRY.
// Copyright (C) 2017-2023 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
@ -28,7 +28,7 @@ impl Bars {
}
}
impl Book {
impl Book<'_> {
pub fn private_add_progress_bar(&mut self, _: bool) {}
/// Sets a finished message to the progress bar, if it is set

View File

@ -41,16 +41,16 @@ rendering.highlight:str:syntect # {renderin
rendering.highlight.theme:str:InspiredGitHub # {rendering_highlight_theme}
rendering.initials:bool:false # {rendering_initials}
rendering.inline_toc:bool:false # {inline_toc}
rendering.inline_toc.name:str:\"{{{{{{loc_toc}}}}}}\" # {toc_name}
rendering.inline_toc.name:str:\"{{{{loc_toc}}}}\" # {toc_name}
rendering.num_depth:int:1 # {num_depth}
rendering.chapter:str # {chapter}
rendering.part:str # {part}
rendering.chapter.roman_numerals:bool:false # {roman_numerals_chapters}
rendering.part.roman_numerals:bool:true # {roman_numerals_parts}
rendering.part.reset_counter:bool:true # {reset_counter}
rendering.chapter.template:str:\"{{{{{{number}}}}}}. {{{{{{chapter_title}}}}}}\" # {chapter_template}
rendering.chapter.template:str:\"{{{{number}}}}. {{{{chapter_title}}}}\" # {chapter_template}
rendering.part.template:str:\"{{{{{{number}}}}}}. {{{{{{part_title}}}}}}\" # {part_template}
rendering.part.template:str:\"{{{{number}}}}. {{{{part_title}}}}\" # {part_template}
@ -72,8 +72,8 @@ html.highlight.js:tpl # {highlight_js}
html.highlight.css:tpl # {highlight_css}
html.side_notes:bool:false # {side_notes}
html.escape_nb_spaces:bool:true # {nb_spaces}
html.chapter.template:str:\"<h1 id = 'link-{{{{{{link}}}}}}'>{{{{#has_number}}}}<span class = 'chapter-header'>{{{{{{header}}}}}} {{{{{{number}}}}}}</span>{{{{#has_title}}}}<br />{{{{/has_title}}}}{{{{/has_number}}}}{{{{{{title}}}}}}</h1>\" # {html_chapter_template}
html.part.template:str:\"<h2 class = 'part'>{{{{{{header}}}}}} {{{{{{number}}}}}}</h2> <h1 id = 'link-{{{{{{link}}}}}}' class = 'part'>{{{{{{title}}}}}}</h1>\" # {html_part_template}
html.chapter.template:str:\"<h1 id = 'link-{{{{link}}}}'>{{% if has_number %}}<span class = 'chapter-header'>{{{{header}}}} {{{{number}}}}</span>{{% if has_title %}}<br />{{% endif %}}{{% endif %}}{{{{title}}}}</h1>\" # {html_chapter_template}
html.part.template:str:\"<h2 class = 'part'>{{{{header}}}} {{{{number}}}}</h2> <h1 id = 'link-{{{{link}}}}' class = 'part'>{{{{title}}}}</h1>\" # {html_part_template}
# {html_single_opt}
html.standalone.template:tpl # {single_html}
@ -559,8 +559,7 @@ impl BookOptions {
})?;
let mut book = Book::new();
book.load_file(file)?;
let options = mem::replace(&mut book.options, BookOptions::new());
self.merge(options)?;
self.merge(&book.options)?;
Ok(None)
} else {
Ok(self.options.insert(key, BookOption::Path(value)))
@ -910,7 +909,7 @@ impl BookOptions {
/// If option is already set in self, don't add it, unless it was the default.
/// Option is not inserted either if new value is equal to default.
#[doc(hidden)]
pub fn merge(&mut self, other: BookOptions) -> Result<()> {
pub fn merge(&mut self, other: &BookOptions) -> Result<()> {
for (key, value) in &other.options {
// Check if option was already set, and if it was to default or to something else
if self.defaults.contains_key(key) {

View File

@ -16,7 +16,7 @@
// along with Crowbook. If not, see <http://www.gnu.org/licenses/>.
use crate::book::Header;
use crate::book::{compile_str, Book};
use crate::book::Book;
use crate::book_renderer::BookRenderer;
use crate::error::{Error, Result, Source};
use crate::html::HtmlRenderer;
@ -34,7 +34,7 @@ use epub_builder::{
EpubBuilder, EpubContent, EpubVersion, ReferenceType, ZipCommand, ZipCommandOrLibrary,
ZipLibrary,
};
use mustache::Template;
use upon::Template;
use std::borrow::Cow;
use std::convert::{AsMut, AsRef};
@ -194,8 +194,9 @@ impl<'a> EpubRenderer<'a> {
}
// Write chapters
let template_chapter = compile_str(
self.html.book.get_template("epub.chapter.xhtml")?.as_ref(),
let template_chapter_src = self.html.book.get_template("epub.chapter.xhtml")?;
let template_chapter = self.html.book.compile_str(
template_chapter_src.as_ref(),
&self.html.book.source,
"epub.chapter.xhtml",
)?;
@ -229,23 +230,21 @@ impl<'a> EpubRenderer<'a> {
self.html.source = Source::empty();
// Render the CSS file and write it
let template_css = compile_str(
self.html.book.get_template("epub.css").unwrap().as_ref(),
let template_css_src = self.html.book.get_template("epub.css").unwrap();
let template_css = self.html.book.compile_str(
template_css_src.as_ref(),
&self.html.book.source,
"epub.css",
)?;
let mut data = self
.html
.book
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?
.insert_bool(self.html.book.options.get_str("lang").unwrap(), true);
if let Ok(epub_css_add) = self.html.book.options.get_str("epub.css.add") {
data = data.insert_str("additional_code", epub_css_add);
}
let data = data.build();
let mut res: Vec<u8> = vec![];
template_css.render_data(&mut res, &data)?;
let css = String::from_utf8_lossy(&res);
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?;
data.insert(self.html.book.options.get_str("lang").unwrap().into(), true.into());
let epub_css_add = self.html.book.options.get_str("epub.css.add").unwrap_or("".into());
data.insert("additional_code".into(), epub_css_add.into());
let css = template_css.render(&data).to_string()?;
maker.stylesheet(css.as_bytes())
.map_err(|err| Error::render(Source::empty(), format!("{}", err)))?;
@ -308,25 +307,17 @@ impl<'a> EpubRenderer<'a> {
/// Render the titlepgae
fn render_titlepage(&mut self) -> Result<String> {
let template = compile_str(
self.html
.book
.get_template("epub.titlepage.xhtml")?
.as_ref(),
let template_src = self.html.book.get_template("epub.titlepage.xhtml")?;
let template = self.html.book.compile_str(
template_src.as_ref(),
&self.html.book.source,
"epub.titlepage.xhtml",
)?;
let data = self
.html
.book
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?
.build();
let mut res: Vec<u8> = vec![];
template.render_data(&mut res, &data)?;
match String::from_utf8(res) {
Err(_) => panic!("generated HTML in titlepage was not utf-8 valid"),
Ok(res) => Ok(res),
}
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?;
Ok(template.render(&data).to_string()?)
}
/// Render cover.xhtml
@ -341,32 +332,22 @@ impl<'a> EpubRenderer<'a> {
));
}
let epub3 = self.html.book.options.get_i32("epub.version").unwrap() == 3;
let template = compile_str(
let template = self.html.book.compile_str(
if epub3 { epub3::COVER } else { COVER },
&self.html.book.source,
"cover.xhtml",
)?;
let data = self
let mut data = self
.html
.book
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?
.insert_str(
"cover",
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?;
data.insert(
"cover".into(),
self.html
.handler
.map_image(&self.html.source, Cow::Owned(cover))?
.into_owned(),
)
.build();
let mut res: Vec<u8> = vec![];
template.render_data(&mut res, &data)?;
match String::from_utf8(res) {
Err(_) => panic!(
"{}",
lformat!("generated HTML for cover.xhtml was not utf-8 valid")
),
Ok(res) => Ok(res),
}
.into());
Ok(template.render(&data).to_string()?)
} else {
panic!(
"{}",
@ -421,21 +402,15 @@ impl<'a> EpubRenderer<'a> {
}
self.toc.push(self.chapter_title.clone());
let data = self
let mut data = self
.html
.book
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?
.insert_str("content", content)
.insert_str("chapter_title_raw", self.chapter_title_raw.clone())
.insert_str("chapter_title", std::mem::take(&mut self.chapter_title))
.build();
self.chapter_title = String::new();
let mut res: Vec<u8> = vec![];
template.render_data(&mut res, &data)?;
match String::from_utf8(res) {
Err(_) => panic!("{}", lformat!("generated HTML was not utf-8 valid")),
Ok(res) => Ok((res, std::mem::take(&mut self.chapter_title_raw))),
}
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?;
data.insert("content".into(), content.into());
data.insert("chapter_title_raw".into(), self.chapter_title_raw.clone(). into());
data.insert("chapter_title".into(), std::mem::take(&mut self.chapter_title).into());
Ok((template.render(&data).to_string()?,
std::mem::take(&mut self.chapter_title_raw)))
}
/// Renders the header section of the book, finding the title of the chapter

View File

@ -179,7 +179,7 @@ impl Error {
/// Creates a new template error.
///
/// Error when compiling a mustache template.
/// Error when compiling a template.
pub fn template<S: Into<Cow<'static, str>>, O: Into<Source>>(source: O, msg: S) -> Error {
Error {
source: source.into(),
@ -360,10 +360,10 @@ impl fmt::Display for Error {
/// Crowbook's Result type, used by many methods that can fail
pub type Result<T> = result::Result<T, Error>;
/// Implement our Error from mustache::Error
impl From<mustache::Error> for Error {
fn from(err: mustache::Error) -> Error {
Error::template(Source::empty(), format!("{err}"))
/// Implement our Error from upon::error
impl From<upon::Error> for Error {
fn from(err: upon::Error) -> Error {
Error::template(Source::empty(), format!("{:#}", err))
}
}

View File

@ -17,7 +17,7 @@
use crate::book::Header;
use crate::book::HeaderData;
use crate::book::{compile_str, Book};
use crate::book::Book;
use crate::error::{Error, Result, Source};
use crate::lang;
use crate::number::Number;
@ -32,12 +32,11 @@ use crate::text_view;
use std::borrow::Cow;
use std::convert::{AsMut, AsRef};
use std::fmt::Write;
use std::collections::BTreeMap;
use crowbook_text_processing::escape;
use epub_builder::Toc;
use epub_builder::TocElement;
use mustache::MapBuilder;
use mustache::Template;
use numerals::roman::Roman;
#[derive(Debug, PartialEq, Copy, Clone)]
@ -63,7 +62,7 @@ pub struct HtmlRenderer<'a> {
filename: String,
/// Book that must be rendered
pub book: &'a Book,
pub book: &'a Book<'a>,
/// Proofread or not
pub proofread: bool,
@ -109,8 +108,8 @@ pub struct HtmlRenderer<'a> {
syntax: Option<Syntax>,
part_template_html: Template,
chapter_template_html: Template,
part_template_html: upon::Template<'a, 'a>,
chapter_template_html: upon::Template<'a, 'a>,
}
impl<'a> HtmlRenderer<'a> {
@ -161,12 +160,12 @@ impl<'a> HtmlRenderer<'a> {
proofread: false,
syntax,
highlight,
part_template_html: compile_str(
part_template_html: book.compile_str(
book.options.get_str("html.part.template").unwrap(),
Source::empty(),
"html.part.template",
)?,
chapter_template_html: compile_str(
chapter_template_html: book.compile_str(
book.options.get_str("html.chapter.template").unwrap(),
Source::empty(),
"html.chapter.template",
@ -278,17 +277,15 @@ impl<'a> HtmlRenderer<'a> {
};
let has_number = !data.header.is_empty();
let has_title = !data.title.is_empty();
let data = MapBuilder::new()
.insert_bool("has_number", has_number)
.insert_bool("has_title", has_title)
.insert_str("header", data.header)
.insert_str("number", data.number)
.insert_str("link", format!("{}", self.link_number))
.insert_str("title", data.title)
.build();
let mut res = vec![];
template.render_data(&mut res, &data)?;
Ok(String::from_utf8(res)?)
let data = upon::value!{
has_number: has_number,
has_title: has_title,
header: data.header,
number: data.number,
title: data.title,
link: format!("{}", self.link_number)
};
Ok(template.render(&data).to_string()?)
}
} else {
Ok(format!(
@ -667,12 +664,12 @@ impl<'a> HtmlRenderer<'a> {
/// Consider the html as a template
fn templatize(&mut self, s: &str) -> Result<String> {
let mapbuilder = self.book.get_metadata(|s| Ok(s.to_owned()))?;
let data = mapbuilder.build();
let template = compile_str(s, &self.book.source, "")?;
let mut res = vec![];
template.render_data(&mut res, &data)?;
Ok(String::from_utf8_lossy(&res).into_owned())
if s.is_empty() {
return Ok(String::new());
}
let data = self.book.get_metadata(|s| Ok(s.to_owned()))?;
let template = self.book.compile_str(s, &self.book.source, "")?;
Ok(template.render(&data).to_string()?)
}
/// Renders the toc name
@ -680,17 +677,14 @@ impl<'a> HtmlRenderer<'a> {
pub fn get_toc_name(&mut self) -> Result<String> {
let data = self
.book
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?
.build();
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?;
let template = self
.book
.options
.get_str("rendering.inline_toc.name")
.unwrap();
let template = compile_str(template, &self.book.source, "rendering.inline_toc.name")?;
let mut res = vec![];
template.render_data(&mut res, &data)?;
Ok(String::from_utf8_lossy(&res).into_owned())
let template = self.book.compile_str(template, &self.book.source, "rendering.inline_toc.name")?;
Ok(template.render(&data).to_string()?)
}
/// Render a section containing schema.org JSON-LD code
@ -700,23 +694,37 @@ impl<'a> HtmlRenderer<'a> {
{
"@context": "http://schema.org/",
"@type": "Book",
"author": "{{{author}}}",
"name": "{{{title}}}",
{{#has_version}}"version": "{{{version}}}",{{/has_version}}
{{#has_subtitle}}"alternateName": "{{{subtitle}}}",{{/has_subtitle}}
{{#has_subject}}"keywords": "{{{subject}}}",{{/has_subject}}
{{#has_license}}"license": "{{{license}}}",{{/has_license}}
{{#has_description}}"about": "{{{description}}}",{{/has_description}}
"inLanguage": "{{{lang}}}"
"author": "{{author}}",
"name": "{{title}}",
{% if has_version %}"version": "{{version}}",{% endif %}
{% if has_subtitle %}"alternateName": "{{subtitle}}",{% endif %}
{% if has_subject %}"keywords": "{{subject}}",{% endif %}
{% if has_license %}"license": "{{license}}",{% endif %}
{% if has_description %}"about": "{{description}}",{% endif %}
"inLanguage": "{{lang}}"
}
</script>"#;
self.templatize(json)
}
/// Get metadata useful for many HTML templates.
/// This could be cached yes.
pub fn get_metadata(&mut self) -> Result<BTreeMap<String, upon::Value>> {
// Get base metadata
let mut data = self
.book
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?;
// Add stuff used for HTMLtemplates
data.insert("json_data".into(), self.get_json_ld()?.into());
data.insert("script".into(), self.book.get_template("html.js").unwrap().into());
data.insert("highlight_code".into(), (self.highlight == Highlight::Js).into());
data.insert("footer".into(), HtmlRenderer::get_footer(self)?.into());
data.insert("header".into(), HtmlRenderer::get_header(self)?.into());
Ok(data)
}
/// Renders a footer, which can include a "Generated by Crowboook" link
/// or a customized text
#[doc(hidden)]

View File

@ -15,7 +15,7 @@
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook. If not, see <http://www.gnu.org/licenses/>.
use crate::book::{compile_str, Book};
use crate::book::Book;
use crate::book_renderer::BookRenderer;
use crate::error::{Error, Result, Source};
use crate::html::Highlight;
@ -58,12 +58,6 @@ impl<'a> HtmlDirRenderer<'a> {
Ok(HtmlDirRenderer { html })
}
/// Set aproofreading to true
pub fn proofread(mut self) -> HtmlDirRenderer<'a> {
self.html.proofread = true;
self
}
/// Render a book
pub fn render_book(&mut self, dest_path: &Path) -> Result<()> {
// Add internal files to resource handler
@ -273,8 +267,9 @@ impl<'a> HtmlDirRenderer<'a> {
let toc = self.html.toc.render(false, false);
// render all chapters
let template = compile_str(
self.html.book.get_template("html.dir.template")?.as_ref(),
let template_src = self.html.book.get_template("html.dir.template")?;
let template = self.html.book.compile_str(
template_src.as_ref(),
&self.html.book.source,
"html.dir.template",
)?;
@ -308,39 +303,33 @@ impl<'a> HtmlDirRenderer<'a> {
};
// Render each HTML document
let mut mapbuilder = self
let mut data = self
.html
.book
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?
.insert_str("content", content?)
.insert_str("chapter_title", titles[i].clone())
.insert_str("json_data", self.html.get_json_ld()?)
.insert_str("chapter_title_raw", titles_raw[i].clone())
.insert_str("toc", toc.clone())
.insert_str("prev_chapter", prev_chapter)
.insert_str("next_chapter", next_chapter)
.insert_str("footer", HtmlRenderer::get_footer(self)?)
.insert_str("header", HtmlRenderer::get_header(self)?)
.insert_str("script", self.html.book.get_template("html.js").unwrap())
.insert_bool(self.html.book.options.get_str("lang").unwrap(), true);
.get_metadata()?;
data.insert("content".into(), content?.into());
data.insert("chapter_title".into(), titles[i].clone().into());
data.insert("chapter_title_raw".into(), titles_raw[i].clone().into());
data.insert("toc".into(), toc.clone().into());
data.insert("prev_chapter".into(), prev_chapter.into());
data.insert("next_chapter".into(), next_chapter.into());
data.insert("is_chapter".into(), true.into());
if let Ok(favicon) = self.html.book.options.get_path("html.icon") {
let favicon = self
.html
.handler
.map_image(&self.html.book.source, favicon)?;
mapbuilder = mapbuilder.insert_str(
"favicon",
format!("<link rel = \"icon\" href = \"{favicon}\">"),
data.insert(
"favicon".into(),
format!("<link rel = \"icon\" href = \"{favicon}\">").into(),
);
} else {
data.insert("favicon".into(), "".into());
}
if self.html.highlight == Highlight::Js {
mapbuilder = mapbuilder.insert_bool("highlight_code", true);
}
let data = mapbuilder.build();
let mut res = vec![];
template.render_data(&mut res, &data)?;
self.write_file(&filenamer(i), &res)?;
let res = template.render(&data).to_string()?;
self.write_file(&filenamer(i), res.as_bytes())?;
}
let mut content = if let Ok(cover) = self.html.book.options.get_path("cover") {
@ -420,38 +409,30 @@ impl<'a> HtmlDirRenderer<'a> {
)?;
}
// Render index.html and write it too
let mut mapbuilder = self
let mut data = self
.html
.book
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?
.insert_str("content", content)
.insert_str("header", HtmlRenderer::get_header(self)?)
.insert_str("footer", HtmlRenderer::get_footer(self)?)
.insert_str("toc", toc.clone())
.insert_str("script", self.html.book.get_template("html.js").unwrap())
.insert_bool(self.html.book.options.get_str("lang").unwrap(), true);
.get_metadata()?;
data.insert("content".into(), content.into());
data.insert("toc".into(), toc.into());
data.insert("is_chapter".into(), false.into());
if let Ok(favicon) = self.html.book.options.get_path("html.icon") {
let favicon = self
.html
.handler
.map_image(&self.html.book.source, favicon)?;
mapbuilder = mapbuilder.insert_str(
"favicon",
format!("<link rel = \"icon\" href = \"{favicon}\">"),
data.insert(
"favicon".into(),
format!("<link rel = \"icon\" href = \"{favicon}\">").into(),
);
}
if self.html.highlight == Highlight::Js {
mapbuilder = mapbuilder.insert_bool("highlight_code", true);
}
let data = mapbuilder.build();
let template = compile_str(
self.html.book.get_template("html.dir.template")?.as_ref(),
let template_src = self.html.book.get_template("html.dir.template")?;
let template = self.html.book.compile_str(
template_src.as_ref(),
&self.html.book.source,
"html.dir.template",
)?;
let mut res = vec![];
template.render_data(&mut res, &data)?;
self.write_file("index.html", &res)?;
let res = template.render(&data).to_string()?;
self.write_file("index.html", res.as_bytes())?;
Ok(())
}
@ -459,20 +440,18 @@ impl<'a> HtmlDirRenderer<'a> {
// Render the CSS file and write it
fn write_css(&self) -> Result<()> {
// Render the CSS
let template_css = compile_str(
self.html.book.get_template("html.css")?.as_ref(),
let template_css_src = self.html.book.get_template("html.css")?;
let template_css = self.html.book.compile_str(
template_css_src.as_ref(),
&self.html.book.source,
"html.css",
)?;
let mut data = self.html.book.get_metadata(|s| Ok(s.to_owned()))?;
data = data.insert_str("colors", self.html.book.get_template("html.css.colors")?);
if let Ok(html_css_add) = self.html.book.options.get_str("html.css.add") {
data = data.insert_str("additional_code", html_css_add);
}
let data = data.build();
let mut res: Vec<u8> = vec![];
template_css.render_data(&mut res, &data)?;
let css = String::from_utf8_lossy(&res);
data.insert("colors".into(), self.html.book.get_template("html.css.colors")?.into());
let html_css_add = self.html.book.options.get_str("html.css.add").unwrap_or("".into());
data.insert("additional_code".into(), html_css_add.into());
let css = template_css.render(&data).to_string()?;
// Write it
self.write_file("stylesheet.css", css.as_bytes())
@ -542,7 +521,6 @@ fn filenamer(i: usize) -> String {
derive_html! {HtmlDirRenderer<'a>, HtmlRenderer::static_render_token}
pub struct HtmlDir {}
pub struct ProofHtmlDir {}
impl BookRenderer for HtmlDir {
fn auto_path(&self, _: &str) -> Result<String> {
@ -560,22 +538,4 @@ impl BookRenderer for HtmlDir {
HtmlDirRenderer::new(book)?.render_book(path)?;
Ok(())
}
}
impl BookRenderer for ProofHtmlDir {
fn auto_path(&self, _: &str) -> Result<String> {
Ok(String::from("output_html_proof"))
}
fn render(&self, _: &Book, _: &mut dyn io::Write) -> Result<()> {
Err(Error::render(
Source::empty(),
lformat!("can only render HTML directory to a path, not to a stream"),
))
}
fn render_to_file(&self, book: &Book, path: &Path) -> Result<()> {
HtmlDirRenderer::new(book)?.proofread().render_book(path)?;
Ok(())
}
}
}

View File

@ -15,7 +15,7 @@
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook. If not, see <http://www.gnu.org/licenses/>.
use crate::book::{compile_str, Book};
use crate::book::Book;
use crate::book_renderer::BookRenderer;
use crate::error::{Error, Result, Source};
use crate::html::Highlight;
@ -261,74 +261,71 @@ return crowbook_return_variable.replace(/<\\/ul><ul>/g, '');\n",
self.html.render_end_notes(&mut content, "section", "");
// Render the CSS
let template_css = compile_str(
self.html.book.get_template("html.css")?.as_ref(),
let template_css_src = self.html.book.get_template("html.css")?;
let template_css = self.html.book.compile_str(
template_css_src.as_ref(),
&self.html.book.source,
"html.css",
)?;
let mut data = self
.html
.book
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?
.insert_str("colors", self.html.book.get_template("html.css.colors")?);
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?;
data.insert("colors".into(), self.html.book.get_template("html.css.colors")?.into());
if let Ok(html_css_add) = self.html.book.options.get_str("html.css.add") {
data = data.insert_str("additional_code", html_css_add);
data.insert("additional_code".into(), html_css_add.into());
}
let data = data.build();
let mut res: Vec<u8> = vec![];
template_css.render_data(&mut res, &data)?;
let css = String::from_utf8_lossy(&res);
let css:String = template_css.render(&data).to_string()?;
// Render the JS
let template_js = compile_str(
self.html.book.get_template("html.if.js")?.as_ref(),
let template_js_src = self.html.book.get_template("html.if.js")?;
let template_js = self.html.book.compile_str(
template_js_src.as_ref(),
&self.html.book.source,
"html.standalone.js",
)?;
let data = self
let mut data = self
.html
.book
.get_metadata(|s| Ok(s.to_owned()))?
.insert_bool("one_chapter", true)
.insert_str("js_prelude", std::mem::take(&mut self.fn_defs))
.insert_str(
"new_game",
self.html.book.get_template("html.if.new_game").unwrap(),
)
.insert_str(
"common_script",
self.html.book.get_template("html.js").unwrap().as_ref(),
)
.build();
let mut res: Vec<u8> = vec![];
template_js.render_data(&mut res, &data)?;
let js = String::from_utf8_lossy(&res);
.get_metadata(|s| Ok(s.to_owned()))?;
data.insert("one_chapter".into(), true.into());
data.insert("js_prelude".into(), self.fn_defs.clone().into());
data.insert(
"new_game".into(),
self.html.book.get_template("html.if.new_game").unwrap().into(),
);
data.insert(
"common_script".into(),
self.html.book.get_template("html.js").unwrap().into(),
);
let js = template_js.render(&data).to_string()?;
// Render the HTML document
let mut mapbuilder = self
let mut data = self
.html
.book
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?
.insert_str("content", content)
.insert_str("script", js)
.insert_bool(self.html.book.options.get_str("lang").unwrap(), true)
.insert_bool("one_chapter", true)
.insert_str("style", css.as_ref())
.insert_str(
"print_style",
self.html.book.get_template("html.css.print").unwrap(),
)
.insert_str("footer", HtmlRenderer::get_footer(self)?)
.insert_str("header", HtmlRenderer::get_header(self)?)
.insert_bool("has_toc", false);
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?;
data.insert("content".into(), content.into());
data.insert("script".into(), js.into());
data.insert(self.html.book.options.get_str("lang").unwrap().into(), true.into());
data.insert("one_chapter".into(), true.into());
data.insert("style".into(), css.into());
data.insert(
"print_style".into(),
self.html.book.get_template("html.css.print").unwrap().into(),
);
data.insert("footer".into(), HtmlRenderer::get_footer(self)?.into());
data.insert("header".into(), HtmlRenderer::get_header(self)?.into());
data.insert("has_toc".into(), false.into());
if let Ok(favicon) = self.html.book.options.get_path("html.icon") {
let favicon = self
.html
.handler
.map_image(&self.html.book.source, favicon)?;
mapbuilder = mapbuilder.insert_str(
"favicon",
format!("<link rel = \"icon\" href = \"{favicon}\">"),
data.insert(
"favicon".into(),
format!("<link rel = \"icon\" href = \"{favicon}\">").into(),
);
}
if self.html.highlight == Highlight::Js {
@ -338,26 +335,20 @@ return crowbook_return_variable.replace(/<\\/ul><ul>/g, '');\n",
.get_template("html.highlight.js")?
.as_bytes());
let highlight_js = format!("data:text/javascript;base64,{highlight_js}");
mapbuilder = mapbuilder
.insert_bool("highlight_code", true)
.insert_str(
"highlight_css",
self.html.book.get_template("html.highlight.css")?,
)
.insert_str("highlight_js", highlight_js);
data.insert("highlight_code".into(), true.into());
data.insert(
"highlight_css".into(),
self.html.book.get_template("html.highlight.css")?.into(),
);
data.insert("highlight_js".into(), highlight_js.into());
}
let data = mapbuilder.build();
let template = compile_str(
self.html
.book
.get_template("html.standalone.template")?
.as_ref(),
let template_src = self.html.book.get_template("html.standalone.template")?;
let template = self.html.book.compile_str(
template_src.as_ref(),
&self.html.book.source,
"html.standalone.template",
)?;
let mut res = vec![];
template.render_data(&mut res, &data)?;
Ok(String::from_utf8_lossy(&res).into_owned())
Ok(template.render(&data).to_string()?)
}
}

View File

@ -15,7 +15,7 @@
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook. If not, see <http://www.gnu.org/licenses/>.
use crate::book::{compile_str, Book};
use crate::book::Book;
use crate::book_renderer::BookRenderer;
use crate::error::{Error, Result, Source};
use crate::html::Highlight;
@ -215,93 +215,92 @@ impl<'a> HtmlSingleRenderer<'a> {
}
// Render the CSS
let template_css = compile_str(
self.html.book.get_template("html.css")?.as_ref(),
let template_css_src = self.html.book.get_template("html.css")?;
let template_css = self.html.book.compile_str(
template_css_src.as_ref(),
&self.html.book.source,
"html.css",
)?;
let mut data = self
.html
.book
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?
.insert_str("colors", self.html.book.get_template("html.css.colors")?);
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?;
data.insert("colors".into(), self.html.book.get_template("html.css.colors")?.into());
if let Ok(html_css_add) = self.html.book.options.get_str("html.css.add") {
data = data.insert_str("additional_code", html_css_add);
data.insert("additional_code".into(), html_css_add.into());
} else {
data.insert("additional_code".into(), "".into());
}
let data = data.build();
let mut res: Vec<u8> = vec![];
template_css.render_data(&mut res, &data)?;
let css = String::from_utf8_lossy(&res);
let css = template_css.render(&data).to_string()?;
// Render the JS
let template_js = compile_str(
self.html.book.get_template("html.standalone.js")?.as_ref(),
let template_js_src = self.html.book.get_template("html.standalone.js")?;
let template_js = self.html.book.compile_str(
template_js_src.as_ref(),
&self.html.book.source,
"html.standalone.js",
)?;
let data = self
let mut data = self
.html
.book
.get_metadata(|s| Ok(s.to_owned()))?
.insert_str("book_svg", book_svg.clone())
.insert_str("pages_svg", pages_svg.clone())
.insert_bool(
"one_chapter",
.get_metadata(|s| Ok(s.to_owned()))?;
data.insert("book_svg".into(), book_svg.clone().into());
data.insert("pages_svg".into(), pages_svg.clone().into());
data.insert(
"one_chapter".into(),
self.html
.book
.options
.get_bool("html.standalone.one_chapter")
.unwrap(),
)
.insert_str(
"common_script",
self.html.book.get_template("html.js").unwrap().as_ref(),
)
.build();
let mut res: Vec<u8> = vec![];
template_js.render_data(&mut res, &data)?;
let js = String::from_utf8_lossy(&res);
.unwrap()
.into(),
);
data.insert(
"common_script".into(),
self.html.book.get_template("html.js").unwrap().into(),
);
let js = template_js.render(&data).to_string()?;
// Render the HTML document
let mut mapbuilder = self
let mut data = self
.html
.book
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?
.insert_str("content", content)
.insert_str("script", js)
.insert_bool(self.html.book.options.get_str("lang").unwrap(), true)
.insert_bool(
"one_chapter",
.get_metadata()?;
data.insert("content".into(), content.into());
data.insert(
"one_chapter".into(),
self.html
.book
.options
.get_bool("html.standalone.one_chapter")
.unwrap(),
)
.insert_str("style", css.as_ref())
.insert_str(
"print_style",
self.html.book.get_template("html.css.print").unwrap(),
)
.insert_str("menu_svg", menu_svg)
.insert_str("book_svg", book_svg)
.insert_str("pages_svg", pages_svg)
.insert_str("json_data", self.html.get_json_ld()?)
.insert_str("footer", HtmlRenderer::get_footer(self)?)
.insert_str("header", HtmlRenderer::get_header(self)?);
.unwrap()
.into(),
);
data.insert("style".into(), css.into());
data.insert(
"print_style".into(),
self.html.book.get_template("html.css.print").unwrap().into(),
);
data.insert("menu_svg".into(), menu_svg.clone().into());
data.insert("book_svg".into(), book_svg.clone().into());
data.insert("pages_svg".into(), pages_svg.clone().into());
if let Ok(favicon) = self.html.book.options.get_path("html.icon") {
let favicon = self
.html
.handler
.map_image(&self.html.book.source, favicon)?;
mapbuilder = mapbuilder.insert_str(
"favicon",
format!("<link rel = \"icon\" href = \"{favicon}\">"),
data.insert(
"favicon".into(),
format!("<link rel = \"icon\" href = \"{favicon}\">").into(),
);
} else {
data.insert("favicon".into(), "".into());
}
if !self.html.toc.is_empty() {
mapbuilder = mapbuilder.insert_bool("has_toc", true);
mapbuilder = mapbuilder.insert_str("toc", toc)
data.insert("has_toc".into(), true.into());
data.insert("toc".into(), toc.into());
} else {
data.insert("has_toc".into(), false.into());
}
if self.html.highlight == Highlight::Js {
let highlight_js = misc::u8_to_base64(&self
@ -310,26 +309,20 @@ impl<'a> HtmlSingleRenderer<'a> {
.get_template("html.highlight.js")?
.as_bytes());
let highlight_js = format!("data:text/javascript;base64,{highlight_js}");
mapbuilder = mapbuilder
.insert_bool("highlight_code", true)
.insert_str(
"highlight_css",
self.html.book.get_template("html.highlight.css")?,
)
.insert_str("highlight_js", highlight_js);
}
let data = mapbuilder.build();
let template = compile_str(
self.html
.book
.get_template("html.standalone.template")?
.as_ref(),
data.insert("highlight_code".into(), true.into());
data.insert(
"highlight_css".into(),
self.html.book.get_template("html.highlight.css")?.into(),
);
data.insert("highlight_js".into(), highlight_js.into());
}
let template_src = self.html.book.get_template("html.standalone.template")?;
let template = self.html.book.compile_str(
template_src.as_ref(),
&self.html.book.source,
"html.standalone.template",
)?;
let mut res = vec![];
template.render_data(&mut res, &data)?;
Ok(String::from_utf8_lossy(&res).into_owned())
Ok(template.render(&data).to_string()?)
}
}

View File

@ -15,7 +15,7 @@
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook. If not, see <http://www.gnu.org/licenses/>.
use crate::book::{compile_str, Book};
use crate::book::Book;
use crate::book_renderer::BookRenderer;
use crate::error::{Error, Result, Source};
use crate::number::Number;
@ -39,7 +39,7 @@ use std::iter::Iterator;
/// LaTeX renderer
pub struct LatexRenderer<'a> {
book: &'a Book,
book: &'a Book<'a>,
current_chapter: Number,
handler: ResourceHandler,
source: Source,
@ -210,96 +210,87 @@ impl<'a> LatexRenderer<'a> {
}
});
let template = compile_str(
self.book.get_template("tex.template")?.as_ref(),
&self.book.source,
"tex.template",
)?;
let template_src = self.book.get_template("tex.template")?;
// We have to use a different template engine because we need different syntax
let syntax = upon::Syntax::builder()
.expr("<<", ">>")
.block("<#", "#>")
.comment("<%", "%>")
.build();
let mut engine = upon::Engine::with_syntax(syntax);
engine.add_template("tex.template", template_src)?;
let template = engine.get_template("tex.template").unwrap();
let mut data = self
.book
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?
.insert_str("content", content)
.insert_str("class", self.book.options.get_str("tex.class").unwrap())
.insert_bool(
"tex_title",
self.book.options.get_bool("tex.title").unwrap(),
)
.insert_str(
"papersize",
self.book.options.get_str("tex.paper.size").unwrap(),
)
.insert_bool(
"stdpage",
self.book.options.get_bool("tex.stdpage").unwrap(),
)
.insert_bool("use_url", self.book.features.url)
.insert_bool("use_taskitem", self.book.features.taskitem)
.insert_bool("use_tables", self.book.features.table)
.insert_bool("use_codeblocks", self.book.features.codeblock)
.insert_bool("use_images", self.book.features.image)
.insert_bool("use_strikethrough", self.book.features.strikethrough)
.insert_str("tex_lang", tex_lang);
if let Ok(tex_tmpl_add) = self.book.options.get_str("tex.template.add") {
data = data.insert_str("additional_code", tex_tmpl_add);
}
.get_metadata(|s| self.render_vec(&Parser::new().parse_inline(s)?))?;
data.insert("content".into(), content.into());
data.insert("class".into(), self.book.options.get_str("tex.class").unwrap().into());
data.insert("tex_title".into(), self.book.options.get_bool("tex.title").unwrap().into());
data.insert("papersize".into(), self.book.options.get_str("tex.paper.size").unwrap().into());
data.insert("stdpage".into(), self.book.options.get_bool("tex.stdpage").unwrap().into());
data.insert("use_url".into(), self.book.features.url.into());
data.insert("use_taskitem".into(), self.book.features.taskitem.into());
data.insert("use_tables".into(), self.book.features.table.into());
data.insert("use_codeblocks".into(), self.book.features.codeblock.into());
data.insert("use_images".into(), self.book.features.image.into());
data.insert("use_strikethrough".into(), self.book.features.strikethrough.into());
data.insert("tex_lang".into(), tex_lang.into());
let tex_tmpl_add = self.book.options.get_str("tex.template.add").unwrap_or("".into());
data.insert("additional_code".into(), tex_tmpl_add.into());
if let Ok(tex_font_size) = self.book.options.get_i32("tex.font.size") {
data = data
.insert_bool("has_tex_size", true)
.insert_str("tex_size", format!("{tex_font_size}"));
data.insert("has_tex_size".into(), true.into());
data.insert("tex_size".into(), format!("{tex_font_size}").into());
} else {
data.insert("has_tex_size".into(), false.into());
}
// If class isn't book, set open_any to true, so margins are symetric.
let mut book = false;
if self.book.options.get_str("tex.class").unwrap() == "book" {
data = data.insert_bool("book", true);
book = true;
}
data = data
.insert_str(
"margin_left",
data.insert("book".into(), book.into());
data.insert(
"margin_left".into(),
self.book
.options
.get_str("tex.margin.left")
.unwrap_or(if book { "2.5cm" } else { "2cm" }),
)
.insert_str(
"margin_right",
.unwrap_or(if book { "2.5cm" } else { "2cm" }).into(),
);
data.insert(
"margin_right".into(),
self.book
.options
.get_str("tex.margin.right")
.unwrap_or(if book { "1.5cm" } else { "2cm" }),
)
.insert_str(
"margin_bottom",
self.book.options.get_str("tex.margin.bottom").unwrap(),
)
.insert_str(
"margin_top",
self.book.options.get_str("tex.margin.top").unwrap(),
);
.unwrap_or(if book { "1.5cm" } else { "2cm" }).into(),
);
data.insert(
"margin_bottom".into(),
self.book.options.get_str("tex.margin.bottom").unwrap().into(),
);
data.insert(
"margin_top".into(),
self.book.options.get_str("tex.margin.top").unwrap().into(),
);
if let Ok(chapter_name) = self.book.options.get_str("rendering.chapter") {
data = data.insert_str("chapter_name", chapter_name);
}
if let Ok(part_name) = self.book.options.get_str("rendering.part") {
data = data.insert_str("part_name", part_name);
}
if self.book.options.get_bool("rendering.initials") == Ok(true) {
data = data.insert_bool("initials", true);
}
let chapter_name = self.book.options.get_str("rendering.chapter").unwrap_or("".into());
data.insert("chapter_name".into(), chapter_name.into());
let part_name = self.book.options.get_str("rendering.part").unwrap_or("".into());
data.insert("part_name".into(), part_name.into());
data.insert("initials".into(), self.book.options.get_bool("rendering.initials").unwrap().into());
// Insert xelatex if tex.command is set to xelatex or tectonic
if (self.book.options.get_str("tex.command") == Ok("xelatex"))
| (self.book.options.get_str("tex.command") == Ok("tectonic"))
{
data = data.insert_bool("xelatex", true);
}
let data = data.build();
let mut res: Vec<u8> = vec![];
template.render_data(&mut res, &data)?;
match String::from_utf8(res) {
Err(_) => panic!("{}", lformat!("generated LaTeX was not valid utf-8")),
Ok(res) => Ok(res),
data.insert("xelatex".into(), true.into());
} else
{
data.insert("xelatex".into(), false.into());
}
Ok(template.render(&data).to_string()?)
}
}

View File

@ -1,4 +1,4 @@
// Copyright (C) 2016, 2017 Élisabeth HENRY.
// Copyright (C) 2016-2023 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
@ -7,7 +7,7 @@
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// Crowbook is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="{{{lang}}}">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="{{lang}}">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
@ -10,7 +10,7 @@
</head>
<body>
<div id="cover">
<img src="{{{cover}}}" alt="{{{loc_cover}}}" />
<img src="{{cover}}" alt="{{loc_cover}}" />
</div>
</body>
</html>

View File

@ -188,13 +188,13 @@ table.notes tr td p {
font-variant: small-caps;
}
{{#lang_fr}}
{% if lang | eq: "fr" %}
/* Make list displays '' instead of bullets */
ul li {
list-style-type: '';
padding-left: .5em;
}
{{/lang_fr}}
{% endif %}
span.initial {
float: left;
@ -217,4 +217,4 @@ p.first-para {
padding: 0;
}
{{{additional_code}}}
{{additional_code}}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="{{{lang}}}" lang="{{{lang}}}">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="{{lang}}" lang="{{lang}}">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
@ -8,9 +8,9 @@
<title>{{chapter_title_raw}}</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" />
</head>
<body xml:lang="{{{lang}}}" lang="{{{lang}}}">
<body xml:lang="{{lang}}" lang="{{lang}}">
<div id = "page">
{{{content}}}
{{content}}
</div>
</body>
</html>

View File

@ -9,12 +9,12 @@
<link rel="stylesheet" type="text/css" href="stylesheet.css" />
</head>
<body>
<h2 class="author">{{{author}}}</h2>
<h1 class="title">{{{title}}}</h1>
{{#has_subtitle}}<h2 class="subtitle">{{{subtitle}}}</h2>{{/has_subtitle}}
<h2 class="author">{{author}}</h2>
<h1 class="title">{{title}}</h1>
{{#has_subtitle}}<h2 class="subtitle">{{subtitle}}</h2>{{/has_subtitle}}
{{#has_autograph}}
<div id = "autograph">
{{{autograph}}}
{{autograph}}
</div>
{{/has_autograph}}
</body>

View File

@ -10,7 +10,7 @@
</head>
<body>
<div id="cover">
<img src="{{{cover}}}" alt="{{{loc_cover}}}" />
<img src="{{cover}}" alt="{{loc_cover}}" />
</div>
</body>
</html>

View File

@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:epub="http://www.idpf.org/2007/ops" xml:lang = "{{{lang}}}" lang="{{{lang}}}">
xmlns:epub="http://www.idpf.org/2007/ops" xml:lang = "{{lang}}" lang="{{lang}}">
<head>
<meta charset = "utf-8" />
<meta name="generator" content="crowbook" />
<title>{{chapter_title_raw}}</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" />
</head>
<body xml:lang="{{{lang}}}" lang="{{{lang}}}">
<body xml:lang="{{lang}}" lang="{{lang}}">
<section class = "level1">
{{{content}}}
{{content}}
</section>
</body>
</html>

View File

@ -10,14 +10,14 @@
</head>
<body>
<section epub:type = "titlepage">
<h2 class="author">{{{author}}}</h2>
<h1 class="title">{{{title}}}</h1>
{{#has_subtitle}}<h2 class="subtitle">{{{subtitle}}}</h2>{{/has_subtitle}}
{{#has_autograph}}
<h2 class="author">{{author}}</h2>
<h1 class="title">{{title}}</h1>
{% if has_subtitle %}<h2 class="subtitle">{{subtitle}}</h2>{% endif %}
{% if has_autograph %}
<div id = "autograph">
{{{autograph}}}
{{autograph}}
</div>
{{/has_autograph}}
{% endif %}
</section>
</body>
</html>

View File

@ -1,6 +1,6 @@
/* Default HTML CSS file includes default EPUB CSS file */
{{{colors}}}
{{colors}}
p.first-para:first-letter {
font-size: 300%;
@ -199,4 +199,4 @@ footer p, #top p {
max-width: 33em;
}
{{{additional_code}}}
{{additional_code}}

View File

@ -1,51 +1,51 @@
<!DOCTYPE html>
<html lang="{{{lang}}}">
<html lang="{{lang}}">
<head>
<meta charset="utf-8">
<meta name="generator" content="crowbook">
<meta name="author" content="{{{author_raw}}}">
<meta name="author" content="{{author_raw}}">
<meta name="viewport" content="width=device-width">
{{{favicon}}}
<title>{{title_raw}} - {{chapter_title_raw}}</title>
{{favicon}}
<title>{{title_raw}}{% if is_chapter %} - {{chapter_title_raw}}{% endif %}</title>
<link rel = "stylesheet" href = "stylesheet.css" type = "text/css"
/>
<link rel = "stylesheet" href = "print.css" type = "text/css"
media = "print" />
{{#highlight_code}}
{% if highlight_code %}
<link rel = "stylesheet" href = "highlight.css" type = "text/css"
/>
<script src = "highlight.js"></script>
<script>
hljs.initHighlightingOnLoad();
</script>
{{/highlight_code}}
{% endif %}
<script>
{{{script}}}
{{script}}
</script>
</head>
<body>
{{{json_data}}}
{{json_data}}
<nav id = "nav">
<h2><a href = "index.html">{{{title}}}</a></h2>
{{{toc}}}
<h2><a href = "index.html">{{title}}</a></h2>
{{toc}}
</nav>
<div id = "content">
{{{header}}}
{{header}}
<div id = "page">
<header>
<div id = "menu">
<img id = "menu-button" onclick="toggle();"
src="menu.svg" alt = "{{{loc_toc}}}" title = "{{{loc_toc}}}" />
src="menu.svg" alt = "{{loc_toc}}" title = "{{loc_toc}}" />
</div>
</header>
{{{prev_chapter}}}
{{{content}}}
{{{next_chapter}}}
{% if is_chapter %}{{prev_chapter}}{% endif %}
{{content}}
{% if is_chapter %}{{next_chapter}}{% endif %}
</div>
{{{footer}}}
{{footer}}
</div>
</body>
</html>

View File

@ -23,13 +23,13 @@ function passageCount(n) {
return count;
}
{{{common_script}}}
{{common_script}}
var initFns = [];
{{{new_game}}}
{{new_game}}
{{{js_prelude}}}
{{js_prelude}}
function showChapter(chap, noreset){
state.current_id = chap;

View File

@ -1,6 +1,6 @@
{{{common_script}}}
{{common_script}}
{{#one_chapter}}
{% if one_chapter %}
function showChapter(chap, noreset){
if (!displayAll) {
var chapters = document.getElementsByClassName("chapter");
@ -62,16 +62,16 @@ function switchAll() {
toc.style.display = "block";
}
displayAllSwitcher = document.getElementById("book-button");
displayAllSwitcher.src="{{{pages_svg}}}";
displayAllSwitcher.alt="{{{loc_display_one}}}";
displayAllSwitcher.title="{{{loc_display_one}}}";
displayAllSwitcher.src="{{pages_svg}}";
displayAllSwitcher.alt="{{loc_display_one}}";
displayAllSwitcher.title="{{loc_display_one}}";
} else {
displayAll = false;
showChapter(0);
displayAllSwitcher = document.getElementById("book-button");
displayAllSwitcher.src="{{{book_svg}}}";
displayAllSwitcher.alt="{{{loc_display_all}}}";
displayAllSwitcher.title="{{{loc_display_all}}}";
displayAllSwitcher.src="{{book_svg}}";
displayAllSwitcher.alt="{{loc_display_all}}";
displayAllSwitcher.title="{{loc_display_all}}";
}
}
@ -99,4 +99,4 @@ window.onload = function(){
};
{{/one_chapter}}
{% endif %}

View File

@ -1,80 +1,80 @@
<!DOCTYPE html>
<html lang="{{{lang}}}">
<html lang="{{lang}}">
<head>
<meta charset="utf-8">
<meta name="generator" content="crowbook">
<meta name="viewport" content="width=device-width">
<meta name="author" content="{{{author_raw}}}">
{{{favicon}}}
<meta name="author" content="{{author_raw}}">
{{favicon}}
<title>{{title_raw}}</title>
<style type = "text/css">
{{{style}}}
{{style}}
</style>
<style type = "text/css" media = "print">
{{{print_style}}}
{{print_style}}
</style>
{{#highlight_code}}
{% if highlight_code %}
<style>
{{{highlight_css}}}
{{highlight_css}}
</style>
<script src = "{{{highlight_js}}}"></script>
<script src = "{{highlight_js}}"></script>
<script>
hljs.initHighlightingOnLoad();
</script>
{{/highlight_code}}
{% endif %}
<script>
{{{script}}}
{{script}}
</script>
</head>
<body>
{{{json_data}}}
{{#has_toc}}
{{json_data}}
{% if has_toc %}
<nav id = "nav">
{{#one_chapter}}
{% if one_chapter %}
<div id = "nav-container">
<div id="toolbar">
<img id="book-button" alt="Display mode"
title = "{{{loc_display_all}}}"
src="{{{book_svg}}}"
title = "{{loc_display_all}}"
src="{{book_svg}}"
onclick="javascript:switchAll()">
</div>
</div>
{{/one_chapter}}
{% endif %}
<div id = "nav-title">
<h2><a href = "#link-0">{{{title}}}</a></h2>
<h2><a href = "#link-0">{{title}}</a></h2>
</div>
{{{toc}}}
{{toc}}
</nav>
{{/has_toc}}
{% endif %}
<div id = "content">
{{{header}}}
{{header}}
<div id = "page">
<header>
<div id = "menu">
{{#has_toc}}
{% if has_toc %}
<img id = "menu-button" onclick="toggle();"
src="{{{menu_svg}}}"
alt = "{{{loc_toc}}}" title = "{{{loc_toc}}}" />
{{/has_toc}}
src="{{menu_svg}}"
alt = "{{loc_toc}}" title = "{{loc_toc}}" />
{% endif %}
</div>
<h2 class="author">{{{author}}}</h2>
<h1 id = "link-0" class="title" >{{{title}}}</h1>
{{#has_subtitle}}<h2 class = "subtitle">{{{subtitle}}}</h2>{{/has_subtitle}}
{{#has_autograph}}
<h2 class="author">{{author}}</h2>
<h1 id = "link-0" class="title" >{{title}}</h1>
{% if has_subtitle %}<h2 class = "subtitle">{{subtitle}}</h2>{% endif %}
{% if has_autograph %}
<div id = "autograph">
{{{autograph}}}
{{autograph}}
</div>
{{/has_autograph}}
{% endif %}
</header>
{{{content}}}
{{content}}
</div>
{{{footer}}}
{{footer}}
</div>
</body>
</html>

View File

@ -1,13 +1,11 @@
{{=<< >>=}} % Use <<&foo>> to include (non HTML-escape) variable foo instead of {{{foo}}}
\documentclass<<#has_tex_size>>[<<&tex_size>>pt]<</has_tex_size>>{<<&class>>}
\documentclass<# if has_tex_size #>[<<tex_size>>pt]<# endif #>{<<class>>}
%% Pacake inclusion
<<#xelatex>>
%% Package inclusion
<# if xelatex #>
% Unicode support if xelatex is used
\usepackage{fontspec}
\usepackage{xunicode}
<</xelatex>>
<<^xelatex>>
<# else #>
% Unicode support if xelatex is not used
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
@ -21,54 +19,54 @@
% (e.g. filenames, urls, ...). The result is not necesarily very
% beautiful, though, but at least it's readable.
\setlength\emergencystretch{.5\textwidth}
<</xelatex>>
<# endif #>
\usepackage[<<&tex_lang>>]{babel} % Language support
\usepackage[<<tex_lang>>]{babel} % Language support
\usepackage{fancyhdr} % Headers
% Allows hyphenatations in \texttt
\usepackage[htt]{hyphenat}
<<#use_strikethrough>>
<# if use_strikethrough #>
% Only included if strikethrough is used in the document
\usepackage[normalem]{ulem}
<</use_strikethrough>>
<<#use_taskitem>>
<# endif #>
<# if use_taskitem #>
\usepackage{amssymb}
<</use_taskitem>>
<# endif #>
% Set hyperlinks and metadata
\usepackage[colorlinks=true,breaklinks=true,hypertexnames=false]{hyperref}
\hypersetup{pdfauthor={<<&author>>},
pdftitle={<<&title>>},
pdfsubject={<<&description>>}
\hypersetup{pdfauthor={<<author>>},
pdftitle={<<title>>},
pdfsubject={<<description>>}
}
<<^xelatex>>
<# if xelatex #>
<# else #>
\usepackage[anythingbreaks]{breakurl}
<</xelatex>>
<# endif #>
<<#initials>>
<# if initials #>
% Only included if use_initials is set to true
\usepackage{lettrine}
<</initials>>
<# endif #>
<<#stdpage>>
<# if stdpage #>
% Only included if the stdpage option is set to true
\usepackage[<<&papersize>>]{geometry}
\usepackage[<<papersize>>]{geometry}
\usepackage[hyphen=false, parskip]{stdpage}
<</stdpage>>
<<^stdpage>>
<# else #>
% Included if the stdpage option if set to false
\usepackage[<<&papersize>>, top=<<&margin_top>>, bottom=<<&margin_bottom>>,
left=<<&margin_left>>,right=<<&margin_right>>]{geometry} % Set dimensions/margins of the parge
<</stdpage>>
\usepackage[<<papersize>>, top=<<margin_top>>, bottom=<<margin_bottom>>,
left=<<margin_left>>,right=<<margin_right>>]{geometry} % Set dimensions/margins of the parge
<# endif #>
\makeatletter
\date{<<&date>>}
\date{<<date>>}
<<^stdpage>>
<<#book>>
<# if not stdpage #>
<# if book #>
% Redefine the \maketitle command, only for book class (not used if stdpage option is set to true)
\renewcommand{\maketitle}{
% First page with only the title
@ -93,7 +91,7 @@
\rule{\textwidth}{0.4pt}\\[\baselineskip]
{\Huge\scshape \@title \\[5mm]}
{\Large <<&subtitle>>}
{\Large <<subtitle>>}
\rule{\textwidth}{0.4pt}\vspace*{-\baselineskip}\vspace{3.2pt}
\rule{\textwidth}{1.6pt}\\[\baselineskip]
@ -101,14 +99,14 @@
\vspace*{4\baselineskip}
{\Large \@author}
<<#has_autograph>>
<# if has_autograph #>
\vspace*{10\baselineskip}
<<&autograph>>
<</has_autograph>>
<<autograph>>
<# endif #>
\vfill
<<#has_date>>\@date<</has_date>>
<# if has_date #>\@date<# endif #>
\end{center}
\pagebreak
@ -118,13 +116,13 @@
\null\vfill
\noindent
\begin{center}
{\emph{\@title}<<#has_version>>{, <<&version>>}<</has_version>><<#has_author>>, © \@author<</has_author>>.\\[5mm]}
<<#has_license>>{<<&license>>\\[5mm]}<</has_license>>
{\emph{\@title}<#if has_version #>{, <<version>>}<# endif #><# if has_author #>, © \@author<# endif #>.\\[5mm]}
<# if has_license #>{<<license>>\\[5mm]}<# endif #>
\end{center}
\pagebreak
\newpage
}
<</book>>
<# endif #>
% Redefine headers
@ -134,7 +132,7 @@
\fancyfoot{}
<</stdpage>>
<# endif #>
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Command and environment definitions
@ -189,7 +187,7 @@
%
% Only used if syntect is used for syntax highlighting is used, else
% the spverbatim environment is preferred.
<<#use_codeblocks>> % This part is only included if document contains code blocks
<# if use_codeblocks #> % This part is only included if document contains code blocks
\usepackage{spverbatim}
\usepackage{color}
\usepackage[
@ -202,9 +200,9 @@
}{%
\end{mdframed}
}
<</use_codeblocks>>
<# endif #>
<<#use_images>>
<# if use_images #>
% Only included if document contains images
\usepackage{graphicx}
@ -219,9 +217,9 @@
% Image
% (an image embedded in a pagraph or other element)
\newcommand\mdimage[1]{\includegraphics{#1}}
<</use_images>>
<# endif #>
<<#use_tables>>
<# if use_tables #>
% Only included if document contains tables
\usepackage{tabularx}
@ -237,34 +235,34 @@
\endtabularx
\endcenter
}
<</use_tables>>
<# endif #>
<<&additional_code>>
<<additional_code>>
\makeatother
\title{<<&title>>}
\author{<<&author>>}
\title{<<title>>}
\author{<<author>>}
\begin{document}
% Redefine chapter and part names if they needs to be
% Needs to be after \begin{document} because babel
<<#chapter_name>>
<# if chapter_name #>
\makeatletter
\renewcommand{\@chapapp}{<<&chapter_name>>}
\renewcommand{\@chapapp}{<<chapter_name>>}
\makeatother
<</chapter_name>>
<# endif #>
<<#part_name>>
\renewcommand{\partname}{<<&part_name>>}
<</part_name>>
<# if part_name #>
\renewcommand{\partname}{<<part_name>>}
<# endif #>
<<#tex_title>>
<# if tex_title #>
\maketitle
<</tex_title>>
<# endif #>
<<&content>>
<<content>>
\end{document}

View File

@ -1,37 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<office:document-content
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0"
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
xmlns:math="http://www.w3.org/1998/Math/MathML"
xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0"
xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0"
xmlns:ooo="http://openoffice.org/2004/office"
xmlns:ooow="http://openoffice.org/2004/writer"
xmlns:oooc="http://openoffice.org/2004/calc"
xmlns:dom="http://www.w3.org/2001/xml-events"
xmlns:xforms="http://www.w3.org/2002/xforms"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
office:version="1.2">
<office:automatic-styles>
{{{automatic_styles}}}
</office:automatic-styles>
<office:body>
<office:text>
<text:p text:style-name="Title">{{title}}</text:p>
<text:p text:style-name="Heading_20_2.author">{{author}}</text:p>
{{{content}}}
</office:text>
</office:body>
</office:document-content>

Binary file not shown.