diff --git a/src/book/bookconfig.rs b/src/book/bookconfig.rs index c30951a3..3e8046b1 100644 --- a/src/book/bookconfig.rs +++ b/src/book/bookconfig.rs @@ -3,6 +3,7 @@ use std::path::PathBuf; pub struct BookConfig { dest: PathBuf, src: PathBuf, + indent_spaces: i32, multilingual: bool, } @@ -12,6 +13,7 @@ impl BookConfig { BookConfig { dest: PathBuf::from("book"), src: PathBuf::from("src"), + indent_spaces: 4, multilingual: false, } } diff --git a/src/book/bookitem.rs b/src/book/bookitem.rs index cc993073..1082302e 100644 --- a/src/book/bookitem.rs +++ b/src/book/bookitem.rs @@ -1,21 +1,41 @@ use std::path::PathBuf; pub struct BookItem { - name: String, - path: PathBuf, - sub_items: Vec, + pub name: String, + pub path: PathBuf, + pub sub_items: Vec, + spacer: bool, } +pub enum ItemType { + Pre, + Chapter, + Post +} impl BookItem { - fn new(name: String, path: PathBuf) -> Self { + pub fn new(name: String, path: PathBuf) -> Self { BookItem { name: name, path: path, sub_items: vec![], + spacer: false, } } + pub fn spacer() -> Self { + BookItem { + name: String::from("SPACER"), + path: PathBuf::new(), + sub_items: vec![], + spacer: true, + } + } + + fn push(&mut self, item: BookItem) { + self.sub_items.push(item); + } + } diff --git a/src/book/mdbook.rs b/src/book/mdbook.rs index 0d585048..4ca92d33 100644 --- a/src/book/mdbook.rs +++ b/src/book/mdbook.rs @@ -1,10 +1,10 @@ use std::path::PathBuf; use std::fs::{self, File, metadata}; -use std::io::Write; -use std::io::Error; +use std::io::{Write, Result}; use book::bookconfig::BookConfig; use book::bookitem::BookItem; +use parse; pub struct MDBook { title: String, @@ -37,7 +37,7 @@ impl MDBook { } } - pub fn init(&self) -> Result<(), Error> { + pub fn init(&self) -> Result<()> { let dest = self.config.dest(); let src = self.config.src(); @@ -67,11 +67,11 @@ impl MDBook { Err(_) => { // There is a very high chance that the error is due to the fact that // the directory / file does not exist - Result::Ok(File::create(&src.join("SUMMARY.md")).unwrap()) + Ok(File::create(&src.join("SUMMARY.md")).unwrap()) }, Ok(_) => { /* If there is no error, the directory / file does exist */ - Result::Err("SUMMARY.md does already exist") + Err("SUMMARY.md does already exist") } }; @@ -87,9 +87,9 @@ impl MDBook { return Ok(()); } - pub fn build(&self) -> Result<(), Error> { - + pub fn build(&mut self) -> Result<()> { + try!(self.parse_summary()); Ok(()) } @@ -116,4 +116,23 @@ impl MDBook { self } + + // Construct book + fn parse_summary(&mut self) -> Result<()> { + + // When append becomes stale, use self.content.append() ... + let book_items = try!(parse::construct_bookitems(&self.config.src().join("SUMMARY.md"))); + + for item in book_items { + self.content.push(item) + } + + // Debug + for item in &self.content { + println!("name: \"{}\" path: {:?}", item.name, item.path); + } + + Ok(()) + } + } diff --git a/src/book/mod.rs b/src/book/mod.rs index ac310a28..0c1861e1 100644 --- a/src/book/mod.rs +++ b/src/book/mod.rs @@ -1,6 +1,7 @@ pub mod mdbook; +pub mod bookitem; mod bookconfig; -mod bookitem; + use self::bookconfig::BookConfig; use self::bookitem::BookItem; diff --git a/src/lib.rs b/src/lib.rs index 7c0f6b72..5c96c703 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ mod book; +mod parse; pub use book::mdbook::MDBook; +use book::bookitem::BookItem; diff --git a/src/main.rs b/src/main.rs index a1c01b70..f8206afb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -143,8 +143,13 @@ fn build(args: Vec) { println!("{}", usage); } - let dir = std::env::current_dir().unwrap(); - let book = MDBook::new(&dir); + let dir = if args.len() <= 2 { + std::env::current_dir().unwrap() + } else { + std::env::current_dir().unwrap().join(&args[2]) + }; + + let mut book = MDBook::new(&dir); if let Err(e) = book.build() { println!("Error: {}", e); diff --git a/src/parse/mod.rs b/src/parse/mod.rs new file mode 100644 index 00000000..c8c8aab7 --- /dev/null +++ b/src/parse/mod.rs @@ -0,0 +1,3 @@ +pub use self::summary::construct_bookitems; + +pub mod summary; diff --git a/src/parse/summary.rs b/src/parse/summary.rs new file mode 100644 index 00000000..ba38f647 --- /dev/null +++ b/src/parse/summary.rs @@ -0,0 +1,121 @@ +use std::path::PathBuf; +use std::fs::File; +use std::io::{Read, Result, Error, ErrorKind}; +use book::bookitem::BookItem; + +/* +pub enum LineType { + Blank, + Header, + Link(String, PathBuf), // Name, Path + ListItem(String, PathBuf, i32), // Name, Path, Level + Other, +} +*/ + +pub fn construct_bookitems(path: &PathBuf) -> Result> { + let mut summary = String::new(); + try!(try!(File::open(path)).read_to_string(&mut summary)); + + let top_items = try!(parse_level(&mut summary.split('\n').collect(), 0)); + + + + Ok(top_items) +} + +fn parse_level(summary: &mut Vec<&str>, current_level: i32) -> Result> { + + let mut items: Vec = vec![]; + + loop { + if summary.len() <= 0 { break } + + let level = try!(level(summary[0], 4)); + + if current_level > level { break } + else if current_level < level { + items.last_mut().unwrap().sub_items = try!(parse_level(summary, level)) + } + else { + // Do the thing + if let Some(item) = parse_line(summary[0].clone()) { + items.push(item); + } + summary.remove(0); + } + } + + Ok(items) +} + +fn level(line: &str, spaces_in_tab: i32) -> Result { + let mut spaces = 0; + let mut level = 0; + + for ch in line.chars() { + match ch { + ' ' => spaces += 1, + '\t' => level += 1, + _ => break, + } + if spaces >= spaces_in_tab { + level += 1; + spaces = 0; + } + } + + // If there are spaces left, there is an indentation error + if spaces > 0 { + return Err(Error::new( + ErrorKind::Other, + format!("There is an indentation error on line:\n\n{}", line) + ) + ) + } + + Ok(level) +} + + +fn parse_line(line: &str) -> Option { + let mut name; + let mut path; + // Remove leading and trailing spaces or tabs + line.trim_matches(|c: char| { c == ' ' || c == '\t' }); + + if let Some(c) = line.chars().nth(0) { + match c { + // List item + '-' | '*' => { + let mut start_delimitor; + let mut end_delimitor; + + // 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 { return None } + + if let Some(i) = line[start_delimitor..].find("](") { + end_delimitor = start_delimitor +i; + } + else { return None } + + name = line[start_delimitor + 1 .. end_delimitor].to_string(); + + start_delimitor = end_delimitor + 1; + if let Some(i) = line[start_delimitor..].find(')') { + end_delimitor = start_delimitor + i; + } + else { return None } + + path = PathBuf::from(line[start_delimitor + 1 .. end_delimitor].to_string()); + + return Some(BookItem::new(name, path)) + } + _ => {} + } + } + + None +}