Mercurial > piecrust-hoedown
comparison piecrust_hoedown.py @ 0:8e0f125ef135 default tip
Initial commit.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Tue, 13 Feb 2018 13:37:39 -0800 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:8e0f125ef135 |
---|---|
1 import logging | |
2 from piecrust.plugins.base import PieCrustPlugin | |
3 from piecrust.formatting.base import Formatter | |
4 | |
5 | |
6 logger = logging.getLogger(__name__) | |
7 | |
8 | |
9 class HoedownPlugin(PieCrustPlugin): | |
10 name = 'Hoedown' | |
11 | |
12 def getFormatters(self): | |
13 return [ | |
14 HoedownFormatter()] | |
15 | |
16 | |
17 __piecrust_plugin__ = HoedownPlugin | |
18 | |
19 | |
20 class HoedownFormatter(Formatter): | |
21 FORMAT_NAMES = ['hoedown'] | |
22 OUTPUT_FORMAT = 'html' | |
23 | |
24 def __init__(self): | |
25 super(HoedownFormatter, self).__init__() | |
26 self._formatter = None | |
27 | |
28 def render(self, format_name, txt): | |
29 assert format_name in self.FORMAT_NAMES | |
30 self._ensureInitialized() | |
31 return self._formatter(txt) | |
32 | |
33 def _ensureInitialized(self): | |
34 if self._formatter is not None: | |
35 return | |
36 | |
37 import misaka | |
38 | |
39 # Don't show warnings once for each worker when baking, so only | |
40 # show them for the first. If the variable is not set, we're not | |
41 # baking so do show them either way. | |
42 show_warnings = (self.app.config.get('baker/worker_id', 0) == 0) | |
43 | |
44 config = self.app.config.get('hoedown') | |
45 if config is None: | |
46 config = self.app.config.get('markdown') | |
47 if config is None: | |
48 config = {} | |
49 elif not isinstance(config, dict): | |
50 raise Exception("The `hoedown` configuration setting must be " | |
51 "a dictionary.") | |
52 | |
53 extensions = config.get('extensions', []) | |
54 if isinstance(extensions, str): | |
55 extensions = [e.strip() for e in extensions.split(',')] | |
56 # Compatibility with PieCrust 1.x | |
57 if config.get('use_markdown_extra'): | |
58 extensions.append('extra') | |
59 | |
60 render_flags = config.get('render_flags') | |
61 if render_flags is None: | |
62 render_flags = [] | |
63 | |
64 # Translate standard Markdown formatter extensions to Hoedown | |
65 # extension/render flags to make it easier to use Hoedown as a drop-in | |
66 # replacement. | |
67 exts = 0 | |
68 rdrf = 0 | |
69 other = 0 | |
70 use_smartypants = False | |
71 for n in extensions: | |
72 # Special case for Smartypants. | |
73 if n.lower() in ['smarty', 'smartypants']: | |
74 use_smartypants = True | |
75 continue | |
76 | |
77 # Try an extension? | |
78 e = getattr(misaka, 'EXT_' + n.upper(), None) | |
79 if e is not None: | |
80 exts |= e | |
81 continue | |
82 | |
83 # Try a render flag? | |
84 f = getattr(misaka, 'HTML_' + n.upper(), None) | |
85 if f is not None: | |
86 rdrf |= f | |
87 | |
88 # Other flag? | |
89 f = getattr(misaka, 'TABLE_' + n.upper(), None) | |
90 if f is not None: | |
91 other |= f | |
92 | |
93 # Try translating from a Markdown extension name. | |
94 t = ext_translate.get(n) | |
95 if t is None: | |
96 if show_warnings: | |
97 logger.warning("Unknown Hoedown Markdown extension or flag: " | |
98 "%s" % n) | |
99 continue | |
100 if not isinstance(t, list): | |
101 t = [t] | |
102 for i in t: | |
103 if i.startswith('EXT_'): | |
104 exts |= getattr(misaka, i) | |
105 elif i.startswith('HTML_'): | |
106 rdrf |= getattr(misaka, i) | |
107 elif show_warnings: | |
108 logger.warning("Unknown Hoedown Markdown extension or flag:" | |
109 "%s" % n) | |
110 if n == 'extra' and show_warnings: | |
111 # Special warning for the 'extra' extension. | |
112 logger.warning( | |
113 "The 'extra' extension doesn't have a full equivalent " | |
114 "in Hoedown Markdown. Only 'fenced_code', 'footnotes' and " | |
115 "'tables' extensions will be active. " | |
116 "To remove this warning, replace 'extra' with those 3 " | |
117 "specific extensions.") | |
118 | |
119 # Enable a few things by default. | |
120 exts |= misaka.EXT_NO_INTRA_EMPHASIS | |
121 | |
122 renderer = misaka.HtmlRenderer(flags=rdrf) | |
123 self._formatter = misaka.Markdown(renderer, extensions=(exts | other)) | |
124 | |
125 if use_smartypants: | |
126 self._formatter = _SmartypantsFormatter(self._formatter, | |
127 misaka.smartypants) | |
128 | |
129 | |
130 ext_translate = { | |
131 'fenced_code': 'EXT_FENCED_CODE', | |
132 'footnotes': 'EXT_FOOTNOTES', | |
133 'tables': 'EXT_TABLES', | |
134 'nl2br': 'HTML_HARD_WRAP', | |
135 'toc': 'HTML_TOC', | |
136 'extra': ['EXT_FENCED_CODE', 'EXT_FOOTNOTES', 'EXT_TABLES'] | |
137 } | |
138 | |
139 | |
140 class _SmartypantsFormatter: | |
141 def __init__(self, formatter, smartier): | |
142 self._fmt = formatter | |
143 self._sp = smartier | |
144 | |
145 def __call__(self, txt): | |
146 return self._sp(self._fmt(txt)) |