Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(442)

Side by Side Diff: third_party/Python-Markdown/markdown/extensions/smarty.py

Issue 1389543003: Revert of Check in a simple pure-python based Markdown previewer. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@add
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # -*- coding: utf-8 -*-
2 '''
3 Smarty extension for Python-Markdown
4 ====================================
5
6 Adds conversion of ASCII dashes, quotes and ellipses to their HTML
7 entity equivalents.
8
9 See <https://pythonhosted.org/Markdown/extensions/smarty.html>
10 for documentation.
11
12 Author: 2013, Dmitry Shachnev <mitya57@gmail.com>
13
14 All changes Copyright 2013-2014 The Python Markdown Project
15
16 License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
17
18 SmartyPants license:
19
20 Copyright (c) 2003 John Gruber <http://daringfireball.net/>
21 All rights reserved.
22
23 Redistribution and use in source and binary forms, with or without
24 modification, are permitted provided that the following conditions are
25 met:
26
27 * Redistributions of source code must retain the above copyright
28 notice, this list of conditions and the following disclaimer.
29
30 * Redistributions in binary form must reproduce the above copyright
31 notice, this list of conditions and the following disclaimer in
32 the documentation and/or other materials provided with the
33 distribution.
34
35 * Neither the name "SmartyPants" nor the names of its contributors
36 may be used to endorse or promote products derived from this
37 software without specific prior written permission.
38
39 This software is provided by the copyright holders and contributors "as
40 is" and any express or implied warranties, including, but not limited
41 to, the implied warranties of merchantability and fitness for a
42 particular purpose are disclaimed. In no event shall the copyright
43 owner or contributors be liable for any direct, indirect, incidental,
44 special, exemplary, or consequential damages (including, but not
45 limited to, procurement of substitute goods or services; loss of use,
46 data, or profits; or business interruption) however caused and on any
47 theory of liability, whether in contract, strict liability, or tort
48 (including negligence or otherwise) arising in any way out of the use
49 of this software, even if advised of the possibility of such damage.
50
51
52 smartypants.py license:
53
54 smartypants.py is a derivative work of SmartyPants.
55 Copyright (c) 2004, 2007 Chad Miller <http://web.chad.org/>
56
57 Redistribution and use in source and binary forms, with or without
58 modification, are permitted provided that the following conditions are
59 met:
60
61 * Redistributions of source code must retain the above copyright
62 notice, this list of conditions and the following disclaimer.
63
64 * Redistributions in binary form must reproduce the above copyright
65 notice, this list of conditions and the following disclaimer in
66 the documentation and/or other materials provided with the
67 distribution.
68
69 This software is provided by the copyright holders and contributors "as
70 is" and any express or implied warranties, including, but not limited
71 to, the implied warranties of merchantability and fitness for a
72 particular purpose are disclaimed. In no event shall the copyright
73 owner or contributors be liable for any direct, indirect, incidental,
74 special, exemplary, or consequential damages (including, but not
75 limited to, procurement of substitute goods or services; loss of use,
76 data, or profits; or business interruption) however caused and on any
77 theory of liability, whether in contract, strict liability, or tort
78 (including negligence or otherwise) arising in any way out of the use
79 of this software, even if advised of the possibility of such damage.
80
81 '''
82
83
84 from __future__ import unicode_literals
85 from . import Extension
86 from ..inlinepatterns import HtmlPattern
87 from ..odict import OrderedDict
88 from ..treeprocessors import InlineProcessor
89
90
91 # Constants for quote education.
92 punctClass = r"""[!"#\$\%'()*+,-.\/:;<=>?\@\[\\\]\^_`{|}~]"""
93 endOfWordClass = r"[\s.,;:!?)]"
94 closeClass = "[^\ \t\r\n\[\{\(\-\u0002\u0003]"
95
96 openingQuotesBase = (
97 '(\s' # a whitespace char
98 '|&nbsp;' # or a non-breaking space entity
99 '|--' # or dashes
100 '|–|—' # or unicode
101 '|&[mn]dash;' # or named dash entities
102 '|&#8211;|&#8212;' # or decimal entities
103 ')'
104 )
105
106 substitutions = {
107 'mdash': '&mdash;',
108 'ndash': '&ndash;',
109 'ellipsis': '&hellip;',
110 'left-angle-quote': '&laquo;',
111 'right-angle-quote': '&raquo;',
112 'left-single-quote': '&lsquo;',
113 'right-single-quote': '&rsquo;',
114 'left-double-quote': '&ldquo;',
115 'right-double-quote': '&rdquo;',
116 }
117
118
119 # Special case if the very first character is a quote
120 # followed by punctuation at a non-word-break. Close the quotes by brute force:
121 singleQuoteStartRe = r"^'(?=%s\B)" % punctClass
122 doubleQuoteStartRe = r'^"(?=%s\B)' % punctClass
123
124 # Special case for double sets of quotes, e.g.:
125 # <p>He said, "'Quoted' words in a larger quote."</p>
126 doubleQuoteSetsRe = r""""'(?=\w)"""
127 singleQuoteSetsRe = r"""'"(?=\w)"""
128
129 # Special case for decade abbreviations (the '80s):
130 decadeAbbrRe = r"(?<!\w)'(?=\d{2}s)"
131
132 # Get most opening double quotes:
133 openingDoubleQuotesRegex = r'%s"(?=\w)' % openingQuotesBase
134
135 # Double closing quotes:
136 closingDoubleQuotesRegex = r'"(?=\s)'
137 closingDoubleQuotesRegex2 = '(?<=%s)"' % closeClass
138
139 # Get most opening single quotes:
140 openingSingleQuotesRegex = r"%s'(?=\w)" % openingQuotesBase
141
142 # Single closing quotes:
143 closingSingleQuotesRegex = r"(?<=%s)'(?!\s|s\b|\d)" % closeClass
144 closingSingleQuotesRegex2 = r"(?<=%s)'(\s|s\b)" % closeClass
145
146 # All remaining quotes should be opening ones
147 remainingSingleQuotesRegex = "'"
148 remainingDoubleQuotesRegex = '"'
149
150
151 class SubstituteTextPattern(HtmlPattern):
152 def __init__(self, pattern, replace, markdown_instance):
153 """ Replaces matches with some text. """
154 HtmlPattern.__init__(self, pattern)
155 self.replace = replace
156 self.markdown = markdown_instance
157
158 def handleMatch(self, m):
159 result = ''
160 for part in self.replace:
161 if isinstance(part, int):
162 result += m.group(part)
163 else:
164 result += self.markdown.htmlStash.store(part, safe=True)
165 return result
166
167
168 class SmartyExtension(Extension):
169 def __init__(self, *args, **kwargs):
170 self.config = {
171 'smart_quotes': [True, 'Educate quotes'],
172 'smart_angled_quotes': [False, 'Educate angled quotes'],
173 'smart_dashes': [True, 'Educate dashes'],
174 'smart_ellipses': [True, 'Educate ellipses'],
175 'substitutions': [{}, 'Overwrite default substitutions'],
176 }
177 super(SmartyExtension, self).__init__(*args, **kwargs)
178 self.substitutions = dict(substitutions)
179 self.substitutions.update(self.getConfig('substitutions', default={}))
180
181 def _addPatterns(self, md, patterns, serie):
182 for ind, pattern in enumerate(patterns):
183 pattern += (md,)
184 pattern = SubstituteTextPattern(*pattern)
185 after = ('>smarty-%s-%d' % (serie, ind - 1) if ind else '_begin')
186 name = 'smarty-%s-%d' % (serie, ind)
187 self.inlinePatterns.add(name, pattern, after)
188
189 def educateDashes(self, md):
190 emDashesPattern = SubstituteTextPattern(
191 r'(?<!-)---(?!-)', (self.substitutions['mdash'],), md
192 )
193 enDashesPattern = SubstituteTextPattern(
194 r'(?<!-)--(?!-)', (self.substitutions['ndash'],), md
195 )
196 self.inlinePatterns.add('smarty-em-dashes', emDashesPattern, '_begin')
197 self.inlinePatterns.add(
198 'smarty-en-dashes', enDashesPattern, '>smarty-em-dashes'
199 )
200
201 def educateEllipses(self, md):
202 ellipsesPattern = SubstituteTextPattern(
203 r'(?<!\.)\.{3}(?!\.)', (self.substitutions['ellipsis'],), md
204 )
205 self.inlinePatterns.add('smarty-ellipses', ellipsesPattern, '_begin')
206
207 def educateAngledQuotes(self, md):
208 leftAngledQuotePattern = SubstituteTextPattern(
209 r'\<\<', (self.substitutions['left-angle-quote'],), md
210 )
211 rightAngledQuotePattern = SubstituteTextPattern(
212 r'\>\>', (self.substitutions['right-angle-quote'],), md
213 )
214 self.inlinePatterns.add(
215 'smarty-left-angle-quotes', leftAngledQuotePattern, '_begin'
216 )
217 self.inlinePatterns.add(
218 'smarty-right-angle-quotes',
219 rightAngledQuotePattern,
220 '>smarty-left-angle-quotes'
221 )
222
223 def educateQuotes(self, md):
224 lsquo = self.substitutions['left-single-quote']
225 rsquo = self.substitutions['right-single-quote']
226 ldquo = self.substitutions['left-double-quote']
227 rdquo = self.substitutions['right-double-quote']
228 patterns = (
229 (singleQuoteStartRe, (rsquo,)),
230 (doubleQuoteStartRe, (rdquo,)),
231 (doubleQuoteSetsRe, (ldquo + lsquo,)),
232 (singleQuoteSetsRe, (lsquo + ldquo,)),
233 (decadeAbbrRe, (rsquo,)),
234 (openingSingleQuotesRegex, (2, lsquo)),
235 (closingSingleQuotesRegex, (rsquo,)),
236 (closingSingleQuotesRegex2, (rsquo, 2)),
237 (remainingSingleQuotesRegex, (lsquo,)),
238 (openingDoubleQuotesRegex, (2, ldquo)),
239 (closingDoubleQuotesRegex, (rdquo,)),
240 (closingDoubleQuotesRegex2, (rdquo,)),
241 (remainingDoubleQuotesRegex, (ldquo,))
242 )
243 self._addPatterns(md, patterns, 'quotes')
244
245 def extendMarkdown(self, md, md_globals):
246 configs = self.getConfigs()
247 self.inlinePatterns = OrderedDict()
248 if configs['smart_ellipses']:
249 self.educateEllipses(md)
250 if configs['smart_quotes']:
251 self.educateQuotes(md)
252 if configs['smart_angled_quotes']:
253 self.educateAngledQuotes(md)
254 if configs['smart_dashes']:
255 self.educateDashes(md)
256 inlineProcessor = InlineProcessor(md)
257 inlineProcessor.inlinePatterns = self.inlinePatterns
258 md.treeprocessors.add('smarty', inlineProcessor, '_end')
259 md.ESCAPED_CHARS.extend(['"', "'"])
260
261
262 def makeExtension(*args, **kwargs):
263 return SmartyExtension(*args, **kwargs)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698