mirror of
https://github.com/rust-lang/mdBook.git
synced 2025-12-28 17:21:52 -05:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
600eb02fee | ||
|
|
41462e8b2d | ||
|
|
43eef7637a | ||
|
|
dc8f6cd5e9 | ||
|
|
5b9d8ee6ac | ||
|
|
8a4d744dc1 | ||
|
|
4f583dfea9 | ||
|
|
678a0906db | ||
|
|
f47d420811 | ||
|
|
5ffee8144b | ||
|
|
e9e8b4239e | ||
|
|
0a0a96808d | ||
|
|
2d00f40a24 | ||
|
|
e40b293336 | ||
|
|
6c94ba8a88 | ||
|
|
eed440ef5a | ||
|
|
e8436d2fd2 | ||
|
|
b40688c880 | ||
|
|
71213f40da | ||
|
|
0620ef1f47 | ||
|
|
d6d0979ecf | ||
|
|
159b300067 | ||
|
|
0dd6a17187 | ||
|
|
f9b6e09c26 | ||
|
|
4dfa15cffa | ||
|
|
7762475b33 | ||
|
|
0ab8a73ba2 | ||
|
|
5b289c1303 | ||
|
|
0ffd638904 | ||
|
|
50504282fb | ||
|
|
1de00f9cd7 | ||
|
|
a2b25232d3 | ||
|
|
b1265862c7 | ||
|
|
f1cd9f54c2 | ||
|
|
95d82a924f | ||
|
|
6bcc592ed9 | ||
|
|
4ca6693a48 | ||
|
|
d376b0663a | ||
|
|
22b6448381 | ||
|
|
cdbb2ee5fd | ||
|
|
522eef9296 |
24
Cargo.toml
24
Cargo.toml
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mdbook"
|
||||
version = "0.0.3"
|
||||
version = "0.0.4"
|
||||
authors = ["Mathieu David <mathieudavid@mathieudavid.org>"]
|
||||
description = "create books from markdown files (like Gitbook)"
|
||||
documentation = "http://azerupi.github.io/mdBook/index.html"
|
||||
@@ -11,22 +11,40 @@ readme = "README.md"
|
||||
build = "build.rs"
|
||||
exclude = [
|
||||
"book-example/*",
|
||||
"src/theme/stylus",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
clap = "~1.5.3"
|
||||
handlebars = "=0.11.2"
|
||||
handlebars = "~0.12.0"
|
||||
rustc-serialize = "~0.3.16"
|
||||
pulldown-cmark = "~0.0.3"
|
||||
|
||||
|
||||
# Watch feature
|
||||
[dependencies.notify]
|
||||
notify = "^2.4.1"
|
||||
optional = true
|
||||
|
||||
[dependencies.time]
|
||||
time = "^0.1.33"
|
||||
optional = true
|
||||
|
||||
[dependencies.crossbeam]
|
||||
time = "^0.2.0"
|
||||
optional = true
|
||||
|
||||
# Tests
|
||||
[dev-dependencies]
|
||||
tempdir = "~0.3.4"
|
||||
|
||||
|
||||
[features]
|
||||
default = ["output"]
|
||||
default = ["output", "watch"]
|
||||
debug = []
|
||||
output = []
|
||||
regenerate-css = []
|
||||
watch = ["notify", "time", "crossbeam"]
|
||||
|
||||
[[bin]]
|
||||
doc = false
|
||||
|
||||
@@ -13,14 +13,10 @@ To have an idea of what a rendered book looks like,take a look at the [**Documen
|
||||
## Installation
|
||||
|
||||
```
|
||||
git clone --depth=1 https://github.com/azerupi/mdBook.git
|
||||
cd mdBook
|
||||
cargo build --release
|
||||
cargo install mdbook
|
||||
```
|
||||
|
||||
The executable `mdbook` will be in the `./target/release` folder, this should be added to the path.
|
||||
|
||||
If you want to regenerate the css (stylesheet), make sure that you installed `stylus` and `nib` from `npm` because it is used to compile the stylesheets
|
||||
If you want to regenerate the css (stylesheet), clone the git repo locally and make sure that you installed `stylus` and `nib` from `npm` because it is used to compile the stylesheets
|
||||
|
||||
Install [node.js](https://nodejs.org/en/)
|
||||
|
||||
|
||||
@@ -4,12 +4,15 @@
|
||||
- [Command Line Tool](cli/cli-tool.md)
|
||||
- [init](cli/init.md)
|
||||
- [build](cli/build.md)
|
||||
- [watch](cli/watch.md)
|
||||
- [test](cli/test.md)
|
||||
- [Format](format/format.md)
|
||||
- [SUMMARY.md](format/summary.md)
|
||||
- [Configuration](format/config.md)
|
||||
- [Theme](format/theme/theme.md)
|
||||
- [index.hbs](format/theme/index-hbs.md)
|
||||
- [Syntax highlighting](format/theme/syntax-highlighting.md)
|
||||
- [MathJax Support](format/mathjax.md)
|
||||
- [Rust Library](lib/lib.md)
|
||||
-----------
|
||||
[Contributors](misc/contributors.md)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
The build command is used to render your book:
|
||||
|
||||
```
|
||||
```bash
|
||||
mdbook build
|
||||
```
|
||||
|
||||
@@ -17,7 +17,7 @@ convenience. Large books will therefore remain structured when rendered.
|
||||
Like `init`, the `build` command can take a directory as argument to use instead of the
|
||||
current working directory.
|
||||
|
||||
```
|
||||
```bash
|
||||
mdbook build path/to/book
|
||||
```
|
||||
|
||||
|
||||
@@ -5,14 +5,28 @@ Let's focus on the command line tool capabilities first.
|
||||
|
||||
## Install
|
||||
|
||||
At the moment, the only way to install mdBook is by downloading the source code from Github and building it yourself. Fortunately
|
||||
this is made very easy with Cargo.
|
||||
### Pre-requisite
|
||||
|
||||
If you haven't already, you should begin by installing [Rust](https://www.rust-lang.org/install.html) and [Git](https://git-scm.com/downloads)
|
||||
mdBook is written in **[Rust](https://www.rust-lang.org/)** and therefore needs to be compiled with **Cargo**, because we don't yet offer ready-to-go binaries. If you haven't already installed Rust, please go ahead and [install it](https://www.rust-lang.org/downloads.html) now.
|
||||
|
||||
Open your terminal and navigate to the directory of you choice. We need to clone the git repository and then build it with Cargo.
|
||||
### Install Crates.io version
|
||||
|
||||
Installing mdBook is relatively easy if you already have Rust and Cargo installed. You just have to type this snippet in your terminal:
|
||||
|
||||
```bash
|
||||
cargo install mdbook
|
||||
```
|
||||
|
||||
This will fetch the source code from [Crates.io](https://crates.io/) and compile it. You will have to add Cargo's `bin` directory to your `PATH`.
|
||||
|
||||
Run `mdbook help` in your terminal to verify if it works. Congratulations, you have installed mdBook!
|
||||
|
||||
|
||||
### Install Git version
|
||||
|
||||
The **[git version](https://github.com/azerupi/mdBook)** contains all the latest bug-fixes and features, that will be released in the next version on **Crates.io**, if you can't wait until the next release. You can build the git version yourself. Open your terminal and navigate to the directory of you choice. We need to clone the git repository and then build it with Cargo.
|
||||
|
||||
```bash
|
||||
git clone --depth=1 https://github.com/azerupi/mdBook.git
|
||||
cd mdBook
|
||||
cargo build --release
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
# The init command
|
||||
There is some minimal boilerplate that is the same for every new book. It's for this purpose that mdBook includes an `init` command.
|
||||
|
||||
The `init` command is used like this:
|
||||
|
||||
```
|
||||
```bash
|
||||
mdbook init
|
||||
```
|
||||
|
||||
It will create a couple of files and directories in the working directory so that you can
|
||||
spend more time writing your book and less setting it up.
|
||||
|
||||
The files set up for you are the following:
|
||||
|
||||
```
|
||||
When using the `init` command for the first time, a couple of files will be set up for you:
|
||||
```bash
|
||||
book-test/
|
||||
├── book
|
||||
└── src
|
||||
@@ -19,22 +16,23 @@ book-test/
|
||||
└── SUMMARY.md
|
||||
```
|
||||
|
||||
The `src` directory is were you write your book in markdown. It contains all the source files,
|
||||
- The `src` directory is were you write your book in markdown. It contains all the source files,
|
||||
configuration files, etc.
|
||||
|
||||
The `book` directory is where your book is rendered. All the output is ready to be uploaded
|
||||
to a server to be seen by the internet.
|
||||
- The `book` directory is where your book is rendered. All the output is ready to be uploaded
|
||||
to a server to be seen by your audience.
|
||||
|
||||
The `SUMMARY.md` file is the most important file, it's the skeleton of your book and is discussed in more detail in another [chapter](../format/summary.html).
|
||||
- The `SUMMARY.md` file is the most important file, it's the skeleton of your book and is discussed in more detail in another [chapter](../format/summary.html).
|
||||
|
||||
When a `SUMMARY.md` file already exists, the `init` command will generate the files according to the paths used in the `SUMMARY.md`
|
||||
#### Tip & Trick: Hidden Feature
|
||||
When a `SUMMARY.md` file already exists, the `init` command will first parse it and generate the missing files according to the paths used in the `SUMMARY.md`. This allows you to think and create the whole structure of your book and then let mdBook generate it for you.
|
||||
|
||||
#### Specify a directory
|
||||
|
||||
When using the `init` command, you can also specify a directory, instead of using the current working directory,
|
||||
by appending a path to the command:
|
||||
|
||||
```
|
||||
```bash
|
||||
mdbook init path/to/book
|
||||
```
|
||||
|
||||
|
||||
19
book-example/src/cli/test.md
Normal file
19
book-example/src/cli/test.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# The test command
|
||||
|
||||
When writing a book, you sometimes need to automate some tests. For example, [The Rust Programming Book](https://doc.rust-lang.org/stable/book/) uses a lot of code examples that could get outdated.
|
||||
Therefore it is very important for them to be able to automatically test these code examples.
|
||||
|
||||
mdBook supports a `test` command that will run all available tests in mdBook. At the moment, only one test is available:
|
||||
*"Test Rust code examples using Rustdoc"*, but I hope this will be expanded in the future to include more tests like:
|
||||
|
||||
- checking for broken links
|
||||
- checking for unused files
|
||||
- ...
|
||||
|
||||
In the future I would like the user to be able to enable / disable test from the `book.json` configuration file and support custom tests.
|
||||
|
||||
**How to use it:**
|
||||
```bash
|
||||
$ mdbook test
|
||||
[*]: Testing file: "/mdBook/book-example/src/README.md”
|
||||
```
|
||||
18
book-example/src/cli/watch.md
Normal file
18
book-example/src/cli/watch.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# The watch command
|
||||
|
||||
The `watch` command is useful when you want your book to be rendered on every file change.
|
||||
You could repeatedly issue `mdbook build` every time a file is changed. But using `mdbook watch` once will watch your files and will trigger a build automatically whenever you modify a file.
|
||||
|
||||
#### Specify a directory
|
||||
|
||||
Like `init` and `build`, `watch` can take a directory as argument to use instead of the
|
||||
current working directory.
|
||||
|
||||
```bash
|
||||
mdbook watch path/to/book
|
||||
```
|
||||
|
||||
|
||||
-----
|
||||
|
||||
***note:*** *the `watch` command has not gotten a lot of testing yet, there could be some rough edges. If you discover a problem, please report it [on Github](https://github.com/azerupi/mdBook/issues)*
|
||||
21
book-example/src/format/mathjax.md
Normal file
21
book-example/src/format/mathjax.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# MathJax Support
|
||||
|
||||
mdBook supports math equations through [MathJax](https://www.mathjax.org/).
|
||||
|
||||
**However the normal method for indication math equations with `$$` does not work (yet?).**
|
||||
|
||||
To indicate an inline equation \\( \int x = \frac{x^2}{2} \\) use
|
||||
```
|
||||
\\( \int x = \frac{x^2}{2} \\)
|
||||
```
|
||||
|
||||
To indicate a block equation
|
||||
|
||||
\\[ \mu = \frac{1}{N} \sum_{i=0} x_i \\]
|
||||
|
||||
|
||||
use
|
||||
|
||||
```
|
||||
\\[ \mu = \frac{1}{N} \sum_{i=0} x_i \\]
|
||||
```
|
||||
@@ -5,12 +5,51 @@ For syntax highlighting I use [Highlight.js](https://highlightjs.org) with a cus
|
||||
Automatic language detection has been turned off, so you will probably want to
|
||||
specify the programming language you use like this
|
||||
|
||||
<pre class="language-markdown"><code class="language-markdown">```rust
|
||||
<pre><code class="language-markdown">```rust
|
||||
fn main() {
|
||||
// Some code
|
||||
}
|
||||
```</code></pre>
|
||||
|
||||
## Custom theme
|
||||
Like the rest of the theme, the files used for syntax highlighting can be overridden with your own.
|
||||
|
||||
- ***highlight.js*** normally you shouldn't have to overwrite this file, unless you want to use a more recent version.
|
||||
- ***highlight.css*** theme used by highlight.js for syntax highlighting.
|
||||
|
||||
If you want to use another theme for `highlight.js` download it from their website, or make it yourself,
|
||||
rename it to `highlight.css` and put it in `src/theme` (or the equivalent if you changed your source folder)
|
||||
|
||||
Now your theme will be used instead of the default theme.
|
||||
|
||||
## Hiding code lines
|
||||
|
||||
There is a feature in mdBook that let's you hide code lines by prepending them with a `#`.
|
||||
|
||||
|
||||
```bash
|
||||
#fn main() {
|
||||
let x = 5;
|
||||
let y = 6;
|
||||
|
||||
println!("{}", x + y);
|
||||
#}
|
||||
```
|
||||
|
||||
Will render as
|
||||
|
||||
```rust
|
||||
#fn main() {
|
||||
let x = 5;
|
||||
let y = 7;
|
||||
|
||||
println!("{}", x + y);
|
||||
#}
|
||||
```
|
||||
|
||||
**At the moment, this only works for code examples that are annotated with `rust`. Because it would collide with semantics of some programming languages. In the future, we want to make this configurable through the `book.json` so that everyone can benefit from it.**
|
||||
|
||||
|
||||
## Improve default theme
|
||||
|
||||
If you think the default theme doesn't look quite right for a specific language, or could be improved.
|
||||
@@ -19,15 +58,3 @@ Feel free to [submit a new issue](https://github.com/azerupi/mdBook/issues) expl
|
||||
You could also create a pull-request with the proposed improvements.
|
||||
|
||||
Overall the theme should be light and sober, without to many flashy colors.
|
||||
|
||||
|
||||
## Custom theme
|
||||
Like the rest of the theme, the files used for syntax highlighting can be overwritten with your own.
|
||||
|
||||
- ***highlight.js*** normally you shouldn't have to overwrite this file. But if you need to, you can.
|
||||
- ***highlight.css*** theme used by highlight.js for syntax highlighting.
|
||||
|
||||
If you want to use another theme for `highlight.js` download it from their website, or make it yourself,
|
||||
rename it to `highlight.css` and put it in `src/theme` (or the equivalent if you changed your source folder)
|
||||
|
||||
Now your theme will be used instead of the default theme.
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# Theme
|
||||
|
||||
The default renderer uses a [handlebars](http://handlebarsjs.com/) template to render your markdown files in and comes with a default theme
|
||||
The default renderer uses a [handlebars](http://handlebarsjs.com/) template to render your markdown files and comes with a default theme
|
||||
included in the mdBook binary.
|
||||
|
||||
But the theme is totally customizable, you can replace every file from the theme by your own by adding a
|
||||
`theme` directory in your source folder. Create a new file with the name of the file you want to overwrite
|
||||
The theme is totally customizable, you can selectively replace every file from the theme by your own by adding a
|
||||
`theme` directory in your source folder. Create a new file with the name of the file you want to override
|
||||
and now that file will be used instead of the default file.
|
||||
|
||||
Here are the files you can overwrite:
|
||||
Here are the files you can override:
|
||||
|
||||
- ***index.hbs*** is the handlebars template.
|
||||
- ***book.css*** is the style used in the output. If you want to change the design of your book, this is probably the file you want to modify. Sometimes in conjunction with `index.hbs` when you want to radically change the layout.
|
||||
@@ -15,4 +15,7 @@ Here are the files you can overwrite:
|
||||
- ***highlight.js*** is the JavaScript that is used to highlight code snippets, you should not need to modify this.
|
||||
- ***highlight.css*** is the theme used for the code highlighting
|
||||
|
||||
***Note:*** *When you overwrite a file, it is possible that you break some functionality. Therefore I recommend to use the file from the default theme as template and only add / modify what you need. You can copy the default theme into your source directory automatically by using `mdbook init --theme`.*
|
||||
Generally, when you want to tweak the theme, you don't need to override all the files. If you only need changes in the stylesheet,
|
||||
there is no point in overriding all the other files. Because custom files take precedence over built-in ones, they will not get updated with new fixes / features.
|
||||
|
||||
**Note:** When you override a file, it is possible that you break some functionality. Therefore I recommend to use the file from the default theme as template and only add / modify what you need. You can copy the default theme into your source directory automatically by using `mdbook init --theme` just remove the files you don't want to override.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
mdBook is not only a command line tool, it can be used as a crate. You can extend it,
|
||||
integrate it in current projects. Here is a short example:
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
extern crate mdbook;
|
||||
|
||||
use mdbook::MDBook;
|
||||
|
||||
@@ -1 +1,13 @@
|
||||
# Contributors
|
||||
|
||||
Here is a list of the contributors who have helped improving mdBook. Big shout-out to them!
|
||||
|
||||
If you have contributed to mdBook and I forgot to add you, don't hesitate to add yourself to the list. If you are in the list, feel free to add your real name & contact information if you wish.
|
||||
|
||||
- [mdinger](https://github.com/mdinger)
|
||||
- Kevin ([kbknapp](https://github.com/kbknapp))
|
||||
- Steve Klabnik ([steveklabnik](https://github.com/steveklabnik))
|
||||
- Adam Solove ([asolove](https://github.com/asolove))
|
||||
- Wayne Nilsen ([waynenilsen](https://github.com/waynenilsen))
|
||||
- [funnkill](https://github.com/funkill)
|
||||
- Fu Gangqiang ([FuGangqiang](https://github.com/FuGangqiang))
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
#[macro_use]
|
||||
extern crate mdbook;
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
extern crate crossbeam;
|
||||
|
||||
// Dependencies for the Watch feature
|
||||
#[cfg(feature = "watch")]
|
||||
extern crate notify;
|
||||
#[cfg(feature = "watch")]
|
||||
extern crate time;
|
||||
|
||||
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
@@ -9,6 +18,13 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
use clap::{App, ArgMatches, SubCommand};
|
||||
|
||||
// Uses for the Watch feature
|
||||
#[cfg(feature = "watch")]
|
||||
use notify::Watcher;
|
||||
#[cfg(feature = "watch")]
|
||||
use std::sync::mpsc::channel;
|
||||
|
||||
|
||||
use mdbook::MDBook;
|
||||
|
||||
const NAME: &'static str = "mdbook";
|
||||
@@ -32,14 +48,19 @@ fn main() {
|
||||
.about("Build the book from the markdown files")
|
||||
.arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'"))
|
||||
.subcommand(SubCommand::with_name("watch")
|
||||
.about("Watch the files for changes"))
|
||||
.about("Watch the files for changes")
|
||||
.arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'"))
|
||||
.subcommand(SubCommand::with_name("test")
|
||||
.about("Test that code samples compile"))
|
||||
.get_matches();
|
||||
|
||||
// Check which subcomamnd the user ran...
|
||||
let res = match matches.subcommand() {
|
||||
("init", Some(sub_matches)) => init(sub_matches),
|
||||
("build", Some(sub_matches)) => build(sub_matches),
|
||||
("watch", _) => unimplemented!(),
|
||||
#[cfg(feature = "watch")]
|
||||
("watch", Some(sub_matches)) => watch(sub_matches),
|
||||
("test", Some(sub_matches)) => test(sub_matches),
|
||||
(_, _) => unreachable!()
|
||||
};
|
||||
|
||||
@@ -48,6 +69,8 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Simple function that user comfirmation
|
||||
fn confirm() -> bool {
|
||||
io::stdout().flush().unwrap();
|
||||
let mut s = String::new();
|
||||
@@ -58,6 +81,8 @@ fn confirm() -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Init command implementation
|
||||
fn init(args: &ArgMatches) -> Result<(), Box<Error>> {
|
||||
|
||||
let book_dir = get_book_dir(args);
|
||||
@@ -95,6 +120,8 @@ fn init(args: &ArgMatches) -> Result<(), Box<Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
// Build command implementation
|
||||
fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
|
||||
let book_dir = get_book_dir(args);
|
||||
let mut book = MDBook::new(&book_dir).read_config();
|
||||
@@ -104,6 +131,88 @@ fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
// Watch command implementation
|
||||
#[cfg(feature = "watch")]
|
||||
fn watch(args: &ArgMatches) -> Result<(), Box<Error>> {
|
||||
let book_dir = get_book_dir(args);
|
||||
let book = MDBook::new(&book_dir).read_config();
|
||||
|
||||
// Create a channel to receive the events.
|
||||
let (tx, rx) = channel();
|
||||
|
||||
let w: Result<notify::RecommendedWatcher, notify::Error> = notify::Watcher::new(tx);
|
||||
|
||||
match w {
|
||||
Ok(mut watcher) => {
|
||||
|
||||
// Add the source directory to the watcher
|
||||
if let Err(e) = watcher.watch(book.get_src()) {
|
||||
println!("Error while watching {:?}:\n {:?}", book.get_src(), e);
|
||||
::std::process::exit(0);
|
||||
};
|
||||
|
||||
// Add the book.json file to the watcher if it exists, because it's not
|
||||
// located in the source directory
|
||||
if let Err(_) = watcher.watch(book_dir.join("book.json")) {
|
||||
// do nothing if book.json is not found
|
||||
}
|
||||
|
||||
let previous_time = time::get_time().sec;
|
||||
|
||||
crossbeam::scope(|scope| {
|
||||
loop {
|
||||
match rx.recv() {
|
||||
Ok(event) => {
|
||||
|
||||
// Skip the event if an event has already been issued in the last second
|
||||
if time::get_time().sec - previous_time < 1 { continue }
|
||||
|
||||
if let Some(path) = event.path {
|
||||
// Trigger the build process in a new thread (to keep receiving events)
|
||||
scope.spawn(move || {
|
||||
println!("File changed: {:?}\nBuilding book...\n", path);
|
||||
match build(args) {
|
||||
Err(e) => println!("Error while building: {:?}", e),
|
||||
_ => {}
|
||||
}
|
||||
println!("");
|
||||
});
|
||||
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
println!("An error occured: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
Err(e) => {
|
||||
println!("Error while trying to watch the files:\n\n\t{:?}", e);
|
||||
::std::process::exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn test(args: &ArgMatches) -> Result<(), Box<Error>> {
|
||||
let book_dir = get_book_dir(args);
|
||||
let mut book = MDBook::new(&book_dir).read_config();
|
||||
|
||||
try!(book.test());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn get_book_dir(args: &ArgMatches) -> PathBuf {
|
||||
if let Some(dir) = args.value_of("dir") {
|
||||
// Check if path is relative from current dir, or absolute...
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
use std::error::Error;
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
use std::io::ErrorKind;
|
||||
use std::process::Command;
|
||||
|
||||
use {BookConfig, BookItem, theme, parse, utils};
|
||||
use book::BookItems;
|
||||
@@ -257,6 +260,39 @@ impl MDBook {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn test(&mut self) -> Result<(), Box<Error>> {
|
||||
// read in the chapters
|
||||
try!(self.parse_summary());
|
||||
for item in self.iter() {
|
||||
|
||||
match *item {
|
||||
BookItem::Chapter(_, ref ch) => {
|
||||
if ch.path != PathBuf::new() {
|
||||
|
||||
let path = self.get_src().join(&ch.path);
|
||||
|
||||
println!("[*]: Testing file: {:?}", path);
|
||||
|
||||
let output_result = Command::new("rustdoc")
|
||||
.arg(&path)
|
||||
.arg("--test")
|
||||
.output();
|
||||
let output = try!(output_result);
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(Box::new(io::Error::new(ErrorKind::Other, format!(
|
||||
"{}\n{}",
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr)))) as Box<Error>);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_dest(mut self, dest: &Path) -> Self {
|
||||
|
||||
// Handle absolute and relative paths
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
extern crate handlebars;
|
||||
extern crate rustc_serialize;
|
||||
extern crate pulldown_cmark;
|
||||
|
||||
use renderer::html_handlebars::helpers;
|
||||
use renderer::Renderer;
|
||||
@@ -16,7 +15,7 @@ use std::collections::BTreeMap;
|
||||
|
||||
use self::handlebars::{Handlebars, JsonRender};
|
||||
use self::rustc_serialize::json::{Json, ToJson};
|
||||
use self::pulldown_cmark::{Parser, html};
|
||||
|
||||
|
||||
pub struct HtmlHandlebars;
|
||||
|
||||
@@ -73,7 +72,7 @@ impl Renderer for HtmlHandlebars {
|
||||
try!(f.read_to_string(&mut content));
|
||||
|
||||
// Render markdown using the pulldown-cmark crate
|
||||
content = render_html(&content);
|
||||
content = utils::render_markdown(&content);
|
||||
print_content.push_str(&content);
|
||||
|
||||
// Remove content from previous file and render content for this one
|
||||
@@ -114,7 +113,7 @@ impl Renderer for HtmlHandlebars {
|
||||
|
||||
// This could cause a problem when someone displays code containing <base href=...>
|
||||
// on the front page, however this case should be very very rare...
|
||||
content = content.lines().filter(|line| !line.contains("<base href=")).collect();
|
||||
content = content.lines().filter(|line| !line.contains("<base href=")).collect::<Vec<&str>>().join("\n");
|
||||
|
||||
try!(index_file.write_all(content.as_bytes()));
|
||||
|
||||
@@ -241,10 +240,3 @@ fn make_data(book: &MDBook) -> Result<BTreeMap<String,Json>, Box<Error>> {
|
||||
debug!("[*]: JSON constructed");
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
fn render_html(text: &str) -> String {
|
||||
let mut s = String::with_capacity(text.len() * 3 / 2);
|
||||
let p = Parser::new(&text);
|
||||
html::push_html(&mut s, p);
|
||||
s
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ pub fn previous(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext
|
||||
// Decode json format
|
||||
let decoded: Vec<BTreeMap<String, String>> = match json::decode(&chapters.to_string()) {
|
||||
Ok(data) => data,
|
||||
Err(_) => return Err(RenderError{ desc: "Could not decode the JSON data"}),
|
||||
Err(_) => return Err(RenderError{ desc: "Could not decode the JSON data".to_owned()}),
|
||||
};
|
||||
let mut previous: Option<BTreeMap<String, String>> = None;
|
||||
|
||||
@@ -55,7 +55,7 @@ pub fn previous(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext
|
||||
},
|
||||
None => {
|
||||
debug!("[*]: No title found for chapter");
|
||||
return Err(RenderError{ desc: "No title found for chapter in JSON data" })
|
||||
return Err(RenderError{ desc: "No title found for chapter in JSON data".to_owned() })
|
||||
}
|
||||
};
|
||||
|
||||
@@ -68,10 +68,10 @@ pub fn previous(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext
|
||||
|
||||
match path.to_str() {
|
||||
Some(p) => { previous_chapter.insert("link".to_owned(), p.to_json()); },
|
||||
None => return Err(RenderError{ desc: "Link could not be converted to str" })
|
||||
None => return Err(RenderError{ desc: "Link could not be converted to str".to_owned() })
|
||||
}
|
||||
},
|
||||
None => return Err(RenderError{ desc: "No path found for chapter in JSON data" })
|
||||
None => return Err(RenderError{ desc: "No path found for chapter in JSON data".to_owned() })
|
||||
}
|
||||
|
||||
debug!("[*]: Inject in context");
|
||||
@@ -84,7 +84,7 @@ pub fn previous(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext
|
||||
Some(t) => {
|
||||
try!(t.render(&updated_context, r, rc));
|
||||
},
|
||||
None => return Err(RenderError{ desc: "Error with the handlebars template" })
|
||||
None => return Err(RenderError{ desc: "Error with the handlebars template".to_owned() })
|
||||
}
|
||||
|
||||
}
|
||||
@@ -124,7 +124,7 @@ pub fn next(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext) ->
|
||||
// Decode json format
|
||||
let decoded: Vec<BTreeMap<String, String>> = match json::decode(&chapters.to_string()) {
|
||||
Ok(data) => data,
|
||||
Err(_) => return Err(RenderError{ desc: "Could not decode the JSON data"}),
|
||||
Err(_) => return Err(RenderError{ desc: "Could not decode the JSON data".to_owned() }),
|
||||
};
|
||||
let mut previous: Option<BTreeMap<String, String>> = None;
|
||||
|
||||
@@ -140,7 +140,7 @@ pub fn next(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext) ->
|
||||
|
||||
let previous_path = match previous.get("path") {
|
||||
Some(p) => p,
|
||||
None => return Err(RenderError{ desc: "No path found for chapter in JSON data"})
|
||||
None => return Err(RenderError{ desc: "No path found for chapter in JSON data".to_owned() })
|
||||
};
|
||||
|
||||
if previous_path == ¤t {
|
||||
@@ -155,7 +155,7 @@ pub fn next(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext) ->
|
||||
debug!("[*]: Inserting title: {}", n);
|
||||
next_chapter.insert("title".to_owned(), n.to_json());
|
||||
}
|
||||
None => return Err(RenderError{ desc: "No title found for chapter in JSON data"})
|
||||
None => return Err(RenderError{ desc: "No title found for chapter in JSON data".to_owned() })
|
||||
}
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ pub fn next(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext) ->
|
||||
|
||||
match link.to_str() {
|
||||
Some(l) => { next_chapter.insert("link".to_owned(), l.to_json()); },
|
||||
None => return Err(RenderError{ desc: "Link could not converted to str"})
|
||||
None => return Err(RenderError{ desc: "Link could not converted to str".to_owned() })
|
||||
}
|
||||
|
||||
debug!("[*]: Inject in context");
|
||||
@@ -178,7 +178,7 @@ pub fn next(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext) ->
|
||||
Some(t) => {
|
||||
try!(t.render(&updated_context, r, rc));
|
||||
},
|
||||
None => return Err(RenderError{ desc: "Error with the handlebars template" })
|
||||
None => return Err(RenderError{ desc: "Error with the handlebars template".to_owned() })
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
extern crate handlebars;
|
||||
extern crate rustc_serialize;
|
||||
extern crate pulldown_cmark;
|
||||
|
||||
use std::path::Path;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use self::rustc_serialize::json;
|
||||
use self::handlebars::{Handlebars, HelperDef, RenderError, RenderContext, Helper, Context};
|
||||
use self::pulldown_cmark::{Parser, html, Event, Tag};
|
||||
|
||||
// Handlebars helper to construct TOC
|
||||
#[derive(Clone, Copy)]
|
||||
@@ -93,7 +95,24 @@ impl HelperDef for RenderToc {
|
||||
}
|
||||
|
||||
if let Some(name) = item.get("name") {
|
||||
try!(rc.writer.write(name.as_bytes()));
|
||||
// Render only inline code blocks
|
||||
|
||||
// filter all events that are not inline code blocks
|
||||
let parser = Parser::new(&name).filter(|event|{
|
||||
match event {
|
||||
&Event::Start(Tag::Code) | &Event::End(Tag::Code) => true,
|
||||
&Event::InlineHtml(_) => true,
|
||||
&Event::Text(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
});
|
||||
|
||||
// render markdown to html
|
||||
let mut markdown_parsed_name = String::with_capacity(name.len() * 3 / 2);
|
||||
html::push_html(&mut markdown_parsed_name, parser);
|
||||
|
||||
// write to the handlebars template
|
||||
try!(rc.writer.write(markdown_parsed_name.as_bytes()));
|
||||
}
|
||||
|
||||
if path_exists {
|
||||
|
||||
@@ -9,10 +9,22 @@ body {
|
||||
.right {
|
||||
float: right;
|
||||
}
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
h2,
|
||||
h3 {
|
||||
margin-top: 2.5em;
|
||||
}
|
||||
h4,
|
||||
h5 {
|
||||
margin-top: 2em;
|
||||
}
|
||||
.header + .header h3,
|
||||
.header + .header h4,
|
||||
.header + .header h5 {
|
||||
margin-top: 1em;
|
||||
}
|
||||
.sidebar {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
@@ -37,6 +49,9 @@ h3 {
|
||||
left: -300px;
|
||||
}
|
||||
}
|
||||
.sidebar code {
|
||||
line-height: 2em;
|
||||
}
|
||||
.sidebar-hidden .sidebar {
|
||||
left: -300px;
|
||||
}
|
||||
@@ -222,7 +237,7 @@ h3 {
|
||||
left: 0;
|
||||
}
|
||||
.next {
|
||||
right: 0;
|
||||
right: 15px;
|
||||
}
|
||||
.theme-popup {
|
||||
position: fixed;
|
||||
@@ -270,9 +285,30 @@ h3 {
|
||||
}
|
||||
}
|
||||
.light {
|
||||
/* Inline code */
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
}
|
||||
.light :not(pre) > .hljs {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
padding: 0.1em 0.3em;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.light pre {
|
||||
position: relative;
|
||||
}
|
||||
.light pre > i {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
color: #364149;
|
||||
cursor: pointer;
|
||||
}
|
||||
.light pre > i :hover {
|
||||
color: #008cff;
|
||||
}
|
||||
.light .sidebar {
|
||||
background-color: #fafafa;
|
||||
color: #364149;
|
||||
@@ -292,8 +328,11 @@ h3 {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.light .menu-bar,
|
||||
.light .menu-bar:visited,
|
||||
.light .nav-chapters,
|
||||
.light .mobile-nav-chapters {
|
||||
.light .nav-chapters:visited,
|
||||
.light .mobile-nav-chapters,
|
||||
.light .mobile-nav-chapters:visited {
|
||||
color: #ccc;
|
||||
}
|
||||
.light .menu-bar i:hover,
|
||||
@@ -307,7 +346,8 @@ h3 {
|
||||
.light .mobile-nav-chapters {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
.light .content a {
|
||||
.light .content a:link,
|
||||
.light a:visited {
|
||||
color: #4183c4;
|
||||
}
|
||||
.light .theme-popup {
|
||||
@@ -318,9 +358,30 @@ h3 {
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
.coal {
|
||||
/* Inline code */
|
||||
color: #98a3ad;
|
||||
background-color: #141617;
|
||||
}
|
||||
.coal :not(pre) > .hljs {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
padding: 0.1em 0.3em;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.coal pre {
|
||||
position: relative;
|
||||
}
|
||||
.coal pre > i {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
color: #a1adb8;
|
||||
cursor: pointer;
|
||||
}
|
||||
.coal pre > i :hover {
|
||||
color: #3473ad;
|
||||
}
|
||||
.coal .sidebar {
|
||||
background-color: #292c2f;
|
||||
color: #a1adb8;
|
||||
@@ -340,8 +401,11 @@ h3 {
|
||||
background-color: #393939;
|
||||
}
|
||||
.coal .menu-bar,
|
||||
.coal .menu-bar:visited,
|
||||
.coal .nav-chapters,
|
||||
.coal .mobile-nav-chapters {
|
||||
.coal .nav-chapters:visited,
|
||||
.coal .mobile-nav-chapters,
|
||||
.coal .mobile-nav-chapters:visited {
|
||||
color: #43484d;
|
||||
}
|
||||
.coal .menu-bar i:hover,
|
||||
@@ -355,7 +419,8 @@ h3 {
|
||||
.coal .mobile-nav-chapters {
|
||||
background-color: #292c2f;
|
||||
}
|
||||
.coal .content a {
|
||||
.coal .content a:link,
|
||||
.coal a:visited {
|
||||
color: #2b79a2;
|
||||
}
|
||||
.coal .theme-popup {
|
||||
@@ -366,9 +431,30 @@ h3 {
|
||||
background-color: #1f2124;
|
||||
}
|
||||
.navy {
|
||||
/* Inline code */
|
||||
color: #bcbdd0;
|
||||
background-color: #161923;
|
||||
}
|
||||
.navy :not(pre) > .hljs {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
padding: 0.1em 0.3em;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.navy pre {
|
||||
position: relative;
|
||||
}
|
||||
.navy pre > i {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
color: #c8c9db;
|
||||
cursor: pointer;
|
||||
}
|
||||
.navy pre > i :hover {
|
||||
color: #2b79a2;
|
||||
}
|
||||
.navy .sidebar {
|
||||
background-color: #282d3f;
|
||||
color: #c8c9db;
|
||||
@@ -388,8 +474,11 @@ h3 {
|
||||
background-color: #2d334f;
|
||||
}
|
||||
.navy .menu-bar,
|
||||
.navy .menu-bar:visited,
|
||||
.navy .nav-chapters,
|
||||
.navy .mobile-nav-chapters {
|
||||
.navy .nav-chapters:visited,
|
||||
.navy .mobile-nav-chapters,
|
||||
.navy .mobile-nav-chapters:visited {
|
||||
color: #737480;
|
||||
}
|
||||
.navy .menu-bar i:hover,
|
||||
@@ -403,7 +492,8 @@ h3 {
|
||||
.navy .mobile-nav-chapters {
|
||||
background-color: #282d3f;
|
||||
}
|
||||
.navy .content a {
|
||||
.navy .content a:link,
|
||||
.navy a:visited {
|
||||
color: #2b79a2;
|
||||
}
|
||||
.navy .theme-popup {
|
||||
@@ -414,9 +504,30 @@ h3 {
|
||||
background-color: #282e40;
|
||||
}
|
||||
.rust {
|
||||
/* Inline code */
|
||||
color: #262625;
|
||||
background-color: #e1e1db;
|
||||
}
|
||||
.rust :not(pre) > .hljs {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
padding: 0.1em 0.3em;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.rust pre {
|
||||
position: relative;
|
||||
}
|
||||
.rust pre > i {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
color: #c8c9db;
|
||||
cursor: pointer;
|
||||
}
|
||||
.rust pre > i :hover {
|
||||
color: #e69f67;
|
||||
}
|
||||
.rust .sidebar {
|
||||
background-color: #3b2e2a;
|
||||
color: #c8c9db;
|
||||
@@ -436,8 +547,11 @@ h3 {
|
||||
background-color: #45373a;
|
||||
}
|
||||
.rust .menu-bar,
|
||||
.rust .menu-bar:visited,
|
||||
.rust .nav-chapters,
|
||||
.rust .mobile-nav-chapters {
|
||||
.rust .nav-chapters:visited,
|
||||
.rust .mobile-nav-chapters,
|
||||
.rust .mobile-nav-chapters:visited {
|
||||
color: #737480;
|
||||
}
|
||||
.rust .menu-bar i:hover,
|
||||
@@ -451,7 +565,8 @@ h3 {
|
||||
.rust .mobile-nav-chapters {
|
||||
background-color: #3b2e2a;
|
||||
}
|
||||
.rust .content a {
|
||||
.rust .content a:link,
|
||||
.rust a:visited {
|
||||
color: #2b79a2;
|
||||
}
|
||||
.rust .theme-popup {
|
||||
|
||||
@@ -8,7 +8,7 @@ $( document ).ready(function() {
|
||||
|
||||
// Set theme
|
||||
var theme = localStorage.getItem('theme');
|
||||
if (theme == null) { theme = 'light'; }
|
||||
if (theme === null) { theme = 'light'; }
|
||||
|
||||
set_theme(theme);
|
||||
|
||||
@@ -23,11 +23,37 @@ $( document ).ready(function() {
|
||||
hljs.highlightBlock(block);
|
||||
});
|
||||
|
||||
var KEY_CODES = {
|
||||
PREVIOUS_KEY: 37,
|
||||
NEXT_KEY: 39
|
||||
};
|
||||
|
||||
$(document).on('keydown', function (e) {
|
||||
switch (e.keyCode) {
|
||||
case KEY_CODES.NEXT_KEY:
|
||||
e.preventDefault();
|
||||
window.location.href = $('.nav-chapters.next').attr('href');
|
||||
break;
|
||||
case KEY_CODES.PREVIOUS_KEY:
|
||||
e.preventDefault();
|
||||
window.location.href = $('.nav-chapters.previous').attr('href');
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// Interesting DOM Elements
|
||||
var html = $("html");
|
||||
var sidebar = $("#sidebar");
|
||||
var page_wrapper = $("#page-wrapper");
|
||||
var content = $("#content");
|
||||
|
||||
|
||||
// Add anchors for all content headers
|
||||
content.find("h1, h2, h3, h4, h5").wrap(function(){
|
||||
var wrapper = $("<a class=\"header\">");
|
||||
wrapper.attr("name", $(this).text());
|
||||
return wrapper;
|
||||
});
|
||||
|
||||
|
||||
// Toggle sidebar
|
||||
@@ -50,6 +76,13 @@ $( document ).ready(function() {
|
||||
});
|
||||
|
||||
|
||||
// Scroll sidebar to current active section
|
||||
var activeSection = sidebar.find(".active");
|
||||
if(activeSection.length) {
|
||||
sidebar.scrollTop(activeSection.offset().top);
|
||||
}
|
||||
|
||||
|
||||
// Print button
|
||||
$("#print-button").click(function(){
|
||||
var printWindow = window.open("print.html");
|
||||
@@ -77,7 +110,7 @@ $( document ).ready(function() {
|
||||
$('.theme').click(function(){
|
||||
var theme = $(this).attr('id');
|
||||
|
||||
set_theme(theme)
|
||||
set_theme(theme);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -96,4 +129,54 @@ $( document ).ready(function() {
|
||||
|
||||
$('body').removeClass().addClass(theme);
|
||||
}
|
||||
|
||||
|
||||
// Hide Rust code lines prepended with a specific character
|
||||
var hiding_character = "#";
|
||||
|
||||
$("code.language-rust").each(function(i, block){
|
||||
|
||||
// hide lines
|
||||
var lines = $(this).html().split("\n");
|
||||
var first_non_hidden_line = false;
|
||||
var lines_hidden = false;
|
||||
|
||||
for(var n = 0; n < lines.length; n++){
|
||||
if($.trim(lines[n])[0] == hiding_character){
|
||||
if(first_non_hidden_line){
|
||||
lines[n] = "<span class=\"hidden\">" + "\n" + lines[n].substr(1) + "</span>";
|
||||
}
|
||||
else {
|
||||
lines[n] = "<span class=\"hidden\">" + lines[n].substr(1) + "\n" + "</span>";
|
||||
}
|
||||
lines_hidden = true;
|
||||
}
|
||||
else if(first_non_hidden_line) {
|
||||
lines[n] = "\n" + lines[n];
|
||||
}
|
||||
else {
|
||||
first_non_hidden_line = true;
|
||||
}
|
||||
}
|
||||
$(this).html(lines.join(""));
|
||||
|
||||
// If no lines were hidden, return
|
||||
if(!lines_hidden) { return; }
|
||||
|
||||
// add expand button
|
||||
$(this).parent().prepend("<i class=\"fa fa-expand\"></i>");
|
||||
|
||||
$(this).parent().find("i").click(function(e){
|
||||
if( $(this).hasClass("fa-expand") ) {
|
||||
$(this).removeClass("fa-expand").addClass("fa-compress");
|
||||
$(this).parent().find("span.hidden").removeClass("hidden").addClass("unhidden");
|
||||
}
|
||||
else {
|
||||
$(this).removeClass("fa-compress").addClass("fa-expand");
|
||||
$(this).parent().find("span.unhidden").removeClass("unhidden").addClass("hidden");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
@@ -10,14 +10,6 @@
|
||||
-webkit-text-size-adjust: none;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre) > .hljs {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
padding: 0.1em 0.3em;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
|
||||
/* Atelier-Dune Comment */
|
||||
.hljs-comment {
|
||||
|
||||
@@ -84,13 +84,13 @@
|
||||
</div>
|
||||
|
||||
{{#previous}}
|
||||
<a href="{{link}}" class="nav-chapters previous">
|
||||
<a href="{{link}}" class="nav-chapters previous" title="You can navigate through the chapters using the arrow keys">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
{{/previous}}
|
||||
|
||||
{{#next}}
|
||||
<a href="{{link}}" class="nav-chapters next">
|
||||
<a href="{{link}}" class="nav-chapters next" title="You can navigate through the chapters using the arrow keys">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
{{/next}}
|
||||
|
||||
@@ -11,4 +11,11 @@ html, body {
|
||||
float: right
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
h2, h3 { margin-top: 2.5em }
|
||||
h4, h5 { margin-top: 2em }
|
||||
|
||||
.header + .header h3, .header + .header h4, .header + .header h5 { margin-top: 1em }
|
||||
|
||||
@@ -20,4 +20,4 @@
|
||||
.mobile-nav-chapters { display: none }
|
||||
.nav-chapters:hover { text-decoration: none }
|
||||
.previous { left: 0 }
|
||||
.next { right: 0 }
|
||||
.next { right: 15px }
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
@media only screen and (max-width: 1060px) {
|
||||
left: - $sidebar-width
|
||||
}
|
||||
|
||||
code {
|
||||
line-height: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-hidden .sidebar {
|
||||
|
||||
@@ -1,4 +1,28 @@
|
||||
.{unquote($theme-name)} {
|
||||
/* Inline code */
|
||||
:not(pre) > .hljs {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
padding: 0.1em 0.3em;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
pre {
|
||||
position: relative;
|
||||
}
|
||||
pre > i {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
|
||||
color: $sidebar-fg;
|
||||
cursor: pointer;
|
||||
|
||||
:hover {
|
||||
color: $sidebar-active;
|
||||
}
|
||||
}
|
||||
|
||||
color: $fg
|
||||
background-color: $bg
|
||||
|
||||
@@ -13,7 +37,7 @@
|
||||
a { color: $sidebar-fg }
|
||||
|
||||
.active,
|
||||
a:hover {
|
||||
a:hover, {
|
||||
/* Animate color change */
|
||||
color: $sidebar-active
|
||||
}
|
||||
@@ -24,8 +48,11 @@
|
||||
}
|
||||
|
||||
.menu-bar,
|
||||
.menu-bar:visited,
|
||||
.nav-chapters,
|
||||
.mobile-nav-chapters {
|
||||
.nav-chapters:visited,
|
||||
.mobile-nav-chapters,
|
||||
.mobile-nav-chapters:visited {
|
||||
color: $icons
|
||||
}
|
||||
|
||||
@@ -43,7 +70,7 @@
|
||||
background-color: $sidebar-bg
|
||||
}
|
||||
|
||||
.content a {
|
||||
.content a:link, a:visited {
|
||||
color: $links
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
extern crate pulldown_cmark;
|
||||
|
||||
use std::path::{Path, PathBuf, Component};
|
||||
use std::error::Error;
|
||||
use std::fs::{self, metadata, File};
|
||||
|
||||
use self::pulldown_cmark::{Parser, html};
|
||||
|
||||
/// This is copied from the rust source code until Path_ Ext stabilizes.
|
||||
/// You can use it, but be aware that it will be removed when those features go to rust stable
|
||||
pub trait PathExt {
|
||||
@@ -131,7 +135,7 @@ pub fn remove_dir_content(dir: &Path) -> Result<(), Box<Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// **Untested!**
|
||||
///
|
||||
///
|
||||
/// Copies all files of a directory to another one except the files with the extensions given in the
|
||||
/// `ext_blacklist` array
|
||||
@@ -178,6 +182,18 @@ pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blackl
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
///
|
||||
/// Wrapper around the pulldown-cmark parser and renderer to render markdown
|
||||
|
||||
pub fn render_markdown(text: &str) -> String {
|
||||
let mut s = String::with_capacity(text.len() * 3 / 2);
|
||||
let p = Parser::new(&text);
|
||||
html::push_html(&mut s, p);
|
||||
s
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user