Merge remote-tracking branch 'upstream/master' into split_commands

This commit is contained in:
Michal Budzynski 2017-06-27 13:06:19 +02:00
commit 5e088d92c9
9 changed files with 76 additions and 92 deletions

View File

@ -247,7 +247,7 @@ impl MDBook {
utils::fs::remove_dir_content(htmlconfig.get_destination())?;
}
self.renderer.render(&self)
self.renderer.render(self)
}
@ -295,8 +295,7 @@ impl MDBook {
}
pub fn write_file<P: AsRef<Path>>(&self, filename: P, content: &[u8]) -> Result<()> {
let path = self.get_destination()
.ok_or(String::from("HtmlConfig not set, could not find a destination"))?
let path = self.get_destination().ok_or_else(|| String::from("HtmlConfig not set, could not find a destination"))?
.join(filename);
utils::fs::create_file(&path)?

View File

@ -18,7 +18,7 @@ pub struct JsonConfig {
}
/// Returns a JsonConfig from a JSON string
/// Returns a `JsonConfig` from a JSON string
///
/// ```
/// # use mdbook::config::jsonconfig::JsonConfig;
@ -35,8 +35,8 @@ pub struct JsonConfig {
impl JsonConfig {
pub fn from_json(input: &str) -> Result<Self> {
let config: JsonConfig = serde_json::from_str(input)
.chain_err(|| format!("Could not parse JSON"))?;
.chain_err(|| "Could not parse JSON")?;
return Ok(config);
Ok(config)
}
}

View File

@ -31,7 +31,7 @@ pub struct TomlHtmlConfig {
pub additional_js: Option<Vec<PathBuf>>,
}
/// Returns a TomlConfig from a TOML string
/// Returns a `TomlConfig` from a TOML string
///
/// ```
/// # use mdbook::config::tomlconfig::TomlConfig;
@ -49,7 +49,7 @@ impl TomlConfig {
let config: TomlConfig = toml::from_str(input)
.chain_err(|| "Could not parse TOML")?;
return Ok(config);
Ok(config)
}
}

View File

@ -77,7 +77,7 @@ impl HtmlHandlebars {
ctx.book.write_file(filename, &rendered.into_bytes())?;
if ctx.is_index {
self.render_index(&ctx.book, ch, &ctx.destination)?;
self.render_index(ctx.book, ch, &ctx.destination)?;
}
}
},
@ -121,10 +121,10 @@ impl HtmlHandlebars {
}
fn post_process(&self, rendered: String) -> String {
let rendered = build_header_links(rendered, "print.html");
let rendered = fix_anchor_links(rendered, "print.html");
let rendered = fix_code_blocks(rendered);
let rendered = add_playpen_pre(rendered);
let rendered = build_header_links(&rendered, "print.html");
let rendered = fix_anchor_links(&rendered, "print.html");
let rendered = fix_code_blocks(&rendered);
let rendered = add_playpen_pre(&rendered);
rendered
}
@ -293,7 +293,7 @@ impl Renderer for HtmlHandlebars {
self.copy_additional_css_and_js(book)?;
// Copy all remaining files
utils::fs::copy_files_except_ext(book.get_source(), &destination, true, &["md"])?;
utils::fs::copy_files_except_ext(book.get_source(), destination, true, &["md"])?;
Ok(())
}
@ -399,12 +399,12 @@ fn make_data(book: &MDBook) -> Result<serde_json::Map<String, serde_json::Value>
/// Goes through the rendered HTML, making sure all header tags are wrapped in
/// an anchor so people can link to sections directly.
fn build_header_links(html: String, filename: &str) -> String {
fn build_header_links(html: &str, filename: &str) -> String {
let regex = Regex::new(r"<h(\d)>(.*?)</h\d>").unwrap();
let mut id_counter = HashMap::new();
regex
.replace_all(&html, |caps: &Captures| {
.replace_all(html, |caps: &Captures| {
let level = caps[1].parse().expect(
"Regex should ensure we only ever get numbers here",
);
@ -477,10 +477,10 @@ fn id_from_content(content: &str) -> String {
// anchors to the same page (href="#anchor") do not work because of
// <base href="../"> pointing to the root folder. This function *fixes*
// that in a very inelegant way
fn fix_anchor_links(html: String, filename: &str) -> String {
fn fix_anchor_links(html: &str, filename: &str) -> String {
let regex = Regex::new(r##"<a([^>]+)href="#([^"]+)"([^>]*)>"##).unwrap();
regex
.replace_all(&html, |caps: &Captures| {
.replace_all(html, |caps: &Captures| {
let before = &caps[1];
let anchor = &caps[2];
let after = &caps[3];
@ -505,10 +505,10 @@ fn fix_anchor_links(html: String, filename: &str) -> String {
// }
// ```
// This function replaces all commas by spaces in the code block classes
fn fix_code_blocks(html: String) -> String {
fn fix_code_blocks(html: &str) -> String {
let regex = Regex::new(r##"<code([^>]+)class="([^"]+)"([^>]*)>"##).unwrap();
regex
.replace_all(&html, |caps: &Captures| {
.replace_all(html, |caps: &Captures| {
let before = &caps[1];
let classes = &caps[2].replace(",", " ");
let after = &caps[3];
@ -518,10 +518,10 @@ fn fix_code_blocks(html: String) -> String {
.into_owned()
}
fn add_playpen_pre(html: String) -> String {
fn add_playpen_pre(html: &str) -> String {
let regex = Regex::new(r##"((?s)<code[^>]?class="([^"]+)".*?>(.*?)</code>)"##).unwrap();
regex
.replace_all(&html, |caps: &Captures| {
.replace_all(html, |caps: &Captures| {
let text = &caps[1];
let classes = &caps[2];
let code = &caps[3];
@ -547,7 +547,7 @@ fn add_playpen_pre(html: String) -> String {
}
} else {
// not language-rust, so no-op
format!("{}", text)
text.to_owned()
}
})
.into_owned()
@ -602,7 +602,7 @@ mod tests {
];
for (src, should_be) in inputs {
let got = build_header_links(src.to_string(), "bar.rs");
let got = build_header_links(src, "bar.rs");
assert_eq!(got, should_be);
}
}

View File

@ -18,8 +18,7 @@ pub fn previous(_h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(
})?;
let current = rc.evaluate_absolute("path")?
.as_str()
.ok_or(RenderError::new("Type error for `path`, string expected"))?
.as_str().ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
.replace("\"", "");
let mut previous: Option<BTreeMap<String, String>> = None;
@ -41,8 +40,7 @@ pub fn previous(_h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(
// Chapter title
previous
.get("name")
.ok_or(RenderError::new("No title found for chapter in JSON data"))
.get("name").ok_or_else(|| RenderError::new("No title found for chapter in JSON data"))
.and_then(|n| {
previous_chapter.insert("title".to_owned(), json!(n));
Ok(())
@ -51,13 +49,11 @@ pub fn previous(_h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(
// Chapter link
previous
.get("path")
.ok_or(RenderError::new("No path found for chapter in JSON data"))
.get("path").ok_or_else(|| RenderError::new("No path found for chapter in JSON data"))
.and_then(|p| {
Path::new(p)
.with_extension("html")
.to_str()
.ok_or(RenderError::new("Link could not be converted to str"))
.to_str().ok_or_else(|| RenderError::new("Link could not be converted to str"))
.and_then(|p| {
previous_chapter
.insert("link".to_owned(), json!(p.replace("\\", "/")));
@ -68,8 +64,7 @@ pub fn previous(_h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(
debug!("[*]: Render template");
// Render template
_h.template()
.ok_or(RenderError::new("Error with the handlebars template"))
_h.template().ok_or_else(|| RenderError::new("Error with the handlebars template"))
.and_then(|t| {
let mut local_rc = rc.with_context(Context::wraps(&previous_chapter));
t.render(r, &mut local_rc)
@ -101,8 +96,7 @@ pub fn next(_h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(), R
.map_err(|_| RenderError::new("Could not decode the JSON data"))
})?;
let current = rc.evaluate_absolute("path")?
.as_str()
.ok_or(RenderError::new("Type error for `path`, string expected"))?
.as_str().ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
.replace("\"", "");
let mut previous: Option<BTreeMap<String, String>> = None;
@ -118,8 +112,7 @@ pub fn next(_h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(), R
if let Some(previous) = previous {
let previous_path = previous
.get("path")
.ok_or(RenderError::new("No path found for chapter in JSON data"))?;
.get("path").ok_or_else(|| RenderError::new("No path found for chapter in JSON data"))?;
if previous_path == &current {
@ -128,8 +121,7 @@ pub fn next(_h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(), R
// Create new BTreeMap to extend the context: 'title' and 'link'
let mut next_chapter = BTreeMap::new();
item.get("name")
.ok_or(RenderError::new("No title found for chapter in JSON data"))
item.get("name").ok_or_else(|| RenderError::new("No title found for chapter in JSON data"))
.and_then(|n| {
next_chapter.insert("title".to_owned(), json!(n));
Ok(())
@ -137,8 +129,7 @@ pub fn next(_h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(), R
Path::new(path)
.with_extension("html")
.to_str()
.ok_or(RenderError::new("Link could not converted to str"))
.to_str().ok_or_else(|| RenderError::new("Link could not converted to str"))
.and_then(|l| {
debug!("[*]: Inserting link: {:?}", l);
// Hack for windows who tends to use `\` as separator instead of `/`
@ -149,8 +140,7 @@ pub fn next(_h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(), R
debug!("[*]: Render template");
// Render template
_h.template()
.ok_or(RenderError::new("Error with the handlebars template"))
_h.template().ok_or_else(|| RenderError::new("Error with the handlebars template"))
.and_then(|t| {
let mut local_rc = rc.with_context(Context::wraps(&next_chapter));
t.render(r, &mut local_rc)

View File

@ -36,11 +36,7 @@ pub fn render_playpen<P: AsRef<Path>>(s: &str, path: P) -> String {
continue;
};
let mut editable = "";
if playpen.editable {
editable = ",editable";
}
let editable = if playpen.editable { ",editable" } else { "" };
let replacement = String::new() + "``` rust" + editable + "\n" + &file_content + "\n```\n";
replaced.push_str(&s[previous_end_index..playpen.start_index]);

View File

@ -21,11 +21,10 @@ impl HelperDef for RenderToc {
.map_err(|_| RenderError::new("Could not decode the JSON data"))
})?;
let current = rc.evaluate_absolute("path")?
.as_str()
.ok_or(RenderError::new("Type error for `path`, string expected"))?
.as_str().ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
.replace("\"", "");
rc.writer.write_all("<ul class=\"chapter\">".as_bytes())?;
rc.writer.write_all(b"<ul class=\"chapter\">")?;
let mut current_level = 1;
@ -34,42 +33,42 @@ impl HelperDef for RenderToc {
// Spacer
if item.get("spacer").is_some() {
rc.writer
.write_all("<li class=\"spacer\"></li>".as_bytes())?;
.write_all(b"<li class=\"spacer\"></li>")?;
continue;
}
let level = if let Some(s) = item.get("section") {
s.matches(".").count()
s.matches('.').count()
} else {
1
};
if level > current_level {
while level > current_level {
rc.writer.write_all("<li>".as_bytes())?;
rc.writer.write_all("<ul class=\"section\">".as_bytes())?;
rc.writer.write_all(b"<li>")?;
rc.writer.write_all(b"<ul class=\"section\">")?;
current_level += 1;
}
rc.writer.write_all("<li>".as_bytes())?;
rc.writer.write_all(b"<li>")?;
} else if level < current_level {
while level < current_level {
rc.writer.write_all("</ul>".as_bytes())?;
rc.writer.write_all("</li>".as_bytes())?;
rc.writer.write_all(b"</ul>")?;
rc.writer.write_all(b"</li>")?;
current_level -= 1;
}
rc.writer.write_all("<li>".as_bytes())?;
rc.writer.write_all(b"<li>")?;
} else {
rc.writer.write_all("<li".as_bytes())?;
rc.writer.write_all(b"<li")?;
if item.get("section").is_none() {
rc.writer.write_all(" class=\"affix\"".as_bytes())?;
rc.writer.write_all(b" class=\"affix\"")?;
}
rc.writer.write_all(">".as_bytes())?;
rc.writer.write_all(b">")?;
}
// Link
let path_exists = if let Some(path) = item.get("path") {
if !path.is_empty() {
rc.writer.write_all("<a href=\"".as_bytes())?;
rc.writer.write_all(b"<a href=\"")?;
let tmp = Path::new(item.get("path").expect("Error: path should be Some(_)"))
.with_extension("html")
@ -80,13 +79,13 @@ impl HelperDef for RenderToc {
// Add link
rc.writer.write_all(tmp.as_bytes())?;
rc.writer.write_all("\"".as_bytes())?;
rc.writer.write_all(b"\"")?;
if path == &current {
rc.writer.write_all(" class=\"active\"".as_bytes())?;
rc.writer.write_all(b" class=\"active\"")?;
}
rc.writer.write_all(">".as_bytes())?;
rc.writer.write_all(b">")?;
true
} else {
false
@ -97,9 +96,9 @@ impl HelperDef for RenderToc {
// Section does not necessarily exist
if let Some(section) = item.get("section") {
rc.writer.write_all("<strong>".as_bytes())?;
rc.writer.write_all(b"<strong>")?;
rc.writer.write_all(section.as_bytes())?;
rc.writer.write_all("</strong> ".as_bytes())?;
rc.writer.write_all(b"</strong> ")?;
}
if let Some(name) = item.get("name") {
@ -123,19 +122,19 @@ impl HelperDef for RenderToc {
}
if path_exists {
rc.writer.write_all("</a>".as_bytes())?;
rc.writer.write_all(b"</a>")?;
}
rc.writer.write_all("</li>".as_bytes())?;
rc.writer.write_all(b"</li>")?;
}
while current_level > 1 {
rc.writer.write_all("</ul>".as_bytes())?;
rc.writer.write_all("</li>".as_bytes())?;
rc.writer.write_all(b"</ul>")?;
rc.writer.write_all(b"</li>")?;
current_level -= 1;
}
rc.writer.write_all("</ul>".as_bytes())?;
rc.writer.write_all(b"</ul>")?;
Ok(())
}
}

View File

@ -11,7 +11,7 @@ fn from_json_source() {
"src": "source"
}"#;
let parsed = JsonConfig::from_json(&json).expect("This should parse");
let parsed = JsonConfig::from_json(json).expect("This should parse");
let config = BookConfig::from_jsonconfig("root", parsed);
assert_eq!(config.get_source(), PathBuf::from("root/source"));
@ -24,7 +24,7 @@ fn from_json_title() {
"title": "Some title"
}"#;
let parsed = JsonConfig::from_json(&json).expect("This should parse");
let parsed = JsonConfig::from_json(json).expect("This should parse");
let config = BookConfig::from_jsonconfig("root", parsed);
assert_eq!(config.get_title(), "Some title");
@ -37,7 +37,7 @@ fn from_json_description() {
"description": "This is a description"
}"#;
let parsed = JsonConfig::from_json(&json).expect("This should parse");
let parsed = JsonConfig::from_json(json).expect("This should parse");
let config = BookConfig::from_jsonconfig("root", parsed);
assert_eq!(config.get_description(), "This is a description");
@ -50,7 +50,7 @@ fn from_json_author() {
"author": "John Doe"
}"#;
let parsed = JsonConfig::from_json(&json).expect("This should parse");
let parsed = JsonConfig::from_json(json).expect("This should parse");
let config = BookConfig::from_jsonconfig("root", parsed);
assert_eq!(config.get_authors(), &[String::from("John Doe")]);
@ -63,7 +63,7 @@ fn from_json_destination() {
"dest": "htmlbook"
}"#;
let parsed = JsonConfig::from_json(&json).expect("This should parse");
let parsed = JsonConfig::from_json(json).expect("This should parse");
let config = BookConfig::from_jsonconfig("root", parsed);
let htmlconfig = config.get_html_config().expect("There should be an HtmlConfig");
@ -78,7 +78,7 @@ fn from_json_output_html_theme() {
"theme_path": "theme"
}"#;
let parsed = JsonConfig::from_json(&json).expect("This should parse");
let parsed = JsonConfig::from_json(json).expect("This should parse");
let config = BookConfig::from_jsonconfig("root", parsed);
let htmlconfig = config.get_html_config().expect("There should be an HtmlConfig");

View File

@ -9,7 +9,7 @@ use std::path::PathBuf;
fn from_toml_source() {
let toml = r#"source = "source""#;
let parsed = TomlConfig::from_toml(&toml).expect("This should parse");
let parsed = TomlConfig::from_toml(toml).expect("This should parse");
let config = BookConfig::from_tomlconfig("root", parsed);
assert_eq!(config.get_source(), PathBuf::from("root/source"));
@ -20,7 +20,7 @@ fn from_toml_source() {
fn from_toml_title() {
let toml = r#"title = "Some title""#;
let parsed = TomlConfig::from_toml(&toml).expect("This should parse");
let parsed = TomlConfig::from_toml(toml).expect("This should parse");
let config = BookConfig::from_tomlconfig("root", parsed);
assert_eq!(config.get_title(), "Some title");
@ -31,7 +31,7 @@ fn from_toml_title() {
fn from_toml_description() {
let toml = r#"description = "This is a description""#;
let parsed = TomlConfig::from_toml(&toml).expect("This should parse");
let parsed = TomlConfig::from_toml(toml).expect("This should parse");
let config = BookConfig::from_tomlconfig("root", parsed);
assert_eq!(config.get_description(), "This is a description");
@ -42,7 +42,7 @@ fn from_toml_description() {
fn from_toml_author() {
let toml = r#"author = "John Doe""#;
let parsed = TomlConfig::from_toml(&toml).expect("This should parse");
let parsed = TomlConfig::from_toml(toml).expect("This should parse");
let config = BookConfig::from_tomlconfig("root", parsed);
assert_eq!(config.get_authors(), &[String::from("John Doe")]);
@ -53,7 +53,7 @@ fn from_toml_author() {
fn from_toml_authors() {
let toml = r#"authors = ["John Doe", "Jane Doe"]"#;
let parsed = TomlConfig::from_toml(&toml).expect("This should parse");
let parsed = TomlConfig::from_toml(toml).expect("This should parse");
let config = BookConfig::from_tomlconfig("root", parsed);
assert_eq!(config.get_authors(), &[String::from("John Doe"), String::from("Jane Doe")]);
@ -65,7 +65,7 @@ fn from_toml_output_html_destination() {
let toml = r#"[output.html]
destination = "htmlbook""#;
let parsed = TomlConfig::from_toml(&toml).expect("This should parse");
let parsed = TomlConfig::from_toml(toml).expect("This should parse");
let config = BookConfig::from_tomlconfig("root", parsed);
let htmlconfig = config.get_html_config().expect("There should be an HtmlConfig");
@ -79,7 +79,7 @@ fn from_toml_output_html_theme() {
let toml = r#"[output.html]
theme = "theme""#;
let parsed = TomlConfig::from_toml(&toml).expect("This should parse");
let parsed = TomlConfig::from_toml(toml).expect("This should parse");
let config = BookConfig::from_tomlconfig("root", parsed);
let htmlconfig = config.get_html_config().expect("There should be an HtmlConfig");
@ -93,7 +93,7 @@ fn from_toml_output_html_curly_quotes() {
let toml = r#"[output.html]
curly-quotes = true"#;
let parsed = TomlConfig::from_toml(&toml).expect("This should parse");
let parsed = TomlConfig::from_toml(toml).expect("This should parse");
let config = BookConfig::from_tomlconfig("root", parsed);
let htmlconfig = config.get_html_config().expect("There should be an HtmlConfig");
@ -107,7 +107,7 @@ fn from_toml_output_html_mathjax_support() {
let toml = r#"[output.html]
mathjax-support = true"#;
let parsed = TomlConfig::from_toml(&toml).expect("This should parse");
let parsed = TomlConfig::from_toml(toml).expect("This should parse");
let config = BookConfig::from_tomlconfig("root", parsed);
let htmlconfig = config.get_html_config().expect("There should be an HtmlConfig");
@ -121,7 +121,7 @@ fn from_toml_output_html_google_analytics() {
let toml = r#"[output.html]
google-analytics = "123456""#;
let parsed = TomlConfig::from_toml(&toml).expect("This should parse");
let parsed = TomlConfig::from_toml(toml).expect("This should parse");
let config = BookConfig::from_tomlconfig("root", parsed);
let htmlconfig = config.get_html_config().expect("There should be an HtmlConfig");
@ -135,7 +135,7 @@ fn from_toml_output_html_additional_stylesheet() {
let toml = r#"[output.html]
additional-css = ["custom.css", "two/custom.css"]"#;
let parsed = TomlConfig::from_toml(&toml).expect("This should parse");
let parsed = TomlConfig::from_toml(toml).expect("This should parse");
let config = BookConfig::from_tomlconfig("root", parsed);
let htmlconfig = config.get_html_config().expect("There should be an HtmlConfig");
@ -149,7 +149,7 @@ fn from_toml_output_html_additional_scripts() {
let toml = r#"[output.html]
additional-js = ["custom.js", "two/custom.js"]"#;
let parsed = TomlConfig::from_toml(&toml).expect("This should parse");
let parsed = TomlConfig::from_toml(toml).expect("This should parse");
let config = BookConfig::from_tomlconfig("root", parsed);
let htmlconfig = config.get_html_config().expect("There should be an HtmlConfig");