diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000..78db360b --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,15 @@ +write_mode = "Overwrite" + +max_width = 120 +ideal_width = 120 +fn_call_width = 100 + +fn_args_density = "Compressed" + +enum_trailing_comma = true +match_block_trailing_comma = true +struct_trailing_comma = "Always" +wrap_comments = true + +report_todo = "Always" +report_fixme = "Always" diff --git a/src/bin/mdbook.rs b/src/bin/mdbook.rs index 4032bfb4..c8ff6d8a 100644 --- a/src/bin/mdbook.rs +++ b/src/bin/mdbook.rs @@ -56,12 +56,12 @@ fn main() { // Check which subcomamnd the user ran... let res = match matches.subcommand() { - ("init", Some(sub_matches)) => init(sub_matches), + ("init", Some(sub_matches)) => init(sub_matches), ("build", Some(sub_matches)) => build(sub_matches), #[cfg(feature = "watch")] ("watch", Some(sub_matches)) => watch(sub_matches), ("test", Some(sub_matches)) => test(sub_matches), - (_, _) => unreachable!() + (_, _) => unreachable!(), }; if let Err(e) = res { @@ -77,7 +77,7 @@ fn confirm() -> bool { io::stdin().read_line(&mut s).ok(); match &*s.trim() { "Y" | "y" | "yes" | "Yes" => true, - _ => false + _ => false, } } @@ -124,7 +124,7 @@ fn init(args: &ArgMatches) -> Result<(), Box> { if confirm() { book.create_gitignore(); println!("\n.gitignore created."); - } + } } println!("\nAll done, no errors..."); @@ -151,66 +151,68 @@ fn watch(args: &ArgMatches) -> Result<(), Box> { let book = MDBook::new(&book_dir).read_config(); // Create a channel to receive the events. - let (tx, rx) = channel(); + let (tx, rx) = channel(); - let w: Result = notify::Watcher::new(tx); + let w: Result = notify::Watcher::new(tx); - match w { - Ok(mut watcher) => { + 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 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 - } + // 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; + let previous_time = time::get_time().sec; - crossbeam::scope(|scope| { - loop { - match rx.recv() { - Ok(event) => { + 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 } + // 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!(""); - }); + 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); - } - } - } - }); + } 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); - } - } + }, + Err(e) => { + println!("Error while trying to watch the files:\n\n\t{:?}", e); + ::std::process::exit(0); + }, + } - Ok(()) - } + Ok(()) +} @@ -230,9 +232,9 @@ fn get_book_dir(args: &ArgMatches) -> PathBuf { // Check if path is relative from current dir, or absolute... let p = Path::new(dir); if p.is_relative() { - env::current_dir().unwrap().join(dir) + env::current_dir().unwrap().join(dir) } else { - p.to_path_buf() + p.to_path_buf() } } else { env::current_dir().unwrap() diff --git a/src/book/bookconfig.rs b/src/book/bookconfig.rs index 95ac2caf..5cc4b00e 100644 --- a/src/book/bookconfig.rs +++ b/src/book/bookconfig.rs @@ -26,7 +26,7 @@ impl BookConfig { root: root.to_owned(), dest: PathBuf::from("book"), src: PathBuf::from("src"), - indent_spaces: 4, // indentation used for SUMMARY.md + indent_spaces: 4, // indentation used for SUMMARY.md multilingual: false, } } @@ -40,7 +40,7 @@ impl BookConfig { Ok(f) => f, Err(_) => { debug!("[*]: Failed to open {:?}", root.join("book.json")); - return self + return self; }, }; @@ -49,7 +49,9 @@ impl BookConfig { // Just return if an error occured. // I would like to propagate the error, but I have to return `&self` - if let Err(_) = config_file.read_to_string(&mut data) { return self } + if let Err(_) = config_file.read_to_string(&mut data) { + return self; + } // Convert to JSON if let Ok(config) = Json::from_str(&data) { @@ -57,9 +59,15 @@ impl BookConfig { debug!("[*]: Extracting data from config"); // Title, author, description - if let Some(a) = config.find_path(&["title"]) { self.title = a.to_string().replace("\"", "") } - if let Some(a) = config.find_path(&["author"]) { self.author = a.to_string().replace("\"", "") } - if let Some(a) = config.find_path(&["description"]) { self.description = a.to_string().replace("\"", "") } + if let Some(a) = config.find_path(&["title"]) { + self.title = a.to_string().replace("\"", "") + } + if let Some(a) = config.find_path(&["author"]) { + self.author = a.to_string().replace("\"", "") + } + if let Some(a) = config.find_path(&["description"]) { + self.description = a.to_string().replace("\"", "") + } // Destination if let Some(a) = config.find_path(&["dest"]) { @@ -71,7 +79,9 @@ impl BookConfig { let dest = self.get_root().join(&dest).to_owned(); self.set_dest(&dest); }, - false => { self.set_dest(&dest); }, + false => { + self.set_dest(&dest); + }, } } } @@ -105,5 +115,4 @@ impl BookConfig { self.src = src.to_owned(); self } - } diff --git a/src/book/bookitem.rs b/src/book/bookitem.rs index d866b5b9..7ab4a2a3 100644 --- a/src/book/bookitem.rs +++ b/src/book/bookitem.rs @@ -27,7 +27,6 @@ pub struct BookItems<'a> { impl Chapter { - pub fn new(name: String, path: PathBuf) -> Self { Chapter { @@ -40,13 +39,14 @@ impl Chapter { impl ToJson for Chapter { - fn to_json(&self) -> Json { let mut m: BTreeMap = BTreeMap::new(); m.insert("name".to_owned(), self.name.to_json()); - m.insert("path".to_owned(),self.path.to_str() - .expect("Json conversion failed for path").to_json() - ); + m.insert("path".to_owned(), + self.path + .to_str() + .expect("Json conversion failed for path") + .to_json()); m.to_json() } } @@ -66,7 +66,7 @@ impl<'a> Iterator for BookItems<'a> { Some((parent_items, parent_idx)) => { self.items = parent_items; self.current_index = parent_idx + 1; - } + }, } } else { let cur = self.items.get(self.current_index).unwrap(); @@ -79,10 +79,10 @@ impl<'a> Iterator for BookItems<'a> { }, BookItem::Spacer => { self.current_index += 1; - } + }, } - return Some(cur) + return Some(cur); } } } diff --git a/src/book/mdbook.rs b/src/book/mdbook.rs index 0b0cb20f..53d12d16 100644 --- a/src/book/mdbook.rs +++ b/src/book/mdbook.rs @@ -18,7 +18,6 @@ pub struct MDBook { } impl MDBook { - /// Create a new `MDBook` struct with root directory `root` /// /// - The default source directory is set to `root/src` @@ -148,11 +147,11 @@ impl MDBook { try!(::std::fs::create_dir_all(path.parent().unwrap())); let mut f = try!(File::create(path)); - //debug!("[*]: Writing to {:?}", path); + // debug!("[*]: Writing to {:?}", path); try!(writeln!(f, "# {}", ch.name)); } } - } + }, } } @@ -172,20 +171,19 @@ impl MDBook { return; } - let relative = self.get_dest().strip_prefix(self.get_root()) - .expect("Destination is not relative to root."); + let relative = self.get_dest() + .strip_prefix(self.get_root()) + .expect("Destination is not relative to root."); let relative = relative.to_str() - .expect("Path could not be yielded into a string slice."); + .expect("Path could not be yielded into a string slice."); debug!("[*]: {:?} does not exist, trying to create .gitignore", gitignore); - let mut f = File::create(&gitignore) - .expect("Could not create file."); + let mut f = File::create(&gitignore).expect("Could not create file."); debug!("[*]: Writing to .gitignore"); - writeln!(f, "{}", relative) - .expect("Could not write to file."); + writeln!(f, "{}", relative).expect("Could not write to file."); } } @@ -310,9 +308,9 @@ impl MDBook { println!("[*]: Testing file: {:?}", path); let output_result = Command::new("rustdoc") - .arg(&path) - .arg("--test") - .output(); + .arg(&path) + .arg("--test") + .output(); let output = try!(output_result); if !output.status.success() { @@ -322,8 +320,8 @@ impl MDBook { String::from_utf8_lossy(&output.stderr)))) as Box); } } - } - _ => {} + }, + _ => {}, } } Ok(()) @@ -337,11 +335,13 @@ impl MDBook { // Handle absolute and relative paths match dest.is_absolute() { - true => { self.config.set_dest(dest); }, + true => { + self.config.set_dest(dest); + }, false => { let dest = self.config.get_root().join(dest).to_owned(); self.config.set_dest(&dest); - } + }, } self @@ -355,11 +355,13 @@ impl MDBook { // Handle absolute and relative paths match src.is_absolute() { - true => { self.config.set_src(src); }, + true => { + self.config.set_src(src); + }, false => { let src = self.config.get_root().join(src).to_owned(); self.config.set_src(&src); - } + }, } self @@ -391,7 +393,7 @@ impl MDBook { self.config.description = description.to_owned(); self } - + pub fn get_description(&self) -> &str { &self.config.description } @@ -402,5 +404,4 @@ impl MDBook { self.content = try!(parse::construct_bookitems(&self.config.get_src().join("SUMMARY.md"))); Ok(()) } - } diff --git a/src/parse/summary.rs b/src/parse/summary.rs index 78c69afb..a4c87a9c 100644 --- a/src/parse/summary.rs +++ b/src/parse/summary.rs @@ -26,7 +26,9 @@ fn parse_level(summary: &mut Vec<&str>, current_level: i32, mut section: Vec current_level we call ourselves to go one level deeper if level > current_level { @@ -42,13 +44,15 @@ fn parse_level(summary: &mut Vec<&str>, current_level: i32, mut section: Vec, current_level: i32, mut section: Vec 0 => { - return Err(Error::new( ErrorKind::Other, format!( - "Your summary.md is messed up\n\n - Prefix, Suffix and Spacer elements can only exist on the root level.\n - Prefix elements can only exist before any chapter and there can be no chapters after suffix elements." - ))) + return Err(Error::new(ErrorKind::Other, + format!("Your summary.md is messed up\n\n + \ + Prefix, Suffix and Spacer elements can only exist on the \ + root level.\n + Prefix \ + elements can only exist before any chapter and there can be \ + no chapters after suffix elements."))) }, // error if BookItem == Chapter and section == -1 BookItem::Chapter(_, _) if section[0] == -1 => { - return Err(Error::new( ErrorKind::Other, format!( - "Your summary.md is messed up\n\n - Prefix, Suffix and Spacer elements can only exist on the root level.\n - Prefix elements can only exist before any chapter and there can be no chapters after suffix elements." - ))) + return Err(Error::new(ErrorKind::Other, + format!("Your summary.md is messed up\n\n + \ + Prefix, Suffix and Spacer elements can only exist on the \ + root level.\n + Prefix \ + elements can only exist before any chapter and there can be \ + no chapters after suffix elements."))) }, // Set section = -1 after suffix BookItem::Affix(_) if section[0] > 0 => { section[0] = -1; - } + }, _ => {}, } @@ -86,12 +96,12 @@ fn parse_level(summary: &mut Vec<&str>, current_level: i32, mut section: Vec { // Increment section - let len = section.len() -1; + let len = section.len() - 1; section[len] += 1; let s = section.iter().fold("".to_owned(), |s, i| s + &i.to_string() + "."); BookItem::Chapter(s, ch) - } - _ => parsed_item + }, + _ => parsed_item, } } else { @@ -131,11 +141,7 @@ fn level(line: &str, spaces_in_tab: i32) -> Result { debug!("[SUMMARY.md]:"); debug!("\t[line]: {}", line); debug!("[*]: There is an indentation error on this line. Indentation should be {} spaces", spaces_in_tab); - return Err(Error::new( - ErrorKind::Other, - format!("Indentation error on line:\n\n{}", line) - ) - ) + return Err(Error::new(ErrorKind::Other, format!("Indentation error on line:\n\n{}", line))); } Ok(level) @@ -146,12 +152,12 @@ fn parse_line(l: &str) -> Option { debug!("[fn]: parse_line"); // Remove leading and trailing spaces or tabs - let line = l.trim_matches(|c: char| { c == ' ' || c == '\t' }); + let line = l.trim_matches(|c: char| c == ' ' || c == '\t'); // Spacers are "------" if line.starts_with("--") { debug!("[*]: Line is spacer"); - return Some(BookItem::Spacer) + return Some(BookItem::Spacer); } if let Some(c) = line.chars().nth(0) { @@ -161,18 +167,22 @@ fn parse_line(l: &str) -> Option { debug!("[*]: Line is list element"); if let Some((name, path)) = read_link(line) { - return Some(BookItem::Chapter("0".to_owned(), Chapter::new(name, path))) - } else { return None } + return Some(BookItem::Chapter("0".to_owned(), Chapter::new(name, path))); + } else { + return None; + } }, // Non-list element '[' => { debug!("[*]: Line is a link element"); if let Some((name, path)) = read_link(line) { - return Some(BookItem::Affix(Chapter::new(name, path))) - } else { return None } - } - _ => {} + return Some(BookItem::Affix(Chapter::new(name, path))); + } else { + return None; + } + }, + _ => {}, } } @@ -185,32 +195,31 @@ fn read_link(line: &str) -> Option<(String, PathBuf)> { // In the future, support for list item that is not a link // Not sure if I should error on line I can't parse or just ignore them... - if let Some(i) = line.find('[') { start_delimitor = i; } - else { + if let Some(i) = line.find('[') { + start_delimitor = i; + } else { debug!("[*]: '[' not found, this line is not a link. Ignoring..."); - return None + return None; } if let Some(i) = line[start_delimitor..].find("](") { - end_delimitor = start_delimitor +i; - } - else { + end_delimitor = start_delimitor + i; + } else { debug!("[*]: '](' not found, this line is not a link. Ignoring..."); - return None + return None; } - let name = line[start_delimitor + 1 .. end_delimitor].to_owned(); + let name = line[start_delimitor + 1..end_delimitor].to_owned(); start_delimitor = end_delimitor + 1; if let Some(i) = line[start_delimitor..].find(')') { end_delimitor = start_delimitor + i; - } - else { + } else { debug!("[*]: ')' not found, this line is not a link. Ignoring..."); - return None + return None; } - let path = PathBuf::from(line[start_delimitor + 1 .. end_delimitor].to_owned()); + let path = PathBuf::from(line[start_delimitor + 1..end_delimitor].to_owned()); Some((name, path)) } diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index e9d9aa15..798defa0 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -51,7 +51,8 @@ impl Renderer for HtmlHandlebars { // Check if dest directory exists debug!("[*]: Check if destination directory exists"); if let Err(_) = fs::create_dir_all(book.get_dest()) { - return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Unexpected error when constructing destination path"))) + return Err(Box::new(io::Error::new(io::ErrorKind::Other, + "Unexpected error when constructing destination path"))); } // Render a file for every entry in the book @@ -83,8 +84,13 @@ impl Renderer for HtmlHandlebars { // Remove content from previous file and render content for this one data.remove("path"); match ch.path.to_str() { - Some(p) => { data.insert("path".to_owned(), p.to_json()); }, - None => return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not convert path to str"))), + Some(p) => { + data.insert("path".to_owned(), p.to_json()); + }, + None => { + return Err(Box::new(io::Error::new(io::ErrorKind::Other, + "Could not convert path to str"))) + }, } @@ -114,23 +120,24 @@ impl Renderer for HtmlHandlebars { let mut index_file = try!(File::create(book.get_dest().join("index.html"))); let mut content = String::new(); let _source = try!(File::open(book.get_dest().join(&ch.path.with_extension("html")))) - .read_to_string(&mut content); + .read_to_string(&mut content); // This could cause a problem when someone displays code containing // on the front page, however this case should be very very rare... - content = content.lines().filter(|line| !line.contains(" {} + }, + _ => {}, } } @@ -159,72 +166,112 @@ impl Renderer for HtmlHandlebars { debug!("[*] Copy static files"); // JavaScript - let mut js_file = if let Ok(f) = File::create(book.get_dest().join("book.js")) { f } else { - return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create book.js"))) + let mut js_file = if let Ok(f) = File::create(book.get_dest().join("book.js")) { + f + } else { + return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create book.js"))); }; try!(js_file.write_all(&theme.js)); // Css - let mut css_file = if let Ok(f) = File::create(book.get_dest().join("book.css")) { f } else { - return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create book.css"))) + let mut css_file = if let Ok(f) = File::create(book.get_dest().join("book.css")) { + f + } else { + return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create book.css"))); }; try!(css_file.write_all(&theme.css)); // Favicon - let mut favicon_file = if let Ok(f) = File::create(book.get_dest().join("favicon.png")) { f } else { - return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create favicon.png"))) + let mut favicon_file = if let Ok(f) = File::create(book.get_dest().join("favicon.png")) { + f + } else { + return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create favicon.png"))); }; try!(favicon_file.write_all(&theme.favicon)); // JQuery local fallback - let mut jquery = if let Ok(f) = File::create(book.get_dest().join("jquery.js")) { f } else { - return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create jquery.js"))) + let mut jquery = if let Ok(f) = File::create(book.get_dest().join("jquery.js")) { + f + } else { + return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create jquery.js"))); }; try!(jquery.write_all(&theme.jquery)); // syntax highlighting - let mut highlight_css = if let Ok(f) = File::create(book.get_dest().join("highlight.css")) { f } else { - return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create highlight.css"))) + let mut highlight_css = if let Ok(f) = File::create(book.get_dest().join("highlight.css")) { + f + } else { + return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create highlight.css"))); }; try!(highlight_css.write_all(&theme.highlight_css)); - let mut tomorrow_night_css = if let Ok(f) = File::create(book.get_dest().join("tomorrow-night.css")) { f } else { - return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create tomorrow-night.css"))) + let mut tomorrow_night_css = if let Ok(f) = File::create(book.get_dest().join("tomorrow-night.css")) { + f + } else { + return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create tomorrow-night.css"))); }; try!(tomorrow_night_css.write_all(&theme.tomorrow_night_css)); - let mut highlight_js = if let Ok(f) = File::create(book.get_dest().join("highlight.js")) { f } else { - return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create highlight.js"))) + let mut highlight_js = if let Ok(f) = File::create(book.get_dest().join("highlight.js")) { + f + } else { + return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create highlight.js"))); }; try!(highlight_js.write_all(&theme.highlight_js)); // Font Awesome local fallback - let mut font_awesome = if let Ok(f) = utils::create_file(&book.get_dest().join("_FontAwesome/css/font-awesome.css")) { f } else { - return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create font-awesome.css"))) + let mut font_awesome = if let Ok(f) = utils::create_file(&book.get_dest() + .join("_FontAwesome/css/font-awesome.css")) { + f + } else { + return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create font-awesome.css"))); }; try!(font_awesome.write_all(theme::FONT_AWESOME)); - let mut font_awesome = if let Ok(f) = utils::create_file(&book.get_dest().join("_FontAwesome/fonts/fontawesome-webfont.eot")) { f } else { - return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create fontawesome-webfont.eot"))) + let mut font_awesome = if let Ok(f) = utils::create_file(&book.get_dest() + .join("_FontAwesome/fonts/fontawesome-webfon\ + t.eot")) { + f + } else { + return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create fontawesome-webfont.eot"))); }; try!(font_awesome.write_all(theme::FONT_AWESOME_EOT)); - let mut font_awesome = if let Ok(f) = utils::create_file(&book.get_dest().join("_FontAwesome/fonts/fontawesome-webfont.svg")) { f } else { - return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create fontawesome-webfont.svg"))) + let mut font_awesome = if let Ok(f) = utils::create_file(&book.get_dest() + .join("_FontAwesome/fonts/fontawesome-webfon\ + t.svg")) { + f + } else { + return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create fontawesome-webfont.svg"))); }; try!(font_awesome.write_all(theme::FONT_AWESOME_SVG)); - let mut font_awesome = if let Ok(f) = utils::create_file(&book.get_dest().join("_FontAwesome/fonts/fontawesome-webfont.ttf")) { f } else { - return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create fontawesome-webfont.ttf"))) + let mut font_awesome = if let Ok(f) = utils::create_file(&book.get_dest() + .join("_FontAwesome/fonts/fontawesome-webfon\ + t.ttf")) { + f + } else { + return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create fontawesome-webfont.ttf"))); }; try!(font_awesome.write_all(theme::FONT_AWESOME_TTF)); - let mut font_awesome = if let Ok(f) = utils::create_file(&book.get_dest().join("_FontAwesome/fonts/fontawesome-webfont.woff")) { f } else { - return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create fontawesome-webfont.woff"))) + let mut font_awesome = if let Ok(f) = utils::create_file(&book.get_dest() + .join("_FontAwesome/fonts/fontawesome-webfon\ + t.woff")) { + f + } else { + return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create fontawesome-webfont.woff"))); }; try!(font_awesome.write_all(theme::FONT_AWESOME_WOFF)); - let mut font_awesome = if let Ok(f) = utils::create_file(&book.get_dest().join("_FontAwesome/fonts/fontawesome-webfont.woff2")) { f } else { - return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create fontawesome-webfont.woff2"))) + let mut font_awesome = if let Ok(f) = utils::create_file(&book.get_dest() + .join("_FontAwesome/fonts/fontawesome-webfon\ + t.woff2")) { + f + } else { + return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create fontawesome-webfont.woff2"))); }; try!(font_awesome.write_all(theme::FONT_AWESOME_WOFF2)); - let mut font_awesome = if let Ok(f) = utils::create_file(&book.get_dest().join("_FontAwesome/fonts/FontAwesome.ttf")) { f } else { - return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create FontAwesome.ttf"))) + let mut font_awesome = if let Ok(f) = utils::create_file(&book.get_dest() + .join("_FontAwesome/fonts/FontAwesome.ttf")) { + f + } else { + return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not create FontAwesome.ttf"))); }; try!(font_awesome.write_all(theme::FONT_AWESOME_TTF)); @@ -235,10 +282,10 @@ impl Renderer for HtmlHandlebars { } } -fn make_data(book: &MDBook) -> Result, Box> { +fn make_data(book: &MDBook) -> Result, Box> { debug!("[fn]: make_data"); - let mut data = BTreeMap::new(); + let mut data = BTreeMap::new(); data.insert("language".to_owned(), "en".to_json()); data.insert("title".to_owned(), book.get_title().to_json()); data.insert("description".to_owned(), book.get_description().to_json()); @@ -254,7 +301,9 @@ fn make_data(book: &MDBook) -> Result, Box> { BookItem::Affix(ref ch) => { chapter.insert("name".to_owned(), ch.name.to_json()); match ch.path.to_str() { - Some(p) => { chapter.insert("path".to_owned(), p.to_json()); }, + Some(p) => { + chapter.insert("path".to_owned(), p.to_json()); + }, None => return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not convert path to str"))), } }, @@ -262,13 +311,15 @@ fn make_data(book: &MDBook) -> Result, Box> { chapter.insert("section".to_owned(), s.to_json()); chapter.insert("name".to_owned(), ch.name.to_json()); match ch.path.to_str() { - Some(p) => { chapter.insert("path".to_owned(), p.to_json()); }, + Some(p) => { + chapter.insert("path".to_owned(), p.to_json()); + }, None => return Err(Box::new(io::Error::new(io::ErrorKind::Other, "Could not convert path to str"))), } }, BookItem::Spacer => { chapter.insert("spacer".to_owned(), "_spacer_".to_json()); - } + }, } diff --git a/src/renderer/html_handlebars/helpers/navigation.rs b/src/renderer/html_handlebars/helpers/navigation.rs index 8fa2f658..c9e7a9ae 100644 --- a/src/renderer/html_handlebars/helpers/navigation.rs +++ b/src/renderer/html_handlebars/helpers/navigation.rs @@ -19,15 +19,15 @@ pub fn previous(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext let chapters = c.navigate(rc.get_path(), "chapters"); let current = c.navigate(rc.get_path(), "path") - .to_string() - .replace("\"", ""); + .to_string() + .replace("\"", ""); debug!("[*]: Decode chapters from JSON"); // Decode json format let decoded: Vec> = match json::decode(&chapters.to_string()) { Ok(data) => data, - Err(_) => return Err(RenderError{ desc: "Could not decode the JSON data".to_owned()}), + Err(_) => return Err(RenderError { desc: "Could not decode the JSON data".to_owned() }), }; let mut previous: Option> = None; @@ -41,7 +41,7 @@ pub fn previous(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext if path == ¤t { debug!("[*]: Found current chapter"); - if let Some(previous) = previous{ + if let Some(previous) = previous { debug!("[*]: Creating BTreeMap to inject in context"); // Create new BTreeMap to extend the context: 'title' and 'link' @@ -55,8 +55,8 @@ 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".to_owned() }) - } + return Err(RenderError { desc: "No title found for chapter in JSON data".to_owned() }); + }, }; // Chapter link @@ -67,11 +67,19 @@ pub fn previous(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext debug!("[*]: Inserting link: {:?}", path); 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".to_owned() }) + Some(p) => { + previous_chapter.insert("link".to_owned(), p.to_json()); + }, + 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".to_owned() }) + None => { + return Err(RenderError { desc: "No path found for chapter in JSON data".to_owned() }) + }, } debug!("[*]: Inject in context"); @@ -84,14 +92,13 @@ 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".to_owned() }) + None => return Err(RenderError { desc: "Error with the handlebars template".to_owned() }), } } break; - } - else { + } else { previous = Some(item.clone()); } }, @@ -117,14 +124,14 @@ pub fn next(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> let chapters = c.navigate(rc.get_path(), "chapters"); let current = c.navigate(rc.get_path(), "path") - .to_string() - .replace("\"", ""); + .to_string() + .replace("\"", ""); debug!("[*]: Decode chapters from JSON"); // Decode json format let decoded: Vec> = match json::decode(&chapters.to_string()) { Ok(data) => data, - Err(_) => return Err(RenderError{ desc: "Could not decode the JSON data".to_owned() }), + Err(_) => return Err(RenderError { desc: "Could not decode the JSON data".to_owned() }), }; let mut previous: Option> = None; @@ -140,7 +147,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".to_owned() }) + None => return Err(RenderError { desc: "No path found for chapter in JSON data".to_owned() }), }; if previous_path == ¤t { @@ -154,8 +161,10 @@ pub fn next(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Some(n) => { 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".to_owned() }) + }, + None => { + return Err(RenderError { desc: "No title found for chapter in JSON data".to_owned() }) + }, } @@ -163,8 +172,10 @@ pub fn next(c: &Context, _h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> debug!("[*]: Inserting link: {:?}", link); 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".to_owned() }) + Some(l) => { + next_chapter.insert("link".to_owned(), l.to_json()); + }, + None => return Err(RenderError { desc: "Link could not converted to str".to_owned() }), } debug!("[*]: Inject in context"); @@ -178,10 +189,10 @@ 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".to_owned() }) + None => return Err(RenderError { desc: "Error with the handlebars template".to_owned() }), } - break + break; } } diff --git a/src/renderer/html_handlebars/helpers/playpen.rs b/src/renderer/html_handlebars/helpers/playpen.rs index 0dbe86bf..c17eb602 100644 --- a/src/renderer/html_handlebars/helpers/playpen.rs +++ b/src/renderer/html_handlebars/helpers/playpen.rs @@ -14,29 +14,37 @@ pub fn render_playpen(s: &str, path: &Path) -> String { for playpen in find_playpens(s, path) { if playpen.escaped { - replaced.push_str(&s[previous_end_index..playpen.start_index-1]); + replaced.push_str(&s[previous_end_index..playpen.start_index - 1]); replaced.push_str(&s[playpen.start_index..playpen.end_index]); previous_end_index = playpen.end_index; - continue + continue; } // Check if the file exists if !playpen.rust_file.exists() || !playpen.rust_file.is_file() { output!("[-] No file exists for {{{{#playpen }}}}\n {}", playpen.rust_file.to_str().unwrap()); - continue + continue; } // Open file & read file - let mut file = if let Ok(f) = File::open(&playpen.rust_file) { f } else { continue }; + let mut file = if let Ok(f) = File::open(&playpen.rust_file) { + f + } else { + continue; + }; let mut file_content = String::new(); - if let Err(_) = file.read_to_string(&mut file_content) { continue }; + if let Err(_) = file.read_to_string(&mut file_content) { + continue; + }; - let replacement = String::new() + "
" + &file_content + "
"; + let replacement = String::new() + "
" + &file_content +
+                          "
"; replaced.push_str(&s[previous_end_index..playpen.start_index]); replaced.push_str(&replacement); previous_end_index = playpen.end_index; - //println!("Playpen{{ {}, {}, {:?}, {} }}", playpen.start_index, playpen.end_index, playpen.rust_file, playpen.editable); + // println!("Playpen{{ {}, {}, {:?}, {} }}", playpen.start_index, playpen.end_index, playpen.rust_file, + // playpen.editable); } replaced.push_str(&s[previous_end_index..]); @@ -45,7 +53,7 @@ pub fn render_playpen(s: &str, path: &Path) -> String { } #[derive(PartialOrd, PartialEq, Debug)] -struct Playpen{ +struct Playpen { start_index: usize, end_index: usize, rust_file: PathBuf, @@ -61,38 +69,50 @@ fn find_playpens(s: &str, base_path: &Path) -> Vec { let mut escaped = false; if i > 0 { - if let Some(c) = s[i-1..].chars().nth(0) { - if c == '\\' { escaped = true } + if let Some(c) = s[i - 1..].chars().nth(0) { + if c == '\\' { + escaped = true + } } } // DON'T forget the "+ i" else you have an index out of bounds error !! - let end_i = if let Some(n) = s[i..].find("}}") { n } else { continue } + i + 2; + let end_i = if let Some(n) = s[i..].find("}}") { + n + } else { + continue; + } + i + 2; debug!("s[{}..{}] = {}", i, end_i, s[i..end_i].to_string()); // If there is nothing between "{{#playpen" and "}}" skip - if end_i-2 - (i+10) < 1 { continue } - if s[i+10..end_i-2].trim().len() == 0 { continue } + if end_i - 2 - (i + 10) < 1 { + continue; + } + if s[i + 10..end_i - 2].trim().len() == 0 { + continue; + } - debug!("{}", s[i+10..end_i-2].to_string()); + debug!("{}", s[i + 10..end_i - 2].to_string()); // Split on whitespaces - let params: Vec<&str> = s[i+10..end_i-2].split_whitespace().collect(); + let params: Vec<&str> = s[i + 10..end_i - 2].split_whitespace().collect(); let mut editable = false; if params.len() > 1 { - editable = if let Some(_) = params[1].find("editable") {true} else {false}; + editable = if let Some(_) = params[1].find("editable") { + true + } else { + false + }; } - playpens.push( - Playpen{ - start_index: i, - end_index: end_i, - rust_file: base_path.join(PathBuf::from(params[0])), - editable: editable, - escaped: escaped - } - ) + playpens.push(Playpen { + start_index: i, + end_index: end_i, + rust_file: base_path.join(PathBuf::from(params[0])), + editable: editable, + escaped: escaped, + }) } playpens @@ -101,8 +121,7 @@ fn find_playpens(s: &str, base_path: &Path) -> Vec { -// -//--------------------------------------------------------------------------------- +// --------------------------------------------------------------------------------- // Tests // @@ -130,10 +149,21 @@ fn test_find_playpens_simple_playpen() { println!("\nOUTPUT: {:?}\n", find_playpens(s, Path::new(""))); - assert!(find_playpens(s, Path::new("")) == vec![ - Playpen{start_index: 22, end_index: 42, rust_file: PathBuf::from("file.rs"), editable: false, escaped: false}, - Playpen{start_index: 47, end_index: 68, rust_file: PathBuf::from("test.rs"), editable: false, escaped: false} - ]); + assert!(find_playpens(s, Path::new("")) == + vec![Playpen { + start_index: 22, + end_index: 42, + rust_file: PathBuf::from("file.rs"), + editable: false, + escaped: false, + }, + Playpen { + start_index: 47, + end_index: 68, + rust_file: PathBuf::from("test.rs"), + editable: false, + escaped: false, + }]); } #[test] @@ -142,10 +172,21 @@ fn test_find_playpens_complex_playpen() { println!("\nOUTPUT: {:?}\n", find_playpens(s, Path::new("dir"))); - assert!(find_playpens(s, Path::new("dir")) == vec![ - Playpen{start_index: 22, end_index: 51, rust_file: PathBuf::from("dir/file.rs"), editable: true, escaped: false}, - Playpen{start_index: 56, end_index: 86, rust_file: PathBuf::from("dir/test.rs"), editable: true, escaped: false} - ]); + assert!(find_playpens(s, Path::new("dir")) == + vec![Playpen { + start_index: 22, + end_index: 51, + rust_file: PathBuf::from("dir/file.rs"), + editable: true, + escaped: false, + }, + Playpen { + start_index: 56, + end_index: 86, + rust_file: PathBuf::from("dir/test.rs"), + editable: true, + escaped: false, + }]); } #[test] @@ -154,7 +195,8 @@ fn test_find_playpens_escaped_playpen() { println!("\nOUTPUT: {:?}\n", find_playpens(s, Path::new(""))); - assert!(find_playpens(s, Path::new("")) == vec![ + assert!(find_playpens(s, Path::new("")) == + vec![ Playpen{start_index: 39, end_index: 68, rust_file: PathBuf::from("file.rs"), editable: true, escaped: true}, ]); } diff --git a/src/renderer/html_handlebars/helpers/toc.rs b/src/renderer/html_handlebars/helpers/toc.rs index 76ec33ba..ea56f5ed 100644 --- a/src/renderer/html_handlebars/helpers/toc.rs +++ b/src/renderer/html_handlebars/helpers/toc.rs @@ -14,117 +14,119 @@ use self::pulldown_cmark::{Parser, html, Event, Tag}; pub struct RenderToc; impl HelperDef for RenderToc { - fn call(&self, c: &Context, _h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> { + fn call(&self, c: &Context, _h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> { - // get value from context data - // rc.get_path() is current json parent path, you should always use it like this - // param is the key of value you want to display - let chapters = c.navigate(rc.get_path(), "chapters"); - let current = c.navigate(rc.get_path(), "path").to_string().replace("\"", ""); - try!(rc.writer.write("".as_bytes())); - Ok(()) - } } diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index 615efbf7..9966a0fa 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -1,5 +1,5 @@ use std::error::Error; pub trait Renderer { - fn render(&self, book: &::book::MDBook) -> Result<(), Box>; + fn render(&self, book: &::book::MDBook) -> Result<(), Box>; } diff --git a/src/theme/mod.rs b/src/theme/mod.rs index e02aca3c..89fd30c2 100644 --- a/src/theme/mod.rs +++ b/src/theme/mod.rs @@ -53,13 +53,13 @@ impl Theme { // Check if the given path exists if !src.exists() || !src.is_dir() { - return theme + return theme; } let src = src.join("theme"); // If src does exist, check if there is a theme directory in it if !src.exists() || !src.is_dir() { - return theme + return theme; } // Check for individual files if they exist @@ -73,7 +73,7 @@ impl Theme { // book.js if let Ok(mut f) = File::open(&src.join("book.js")) { theme.js.clear(); - let _ = f.read_to_end(&mut theme.js); + let _ = f.read_to_end(&mut theme.js); } // book.css diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 18e44713..c579d692 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -32,13 +32,16 @@ pub fn path_to_root(path: &Path) -> String { debug!("[fn]: path_to_root"); // Remove filename and add "../" for every directory - path.to_path_buf().parent().expect("") - .components().fold(String::new(), |mut s, c| { + path.to_path_buf() + .parent() + .expect("") + .components() + .fold(String::new(), |mut s, c| { match c { Component::Normal(_) => s.push_str("../"), _ => { debug!("[*]: Other path component... {:?}", c); - } + }, } s }) @@ -64,7 +67,7 @@ pub fn create_file(path: &Path) -> Result> { Ok(f) => f, Err(e) => { debug!("File::create: {}", e); - return Err(Box::new(io::Error::new(io::ErrorKind::Other, format!("{}", e)))) + return Err(Box::new(io::Error::new(io::ErrorKind::Other, format!("{}", e)))); }, }; @@ -77,7 +80,11 @@ pub fn remove_dir_content(dir: &Path) -> Result<(), Box> { for item in try!(fs::read_dir(dir)) { if let Ok(item) = item { let item = item.path(); - if item.is_dir() { try!(fs::remove_dir_all(item)); } else { try!(fs::remove_file(item)); } + if item.is_dir() { + try!(fs::remove_dir_all(item)); + } else { + try!(fs::remove_file(item)); + } } } Ok(()) @@ -91,7 +98,9 @@ pub fn remove_dir_content(dir: &Path) -> Result<(), Box> { pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blacklist: &[&str]) -> Result<(), Box> { debug!("[fn] copy_files_except_ext"); // Check that from and to are different - if from == to { return Ok(()) } + if from == to { + return Ok(()); + } debug!("[*] Loop"); for entry in try!(fs::read_dir(from)) { let entry = try!(entry); @@ -100,7 +109,9 @@ pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blackl // If the entry is a dir and the recursive option is enabled, call itself if metadata.is_dir() && recursive { - if entry.path() == to.to_path_buf() { continue } + if entry.path() == to.to_path_buf() { + continue; + } debug!("[*] is dir"); // check if output dir already exists @@ -108,21 +119,25 @@ pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blackl try!(fs::create_dir(&to.join(entry.file_name()))); } - try!(copy_files_except_ext( - &from.join(entry.file_name()), - &to.join(entry.file_name()), - true, - ext_blacklist - )); + try!(copy_files_except_ext(&from.join(entry.file_name()), + &to.join(entry.file_name()), + true, + ext_blacklist)); } else if metadata.is_file() { // Check if it is in the blacklist if let Some(ext) = entry.path().extension() { - if ext_blacklist.contains(&ext.to_str().unwrap()) { continue } - debug!("[*] creating path for file: {:?}", &to.join(entry.path().file_name().expect("a file should have a file name..."))); + if ext_blacklist.contains(&ext.to_str().unwrap()) { + continue; + } + debug!("[*] creating path for file: {:?}", + &to.join(entry.path().file_name().expect("a file should have a file name..."))); - output!("[*] copying file: {:?}\n to {:?}", entry.path(), &to.join(entry.path().file_name().expect("a file should have a file name..."))); - try!(fs::copy(entry.path(), &to.join(entry.path().file_name().expect("a file should have a file name...")))); + output!("[*] copying file: {:?}\n to {:?}", + entry.path(), + &to.join(entry.path().file_name().expect("a file should have a file name..."))); + try!(fs::copy(entry.path(), + &to.join(entry.path().file_name().expect("a file should have a file name...")))); } } } @@ -168,17 +183,35 @@ mod tests { }; // Create a couple of files - if let Err(_) = fs::File::create(&tmp.path().join("file.txt")) { panic!("Could not create file.txt") } - if let Err(_) = fs::File::create(&tmp.path().join("file.md")) { panic!("Could not create file.md") } - if let Err(_) = fs::File::create(&tmp.path().join("file.png")) { panic!("Could not create file.png") } - if let Err(_) = fs::create_dir(&tmp.path().join("sub_dir")) { panic!("Could not create sub_dir") } - if let Err(_) = fs::File::create(&tmp.path().join("sub_dir/file.png")) { panic!("Could not create sub_dir/file.png") } - if let Err(_) = fs::create_dir(&tmp.path().join("sub_dir_exists")) { panic!("Could not create sub_dir_exists") } - if let Err(_) = fs::File::create(&tmp.path().join("sub_dir_exists/file.txt")) { panic!("Could not create sub_dir_exists/file.txt") } + if let Err(_) = fs::File::create(&tmp.path().join("file.txt")) { + panic!("Could not create file.txt") + } + if let Err(_) = fs::File::create(&tmp.path().join("file.md")) { + panic!("Could not create file.md") + } + if let Err(_) = fs::File::create(&tmp.path().join("file.png")) { + panic!("Could not create file.png") + } + if let Err(_) = fs::create_dir(&tmp.path().join("sub_dir")) { + panic!("Could not create sub_dir") + } + if let Err(_) = fs::File::create(&tmp.path().join("sub_dir/file.png")) { + panic!("Could not create sub_dir/file.png") + } + if let Err(_) = fs::create_dir(&tmp.path().join("sub_dir_exists")) { + panic!("Could not create sub_dir_exists") + } + if let Err(_) = fs::File::create(&tmp.path().join("sub_dir_exists/file.txt")) { + panic!("Could not create sub_dir_exists/file.txt") + } // Create output dir - if let Err(_) = fs::create_dir(&tmp.path().join("output")) { panic!("Could not create output") } - if let Err(_) = fs::create_dir(&tmp.path().join("output/sub_dir_exists")) { panic!("Could not create output/sub_dir_exists") } + if let Err(_) = fs::create_dir(&tmp.path().join("output")) { + panic!("Could not create output") + } + if let Err(_) = fs::create_dir(&tmp.path().join("output/sub_dir_exists")) { + panic!("Could not create output/sub_dir_exists") + } match copy_files_except_ext(&tmp.path(), &tmp.path().join("output"), true, &["md"]) { Err(e) => panic!("Error while executing the function:\n{:?}", e), @@ -186,11 +219,21 @@ mod tests { } // Check if the correct files where created - if !(&tmp.path().join("output/file.txt")).exists() { panic!("output/file.txt should exist") } - if (&tmp.path().join("output/file.md")).exists() { panic!("output/file.md should not exist") } - if !(&tmp.path().join("output/file.png")).exists() { panic!("output/file.png should exist") } - if !(&tmp.path().join("output/sub_dir/file.png")).exists() { panic!("output/sub_dir/file.png should exist") } - if !(&tmp.path().join("output/sub_dir_exists/file.txt")).exists() { panic!("output/sub_dir/file.png should exist") } + if !(&tmp.path().join("output/file.txt")).exists() { + panic!("output/file.txt should exist") + } + if (&tmp.path().join("output/file.md")).exists() { + panic!("output/file.md should not exist") + } + if !(&tmp.path().join("output/file.png")).exists() { + panic!("output/file.png should exist") + } + if !(&tmp.path().join("output/sub_dir/file.png")).exists() { + panic!("output/sub_dir/file.png should exist") + } + if !(&tmp.path().join("output/sub_dir_exists/file.txt")).exists() { + panic!("output/sub_dir/file.png should exist") + } } }