Added RST image parsing

+ Added DIP project
This commit is contained in:
2020-10-04 10:41:46 -05:00
parent 9fbad90eb8
commit 68ecb118a9
7 changed files with 191 additions and 51 deletions
+15 -16
View File
@@ -5,9 +5,10 @@ extern crate rocket;
#[macro_use]
extern crate serde_derive;
mod rst_parser;
mod tests;
mod rst_parser;
use crate::rst_parser::parse_images;
use regex::Regex;
use rocket::Request;
use rocket_contrib::serve::StaticFiles;
@@ -16,9 +17,9 @@ use rst_parser::parse_links;
use std::collections::HashMap;
use std::error;
use std::fmt;
use std::path::{PathBuf, Path};
use std::{fs, io};
use std::io::Error;
use std::path::{Path, PathBuf};
use std::{fs, io};
type PageResult<T> = std::result::Result<T, JSiteError>;
@@ -117,7 +118,7 @@ fn get_pages(path: &str, pages: &mut Vec<SiteFile>) -> io::Result<()> {
} else {
match rank.parse() {
Ok(r) => r,
Err(_) => std::u32::MAX
Err(_) => std::u32::MAX,
}
};
@@ -144,16 +145,15 @@ fn get_pages(path: &str, pages: &mut Vec<SiteFile>) -> io::Result<()> {
/// * `page_name` - file to look for
fn get_page(path: &Path) -> PageResult<SiteFile> {
let file_name = path.file_name().ok_or(PageNotFoundError)?;
let file_name = file_name.to_str().ok_or(PageNotFoundError)?.to_string();
let file_name = file_name.to_str().ok_or(PageNotFoundError)?.to_string();
if path.exists() {
return Ok(SiteFile {
rank: 0,
file_name: file_name.clone(),
link_name: file_name,
path: path.to_path_buf()
})
}
else {
path: path.to_path_buf(),
});
} else {
let mut dir_path = path.to_path_buf();
dir_path.pop();
@@ -166,8 +166,8 @@ fn get_page(path: &Path) -> PageResult<SiteFile> {
rank: 0,
file_name: entry_name,
link_name: file_name,
path: entry.path()
})
path: entry.path(),
});
}
}
}
@@ -191,9 +191,7 @@ fn rst_page(page: PathBuf) -> Template {
path.push(page);
// Try and get the page
let site_page = match get_page(
path.as_path()
) {
let site_page = match get_page(path.as_path()) {
Ok(site_page) => site_page,
Err(_) => {
return error_page(path.to_str().unwrap());
@@ -206,7 +204,7 @@ fn rst_page(page: PathBuf) -> Template {
let mut sub_files: Vec<SiteFile> = Vec::new();
match get_pages(site_page.path.to_str().unwrap(), &mut sub_files) {
Ok(_) => (),
Err(_) => return error_page(&site_page.link_name)
Err(_) => return error_page(&site_page.link_name),
}
let page_data = PageData {
@@ -229,7 +227,8 @@ fn rst_page(page: PathBuf) -> Template {
};
// Render links
let mut contents = parse_links(&contents);
let mut contents = parse_links(&contents).unwrap();
contents = parse_images(contents.as_str()).unwrap();
// Ensure render will look good
contents = contents.replace("\n", "<br>");
-32
View File
@@ -1,32 +0,0 @@
use regex::{Regex, Captures};
use std::collections::HashMap;
/// Renders RST links as HTML links
///
/// # Arguments
///
/// * `string` - input RST string
///
pub fn parse_links(string: &str) -> String {
let re_link_ref = Regex::new(r"\n?.. _(.*): (.*)\n").unwrap();
let mut link_map: HashMap<String, String> = HashMap::new();
for cap in re_link_ref.captures_iter(string) {
link_map.insert(String::from(&cap[1]), String::from(&cap[2]));
}
let text: String = re_link_ref.replace_all(string, "").to_string();
let re_link = Regex::new(r"`(.*)`_").unwrap();
let output = re_link.replace_all(&text, |cap: &Captures| {
let link = match link_map.get(&cap[1]) {
None => String::from(""),
Some(link) => link.to_owned(),
};
format!("<a class=\"link\" href=\"{}\">{}</a>", link, &cap[1])
});
output.to_string()
}
+111
View File
@@ -0,0 +1,111 @@
pub mod rst_error;
use regex::{Captures, Regex};
use std::collections::HashMap;
use rst_error::RSTError;
use std::convert::TryFrom;
/// RST Image
struct RSTImage {
/// File location
image_file: String,
/// Height
height: Option<String>,
/// Width
width: Option<String>,
/// Alt Text
alt: Option<String>,
/// Align (not implemented)
#[allow(dead_code)]
align: Option<String>,
}
impl RSTImage {
/// Convert to HTML img tag
fn to_html(&self) -> String {
let mut html = format!("<img src=\"{}\"", self.image_file);
let mut style = "".to_string();
if let Some(alt) = &self.alt {
html = format!("{} {}", html, alt);
}
if let Some(height) = &self.height {
style = format!("{}height;{};", style, height);
}
if let Some(width) = &self.width {
style = format!("{}width:{};", style, width);
}
html = format!("{} style=\"{}\">", html, style);
html
}
}
impl TryFrom<&Captures<'_>> for RSTImage {
type Error = RSTError;
/// Convert from a regex capture to a RSTImage
///
/// # Arguments
///
/// * cap - regex capture
fn try_from(cap: &Captures<'_>) -> Result<Self, Self::Error> {
let image = Self {
image_file: cap
.name("file_name")
.map(|m| m.as_str().to_string())
.ok_or(RSTError::NotFound("file_name"))?,
height: cap.name("width").map(|m| m.as_str().to_string()),
width: cap.name("width").map(|m| m.as_str().to_string()),
alt: cap.name("alt").map(|m| m.as_str().to_string()),
align: cap.name("align").map(|m| m.as_str().to_string()),
};
Ok(image)
}
}
/// Renders RST links as HTML links
///
/// # Arguments
///
/// * `string` - input RST string
pub fn parse_links(string: &str) -> Result<String, RSTError> {
let re_link_ref = Regex::new(r"\n?.. _(.*): (.*)\n")?;
let mut link_map: HashMap<String, String> = HashMap::new();
for cap in re_link_ref.captures_iter(string) {
link_map.insert(String::from(&cap[1]), String::from(&cap[2]));
}
let text: String = re_link_ref.replace_all(string, "").to_string();
let re_link = Regex::new(r"`(.*)`_")?;
let output = re_link.replace_all(&text, |cap: &Captures| {
let link = match link_map.get(&cap[1]) {
None => String::from(""),
Some(link) => link.to_owned(),
};
format!("<a class=\"link\" href=\"{}\">{}</a>", link, &cap[1])
});
Ok(output.to_string())
}
/// Renders RST images as HTML embedded images
///
/// # Arguments
///
/// * `string` - input rst string
pub fn parse_images(string: &str) -> Result<String, RSTError> {
let re_image = Regex::new(
r".. image:: (?P<file_name>.*)\n( *((:height: (?P<height>.*))|(:width: (?P<width>.*))|(:scale: (?P<scale>.*%))|(:alt: (?P<alt>.*))|(:align: (?P<align>.*)))\n)*",
)?;
Ok(re_image
.replace_all(string, |cap: &Captures| RSTImage::try_from(cap).unwrap().to_html())
.to_string())
}
+28
View File
@@ -0,0 +1,28 @@
use regex::Error;
#[derive(Debug)]
pub enum RSTError {
/// Regex compile error
RegexError(regex::Error),
/// Required element not found
NotFound(&'static str),
}
impl std::error::Error for RSTError {}
impl From<regex::Error> for RSTError {
/// From regex error
fn from(e: Error) -> Self {
Self::RegexError(e)
}
}
impl std::fmt::Display for RSTError {
/// fmt error
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
RSTError::NotFound(s) => write!(f, "required element missing: `{}`", s),
RSTError::RegexError(e) => write!(f, "regex compile error: `{:?}`", e),
}
}
}