summaryrefslogtreecommitdiffstats
path: root/src/utils.rs
blob: 828ae46693aa7e99eba1c57953067b4ef260e8a9 (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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use std::path::{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>;

pub trait PathExt {
    fn to_string(&self) -> String;
}

impl PathExt for Path {
    fn to_string(&self) -> String {
        self.to_str().expect("Path is not valid UTF-8").to_string()
    }
}

impl PathExt for PathBuf {
    fn to_string(&self) -> String {
        self.to_str().expect("Path is not valid UTF-8").to_string()
    }
}