PageRenderTime 84ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/documentation/doctools/tags/0.2/sphinx/util/smartypants.py

https://github.com/creasyw/IMTAphy
Python | 261 lines | 197 code | 18 blank | 46 comment | 0 complexity | 203b28ec608ab0ad53a1e59e9e2609fe MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0, LGPL-2.1
  1. r"""
  2. This is based on SmartyPants.py by `Chad Miller`_.
  3. Copyright and License
  4. =====================
  5. SmartyPants_ license::
  6. Copyright (c) 2003 John Gruber
  7. (http://daringfireball.net/)
  8. All rights reserved.
  9. Redistribution and use in source and binary forms, with or without
  10. modification, are permitted provided that the following conditions are
  11. met:
  12. * Redistributions of source code must retain the above copyright
  13. notice, this list of conditions and the following disclaimer.
  14. * Redistributions in binary form must reproduce the above copyright
  15. notice, this list of conditions and the following disclaimer in
  16. the documentation and/or other materials provided with the
  17. distribution.
  18. * Neither the name "SmartyPants" nor the names of its contributors
  19. may be used to endorse or promote products derived from this
  20. software without specific prior written permission.
  21. This software is provided by the copyright holders and contributors "as
  22. is" and any express or implied warranties, including, but not limited
  23. to, the implied warranties of merchantability and fitness for a
  24. particular purpose are disclaimed. In no event shall the copyright
  25. owner or contributors be liable for any direct, indirect, incidental,
  26. special, exemplary, or consequential damages (including, but not
  27. limited to, procurement of substitute goods or services; loss of use,
  28. data, or profits; or business interruption) however caused and on any
  29. theory of liability, whether in contract, strict liability, or tort
  30. (including negligence or otherwise) arising in any way out of the use
  31. of this software, even if advised of the possibility of such damage.
  32. smartypants.py license::
  33. smartypants.py is a derivative work of SmartyPants.
  34. Redistribution and use in source and binary forms, with or without
  35. modification, are permitted provided that the following conditions are
  36. met:
  37. * Redistributions of source code must retain the above copyright
  38. notice, this list of conditions and the following disclaimer.
  39. * Redistributions in binary form must reproduce the above copyright
  40. notice, this list of conditions and the following disclaimer in
  41. the documentation and/or other materials provided with the
  42. distribution.
  43. This software is provided by the copyright holders and contributors "as
  44. is" and any express or implied warranties, including, but not limited
  45. to, the implied warranties of merchantability and fitness for a
  46. particular purpose are disclaimed. In no event shall the copyright
  47. owner or contributors be liable for any direct, indirect, incidental,
  48. special, exemplary, or consequential damages (including, but not
  49. limited to, procurement of substitute goods or services; loss of use,
  50. data, or profits; or business interruption) however caused and on any
  51. theory of liability, whether in contract, strict liability, or tort
  52. (including negligence or otherwise) arising in any way out of the use
  53. of this software, even if advised of the possibility of such damage.
  54. .. _Chad Miller: http://web.chad.org/
  55. """
  56. import re
  57. def sphinx_smarty_pants(t):
  58. t = t.replace('"', '"')
  59. t = educateDashesOldSchool(t)
  60. t = educateQuotes(t)
  61. t = t.replace('"', '"')
  62. return t
  63. # Constants for quote education.
  64. punct_class = r"""[!"#\$\%'()*+,-.\/:;<=>?\@\[\\\]\^_`{|}~]"""
  65. close_class = r"""[^\ \t\r\n\[\{\(\-]"""
  66. dec_dashes = r"""&#8211;|&#8212;"""
  67. # Special case if the very first character is a quote
  68. # followed by punctuation at a non-word-break. Close the quotes by brute force:
  69. single_quote_start_re = re.compile(r"""^'(?=%s\\B)""" % (punct_class,))
  70. double_quote_start_re = re.compile(r"""^"(?=%s\\B)""" % (punct_class,))
  71. # Special case for double sets of quotes, e.g.:
  72. # <p>He said, "'Quoted' words in a larger quote."</p>
  73. double_quote_sets_re = re.compile(r""""'(?=\w)""")
  74. single_quote_sets_re = re.compile(r"""'"(?=\w)""")
  75. # Special case for decade abbreviations (the '80s):
  76. decade_abbr_re = re.compile(r"""\b'(?=\d{2}s)""")
  77. # Get most opening double quotes:
  78. opening_double_quotes_regex = re.compile(r"""
  79. (
  80. \s | # a whitespace char, or
  81. &nbsp; | # a non-breaking space entity, or
  82. -- | # dashes, or
  83. &[mn]dash; | # named dash entities
  84. %s | # or decimal entities
  85. &\#x201[34]; # or hex
  86. )
  87. " # the quote
  88. (?=\w) # followed by a word character
  89. """ % (dec_dashes,), re.VERBOSE)
  90. # Double closing quotes:
  91. closing_double_quotes_regex = re.compile(r"""
  92. #(%s)? # character that indicates the quote should be closing
  93. "
  94. (?=\s)
  95. """ % (close_class,), re.VERBOSE)
  96. closing_double_quotes_regex_2 = re.compile(r"""
  97. (%s) # character that indicates the quote should be closing
  98. "
  99. """ % (close_class,), re.VERBOSE)
  100. # Get most opening single quotes:
  101. opening_single_quotes_regex = re.compile(r"""
  102. (
  103. \s | # a whitespace char, or
  104. &nbsp; | # a non-breaking space entity, or
  105. -- | # dashes, or
  106. &[mn]dash; | # named dash entities
  107. %s | # or decimal entities
  108. &\#x201[34]; # or hex
  109. )
  110. ' # the quote
  111. (?=\w) # followed by a word character
  112. """ % (dec_dashes,), re.VERBOSE)
  113. closing_single_quotes_regex = re.compile(r"""
  114. (%s)
  115. '
  116. (?!\s | s\b | \d)
  117. """ % (close_class,), re.VERBOSE)
  118. closing_single_quotes_regex_2 = re.compile(r"""
  119. (%s)
  120. '
  121. (\s | s\b)
  122. """ % (close_class,), re.VERBOSE)
  123. def educateQuotes(s):
  124. """
  125. Parameter: String.
  126. Returns: The string, with "educated" curly quote HTML entities.
  127. Example input: "Isn't this fun?"
  128. Example output: &#8220;Isn&#8217;t this fun?&#8221;
  129. """
  130. # Special case if the very first character is a quote
  131. # followed by punctuation at a non-word-break. Close the quotes by brute force:
  132. s = single_quote_start_re.sub("&#8217;", s)
  133. s = double_quote_start_re.sub("&#8221;", s)
  134. # Special case for double sets of quotes, e.g.:
  135. # <p>He said, "'Quoted' words in a larger quote."</p>
  136. s = double_quote_sets_re.sub("&#8220;&#8216;", s)
  137. s = single_quote_sets_re.sub("&#8216;&#8220;", s)
  138. # Special case for decade abbreviations (the '80s):
  139. s = decade_abbr_re.sub("&#8217;", s)
  140. s = opening_single_quotes_regex.sub(r"\1&#8216;", s)
  141. s = closing_single_quotes_regex.sub(r"\1&#8217;", s)
  142. s = closing_single_quotes_regex_2.sub(r"\1&#8217;\2", s)
  143. # Any remaining single quotes should be opening ones:
  144. s = s.replace("'", "&#8216;")
  145. s = opening_double_quotes_regex.sub(r"\1&#8220;", s)
  146. s = closing_double_quotes_regex.sub(r"&#8221;", s)
  147. s = closing_double_quotes_regex_2.sub(r"\1&#8221;", s)
  148. # Any remaining quotes should be opening ones.
  149. return s.replace('"', "&#8220;")
  150. def educateBackticks(s):
  151. """
  152. Parameter: String.
  153. Returns: The string, with ``backticks'' -style double quotes
  154. translated into HTML curly quote entities.
  155. Example input: ``Isn't this fun?''
  156. Example output: &#8220;Isn't this fun?&#8221;
  157. """
  158. return s.replace("``", "&#8220;").replace("''", "&#8221;")
  159. def educateSingleBackticks(s):
  160. """
  161. Parameter: String.
  162. Returns: The string, with `backticks' -style single quotes
  163. translated into HTML curly quote entities.
  164. Example input: `Isn't this fun?'
  165. Example output: &#8216;Isn&#8217;t this fun?&#8217;
  166. """
  167. return s.replace('`', "&#8216;").replace("'", "&#8217;")
  168. def educateDashesOldSchool(s):
  169. """
  170. Parameter: String.
  171. Returns: The string, with each instance of "--" translated to
  172. an en-dash HTML entity, and each "---" translated to
  173. an em-dash HTML entity.
  174. """
  175. return s.replace('---', "&#8212;").replace('--', "&#8211;")
  176. def educateDashesOldSchoolInverted(s):
  177. """
  178. Parameter: String.
  179. Returns: The string, with each instance of "--" translated to
  180. an em-dash HTML entity, and each "---" translated to
  181. an en-dash HTML entity. Two reasons why: First, unlike the
  182. en- and em-dash syntax supported by
  183. EducateDashesOldSchool(), it's compatible with existing
  184. entries written before SmartyPants 1.1, back when "--" was
  185. only used for em-dashes. Second, em-dashes are more
  186. common than en-dashes, and so it sort of makes sense that
  187. the shortcut should be shorter to type. (Thanks to Aaron
  188. Swartz for the idea.)
  189. """
  190. return s.replace('---', "&#8211;").replace('--', "&#8212;")
  191. def educateEllipses(s):
  192. """
  193. Parameter: String.
  194. Returns: The string, with each instance of "..." translated to
  195. an ellipsis HTML entity.
  196. Example input: Huh...?
  197. Example output: Huh&#8230;?
  198. """
  199. return s.replace('...', "&#8230;").replace('. . .', "&#8230;")
  200. __author__ = "Chad Miller <smartypantspy@chad.org>"
  201. __version__ = "1.5_1.5: Sat, 13 Aug 2005 15:50:24 -0400"
  202. __url__ = "http://wiki.chad.org/SmartyPantsPy"
  203. __description__ = \
  204. "Smart-quotes, smart-ellipses, and smart-dashes for weblog entries in pyblosxom"