Passed
Push — develop ( 04581e...6ee6c6 )
by Christophe
01:36
created

pandoc_glfm._main   A

Complexity

Total Complexity 38

Size/Duplication

Total Lines 242
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 38
eloc 115
dl 0
loc 242
rs 9.36
c 0
b 0
f 0

5 Functions

Rating   Name   Duplication   Size   Complexity  
A remove_strikeout() 0 21 3
F alert() 0 115 17
C task() 0 29 10
B cell() 0 29 7
A main() 0 15 1
1
#!/usr/bin/env python
2
3
"""
4
Pandoc filter for adding glfm features to pandoc.
5
"""
6
7
from panflute import (
8
    Div,
9
    Doc,
10
    Element,
11
    Para,
12
    Plain,
13
    Str,
14
    Strikeout,
15
    convert_text,
16
    run_filters,
17
)
18
19
20
# pylint: disable=inconsistent-return-statements,unused-argument
21
def alert(elem: Element, doc: Doc) -> Element | None:
22
    """
23
    Transform some blockquote elements to alerts.
24
25
    Arguments
26
    ---------
27
    elem
28
        The current element
29
    doc
30
        The pandoc document
31
32
    Returns
33
    -------
34
    Element | None
35
        The modified element or None
36
    """
37
    if (
38
        elem.tag == "BlockQuote"
39
        and elem.content
40
        and elem.content[0].tag == "Para"
41
        and elem.content[0].content
42
        and elem.content[0].content[0].tag == "Str"
43
    ):
44
45
        def extract_first_lines(
46
            first: list[Element],
47
            rest: list[Element],
48
        ) -> list[Element]:
49
            result = []
50
            for item in first:
51
                if item.tag == "Str":
52
                    result.append(item.text)
53
                elif item.tag == "SoftBreak":
54
                    result.append("\n")
55
                elif item.tag == "Space":
56
                    result.append(" ")
57
                else:
58
                    result.append(
59
                        convert_text(
60
                            Plain(item),
61
                            input_format="panflute",
62
                            output_format="markdown",
63
                        ),
64
                    )
65
            for item in rest:
66
                result.extend(
67
                    [
68
                        "\n",
69
                        convert_text(
70
                            item,
71
                            input_format="panflute",
72
                            output_format="markdown",
73
                        ),
74
                    ]
75
                )
76
77
            return convert_text("".join(result))
78
79
        text = elem.content[0].content[0].text.lower()
80
        if text in ("[!note]", "[!tip]", "[!important]", "[!caution]", "[!warning]"):
81
            # Case
82
            #
83
            # > [!tip]
84
            #
85
            # and
86
            #
87
            # > [!tip]
88
            # >
89
            # > Rest of text
90
            if len(elem.content[0].content) == 1:
91
                title = Div(Para(Str(text[2:-1].capitalize())), classes=["title"])
92
                content = [*elem.content[1:]]
93
            # Case
94
            #
95
            # > [!tip]
96
            # > Rest of text
97
            elif elem.content[0].content[1].tag == "SoftBreak":
98
                title = Div(Para(Str(text[2:-1].capitalize())), classes=["title"])
99
                content = extract_first_lines(
100
                    elem.content[0].content[2:],
101
                    elem.content[1:],
102
                )
103
            # Case
104
            #
105
            # > [!tip] title
106
            # > Rest of text
107
            #
108
            # and
109
            #
110
            # > [!tip] title
111
            # >
112
            # > Rest of text
113
            else:
114
                alternate = []
115
                for index in range(2, len(elem.content[0].content)):
116
                    if elem.content[0].content[index].tag == "SoftBreak":
117
                        title = Div(Para(*alternate), classes=["title"])
118
                        content = extract_first_lines(
119
                            elem.content[0].content[index:],
120
                            elem.content[1:],
121
                        )
122
                        break
123
                    alternate.append(elem.content[0].content[index])
124
                else:
125
                    title = Div(Para(*alternate), classes=["title"])
126
                    content = [*elem.content[1:]]
127
128
            return convert_text(
129
                convert_text(
130
                    Div(title, *content, classes=[text[2:-1]]),
131
                    input_format="panflute",
132
                    output_format="markdown",
133
                )
134
            )
135
    return None
136
137
138
def task(elem: Element, doc: Doc) -> None:
139
    """
140
    Deal with glfm task lists.
141
142
    Arguments
143
    ---------
144
    elem
145
        The current element
146
    doc
147
        The pandoc document
148
    """
149
    if elem.tag in ("BulletList", "OrderedList"):
150
        for item in elem.content:
151
            if (
152
                item.content[0].tag in ("Plain", "Para")
153
                and item.content[0].content
154
                and item.content[0].content[0].tag == "Str"
155
                and item.content[0].content[0].text == "[~]"
156
                and len(item.content[0].content) >= 3
157
            ):
158
                item.content[0].content[0].text = "☐"
159
                item.content[0].content[2] = Strikeout(
160
                    *remove_strikeout(item.content[0].content[2:]),
161
                )
162
                item.content[0].content[3:] = []
163
                for block in item.content[1:]:
164
                    if block.tag in ("Plain", "Para"):
165
                        block.content[0] = Strikeout(*remove_strikeout(block.content))
166
                        block.content[1:] = []
167
168
169
def remove_strikeout(elems: list[Element]) -> list[Element]:
170
    """
171
    Remove Strikeout from elements.
172
173
    Parameters
174
    ----------
175
    elems
176
        Elements from which Strikeout must be removed
177
178
    Returns
179
    -------
180
    list[Element]
181
        The elements without the Strikeout.
182
    """
183
    result = []
184
    for elem in elems:
185
        if elem.tag == "Strikeout":
186
            result.extend(elem.content)
187
        else:
188
            result.append(elem)
189
    return result
190
191
192
def cell(elem: Element, doc: Doc) -> None:
193
    """
194
    Transfom cell elements that contain <br />.
195
196
    Parameters
197
    ----------
198
        The current element
199
    doc
200
        The pandoc document
201
202
    """
203
    if elem.tag == "TableCell":
204
        convert = False
205
        for index, item in enumerate(elem.content[0].content):
206
            if (
207
                item.tag == "RawInline"
208
                and item.format == "html"
209
                and item.text in ("<br>", "<br/>", "<br />")
210
            ):
211
                convert = True
212
                elem.content[0].content[index] = Str("\n")
213
214
        if convert:
215
            text = convert_text(
216
                elem.content[0],
217
                input_format="panflute",
218
                output_format="markdown",
219
            )
220
            elem.content = convert_text(text)
221
222
223
def main(doc: Doc | None = None) -> Doc:
224
    """
225
    Convert the pandoc document.
226
227
    Arguments
228
    ---------
229
    doc
230
        The pandoc document
231
232
    Returns
233
    -------
234
    Doc
235
        The modified pandoc document
236
    """
237
    return run_filters([alert, task, cell], doc=doc)
238
239
240
if __name__ == "__main__":
241
    main()
242