Completed
Push — master ( dda568...7b6dda )
by Christophe
25s
created

latex_code()   B

Complexity

Conditions 2

Size

Total Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
dl 0
loc 36
rs 8.8571
c 0
b 0
f 0
1
#!/usr/bin/env python
2
3
"""
4
Pandoc filter for adding tip in LaTeX
5
"""
6
7
from panflute import *
8
import os
9
10
try:
11
    FileNotFoundError
12
except NameError:
13
    #py2
14
    FileNotFoundError = IOError
15
16
def tip(elem, doc):
17
    # Is it in the right format and is it a Span, Div?
18
    if doc.format == 'latex' and elem.tag in ['Span', 'Div', 'Code', 'CodeBlock']:
19
20
        # Is there a latex-tip-icon attribute?
21
        if 'latex-tip-icon' in elem.attributes:
22
            return add_latex(
23
                elem,
24
                latex_code(
25
                    doc,
26
                    elem.attributes,
27
                    'latex-tip-icon',
28
                    'latex-tip-position',
29
                    'latex-tip-size',
30
                    'latex-tip-color'
31
                )
32
            )
33
        else:
34
            # Get the classes
35
            classes = set(elem.classes)
36
37
            # Loop on all fontsize definition
38
            for definition in doc.defined:
39
40
                # Are the classes correct?
41
                if classes >= definition['classes']:
42
                    return add_latex(elem, definition['latex'])
43
44
def add_latex(elem, latex):
45
    if bool(latex):
46
        # Is it a Span or a Code?
47
        if isinstance(elem, Span) or isinstance(elem, Code):
48
            return [RawInline(latex, 'tex'), elem]
49
50
        # It is a Div or a CodeBlock
51
        else:
52
            return [RawBlock(latex, 'tex'), elem]
53
54
def latex_code(doc, definition, key_icon, key_position, key_size, key_color):
55
    # Get the default color
56
    color = get_color(doc, definition, key_color)
57
58
    # Get the size
59
    size = get_size(doc, definition, key_size)
60
61
    # Get the prefix
62
    prefix = get_prefix(doc, definition, key_position)
63
64
    # Get the icons
65
    icons = get_icons(doc, definition, key_icon, color)
66
67
    # Get the images
68
    images = create_images(doc, icons, size)
69
70
    if bool(images):
71
        # Prepare LaTeX code
72
        latex = [
73
            '{',
74
            '\\makeatletter',
75
            '\\patchcmd{\\@mn@margintest}{\\@tempswafalse}{\\@tempswatrue}{}{}',
76
            '\\patchcmd{\\@mn@margintest}{\\@tempswafalse}{\\@tempswatrue}{}{}',
77
            '\\makeatother',
78
            prefix,
79
            '\\marginnote{'
80
        ] + images + [
81
            '}[0pt]',
82
            '\\vspace{0cm}',
83
            '}',
84
        ]
85
86
        # Return LaTeX code
87
        return ''.join(latex)
88
    else:
89
        return ''
90
91
92
def get_icons(doc, definition, key_icons, color):
93
    icons = [{'name': 'exclamation-circle', 'color': color}]
94
95
    # Test the icons definition
96
    if key_icons in definition:
97
        icons = []
98
        if isinstance(definition[key_icons], str) or isinstance(definition[key_icons], unicode):
99
            check_icon(doc, icons, definition[key_icons], color)
100
        elif isinstance(definition[key_icons], list):
101
            for icon in definition[key_icons]:
102
                check_icon(doc, icons, icon, color)
103
104
    return icons
105
106
# Fix unicode for python3
107
try:
108
    unicode = unicode
109
except (NameError):
110
    unicode = str
111
112
def check_icon(doc, icons, icon, color):
113
    if isinstance(icon, str) or isinstance(icon, unicode):
114
        # Simple icon
115
        name = icon
116
    elif isinstance(icon, dict) and 'color' in icon and 'name' in icon:
117
        # Complex icon with name and color
118
        color = str(icon['color'])
119
        name = str(icon['name'])
120
    else:
121
        # Bad formed icon
122
        debug('[WARNING] pandoc-latex-tip: Bad formed icon')
123
        return
124
125
    add_icon(doc, icons, color, name)
126
127
def add_icon(doc, icons, color, name):
128
    # Lower the color
129
    lowerColor = color.lower()
130
131
    # Convert the color to black if unexisting
132
    from PIL import ImageColor
133
    if lowerColor not in ImageColor.colormap:
134
        debug('[WARNING] pandoc-latex-tip: ' + lowerColor + ' is not a correct color name; using black')
135
        lowerColor = 'black'
