Add bibliography, references and settings placeholders

pull/1/head
trivernis 4 years ago
parent cfc02b8da7
commit e2f0d88acf

40
Cargo.lock generated

@ -5,6 +5,14 @@ name = "adler32"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "aho-corasick"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
@ -182,6 +190,11 @@ name = "linked-hash-map"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "minify"
version = "1.1.1"
@ -308,6 +321,17 @@ dependencies = [
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "1.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.6.18"
@ -358,12 +382,14 @@ dependencies = [
[[package]]
name = "snekdown"
version = "0.7.0"
version = "0.8.0"
dependencies = [
"chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"htmlescape 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"minify 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"syntect 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -456,6 +482,14 @@ dependencies = [
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "time"
version = "0.1.43"
@ -542,6 +576,7 @@ dependencies = [
[metadata]
"checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
@ -567,6 +602,7 @@ dependencies = [
"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
"checksum line-wrap 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9"
"checksum linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
"checksum minify 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ef7c582bd7587da887914eaf294897e82f2f5c98b741f137f2a918cd26a885b"
"checksum miniz_oxide 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aa679ff6578b1cddee93d7e82e263b94a575e0bfced07284eb0c037c1d2416a5"
"checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
@ -582,6 +618,7 @@ dependencies = [
"checksum quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea"
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
"checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
"checksum ryu 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1"
"checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
@ -597,6 +634,7 @@ dependencies = [
"checksum syntect 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83b43a6ca1829ccb0c933b615c9ea83ffc8793ae240cecbd15119b13d741161d"
"checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
"checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"

@ -1,6 +1,6 @@
[package]
name = "snekdown"
version = "0.7.0"
version = "0.8.0"
authors = ["trivernis <trivernis@protonmail.com>"]
edition = "2018"
license-file = "LICENSE"
@ -25,4 +25,6 @@ termion = "1.5.5"
minify = "1.1.1"
htmlescape = "0.3.1"
syntect = "4.2.0"
chrono = "0.4.11"
chrono = "0.4.11"
regex = "1.3.9"
lazy_static = "1.4.0"

@ -37,6 +37,7 @@ impl ToHtml for Line {
Line::Ruler(ruler) => ruler.to_html(),
Line::Anchor(anchor) => anchor.to_html(),
Line::Centered(centered) => centered.to_html(),
Line::ReferenceEntry(ref_entry) => ref_entry.to_html(),
}
}
}
@ -53,6 +54,7 @@ impl ToHtml for Inline {
Inline::Bold(bold) => bold.to_html(),
Inline::Image(img) => img.to_html(),
Inline::Placeholder(placeholder) => placeholder.lock().unwrap().to_html(),
Inline::Reference(reference) => reference.to_html(),
}
}
}
@ -421,3 +423,31 @@ impl ToHtml for Centered {
format!("<div class='centered'>{}</div>", self.line.to_html())
}
}
impl ToHtml for Reference {
fn to_html(&self) -> String {
if let Some(value) = &self.value {
value.to_html()
} else {
"Unknown reference".to_string()
}
}
}
impl ToHtml for RefValue {
fn to_html(&self) -> String {
match self {
RefValue::BibEntry(bib) => encode_minimal(bib.lock().unwrap().get_formatted().as_str()),
}
}
}
impl ToHtml for ReferenceEntry {
fn to_html(&self) -> String {
if let Some(val) = &self.value {
val.to_html()
} else {
"Unknown reference".to_string()
}
}
}

@ -1,3 +1,4 @@
use crate::parsing::placeholders::BibEntry;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
@ -58,6 +59,7 @@ pub enum Line {
Ruler(Ruler),
Anchor(Anchor),
Centered(Centered),
ReferenceEntry(ReferenceEntry),
}
#[derive(Clone, Debug)]
@ -66,6 +68,8 @@ pub struct Document {
pub(crate) is_root: bool,
pub(crate) path: Option<String>,
pub(crate) placeholders: Vec<Arc<Mutex<Placeholder>>>,
pub bib_entries: HashMap<String, Arc<Mutex<BibEntry>>>,
pub config_settings: HashMap<String, Arc<Mutex<ConfigValue>>>,
}
#[derive(Clone, Debug)]
@ -164,6 +168,7 @@ pub enum Inline {
Url(Url),
Image(Image),
Placeholder(Arc<Mutex<Placeholder>>),
Reference(Reference),
}
#[derive(Clone, Debug)]
@ -226,15 +231,56 @@ pub struct Centered {
pub(crate) line: TextLine,
}
#[derive(Clone, Debug)]
pub struct Reference {
pub(crate) value: Option<RefValue>,
pub(crate) metadata: Option<InlineMetadata>,
}
#[derive(Clone, Debug)]
pub struct ReferenceEntry {
pub(crate) value: Option<RefValue>,
}
#[derive(Clone, Debug)]
pub enum RefValue {
BibEntry(Arc<Mutex<BibEntry>>),
}
#[derive(Clone, Debug)]
pub struct ConfigValue {
pub(crate) value: MetadataValue,
}
impl ConfigValue {
fn set_value(&mut self, value: MetadataValue) {
self.value = value;
}
}
// implementations
impl Document {
fn get_default_config() -> HashMap<String, Arc<Mutex<ConfigValue>>> {
let mut config: HashMap<String, Arc<Mutex<ConfigValue>>> = HashMap::new();
config.insert(
"bib-display".to_string(),
Arc::new(Mutex::new(ConfigValue {
value: MetadataValue::String("title - author - year - (notes)".to_string()),
})),
);
config
}
pub fn new(is_root: bool) -> Self {
Self {
elements: Vec::new(),
is_root,
path: None,
placeholders: Vec::new(),
bib_entries: HashMap::new(),
config_settings: Self::get_default_config(),
}
}
@ -289,6 +335,29 @@ impl Document {
list
}
pub fn set_config_param(
&mut self,
key: String,
value: ConfigValue,
) -> Option<Arc<Mutex<ConfigValue>>> {
if let Some(arc_val) = self.config_settings.get(&key) {
arc_val.lock().unwrap().set_value(value.value);
Some(Arc::clone(&arc_val))
} else {
self.config_settings
.insert(key, Arc::new(Mutex::new(value)))
}
}
pub fn get_config_param(&self, key: &str) -> Option<Arc<Mutex<ConfigValue>>> {
if let Some(val) = self.config_settings.get(key) {
Some(Arc::clone(val))
} else {
None
}
}
}
impl Section {
@ -497,4 +566,12 @@ impl InlineMetadata {
false
}
}
pub fn get_string(&self, key: &str) -> Option<String> {
if let Some(MetadataValue::String(value)) = self.data.get(key) {
Some(value.clone())
} else {
None
}
}
}

@ -1,5 +1,7 @@
use super::elements::*;
use chrono::prelude::*;
use regex::Regex;
use std::sync::{Arc, Mutex, MutexGuard};
macro_rules! block {
($inner:expr) => {
@ -22,8 +24,67 @@ macro_rules! inline {
pub(crate) trait ProcessPlaceholders {
fn process_placeholders(&mut self);
fn process_definitions(&mut self);
fn add_bib_entry(&mut self, key: String, value: BibEntry) -> Arc<Mutex<BibEntry>>;
fn get_bib_entry(&self, ph: &MutexGuard<Placeholder>, key: &str) -> BibEntry;
}
const B_AUTHOR: &str = "author";
const B_DATE: &str = "date";
const B_URL: &str = "url";
const B_TITLE: &str = "title";
const B_PUBLISHER: &str = "publisher";
const B_NOTES: &str = "notes";
#[derive(Clone, Debug)]
pub struct BibEntry {
key: String,
author: Option<String>,
date: Option<String>,
url: Option<String>,
title: Option<String>,
publisher: Option<String>,
notes: Option<String>,
display: Option<Arc<Mutex<ConfigValue>>>,
}
impl BibEntry {
pub fn get_formatted(&self) -> String {
if let Some(display) = &self.display {
let value = display.lock().unwrap();
if let MetadataValue::String(format) = &value.value {
let mut format = format.clone();
if let Some(author) = &self.author {
format = format.replace("author", author);
}
if let Some(date) = &self.date {
format = format.replace("date", date);
}
if let Some(url) = &self.url {
format = format.replace("url", url)
}
if let Some(title) = &self.title {
format = format.replace("title", title);
}
if let Some(publisher) = &self.publisher {
format = format.replace("publisher", publisher);
}
if let Some(notes) = &self.notes {
format = format.replace("notes", notes);
}
format
} else {
format!("'Invalid formatter!' {:?}", self)
}
} else {
format!("{:?}", self)
}
}
}
const S_VALUE: &str = "value";
const P_TOC: &str = "toc";
const P_DATE: &str = "date";
const P_TIME: &str = "time";
@ -32,8 +93,25 @@ const P_DATETIME: &str = "datetime";
impl ProcessPlaceholders for Document {
/// parses all placeholders and assigns values to them
fn process_placeholders(&mut self) {
self.process_definitions();
lazy_static::lazy_static! {static ref RE_REF: Regex = Regex::new(r"^ref:(.*)$").unwrap();}
self.placeholders.iter().for_each(|p| {
let mut pholder = p.lock().unwrap();
if let Some(cap) = RE_REF.captures(&pholder.name) {
if let Some(key) = cap.get(1) {
if let Some(entry) = self.bib_entries.get(key.as_str()) {
pholder.value = Some(inline!(Inline::Reference(Reference {
value: Some(RefValue::BibEntry(entry.clone())),
metadata: pholder.metadata.clone()
})))
} else {
pholder.value = Some(inline!(Inline::Reference(Reference {
value: None,
metadata: pholder.metadata.clone()
})))
}
}
}
match pholder.name.to_ascii_lowercase().as_str() {
P_TOC => {
let ordered = if let Some(meta) = &pholder.metadata {
@ -56,6 +134,89 @@ impl ProcessPlaceholders for Document {
}
})
}
fn process_definitions(&mut self) {
lazy_static::lazy_static! {
static ref RE_BIB: Regex = Regex::new(r"^bib:(.*)$").unwrap();
}
lazy_static::lazy_static! {
static ref RE_SET: Regex = Regex::new(r"^set:(.*)$").unwrap();
}
let placeholders = self.placeholders.clone();
placeholders.iter().for_each(|p| {
let mut pholder = p.lock().unwrap();
let name = pholder.name.clone();
if let Some(cap) = RE_BIB.captures(&name) {
if let Some(key) = cap.get(1) {
let key: &str = key.as_str();
let entry = self.get_bib_entry(&pholder, key);
let entry = self.add_bib_entry(key.to_string(), entry);
pholder.value = Some(Element::Line(Box::new(Line::ReferenceEntry(
ReferenceEntry {
value: Some(RefValue::BibEntry(entry)),
},
))));
}
return;
}
if let Some(cap) = RE_SET.captures(&name) {
if let Some(key) = cap.get(1) {
let key: &str = key.as_str();
pholder.value = Some(inline!(Inline::Plain(PlainText {
value: "".to_string()
})));
if let Some(meta) = &pholder.metadata {
if let Some(value) = meta.data.get(S_VALUE) {
self.set_config_param(
key.to_string(),
ConfigValue {
value: value.clone(),
},
);
}
}
}
return;
}
});
}
fn add_bib_entry(&mut self, key: String, value: BibEntry) -> Arc<Mutex<BibEntry>> {
let arc_entry = Arc::new(Mutex::new(value));
self.bib_entries.insert(key, Arc::clone(&arc_entry));
arc_entry
}
fn get_bib_entry(&self, ph: &MutexGuard<Placeholder>, key: &str) -> BibEntry {
if let Some(meta) = &ph.metadata {
BibEntry {
key: key.to_string(),
author: meta.get_string(B_AUTHOR),
date: meta.get_string(B_DATE),
url: meta.get_string(B_URL),
title: meta.get_string(B_TITLE),
publisher: meta.get_string(B_PUBLISHER),
notes: meta.get_string(B_NOTES),
display: self.get_config_param("bib-display"),
}
} else {
BibEntry {
key: key.to_string(),
author: None,
date: None,
url: None,
title: None,
publisher: None,
notes: None,
display: self.get_config_param("bib-display"),
}
}
}
}
fn get_time_string() -> String {

Loading…
Cancel
Save