summaryrefslogtreecommitdiff
path: root/support/texlab/src/citeproc/mod.rs
blob: 9827c190f37727d5544da16e03de4069de4d7f91 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
mod name;
mod ris;

use self::ris::*;
use crate::formatting::bibtex::{format_entry, format_string, BibtexFormattingParams};
use crate::syntax::*;
use bibutils::{InputFormat, OutputFormat};
use citeproc::prelude::*;
use citeproc_db::PredefinedLocales;
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.replace("..", "."),
    };
    Some(content)
}

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

    for string in tree.strings() {
        bib_code.push_str(&format_string(string, &bib_params));
        bib_code.push('\n');
    }

    let entry = tree.find_entry(key)?;
    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 = bibutils::convert(bib_code, InputFormat::Biblatex, OutputFormat::Ris)?;
    let ris_lib = RisLibrary::parse(ris_code.lines());
    ris_lib
        .references
        .into_iter()
        .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 cite = Cite::basic(&reference.id);
    let cluster = Cluster2::Note {
        id: 1,
        note: IntraNote::Single(1),
        cites: vec![cite],
    };
    processor.insert_reference(reference);
    processor.init_clusters(vec![cluster]);
    processor.get_bibliography().pop()
}