summaryrefslogtreecommitdiffstats
path: root/src/utils.rs
blob: 8928cfb9fc292c0b1bb55e1fb025cc3ae324c55d (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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use std::path::PathBuf;

pub fn pandoc_stringify(inlines: &[pandoc_ast::Inline]) -> String {
    fn pandoc_stringify_(result: &mut String, inlines: &[pandoc_ast::Inline]) {
        for inline in inlines {
            match inline {
                pandoc_ast::Inline::Str(s)
                | pandoc_ast::Inline::Code(_, s)
                | pandoc_ast::Inline::Math(_, s) => result.push_str(s),
                pandoc_ast::Inline::Emph(inner)
                | pandoc_ast::Inline::Underline(inner)
                | pandoc_ast::Inline::Strong(inner)
                | pandoc_ast::Inline::Strikeout(inner)
                | pandoc_ast::Inline::Superscript(inner)
                | pandoc_ast::Inline::Subscript(inner)
                | pandoc_ast::Inline::SmallCaps(inner)
                | pandoc_ast::Inline::Quoted(_, inner)
                | pandoc_ast::Inline::Cite(_, inner)
                | pandoc_ast::Inline::Link(_, inner, _)
                | pandoc_ast::Inline::Image(_, inner, _)
                | pandoc_ast::Inline::Span(_, inner) => pandoc_stringify_(result, inner),
                pandoc_ast::Inline::Space => result.push(' '),
                pandoc_ast::Inline::SoftBreak => todo!(),
                pandoc_ast::Inline::LineBreak => todo!(),
                pandoc_ast::Inline::RawInline(_, _) => todo!(),
                pandoc_ast::Inline::Note(_) => todo!(),
            }
        }
    }

    let mut result = String::new();
    pandoc_stringify_(&mut result, inlines);
    result
}

/// Follows the algorithm specified in the Pandoc manual[1]
///
/// [1]: <https://pandoc.org/MANUAL.html#extension-auto_identifiers>
#[derive(Debug)]
pub struct AutoIdentifier(pub String);

impl std::ops::Deref for AutoIdentifier {
    type Target = String;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl From<AutoIdentifier> for String {
    fn from(id: AutoIdentifier) -> Self {
        id.0
    }
}

impl From<&[pandoc_ast::Inline]> for AutoIdentifier {
    fn from(inlines: &[pandoc_ast::Inline]) -> Self {
        let text = pandoc_stringify(inlines);
        AutoIdentifier::from(text.as_str())
    }
}

impl From<&str> for AutoIdentifier {
    fn from(text: &str) -> Self {
        let id = text
            .chars()
            .skip_while(|ch| !ch.is_alphabetic())
            .filter_map(|ch| {
                if !ch.is_ascii_alphanumeric()
                    && !ch.is_whitespace()
                    && ch != '_'
                    && ch != '-'
                    && ch != '.'
                {
                    return None;
                }

                if ch.is_whitespace() {
                    return Some('-');
                }

                Some(ch.to_ascii_lowercase())
            })
            .collect();

        AutoIdentifier(id)
    }
}

pub trait PandocOutputExt {
    fn buffer(self) -> String;
    fn file(self) -> PathBuf;
}

impl PandocOutputExt for pandoc::PandocOutput {
    fn buffer(self) -> String {
        match self {
            pandoc::PandocOutput::ToBuffer(buffer) => buffer,
            pandoc::PandocOutput::ToBufferRaw(_) => {
                panic!("Expected text pandoc output, found binary format")
            }
            pandoc::PandocOutput::ToFile(_) => {
                panic!("Expected buffered pandoc output, found file")
            }
        }
    }

    fn file(self) -> PathBuf {
        match self {
            pandoc::PandocOutput::ToFile(file) => file,
            _ => panic!("Expected file pandoc output, found buffer"),
        }
    }
}

pub type PandocMeta = pandoc_ast::Map<String, pandoc_ast::MetaValue>;