|
|
@ -12,7 +12,7 @@ use std::collections::HashMap;
|
|
|
|
use std::fs::File;
|
|
|
|
use std::fs::File;
|
|
|
|
use std::io;
|
|
|
|
use std::io;
|
|
|
|
use std::io::{BufRead, BufReader, Cursor};
|
|
|
|
use std::io::{BufRead, BufReader, Cursor};
|
|
|
|
use std::path::Path;
|
|
|
|
use std::path::PathBuf;
|
|
|
|
use std::sync::{Arc, Mutex, RwLock};
|
|
|
|
use std::sync::{Arc, Mutex, RwLock};
|
|
|
|
use std::thread;
|
|
|
|
use std::thread;
|
|
|
|
|
|
|
|
|
|
|
@ -23,8 +23,8 @@ pub struct Parser {
|
|
|
|
section_nesting: u8,
|
|
|
|
section_nesting: u8,
|
|
|
|
sections: Vec<u8>,
|
|
|
|
sections: Vec<u8>,
|
|
|
|
section_return: Option<u8>,
|
|
|
|
section_return: Option<u8>,
|
|
|
|
path: Option<String>,
|
|
|
|
path: Option<PathBuf>,
|
|
|
|
paths: Arc<Mutex<Vec<String>>>,
|
|
|
|
paths: Arc<Mutex<Vec<PathBuf>>>,
|
|
|
|
wg: WaitGroup,
|
|
|
|
wg: WaitGroup,
|
|
|
|
is_child: bool,
|
|
|
|
is_child: bool,
|
|
|
|
pub(crate) block_break_at: Vec<char>,
|
|
|
|
pub(crate) block_break_at: Vec<char>,
|
|
|
@ -37,10 +37,10 @@ pub struct Parser {
|
|
|
|
|
|
|
|
|
|
|
|
impl Parser {
|
|
|
|
impl Parser {
|
|
|
|
/// Creates a new parser from a path
|
|
|
|
/// Creates a new parser from a path
|
|
|
|
pub fn new_from_file(path: String) -> Result<Self, io::Error> {
|
|
|
|
pub fn new_from_file(path: PathBuf) -> Result<Self, io::Error> {
|
|
|
|
let f = File::open(&path)?;
|
|
|
|
let f = File::open(&path)?;
|
|
|
|
Ok(Self::create(
|
|
|
|
Ok(Self::create(
|
|
|
|
Some(path),
|
|
|
|
Some(PathBuf::from(path)),
|
|
|
|
Arc::new(Mutex::new(Vec::new())),
|
|
|
|
Arc::new(Mutex::new(Vec::new())),
|
|
|
|
false,
|
|
|
|
false,
|
|
|
|
Box::new(BufReader::new(f)),
|
|
|
|
Box::new(BufReader::new(f)),
|
|
|
@ -48,8 +48,13 @@ impl Parser {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Creates a new parser with text being the markdown text
|
|
|
|
/// Creates a new parser with text being the markdown text
|
|
|
|
pub fn new(text: String, path: Option<String>) -> Self {
|
|
|
|
pub fn new(text: String, path: Option<PathBuf>) -> Self {
|
|
|
|
let text_bytes = text.as_bytes();
|
|
|
|
let text_bytes = text.as_bytes();
|
|
|
|
|
|
|
|
let path = if let Some(inner_path) = path {
|
|
|
|
|
|
|
|
Some(PathBuf::from(inner_path))
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
None
|
|
|
|
|
|
|
|
};
|
|
|
|
Parser::create(
|
|
|
|
Parser::create(
|
|
|
|
path,
|
|
|
|
path,
|
|
|
|
Arc::new(Mutex::new(Vec::new())),
|
|
|
|
Arc::new(Mutex::new(Vec::new())),
|
|
|
@ -59,10 +64,10 @@ impl Parser {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Creates a child parser from string text
|
|
|
|
/// Creates a child parser from string text
|
|
|
|
pub fn child(text: String, path: String, paths: Arc<Mutex<Vec<String>>>) -> Self {
|
|
|
|
pub fn child(text: String, path: PathBuf, paths: Arc<Mutex<Vec<PathBuf>>>) -> Self {
|
|
|
|
let text_bytes = text.as_bytes();
|
|
|
|
let text_bytes = text.as_bytes();
|
|
|
|
Self::create(
|
|
|
|
Self::create(
|
|
|
|
Some(path),
|
|
|
|
Some(PathBuf::from(path)),
|
|
|
|
paths,
|
|
|
|
paths,
|
|
|
|
true,
|
|
|
|
true,
|
|
|
|
Box::new(Cursor::new(text_bytes.to_vec())),
|
|
|
|
Box::new(Cursor::new(text_bytes.to_vec())),
|
|
|
@ -71,12 +76,12 @@ impl Parser {
|
|
|
|
|
|
|
|
|
|
|
|
/// Creates a child parser from a file
|
|
|
|
/// Creates a child parser from a file
|
|
|
|
pub fn child_from_file(
|
|
|
|
pub fn child_from_file(
|
|
|
|
path: String,
|
|
|
|
path: PathBuf,
|
|
|
|
paths: Arc<Mutex<Vec<String>>>,
|
|
|
|
paths: Arc<Mutex<Vec<PathBuf>>>,
|
|
|
|
) -> Result<Self, io::Error> {
|
|
|
|
) -> Result<Self, io::Error> {
|
|
|
|
let f = File::open(&path)?;
|
|
|
|
let f = File::open(&path)?;
|
|
|
|
Ok(Self::create(
|
|
|
|
Ok(Self::create(
|
|
|
|
Some(path),
|
|
|
|
Some(PathBuf::from(path)),
|
|
|
|
paths,
|
|
|
|
paths,
|
|
|
|
true,
|
|
|
|
true,
|
|
|
|
Box::new(BufReader::new(f)),
|
|
|
|
Box::new(BufReader::new(f)),
|
|
|
@ -84,17 +89,13 @@ impl Parser {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn create(
|
|
|
|
fn create(
|
|
|
|
path: Option<String>,
|
|
|
|
path: Option<PathBuf>,
|
|
|
|
paths: Arc<Mutex<Vec<String>>>,
|
|
|
|
paths: Arc<Mutex<Vec<PathBuf>>>,
|
|
|
|
is_child: bool,
|
|
|
|
is_child: bool,
|
|
|
|
mut reader: Box<dyn BufRead>,
|
|
|
|
mut reader: Box<dyn BufRead>,
|
|
|
|
) -> Self {
|
|
|
|
) -> Self {
|
|
|
|
if let Some(path) = path.clone() {
|
|
|
|
if let Some(path) = path.clone() {
|
|
|
|
let path_info = Path::new(&path);
|
|
|
|
paths.lock().unwrap().push(path.clone())
|
|
|
|
paths
|
|
|
|
|
|
|
|
.lock()
|
|
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
|
|
.push(path_info.to_str().unwrap().to_string())
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let mut text = Vec::new();
|
|
|
|
let mut text = Vec::new();
|
|
|
|
let mut current_char = ' ';
|
|
|
|
let mut current_char = ' ';
|
|
|
@ -142,37 +143,36 @@ impl Parser {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns the import paths of the parser
|
|
|
|
/// Returns the import paths of the parser
|
|
|
|
pub fn get_paths(&self) -> Vec<String> {
|
|
|
|
pub fn get_paths(&self) -> Vec<PathBuf> {
|
|
|
|
self.paths.lock().unwrap().clone()
|
|
|
|
self.paths.lock().unwrap().clone()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// transform an import path to be relative to the current parsers file
|
|
|
|
/// transform an import path to be relative to the current parsers file
|
|
|
|
fn transform_path(&mut self, path: String) -> String {
|
|
|
|
fn transform_path(&mut self, path: String) -> PathBuf {
|
|
|
|
let mut path = path;
|
|
|
|
let mut path = PathBuf::from(path);
|
|
|
|
let first_path_info = Path::new(&path);
|
|
|
|
|
|
|
|
if first_path_info.is_absolute() {
|
|
|
|
if !path.is_absolute() {
|
|
|
|
return first_path_info.to_str().unwrap().to_string();
|
|
|
|
if let Some(selfpath) = &self.path {
|
|
|
|
}
|
|
|
|
if let Some(dir) = selfpath.parent() {
|
|
|
|
if let Some(selfpath) = &self.path {
|
|
|
|
path = PathBuf::new().join(dir).join(path);
|
|
|
|
let path_info = Path::new(&selfpath);
|
|
|
|
|
|
|
|
if path_info.is_file() {
|
|
|
|
|
|
|
|
if let Some(dir) = path_info.parent() {
|
|
|
|
|
|
|
|
path = format!("{}/{}", dir.to_str().unwrap(), path);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let path_info = Path::new(&path);
|
|
|
|
|
|
|
|
return path_info.to_str().unwrap().to_string();
|
|
|
|
path
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// starts up a new thread to parse the imported document
|
|
|
|
/// starts up a new thread to parse the imported document
|
|
|
|
fn import_document(&mut self, path: String) -> ParseResult<Arc<RwLock<ImportAnchor>>> {
|
|
|
|
fn import_document(&mut self, path: String) -> ParseResult<Arc<RwLock<ImportAnchor>>> {
|
|
|
|
let path = self.transform_path(path);
|
|
|
|
let path = self.transform_path(path);
|
|
|
|
let path_info = Path::new(&path);
|
|
|
|
if !path.exists() || !path.is_file() {
|
|
|
|
if !path_info.exists() || !path_info.is_file() {
|
|
|
|
|
|
|
|
println!(
|
|
|
|
println!(
|
|
|
|
"{}",
|
|
|
|
"{}",
|
|
|
|
format!("Import of \"{}\" failed: The file doesn't exist.", path,).red()
|
|
|
|
format!(
|
|
|
|
|
|
|
|
"Import of \"{}\" failed: The file doesn't exist.",
|
|
|
|
|
|
|
|
path.to_str().unwrap()
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.red()
|
|
|
|
);
|
|
|
|
);
|
|
|
|
return Err(ParseError::new_with_message(
|
|
|
|
return Err(ParseError::new_with_message(
|
|
|
|
self.index,
|
|
|
|
self.index,
|
|
|
@ -184,7 +184,11 @@ impl Parser {
|
|
|
|
if paths.iter().find(|item| **item == path) != None {
|
|
|
|
if paths.iter().find(|item| **item == path) != None {
|
|
|
|
println!(
|
|
|
|
println!(
|
|
|
|
"{}",
|
|
|
|
"{}",
|
|
|
|
format!("Import of \"{}\" failed: Cyclic import.", path).yellow()
|
|
|
|
format!(
|
|
|
|
|
|
|
|
"Import of \"{}\" failed: Cyclic import.",
|
|
|
|
|
|
|
|
path.to_str().unwrap()
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.yellow()
|
|
|
|
);
|
|
|
|
);
|
|
|
|
return Err(ParseError::new_with_message(self.index, "cyclic import"));
|
|
|
|
return Err(ParseError::new_with_message(self.index, "cyclic import"));
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -210,7 +214,11 @@ impl Parser {
|
|
|
|
|
|
|
|
|
|
|
|
/// parses the given text into a document
|
|
|
|
/// parses the given text into a document
|
|
|
|
pub fn parse(&mut self) -> Document {
|
|
|
|
pub fn parse(&mut self) -> Document {
|
|
|
|
self.document.path = self.path.clone();
|
|
|
|
self.document.path = if let Some(path) = &self.path {
|
|
|
|
|
|
|
|
Some(path.canonicalize().unwrap().to_str().unwrap().to_string())
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
None
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
while self.index < self.text.len() {
|
|
|
|
while self.index < self.text.len() {
|
|
|
|
match self.parse_block() {
|
|
|
|
match self.parse_block() {
|
|
|
@ -225,12 +233,18 @@ impl Parser {
|
|
|
|
"{}",
|
|
|
|
"{}",
|
|
|
|
format!(
|
|
|
|
format!(
|
|
|
|
"Error in File {}:{}:{} - {}",
|
|
|
|
"Error in File {}:{}:{} - {}",
|
|
|
|
path, position.0, position.1, err
|
|
|
|
path.to_str().unwrap(),
|
|
|
|
|
|
|
|
position.0,
|
|
|
|
|
|
|
|
position.1,
|
|
|
|
|
|
|
|
err
|
|
|
|
)
|
|
|
|
)
|
|
|
|
.red()
|
|
|
|
.red()
|
|
|
|
);
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
println!("{}", format!("Error in File {}: {}", path, err).red());
|
|
|
|
println!(
|
|
|
|
|
|
|
|
"{}",
|
|
|
|
|
|
|
|
format!("Error in File {}: {}", path.to_str().unwrap(), err).red()
|
|
|
|
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
println!("{}", err);
|
|
|
|
println!("{}", err);
|
|
|
|