Change bibliography to an easier concept
Definitions are similar to the markdown key-url definitions: [key]:url [key]:[metadata] References work like some markdown-footnote concepts: [^key]pull/1/head
parent
1eea0e3b86
commit
8498f4c66c
@ -0,0 +1,200 @@
|
||||
use crate::format::Template;
|
||||
use crate::parsing::configuration::keys::{BIB_DISPLAY, BIB_HIDE_UNUSED};
|
||||
use crate::parsing::configuration::{ConfigRefEntry, Configuration, Value};
|
||||
use crate::parsing::elements::Metadata;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
const B_NUMBER: &str = "number";
|
||||
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 {
|
||||
pub(crate) number: usize,
|
||||
pub(crate) ref_count: usize,
|
||||
pub key: String,
|
||||
pub author: Option<String>,
|
||||
pub date: Option<String>,
|
||||
pub url: Option<String>,
|
||||
pub title: Option<String>,
|
||||
pub publisher: Option<String>,
|
||||
pub notes: Option<String>,
|
||||
pub display: Option<ConfigRefEntry>,
|
||||
pub hide_unused: Option<ConfigRefEntry>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BibReference {
|
||||
pub(crate) key: String,
|
||||
pub(crate) reference_entry: Option<Arc<Mutex<BibEntry>>>,
|
||||
pub(crate) display: Option<ConfigRefEntry>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Bibliography {
|
||||
entries: HashMap<String, Arc<Mutex<BibEntry>>>,
|
||||
references: Vec<Arc<Mutex<BibReference>>>,
|
||||
}
|
||||
|
||||
impl BibEntry {
|
||||
pub fn as_map(&self) -> HashMap<String, String> {
|
||||
let mut map = HashMap::new();
|
||||
map.insert(B_NUMBER.to_string(), format!("{}", self.number));
|
||||
map.insert("key".to_string(), self.key.clone());
|
||||
if let Some(author) = &self.author {
|
||||
map.insert(B_AUTHOR.to_string(), author.clone());
|
||||
}
|
||||
if let Some(date) = &self.date {
|
||||
map.insert(B_DATE.to_string(), date.clone());
|
||||
}
|
||||
if let Some(url) = &self.url {
|
||||
map.insert(B_URL.to_string(), url.clone());
|
||||
}
|
||||
if let Some(title) = &self.title {
|
||||
map.insert(B_TITLE.to_string(), title.clone());
|
||||
}
|
||||
if let Some(publisher) = &self.publisher {
|
||||
map.insert(B_PUBLISHER.to_string(), publisher.clone());
|
||||
}
|
||||
if let Some(notes) = &self.notes {
|
||||
map.insert(B_NOTES.to_string(), notes.clone());
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
pub fn from_metadata(key: String, data: Box<dyn Metadata>, config: &Configuration) -> Self {
|
||||
BibEntry {
|
||||
number: 0,
|
||||
ref_count: 0,
|
||||
key,
|
||||
author: data.get_string(B_AUTHOR),
|
||||
date: data.get_string(B_DATE),
|
||||
url: data.get_string(B_URL),
|
||||
title: data.get_string(B_TITLE),
|
||||
publisher: data.get_string(B_PUBLISHER),
|
||||
notes: data.get_string(B_NOTES),
|
||||
display: config.get_ref_entry(BIB_DISPLAY),
|
||||
hide_unused: config.get_ref_entry(BIB_HIDE_UNUSED),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_url(key: String, url: String, config: &Configuration) -> Self {
|
||||
BibEntry {
|
||||
number: 0,
|
||||
ref_count: 0,
|
||||
key,
|
||||
author: None,
|
||||
date: None,
|
||||
url: Some(url),
|
||||
title: None,
|
||||
publisher: None,
|
||||
notes: None,
|
||||
display: config.get_ref_entry(BIB_DISPLAY),
|
||||
hide_unused: config.get_ref_entry(BIB_HIDE_UNUSED),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_number(&mut self, number: usize) {
|
||||
self.number = number
|
||||
}
|
||||
|
||||
pub fn set_ref_count(&mut self, number: usize) {
|
||||
self.ref_count = number
|
||||
}
|
||||
|
||||
pub fn is_visible(&self) -> bool {
|
||||
if let Some(hide_cfg) = &self.hide_unused {
|
||||
let hide_cfg = hide_cfg.lock().unwrap();
|
||||
if let Value::Bool(b) = hide_cfg.get() {
|
||||
if *b && self.ref_count == 0 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl BibReference {
|
||||
pub fn new(key: String, display: Option<ConfigRefEntry>) -> Self {
|
||||
Self {
|
||||
key: key.to_string(),
|
||||
display,
|
||||
reference_entry: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// sets the reference to the bib entry
|
||||
pub(crate) fn set_entry(&mut self, entry: Arc<Mutex<BibEntry>>) {
|
||||
self.reference_entry = Some(entry)
|
||||
}
|
||||
|
||||
pub(crate) fn get_formatted(&self) -> String {
|
||||
if let Some(entry) = &self.reference_entry {
|
||||
let entry = entry.lock().unwrap();
|
||||
if let Some(display) = &self.display {
|
||||
let display = display.lock().unwrap();
|
||||
let mut template = Template::new(display.get().as_string());
|
||||
template.set_replacements(entry.as_map());
|
||||
return template.render();
|
||||
}
|
||||
return format!("{}", entry.number);
|
||||
}
|
||||
|
||||
return "citation needed".to_string();
|
||||
}
|
||||
}
|
||||
|
||||
impl Bibliography {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
entries: HashMap::new(),
|
||||
references: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn assign_entry_data(&mut self) {
|
||||
let mut count = 0;
|
||||
self.references.iter().for_each(|e| {
|
||||
let mut reference = e.lock().unwrap();
|
||||
if let Some(entry) = self.entries.get(&reference.key) {
|
||||
{
|
||||
let mut entry_raw = entry.lock().unwrap();
|
||||
let ref_count = entry_raw.ref_count;
|
||||
entry_raw.set_ref_count(ref_count + 1);
|
||||
}
|
||||
reference.set_entry(Arc::clone(entry));
|
||||
}
|
||||
});
|
||||
self.entries.iter().for_each(|(_, e)| {
|
||||
let mut entry = e.lock().unwrap();
|
||||
if entry.is_visible() {
|
||||
count += 1;
|
||||
entry.set_number(count)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn add_ref_entry(&mut self, entry: Arc<Mutex<BibReference>>) {
|
||||
self.references.push(entry)
|
||||
}
|
||||
|
||||
pub fn add_bib_entry(&mut self, entry: Arc<Mutex<BibEntry>>) {
|
||||
let key = entry.lock().unwrap().key.clone();
|
||||
self.entries.insert(key, entry);
|
||||
}
|
||||
|
||||
pub fn combine(&mut self, other: &mut Bibliography) {
|
||||
let other_entries = other.entries.clone();
|
||||
other.entries = HashMap::new();
|
||||
self.entries.extend(other_entries.into_iter());
|
||||
self.references.append(&mut other.references);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct RootConfig {
|
||||
pub(crate) bibliography: Option<BibConfig>,
|
||||
pub(crate) metadata: Option<MetaConfig>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct BibConfig {
|
||||
pub(crate) entry_display: Option<String>,
|
||||
pub(crate) reference_display: Option<String>,
|
||||
pub(crate) hide_unused: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct MetaConfig {
|
||||
pub(crate) author: Option<String>,
|
||||
pub(crate) date: Option<String>,
|
||||
pub(crate) title: Option<String>,
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
[bibliography]
|
||||
entry_display = "{{number}}: {{author}} - {{title}} - {{date}} - {{url}}"
|
||||
reference_display = "{{number}}"
|
||||
hide_unused = true
|
@ -0,0 +1,7 @@
|
||||
pub const BIB_DISPLAY: &str = "bib-entry-display";
|
||||
pub const BIB_REF_DISPLAY: &str = "bib-ref-display";
|
||||
pub const BIB_HIDE_UNUSED: &str = "bib-hide-unused";
|
||||
|
||||
pub const META_AUTHOR: &str = "author";
|
||||
pub const META_TITLE: &str = "title";
|
||||
pub const META_DATE: &str = "date";
|
@ -0,0 +1,141 @@
|
||||
use crate::parsing::configuration::config::RootConfig;
|
||||
use crate::parsing::configuration::keys::{
|
||||
BIB_DISPLAY, BIB_HIDE_UNUSED, BIB_REF_DISPLAY, META_AUTHOR, META_DATE, META_TITLE,
|
||||
};
|
||||
use crate::parsing::elements::MetadataValue;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
pub mod config;
|
||||
pub(crate) mod keys;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Value {
|
||||
String(String),
|
||||
Bool(bool),
|
||||
Float(f64),
|
||||
Integer(i64),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ConfigEntry {
|
||||
inner: Value,
|
||||
}
|
||||
|
||||
pub type ConfigRefEntry = Arc<Mutex<ConfigEntry>>;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Configuration {
|
||||
config: Arc<Mutex<HashMap<String, ConfigRefEntry>>>,
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn as_string(&self) -> String {
|
||||
match self {
|
||||
Value::String(string) => string.clone(),
|
||||
Value::Integer(int) => format!("{}", int),
|
||||
Value::Float(f) => format!("{:02}", f),
|
||||
Value::Bool(b) => format!("{}", b),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigEntry {
|
||||
pub fn new(value: Value) -> Self {
|
||||
Self { inner: value }
|
||||
}
|
||||
|
||||
pub fn set(&mut self, value: Value) {
|
||||
self.inner = value;
|
||||
}
|
||||
|
||||
pub fn get(&self) -> &Value {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl Configuration {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
config: Arc::new(Mutex::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default() -> Self {
|
||||
let mut self_config = Self::new();
|
||||
lazy_static::lazy_static! { static ref CONFIG: RootConfig = toml::from_str(std::include_str!("default.toml")).unwrap();}
|
||||
self_config.assign_config(&CONFIG);
|
||||
|
||||
self_config
|
||||
}
|
||||
|
||||
pub fn assign_config(&mut self, config: &RootConfig) {
|
||||
if let Some(bib) = &config.bibliography {
|
||||
if let Some(cfg) = &bib.entry_display {
|
||||
self.set(BIB_DISPLAY, Value::String(cfg.clone()))
|
||||
}
|
||||
if let Some(cfg) = &bib.reference_display {
|
||||
self.set(BIB_REF_DISPLAY, Value::String(cfg.clone()))
|
||||
}
|
||||
if let Some(cfg) = &bib.hide_unused {
|
||||
self.set(BIB_HIDE_UNUSED, Value::Bool(*cfg));
|
||||
}
|
||||
}
|
||||
if let Some(meta) = &config.metadata {
|
||||
if let Some(cfg) = &meta.author {
|
||||
self.set(META_AUTHOR, Value::String(cfg.clone()))
|
||||
}
|
||||
if let Some(cfg) = &meta.date {
|
||||
self.set(META_DATE, Value::String(cfg.clone()))
|
||||
}
|
||||
if let Some(cfg) = &meta.title {
|
||||
self.set(META_TITLE, Value::String(cfg.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// returns the value of a config entry
|
||||
pub fn get_entry(&self, key: &str) -> Option<ConfigEntry> {
|
||||
let config = self.config.lock().unwrap();
|
||||
if let Some(entry) = config.get(key) {
|
||||
let value = entry.lock().unwrap();
|
||||
Some(value.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// returns a config entry that is a reference to a value
|
||||
pub fn get_ref_entry(&self, key: &str) -> Option<ConfigRefEntry> {
|
||||
let config = self.config.lock().unwrap();
|
||||
if let Some(entry) = config.get(&key.to_string()) {
|
||||
Some(Arc::clone(entry))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets a config parameter
|
||||
pub fn set(&mut self, key: &str, value: Value) {
|
||||
let mut config = self.config.lock().unwrap();
|
||||
if let Some(entry) = config.get(&key.to_string()) {
|
||||
entry.lock().unwrap().set(value)
|
||||
} else {
|
||||
config.insert(
|
||||
key.to_string(),
|
||||
Arc::new(Mutex::new(ConfigEntry::new(value))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets a config value based on a metadata value
|
||||
pub fn set_from_meta(&mut self, key: &str, value: MetadataValue) {
|
||||
match value {
|
||||
MetadataValue::String(string) => self.set(key, Value::String(string)),
|
||||
MetadataValue::Bool(bool) => self.set(key, Value::Bool(bool)),
|
||||
MetadataValue::Float(f) => self.set(key, Value::Float(f)),
|
||||
MetadataValue::Integer(i) => self.set(key, Value::Integer(i)),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,11 @@
|
||||
pub mod bibliography;
|
||||
pub mod charstate;
|
||||
pub mod configuration;
|
||||
pub mod elements;
|
||||
pub mod inline;
|
||||
pub mod parser;
|
||||
pub mod placeholders;
|
||||
pub mod tokens;
|
||||
|
||||
#[macro_use]
|
||||
pub mod utils;
|
||||
|
Loading…
Reference in New Issue