136
137
    # Is the icon correct?
138
    try:
139
        if name in doc.getIconFont.css_icons:
140
            icons.append({'name': name, 'color': lowerColor})
141
        else:
142
            debug('[WARNING] pandoc-latex-tip: ' + name + ' is not a correct icon name')
143
    except FileNotFoundError:
144
        debug('[WARNING] pandoc-latex-tip: error in accessing to icons definition')
145
146
def get_color(doc, definition, key):
147
    if key in definition:
148
        return str(definition[key])
149
    else:
150
        return 'black'
151
152
def get_prefix(doc, definition, key):
153
    if key in definition:
154
        if definition[key] == 'right':
155
            return '\\normalmarginpar'
156
        elif definition[key] == 'left':
157
            return '\\reversemarginpar'
158
        else:
159
            debug('[WARNING] pandoc-latex-tip: ' + str(definition[key]) + ' is not a correct position; using left')
160
            return '\\reversemarginpar'
161
    return '\\reversemarginpar'
162
163
def get_size(doc, definition, key):
164
   # Get the size
165
    size = '18'
166
    if key in definition:
167
        try:
168
            intValue = int(definition[key])
169
            if intValue > 0:
170
                size = str(intValue)
171
            else:
172
                debug('[WARNING] pandoc-latex-tip: size must be greater than 0; using ' + size)
173
        except ValueError:
174
            debug('[WARNING] pandoc-latex-tip: size must be a number; using ' + size)
175
    return size
176
177
def create_images(doc, icons, size):
178
    # Generate the LaTeX image code
179
    images = []
180
181
    for icon in icons:
182
183
        # Get the apps dirs
184
        from pkg_resources import get_distribution
185
        from appdirs import AppDirs
186
        dirs = AppDirs('pandoc_latex_tip', version = get_distribution('pandoc_latex_tip').version)
187
188
        # Get the image from the App cache folder
189
        image = dirs.user_cache_dir + '/' + icon['color'] + '/' + icon['name'] + '.png'
190
191
        # Create the image if not existing in the cache
192
        try:
193
            if not os.path.isfile(image):
194
195
                # Create the image in the cache
196
                doc.getIconFont.export_icon(
197
                    icon['name'],
198
                    size = 512,
199
                    color = icon['color'],
200
                    export_dir = dirs.user_cache_dir + '/' + icon['color']
201
                )
202
203
            # Add the LaTeX image
204
            images.append('\\includegraphics[width=' + size + 'pt]{' + image + '}')
205
        except FileNotFoundError:
206
            debug('[WARNING] pandoc-latex-tip: error in generating image')
207
208
    return images
209
210
def add_definition(doc, definition):
211
    # Get the classes
212
    classes = definition['classes']
213
214
    # Add a definition if correct
215
    if bool(classes):
216
        latex = latex_code(doc, definition, 'icons', 'position', 'size', 'color')
217
        if latex:
218
            doc.defined.append({'classes' : set(classes), 'latex': latex})
219
220
def prepare(doc):
221
    # Add getIconFont library to doc
222
    import icon_font_to_png
223
    from pkg_resources import get_distribution
224
    from appdirs import AppDirs
225
    dirs = AppDirs('pandoc_latex_tip', version = get_distribution('pandoc_latex_tip').version)
226
    doc.getIconFont = icon_font_to_png.IconFont(
227
        dirs.user_data_dir + '/font-awesome.css',
228
        dirs.user_data_dir + '/fontawesome-webfont.ttf'
229
    )
230
231
    # Prepare the definitions
232
    doc.defined = []
233
234
    # Get the meta data
235
    meta = doc.get_metadata('pandoc-latex-tip')
236
237
    if isinstance(meta, list):
238
239
        # Loop on all definitions
240
        for definition in meta:
241
242
            # Verify the definition
243
            if isinstance(definition, dict) and 'classes' in definition and isinstance(definition['classes'], list):
244
                add_definition(doc, definition)
245
246
def finalize(doc):
247
    if 'header-includes' not in doc.metadata:
248
        doc.metadata['header-includes'] = []
249
    doc.metadata['header-includes'].append(MetaInlines(RawInline('\\usepackage{graphicx,grffile}', 'tex')))
250
    doc.metadata['header-includes'].append(MetaInlines(RawInline('\\usepackage{marginnote}', 'tex')))
251
    doc.metadata['header-includes'].append(MetaInlines(RawInline('\\usepackage{etoolbox}', 'tex')))
252
253
def main(doc = None):
254
    run_filter(tip, prepare = prepare, finalize = finalize, doc = doc)
255
256
if __name__ == '__main__':
257
    main()
258
259