Skip to content

Commit

Permalink
Refactor citeproc module
Browse files Browse the repository at this point in the history
  • Loading branch information
pfoerster committed Nov 30, 2019
1 parent 7b60df4 commit 9cd61eb
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 34 deletions.
63 changes: 30 additions & 33 deletions src/citeproc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,29 @@ use crate::formatting::bibtex::{format_entry, format_string, BibtexFormattingPar
use crate::syntax::*;
use bibutils::{InputFormat, OutputFormat};
use citeproc::prelude::*;
use citeproc::Processor;
use citeproc_db::PredefinedLocales;
use citeproc_io::Reference;
use lsp_types::*;
use lsp_types::{MarkupContent, MarkupKind};
use std::sync::Arc;

static APA_STYLE: &str = include_str!("apa.csl");

pub fn render_citation(tree: &BibtexSyntaxTree, key: &str) -> Option<MarkupContent> {
let reference: Reference = convert_to_ris(tree, key)?.into();

let html = generate_bibliography(reference)?;
let markdown = html2md::parse_html(&html).trim().to_owned();
if markdown == "" {
return None;
}

let content = MarkupContent {
kind: MarkupKind::Markdown,
value: markdown,
};
Some(content)
}

fn convert_to_ris(tree: &BibtexSyntaxTree, key: &str) -> Option<RisReference> {
let bib_params = BibtexFormattingParams::default();
let mut bib_code = String::new();

Expand All @@ -24,49 +38,32 @@ pub fn render_citation(tree: &BibtexSyntaxTree, key: &str) -> Option<MarkupConte
}

let entry = tree.find_entry(key)?;

if let Some(crossref_field) = entry.find_field("crossref") {
if let Some(BibtexContent::BracedContent(crossref_content)) = &crossref_field.content {
if let Some(BibtexContent::Word(crossref_name)) = crossref_content.children.get(0) {
if let Some(crossref_entry) = tree.find_entry(crossref_name.token.text()) {
bib_code.push_str(&format_entry(crossref_entry, &bib_params));
bib_code.push('\n');
}
}
}
if let Some(crossref) = tree.resolve_crossref(entry) {
bib_code.push_str(&format_entry(crossref, &bib_params));
bib_code.push('\n');
}

bib_code.push_str(&format_entry(entry, &bib_params));
bib_code.push('\n');

let ris_code = unsafe { bibutils::convert(bib_code, InputFormat::Biblatex, OutputFormat::Ris) };
let ris_lib = RisLibrary::parse(ris_code.lines());
let ris_ref = ris_lib
ris_lib
.references
.into_iter()
.find(|reference| reference.id.as_ref().map(AsRef::as_ref) == Some(key))?;

let csl_ref: Reference = ris_ref.into();
.find(|reference| reference.id.as_ref().map(AsRef::as_ref) == Some(key))
}

fn generate_bibliography(reference: Reference) -> Option<String> {
let locales = Arc::new(PredefinedLocales::bundled_en_us());
let mut processor = Processor::new(APA_STYLE, locales, false, SupportedFormat::Html).unwrap();
let mut clusters = Vec::new();
let cite = Cite::basic(&csl_ref.id);
clusters.push(Cluster2::Note {
let cite = Cite::basic(&reference.id);
let cluster = Cluster2::Note {
id: 1,
note: IntraNote::Single(1),
cites: vec![cite],
});
processor.insert_reference(csl_ref);
processor.init_clusters(clusters);
let html = processor.get_bibliography().pop().unwrap();
let markdown = html2md::parse_html(&html).trim().to_owned();
if markdown == "" {
return None;
}

Some(MarkupContent {
kind: MarkupKind::Markdown,
value: markdown,
})
};
processor.insert_reference(reference);
processor.init_clusters(vec![cluster]);
processor.get_bibliography().pop()
}
5 changes: 4 additions & 1 deletion src/citeproc/name/parser.lalrpop
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// Ported from: https://github.com/michel-kraemer/citeproc-java/blob/master/citeproc-java/grammars/InternalName.g4
// Michel Kraemer
// Apache License 2.0
use citeproc_io::{Name, PersonName};
use itertools::Itertools;

grammar;

pub Names: Vec<Name> = And<Name>;

And<T>: Vec<T> = { // (1)
And<T>: Vec<T> = {
<v:(<T> "and")*> <e:T?> => match e {
None => v,
Some(e) => {
Expand Down
11 changes: 11 additions & 0 deletions src/syntax/bibtex/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ impl BibtexSyntaxTree {
.into_iter()
.find(|entry| entry.key.as_ref().map(BibtexToken::text) == Some(key))
}

pub fn resolve_crossref(&self, entry: &BibtexEntry) -> Option<&BibtexEntry> {
if let Some(field) = entry.find_field("crossref") {
if let Some(BibtexContent::BracedContent(content)) = &field.content {
if let Some(BibtexContent::Word(name)) = content.children.get(0) {
return self.find_entry(name.token.text());
}
}
}
None
}
}

impl From<BibtexRoot> for BibtexSyntaxTree {
Expand Down

0 comments on commit 9cd61eb

Please sign in to comment.