1
0
Fork 0
mirror of https://github.com/lise-henry/crowbook synced 2024-05-28 09:56:23 +02:00

added a book_example

This commit is contained in:
Elisabeth Henry 2016-02-19 21:35:49 +01:00
parent 1db5f79107
commit 90504e2acc
13 changed files with 465 additions and 70 deletions

View File

@ -1,4 +1,6 @@
Bugs
====
* characters are escaped for HTML... but not for LaTeX, which
sometimes causes issues
* Book: can't parse specified numbers for negative chapter (though, well...)

28
book_example/config.book Normal file
View File

@ -0,0 +1,28 @@
# Metadatas
author: Élisabeth Henry
title: Crowbook
description: More like some kind of manual really
lang: en
# Generic options (though not used with LaTeX)
numbering: true
autoclean: true
numbering_template: Chapter {{number}}: {{title}}
verbose: true
# Latex option
tex_command: pdflatex
# Options for generating files
temp_dir: .
# Specify a) where to write files b) which ones to generate
output_epub: book.epub
output_html: book.html
#output_pdf: book.pdf
#output_tex: book.tex
# finally, our files
# paths are relative to the directory where this file is
+ introduction.md
+ config.md

280
book_example/config.md Normal file
View File

@ -0,0 +1,280 @@
The configuration file
======================
If you want to use Crowbook for your book, this configuration file
is all you'll have to add (assuming you'll already have the book in
Markdown files; if you don't, you'll also have to write a book first,
but that's besides the scope of this document).
The format is not very complicated. This is an example of it:
```
author: Joan Doe
title: Some book
lang: en
output_html: some_book.html
- preface.md
+ chapter_1.md
+ chapter_2.md
+ chapter_3.md
+ chapter_4.md
- epilogue.md
```
Basically, it is divided in two parts:
* a list of options, under the form `option: value`;
* a list of Markdown files.
Let's start by the second one, though it appears at the end of the
document.
The list of files
-----------------
There are three options to include a markdown file:
* `- file_name.md`: include an unnumbered chapter;
* `+ file_name.md`: a numbered chapter;
* `42. file_name.md`: a chapter numbered to 42.
There are two important things to note:
1. you must *not* use quotes around the file names
2. the path of these files are relative to the directory where your
config file is, *not* to the directory where you are when running
`crowbook`. E.g. you can run `crowbook
books/my_trilogy/first_book/config.book` without being in the
book's directory.
Also note that you don't have to specify a title. This is because the title
of the chapter is inferred from the Markdown document. To go back to
our previous example:
```
+ chapter_1.md
```
does not specify a chapter title, because it will read it directly in
`chapter_1.md`, e.g.:
```markdown
The day I was born
==================
Content of this chapter
```
*Normally*, you should have one and only one level-one header in each
markdown file. Really. It's good practice.
If you have more than one, Crowbook won't get too angry at you and
it will just treat it as another chapter. It's not a big problem
for single-page HTML output, or for LaTeX, but it is for Epub
generation, because it will mess the table of contents.
It's also a problem if you do *not* have a level-1 header in a
markdown file. If it is a numbered chapter Crowbook will still be
able to infer a chapter name, but if it is not numbered Crowbook
will give up, because it can't hope to generate a decent table of
content with that.
****
Anyway, *please*: one file = one chapter, a chapter starts with a
title, and this way this will work nice.
Crowbook options
----------------
The first part of the configuration file is dedicated to pass options
to Crowbook. Each one is of the form `option: value`. Note that you
don't have to put string in quotes, e.g.:
```
title: My title
```
If you *do* use quotes, Crowbook will actually put those quotes in the
string, so basically don't do that.
### Metadata ###
#### author ####
Quite obviously, the author of the book. Note that it's currently just
a single string, so if you want to have multiple authors, you'll have
to do something like:
```
author: Jane Doe, John Smith
```
**default**: `Anonymous`
#### title ####
The title of the book.
**default**: `Untitled`
#### lang ####
The language of the book, in a standard format. "en", "fr", and so on.
**default**: `en`
#### cover ####
The file name of a cover image for the book. Note that, here again,
you must not use quotes:
```
cover: cover.png
```
**default**: `None`
#### subject ####
What your book is about: e.g. Programming, Science-Fiction...
**default**: `None`
#### description ####
A description of your book. Note that Crowbook does *not* support
multi-line strings in configuration field, and it is a field where it
might be a problem if you don't like very long lines.
**default**: `None`
### Output options ###
These options specify which files to generate. You must at least set
one of this option, or Crowbook won't do anything.
Recall that all file paths are relative to the directory where the
config file is, not to the one where you run `crowbook`. So if you set
```
output_epub = foo.epub
```
and runs
```bash
$ crowbook some/dir/config.book
```
`foo.epub` will be generated in `some/dir`, not in your current directory.
#### output_epub ####
The name of the epub file you want to generate.
**default**: `None`
#### output_html ####
The name of the HTML file you want to generate. Note that this HTML
file is self-contained, it doesn't require e.g. CSS from other files.
**default**: `None`
#### output_tex ####
The name of the LaTeX file you want to generate.
**default**: `None`
#### output_pdf ####
The name of the PDF file you want to generate. Crowbook uses LaTeX to
generate it, so it won't work if it isn't installed on your computer.
**default**:: `None`
### Additional options ###
#### temp_dir ####
When it is generating epub or pdf files, Crowbook creates a temporary
directory (which is then removed), named from a random uuid (so we can
be pretty certain it's not gonna exist). This option specify where to
create this directory. E.g., if you set:
```
temp_dir: /tmp
```
crowbook might create a temporary directory
`/tmp/7fcbe41e-1676-46ba-b1a7-40c2fa37a3a7`.
By default, this temporary directory is created where the config file
is.
**default**: `.`
#### numbering ####
A boolean that sets whether or not you want numbering. Setting it to
`false` is equivalent to including all your chapters with `-
my_chapter.md`. Note that even if it is set to `true`, numbering will
be desactivated for chapters that are included with `- my_chapter.md`.
**default**:: `true`
#### numbering_template ####
A string will be used as chapter title. You can use `{{number}}` and
`{{title}}` in this string, e.g.:
```
numbering_template: Chapter {{number}} {{title}}
```
Note that:
* this string isn't used for unnumbered chapters;
* this string isn't used for LaTeX, either.
**default**: `{{number}}. {{title}}`
#### verbose ####
Crowbook will print a little more stuff on the standard output if this
option is set to true.
**default**: `false`
#### autoclean ####
This option cleans a bit the input markdown. With the default
implementation, it only removes consecutive spaces, which has not real
impact (they are ignored anyway both by HTML viewers and by LaTeX).
However, if `lang` is set to `fr`, it also tries to add non-breaking
spaces in front (or after) characters like '?', '!', ';' to respect
french typography.
**default**: `true`
#### nb_char ####
This option allows you to specify the non breaking character used by
the french cleaning method (see above). Probably not really something
you need to modify.
**default**: `''` (i.e. narrrow non-breaking space)
#### tex_command ####
The command used to generate a PDF file.
**default**: `pdflatex`

View File

@ -0,0 +1,60 @@
Introduction
============
What is Crowbook
----------------
As its name suggests, Crowbook is a tool to render books and, more
specifically, books written in *Markdown*. Its primary target are
novels, with a focus on generating PDF and Epub files.
This doesn't mean that it is impossible to use Crowbook for
technical documentations (though some features, like footnotes, *are*
actually currently unsupported), but the result won't probably be as
beautiful as tools that are more focused to that, such as
[mdBook](https://github.com/azerupi/mdBook). Let's see an example with
code formatting:
```rust
fn main() {
println!("Hello, world!");
}
```
Now, that's not nearly as nice as cool syntax highlighting and even
the possibility to actually run the code in your browser. But that's
OK because, again, Crowbook is focused on novels, and you don't
expect to see a lot of programming in a novel.
*****
At the opposite, having a decent separation ruler to separate lists of
paragraphs, and not some ugly line, is more relevant to our objectives.
Installing Crowbook
-------------------
Crowbook is written in [Rust](https://www.rust-lang.org/), so you'll
first need to install the Rust compiler, which you can
[download here](https://www.rust-lang.org/downloads.html) if you don't
already have it.
Then you'll need to clone the github repository of Crowbook and run
`cargo build` in it:
```bash
$ git clone https://github.com/lise-henry/crowbook.git
$ cd crowbook
$ cargo build
```
Then you'll have two options: either run `crowbook` directly in this
directory, with `cargo run`, or install it with `cargo install`.
Either way, you'll need to pass it a configuration file. E.g., to
generate this book, you'll do:
```
$ cargo run book_example/config.book
```

View File

@ -52,6 +52,14 @@ pub struct Book {
// for latex
pub tex_command: String,
// for epub
pub epub_css: Option<String>,
pub epub_template: Option<String>,
// for HTML
pub html_template: Option<String>,
pub html_css: Option<String>,
}
impl Book {
@ -70,12 +78,16 @@ impl Book {
cover: None,
nb_char: '',
numbering_template: String::from("{{number}}. {{title}}"),
temp_dir: String::from("/tmp/"),
temp_dir: String::from("."),
output_epub: None,
output_html: None,
output_pdf: None,
output_tex: None,
tex_command: String::from("pdflatex"),
epub_css: None,
epub_template: None,
html_template: None,
html_css: None,
}
}
@ -220,6 +232,10 @@ impl Book {
"lang" => self.lang = String::from(value),
"description" => self.description = Some(String::from(value)),
"subject" => self.subject = Some(String::from(value)),
"epub_css" | "epub-css" => self.epub_css = Some(String::from(value)),
"epub_template" | "epub-template" => self.epub_template = Some(String::from(value)),
"html_template" | "html-template" => self.html_template = Some(String::from(value)),
"html_css" | "html-css" => self.html_css = Some(String::from(value)),
_ => return Err(Error::ConfigParser("unrecognized option", String::from(line))),
}
}

View File

@ -3,6 +3,7 @@ use token::Token;
use html::HtmlRenderer;
use book::{Book,Number};
use zipper::Zipper;
use templates::epub::*;
use mustache;
use chrono;
@ -60,16 +61,16 @@ impl<'a> EpubRenderer<'a> {
}
// Write CSS file
try!(zipper.write("stylesheet.css", include_str!("../../templates/epub/stylesheet.css").as_bytes()));
try!(zipper.write("stylesheet.css", CSS.as_bytes()));
// Write titlepage
try!(zipper.write("title_page.xhtml", &try!(self.render_titlepage()).as_bytes()));
// Write file for ibook (why?)
try!(zipper.write("META-INF/com.apple.ibooks.display-options.xml", include_str!("../../templates/epub/ibookstuff.xml").as_bytes()));
try!(zipper.write("META-INF/com.apple.ibooks.display-options.xml", IBOOK.as_bytes()));
// Write container.xml
try!(zipper.write("META-INF/container.xml", include_str!("../../templates/epub/container.xml").as_bytes()));
try!(zipper.write("META-INF/container.xml", CONTAINER.as_bytes()));
// Write nav.xhtml
try!(zipper.write("nav.xhtml", &try!(self.render_nav()).as_bytes()));
@ -102,7 +103,7 @@ impl<'a> EpubRenderer<'a> {
/// Render the titlepgae
fn render_titlepage(&self) -> Result<String> {
let template = mustache::compile_str(include_str!("../../templates/epub/titlepage.xhtml"));
let template = mustache::compile_str(TITLE);
let data = self.book.get_mapbuilder()
.build();
let mut res:Vec<u8> = vec!();
@ -128,7 +129,7 @@ impl<'a> EpubRenderer<'a> {
<content src = \"{}\" />
</navPoint>\n", id, title, filename));
}
let template = mustache::compile_str(include_str!("../../templates/epub/toc.ncx"));
let template = mustache::compile_str(TOC);
let data = self.book.get_mapbuilder()
.insert_str("nav_points", nav_points)
.build();
@ -200,7 +201,7 @@ impl<'a> EpubRenderer<'a> {
items.push_str(&format!("<item media-type = \"image/{}\" id =\"{}\" href = \"{}\" />\n", format, s, s));
}
let template = mustache::compile_str(include_str!("../../templates/epub/content.opf"));
let template = mustache::compile_str(OPF);
let data = self.book.get_mapbuilder()
.insert_str("optional", optional)
.insert_str("items", items)
@ -221,7 +222,7 @@ impl<'a> EpubRenderer<'a> {
/// Render cover.xhtml
fn render_cover(&self) -> Result<String> {
if let Some(ref cover) = self.book.cover {
let template = mustache::compile_str(include_str!("../../templates/epub/cover.xhtml"));
let template = mustache::compile_str(COVER);
let data = self.book.get_mapbuilder()
.insert_str("cover", cover.clone())
.build();
@ -246,7 +247,7 @@ impl<'a> EpubRenderer<'a> {
title));
}
let template = mustache::compile_str(include_str!("../../templates/epub/nav.xhtml"));
let template = mustache::compile_str(NAV);
let data = self.book.get_mapbuilder()
.insert_str("content", content)
.build();
@ -276,7 +277,7 @@ impl<'a> EpubRenderer<'a> {
}
self.toc.push(title.clone());
let template = mustache::compile_str(include_str!("../../templates/epub/template.xhtml"));
let template = mustache::compile_str(TEMPLATE);
let data = self.book.get_mapbuilder()
.insert_str("content", content)
.insert_str("chapter_title", title)

View File

@ -2,6 +2,7 @@ use escape::escape_html;
use token::Token;
use book::{Book, Number};
use error::{Error,Result};
use templates::html::*;
use mustache;
@ -42,10 +43,11 @@ impl<'a> HtmlRenderer<'a> {
}
}
let template = mustache::compile_str(include_str!("../../templates/template.html"));
let template = mustache::compile_str(TEMPLATE);
let data = self.book.get_mapbuilder()
.insert_str("content", content)
.insert_str("style", CSS)
.build();
let mut res:Vec<u8> = vec!();
@ -89,7 +91,7 @@ impl<'a> HtmlRenderer<'a> {
Token::CodeBlock(ref language, ref vec) => {
let s = self.render_vec(vec);
if language.is_empty() {
format!("<pre><code>\n{}</code></pre>\n", s)
format!("<pre><code>{}</code></pre>\n", s)
} else {
format!("<pre><code class = \"language-{}\">{}</code></pre>\n", language, s)
}

View File

@ -2,6 +2,7 @@ use book::{Book, Number};
use error::{Error,Result};
use token::Token;
use zipper::Zipper;
use templates::latex::*;
use std::path::Path;
@ -54,7 +55,7 @@ impl<'a> LatexRenderer<'a> {
}
});
let template = mustache::compile_str(include_str!("../../templates/template.tex"));
let template = mustache::compile_str(TEMPLATE);
let data = self.book.get_mapbuilder()
.insert_str("content", content)
.insert_str("tex_lang", tex_lang)

View File

@ -25,3 +25,4 @@ pub use epub::EpubRenderer;
pub use latex::LatexRenderer;
mod zipper;
mod templates;

20
src/lib/templates.rs Normal file
View File

@ -0,0 +1,20 @@
pub mod html {
pub static TEMPLATE:&'static str = include_str!("../../templates/template.html");
pub static CSS:&'static str = include_str!("../../templates/epub/stylesheet.css");
}
pub mod latex {
pub static TEMPLATE:&'static str = include_str!("../../templates/template.tex");
}
pub mod epub {
pub static TEMPLATE:&'static str = include_str!("../../templates/epub/template.xhtml");
pub static CSS:&'static str = include_str!("../../templates/epub/stylesheet.css");
pub static CONTAINER:&'static str = include_str!("../../templates/epub/container.xml");
pub static OPF:&'static str = include_str!("../../templates/epub/content.opf");
pub static COVER:&'static str = include_str!("../../templates/epub/cover.xhtml");
pub static IBOOK:&'static str = include_str!("../../templates/epub/ibookstuff.xml");
pub static NAV:&'static str = include_str!("../../templates/epub/nav.xhtml");
pub static TITLE:&'static str = include_str!("../../templates/epub/titlepage.xhtml");
pub static TOC:&'static str = include_str!("../../templates/epub/toc.ncx");
}

View File

@ -1,7 +1,6 @@
use error::{Error,Result};
use std::env;
use std::str;
use std::path::{Path,PathBuf};
use std::io::Write;
use std::process::Command;

View File

@ -13,11 +13,32 @@ p {
margin:0;
hyphens: auto;
}
code {
font-family: monospace;
margin-top: 2em;
margin-bottem: 2em;
blockquote {
margin: 1em;
font-style: italic;o
}
code {
font-size: .8em;
font-family: "Linux Libertine Mono", monospace;
background-color: #F0F0F0;
}
pre {
font-family: "Linux Libertine Mono", monospace;
margin: 1em;
padding-top: 0;
background-color: #F0F0F0;
white-space: pre-wrap;
word-wrap: break-word;
}
h1, h2, h3, h4, h5, h5 {
adobe-hyphenate: none;
-ms-hyphens: none; /* Trident (Windows) */
-moz-hyphens: none; /* Gecko (Firefox) */
-webkit-hyphens: none; /* Webkit */
-epub-hyphens: none; /* EPUB 3 */
hyphens: none; /* Futur standard */
}
h1 {
text-align: left;
font-family: Linux Biolinum, sans-serif;
@ -36,11 +57,20 @@ h3 {
h4 { text-align: left; }
h5 { text-align: left; }
h6 { text-align: left; }
h1.title { }
h2.author { }
h1.title {
text-align: center;
font-size: 300%;
}
h2.author {
text-align: right;
font-size: 200%;
}
h3.date { }
ol.toc { padding: 0; margin-left: 1em; }
ol.toc li { list-style-type: none; margin: 0; padding: 0; }
p img {
float: right;
}
#cover img {
width: 100%;
}

View File

@ -6,59 +6,14 @@
<meta name="author" content="{{author}}">
<title>{{title}}</title>
<style type = "text/css">
{{{style}}}
body {
font-family: "Linux Libertine", "Georgia", serif;
margin-left: 15%;
margin-right: 15%;
margin-top: 5%;
margin-bottom: 5%;
text-align: justify;
font-size: 14pt;
margin-left: 15%;
margin-right: 15%;
}
.rule {
text-align: center;
margin-top: 1em;
margin-bottom: 1em;
font-weight: bold;
}
p {
text-indent: 1.25em;
font-size: 1em;
margin:0;
hyphens: auto;
}
code {
font-family: monospace;
margin-top: 2em;
margin-bottem: 2em;
}
h1 {
text-align: left;
font-family: Linux Biolinum, sans-serif;
font-variant: small-caps;
}
h2 {
text-align: left;
font-family: Linux Biolinum, sans-serif;
font-variant: small-caps;
}
h3 {
text-align: left;
font-family: Linux Biolinum, sans-serif;
font-variant: small-caps;
}
h4 { text-align: left; }
h5 { text-align: left; }
h6 { text-align: left; }
h1.title {
text-align: center;
text-size: 200%;
}
h2.author {
text-align: right;
}
h3.date { }
</style>
</head>
<body>
<header>