diff --git a/Cargo.lock b/Cargo.lock index 0e86c37..7cc8ff5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -594,7 +594,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "snekdown" -version = "0.19.4" +version = "0.20.0" dependencies = [ "asciimath-rs 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "charred 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index e55a909..fc67431 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snekdown" -version = "0.19.4" +version = "0.20.0" authors = ["trivernis "] edition = "2018" license-file = "LICENSE" diff --git a/README.md b/README.md index 0fad079..0a85e4f 100644 --- a/README.md +++ b/README.md @@ -219,5 +219,5 @@ The end goal is to have a markup language with features similar to LaTeX. - [ ] Figures - [ ] EPUB Rendering (PDF is too hard) - [ ] Custom Elements via templates (50%) -- [ ] Custom Stylesheets +- [x] Custom Stylesheets - [ ] Smart arrows diff --git a/src/elements/mod.rs b/src/elements/mod.rs index 9c13514..9df1686 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -45,6 +45,7 @@ pub enum Block { Quote(Quote), Import(Import), Placeholder(Arc>), + Null, } #[derive(Clone, Debug)] @@ -64,6 +65,7 @@ pub struct Document { pub(crate) placeholders: Vec>>, pub config: Configuration, pub bibliography: Bibliography, + pub stylesheets: Vec, } #[derive(Clone, Debug)] @@ -275,6 +277,7 @@ impl Document { placeholders: Vec::new(), config: Configuration::default(), bibliography: Bibliography::new(), + stylesheets: Vec::new(), } } diff --git a/src/format/html.rs b/src/format/html.rs index feb8ebf..7e8f502 100644 --- a/src/format/html.rs +++ b/src/format/html.rs @@ -83,6 +83,7 @@ impl ToHtml for Block { Block::Import(import) => import.to_html(), Block::Placeholder(placeholder) => placeholder.read().unwrap().to_html(), Block::MathBlock(m) => m.to_html(), + Block::Null => "".to_string(), } } } @@ -119,12 +120,13 @@ impl ToHtml for Document { \ \ + {}\ \ \
{}
\ \ ", - path, style, inner + path, style, self.stylesheets.iter().fold("".to_string(), |a, b| format!("{}", a, encode_minimal(b))), inner ) } else { format!( diff --git a/src/parser/block.rs b/src/parser/block.rs index f31d68f..5163bb7 100644 --- a/src/parser/block.rs +++ b/src/parser/block.rs @@ -5,6 +5,7 @@ use crate::elements::{ }; use crate::parser::inline::ParseInline; use crate::parser::line::ParseLine; +use crate::parser::ImportType; use crate::Parser; pub(crate) trait ParseBlock { @@ -16,7 +17,7 @@ pub(crate) trait ParseBlock { fn parse_paragraph(&mut self) -> ParseResult; fn parse_list(&mut self) -> ParseResult; fn parse_table(&mut self) -> ParseResult; - fn parse_import(&mut self) -> ParseResult; + fn parse_import(&mut self) -> ParseResult>; } impl ParseBlock for Parser { @@ -44,7 +45,11 @@ impl ParseBlock for Parser { } else if let Ok(quote) = self.parse_quote() { Block::Quote(quote) } else if let Ok(import) = self.parse_import() { - Block::Import(import) + if let Some(import) = import { + Block::Import(import) + } else { + Block::Null + } } else if let Some(_) = self.section_return { return Err(self.ctm.err()); } else if let Ok(pholder) = self.parse_placeholder() { @@ -294,7 +299,7 @@ impl ParseBlock for Parser { } /// parses an import and starts a new task to parse the document of the import - fn parse_import(&mut self) -> ParseResult { + fn parse_import(&mut self) -> ParseResult> { let start_index = self.ctm.get_index(); self.ctm.seek_whitespace(); self.ctm @@ -321,10 +326,13 @@ impl ParseBlock for Parser { self.ctm.seek_whitespace(); - if let Ok(anchor) = self.import_document(path.clone()) { - Ok(Import { path, anchor }) - } else { - Err(self.ctm.err()) + match self.import(path.clone()) { + ImportType::Document(Ok(anchor)) => Ok(Some(Import { path, anchor })), + ImportType::Stylesheet(Ok(content)) => { + self.document.stylesheets.push(content); + Ok(None) + } + _ => Err(self.ctm.err()), } } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 4d1c1c4..0a17781 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -8,7 +8,7 @@ use crate::references::configuration::Configuration; use charred::tapemachine::{CharTapeMachine, TapeError, TapeResult}; use colored::*; use crossbeam_utils::sync::WaitGroup; -use std::fs::File; +use std::fs::{read_to_string, File}; use std::io; use std::io::{BufRead, BufReader, Cursor}; use std::path::PathBuf; @@ -142,8 +142,7 @@ impl Parser { } /// starts up a new thread to parse the imported document - fn import_document(&mut self, path: String) -> ParseResult>> { - let path = self.transform_path(path); + fn import_document(&mut self, path: PathBuf) -> ParseResult>> { if !path.exists() || !path.is_file() { println!( "{}", @@ -189,6 +188,20 @@ impl Parser { Ok(anchor) } + fn import(&mut self, path: String) -> ImportType { + let path = self.transform_path(path); + match path.extension() { + Some(e) if e.to_str().unwrap() == "css" => { + if let Ok(content) = read_to_string(path) { + ImportType::Stylesheet(Ok(content)) + } else { + ImportType::Stylesheet(Err(ParseError::new(self.ctm.get_index()))) + } + } + _ => ImportType::Document(self.import_document(path)), + } + } + /// parses the given text into a document pub fn parse(&mut self) -> Document { self.document.path = if let Some(path) = &self.path { @@ -220,3 +233,8 @@ impl Parser { document } } + +pub(crate) enum ImportType { + Document(ParseResult>>), + Stylesheet(ParseResult), +}