feat: markdown implementation
#18
4 changed files with 154 additions and 2 deletions
43
Cargo.lock
generated
43
Cargo.lock
generated
|
@ -463,9 +463,12 @@ dependencies = [
|
||||||
"actix-files",
|
"actix-files",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"glob",
|
"glob",
|
||||||
|
"latex2mathml",
|
||||||
|
"markdown",
|
||||||
"minify-html",
|
"minify-html",
|
||||||
"ramhorns",
|
"ramhorns",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_yaml",
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -664,6 +667,12 @@ version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388"
|
checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "latex2mathml"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "678cf5bdb3ba63a264e6e0c9eee36538ca1d2da0afa4dd801c1f96309e710765"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
@ -736,6 +745,15 @@ dependencies = [
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "markdown"
|
||||||
|
version = "1.0.0-alpha.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "98de49c677e95e00eaa74c42a0b07ea55e1e0b1ebca5b2cbc7657f288cd714eb"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-id",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
@ -1126,6 +1144,19 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_yaml"
|
||||||
|
version = "0.9.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
"unsafe-libyaml",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha1"
|
name = "sha1"
|
||||||
version = "0.10.5"
|
version = "0.10.5"
|
||||||
|
@ -1342,6 +1373,12 @@ version = "0.3.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-id"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d70b6494226b36008c8366c288d77190b3fad2eb4c10533139c1c1f461127f1a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.8"
|
version = "1.0.8"
|
||||||
|
@ -1363,6 +1400,12 @@ version = "1.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unsafe-libyaml"
|
||||||
|
version = "0.2.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1865806a559042e51ab5414598446a5871b561d21b6764f2eabb0dd481d880a6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
|
|
|
@ -15,5 +15,8 @@ actix-files = "0.6"
|
||||||
ramhorns = "0.14.0"
|
ramhorns = "0.14.0"
|
||||||
toml = "0.7.3"
|
toml = "0.7.3"
|
||||||
serde = { version = "1.0.159", features = ["derive"] }
|
serde = { version = "1.0.159", features = ["derive"] }
|
||||||
|
serde_yaml = "0.9"
|
||||||
minify-html = "0.10.8"
|
minify-html = "0.10.8"
|
||||||
glob = "0.3.1"
|
glob = "0.3.1"
|
||||||
|
markdown = "1.0.0-alpha.7"
|
||||||
|
latex2mathml = "0.2.3"
|
||||||
|
|
|
@ -14,6 +14,7 @@ pub struct FileConfig {
|
||||||
pub mail: Option<String>,
|
pub mail: Option<String>,
|
||||||
pub lang: Option<String>,
|
pub lang: Option<String>,
|
||||||
pub onion: Option<String>,
|
pub onion: Option<String>,
|
||||||
|
pub app_name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileConfig {
|
impl FileConfig {
|
||||||
|
@ -21,6 +22,7 @@ impl FileConfig {
|
||||||
Self {
|
Self {
|
||||||
scheme: Some("http".to_string()),
|
scheme: Some("http".to_string()),
|
||||||
port: Some(8080),
|
port: Some(8080),
|
||||||
|
app_name: Some("EWP".to_string()),
|
||||||
..FileConfig::default()
|
..FileConfig::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,6 +46,7 @@ impl FileConfig {
|
||||||
mail: test(a.mail, d.mail),
|
mail: test(a.mail, d.mail),
|
||||||
lang: test(a.lang, d.lang),
|
lang: test(a.lang, d.lang),
|
||||||
onion: test(a.onion, d.onion),
|
onion: test(a.onion, d.onion),
|
||||||
|
app_name: test(a.app_name, d.app_name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,10 +86,11 @@ pub fn get_config(file_path: &str) -> Config {
|
||||||
);
|
);
|
||||||
|
|
||||||
Config {
|
Config {
|
||||||
fc: internal_config,
|
fc: internal_config.clone(),
|
||||||
static_location: format!("{}/{}", files_root, static_dir),
|
static_location: format!("{}/{}", files_root, static_dir),
|
||||||
tmpl: Template {
|
tmpl: Template {
|
||||||
directory: format!("{}/{}", files_root, templates_dir),
|
directory: format!("{}/{}", files_root, templates_dir),
|
||||||
|
app_name: internal_config.app_name.unwrap(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
104
src/template.rs
104
src/template.rs
|
@ -1,8 +1,16 @@
|
||||||
use ramhorns::{Content, Ramhorns};
|
use ramhorns::{Content, Ramhorns};
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Template {
|
pub struct Template {
|
||||||
pub directory: String,
|
pub directory: String,
|
||||||
|
pub app_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Content)]
|
||||||
|
struct Data<T> {
|
||||||
|
app_name: String,
|
||||||
|
data: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Template {
|
impl Template {
|
||||||
|
@ -10,6 +18,100 @@ impl Template {
|
||||||
let mut templates: Ramhorns = Ramhorns::lazy(&self.directory).unwrap();
|
let mut templates: Ramhorns = Ramhorns::lazy(&self.directory).unwrap();
|
||||||
let tplt = templates.from_file(template).unwrap();
|
let tplt = templates.from_file(template).unwrap();
|
||||||
|
|
||||||
tplt.render(&data)
|
tplt.render(&Data {
|
||||||
|
app_name: self.app_name.clone(),
|
||||||
|
data,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum FrontMatter<'a> {
|
||||||
|
Yaml(&'a str),
|
||||||
|
Toml(&'a str),
|
||||||
|
Json(&'a str),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FrontMatter<'_> {
|
||||||
|
fn parse(&self) -> FileMetadata {
|
||||||
|
match self {
|
||||||
|
Self::Yaml(val) => serde_yaml::from_str(val).unwrap_or_default(),
|
||||||
|
Self::Toml(_val) => todo!(),
|
||||||
|
Self::Json(_val) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Deserialize, Content)]
|
||||||
|
pub struct FileMetadata {
|
||||||
|
pub title: Option<String>,
|
||||||
|
pub link: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Content)]
|
||||||
|
pub struct Metadata {
|
||||||
|
pub info: FileMetadata,
|
||||||
|
pub mermaid: bool,
|
||||||
|
pub syntax_highlight: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_md(filename: &str) -> (Metadata, String) {
|
||||||
|
// Read markdown file
|
||||||
|
let mut text = std::fs::read_to_string(filename).unwrap();
|
||||||
|
|
||||||
|
// Transform LaTeX to MathML
|
||||||
|
text = latex2mathml::replace(&text).unwrap();
|
||||||
|
|
||||||
|
let parse_option = markdown::ParseOptions {
|
||||||
|
constructs: markdown::Constructs {
|
||||||
|
frontmatter: true,
|
||||||
|
..markdown::Constructs::gfm()
|
||||||
|
},
|
||||||
|
..markdown::ParseOptions::gfm()
|
||||||
|
};
|
||||||
|
|
||||||
|
let compile_option = markdown::CompileOptions {
|
||||||
|
allow_dangerous_html: true,
|
||||||
|
..markdown::CompileOptions::gfm()
|
||||||
|
};
|
||||||
|
|
||||||
|
let md_tree = markdown::to_mdast(&text, &parse_option).unwrap();
|
||||||
|
let md_nodes = md_tree.children().unwrap();
|
||||||
|
let metadata = match &md_nodes[0] {
|
||||||
|
markdown::mdast::Node::Yaml(v) => FrontMatter::Yaml(&v.value).parse(),
|
||||||
|
markdown::mdast::Node::Toml(v) => FrontMatter::Toml(&v.value).parse(),
|
||||||
|
markdown::mdast::Node::MdxjsEsm(v) => FrontMatter::Json(&v.value).parse(),
|
||||||
|
_ => FileMetadata::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert to HTML
|
||||||
|
let html = markdown::to_html_with_options(
|
||||||
|
&text,
|
||||||
|
&markdown::Options {
|
||||||
|
parse: parse_option,
|
||||||
|
compile: compile_option,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Find if document contains mermaid diagram
|
||||||
|
let mermaid = Some(String::from("mermaid"));
|
||||||
|
let presence_mermaid = md_nodes.iter().any(|x| match x {
|
||||||
|
markdown::mdast::Node::Code(code) => code.lang == mermaid,
|
||||||
|
_ => false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Find if document contains code to highlight
|
||||||
|
let presence_code = md_nodes.iter().any(|x| match x {
|
||||||
|
markdown::mdast::Node::Code(code) => code.lang != mermaid,
|
||||||
|
_ => false,
|
||||||
|
});
|
||||||
|
|
||||||
|
(
|
||||||
|
Metadata {
|
||||||
|
info: metadata,
|
||||||
|
mermaid: presence_mermaid,
|
||||||
|
syntax_highlight: presence_code,
|
||||||
|
},
|
||||||
|
html,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue