Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

init

  • Loading branch information...
commit 107abe7a3d424306d412ca396ba4fa5dd1511a8d 0 parents
@erinata authored
Showing with 6,522 additions and 0 deletions.
  1. +2 −0  .gitignore
  2. +4 −0 Markdown.sublime-build
  3. +1,178 −0 Markdown.tmLanguage
  4. +29 −0 MarkdownBuild.py
  5. +80 −0 MultiMarkdown.tmLanguage
  6. +25 −0 README.md
  7. +107 −0 markdown.css
  8. +428 −0 markdown_python/__init__.py
  9. +87 −0 markdown_python/__main__.py
  10. +97 −0 markdown_python/blockparser.py
  11. +555 −0 markdown_python/blockprocessors.py
  12. +31 −0 markdown_python/etree_loader.py
  13. +51 −0 markdown_python/extensions/__init__.py
  14. +96 −0 markdown_python/extensions/abbr.py
  15. +128 −0 markdown_python/extensions/attr_list.py
  16. +226 −0 markdown_python/extensions/codehilite.py
  17. +110 −0 markdown_python/extensions/def_list.py
  18. +52 −0 markdown_python/extensions/extra.py
  19. +165 −0 markdown_python/extensions/fenced_code.py
  20. +299 −0 markdown_python/extensions/footnotes.py
  21. +201 −0 markdown_python/extensions/headerid.py
  22. +69 −0 markdown_python/extensions/html_tidy.py
  23. +96 −0 markdown_python/extensions/meta.py
  24. +36 −0 markdown_python/extensions/nl2br.py
  25. +114 −0 markdown_python/extensions/rss.py
  26. +49 −0 markdown_python/extensions/sane_lists.py
  27. +45 −0 markdown_python/extensions/smart_strong.py
  28. +98 −0 markdown_python/extensions/tables.py
  29. +154 −0 markdown_python/extensions/toc.py
  30. +155 −0 markdown_python/extensions/wikilinks.py
  31. +458 −0 markdown_python/inlinepatterns.py
  32. +162 −0 markdown_python/odict.py
  33. +101 −0 markdown_python/postprocessors.py
  34. +282 −0 markdown_python/preprocessors.py
  35. +275 −0 markdown_python/serializers.py
  36. +359 −0 markdown_python/treeprocessors.py
  37. +114 −0 markdown_python/util.py
  38. +3 −0  messages.json
  39. +1 −0  messages/0.1.0.txt
2  .gitignore
@@ -0,0 +1,2 @@
+*.pyc
+*.rb
4 Markdown.sublime-build
@@ -0,0 +1,4 @@
+{
+ "target": "markdown_build",
+ "selector": "text.html.markdown"
+}
1,178 Markdown.tmLanguage
@@ -0,0 +1,1178 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>fileTypes</key>
+ <array>
+ <string>mdown</string>
+ <string>markdown</string>
+ <string>markdn</string>
+ <string>md</string>
+ </array>
+ <key>foldingStartMarker</key>
+ <string>(?x)
+ (&lt;(?i:head|body|table|thead|tbody|tfoot|tr|div|select|fieldset|style|script|ul|ol|form|dl)\b.*?&gt;
+ |&lt;!--(?!.*--&gt;)
+ |\{\s*($|\?&gt;\s*$|//|/\*(.*\*/\s*$|(?!.*?\*/)))
+ )</string>
+ <key>foldingStopMarker</key>
+ <string>(?x)
+ (&lt;/(?i:head|body|table|thead|tbody|tfoot|tr|div|select|fieldset|style|script|ul|ol|form|dl)&gt;
+ |^\s*--&gt;
+ |(^|\s)\}
+ )</string>
+ <key>keyEquivalent</key>
+ <string>^~M</string>
+ <key>name</key>
+ <string>Markdown</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>begin</key>
+ <string>(?x)^
+ (?= [ ]{,3}&gt;.
+ | ([ ]{4}|\t)(?!$)
+ | [#]{1,6}\s*+
+ | [ ]{,3}(?&lt;marker&gt;[-*_])([ ]{,2}\k&lt;marker&gt;){2,}[ \t]*+$
+ )</string>
+ <key>comment</key>
+ <string>
+ We could also use an empty end match and set
+ applyEndPatternLast, but then we must be sure that the begin
+ pattern will only match stuff matched by the sub-patterns.
+ </string>
+ <key>end</key>
+ <string>(?x)^
+ (?! [ ]{,3}&gt;.
+ | ([ ]{4}|\t)
+ | [#]{1,6}\s*+
+ | [ ]{,3}(?&lt;marker&gt;[-*_])([ ]{,2}\k&lt;marker&gt;){2,}[ \t]*+$
+ )</string>
+ <key>name</key>
+ <string>meta.block-level.markdown</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>include</key>
+ <string>#block_quote</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#block_raw</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#heading</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#separator</string>
+ </dict>
+ </array>
+ </dict>
+ <dict>
+ <key>begin</key>
+ <string>^[ ]{0,3}([*+-])(?=\s)</string>
+ <key>captures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.list_item.markdown</string>
+ </dict>
+ </dict>
+ <key>end</key>
+ <string>^(?=\S)</string>
+ <key>name</key>
+ <string>markup.list.unnumbered.markdown</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>include</key>
+ <string>#list-paragraph</string>
+ </dict>
+ </array>
+ </dict>
+ <dict>
+ <key>begin</key>
+ <string>^[ ]{0,3}[0-9]+(\.)(?=\s)</string>
+ <key>captures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.list_item.markdown</string>
+ </dict>
+ </dict>
+ <key>end</key>
+ <string>^(?=\S)</string>
+ <key>name</key>
+ <string>markup.list.numbered.markdown</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>include</key>
+ <string>#list-paragraph</string>
+ </dict>
+ </array>
+ </dict>
+ <dict>
+ <key>begin</key>
+ <string>^(?=&lt;(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b)(?!.*?&lt;/\1&gt;)</string>
+ <key>comment</key>
+ <string>
+ Markdown formatting is disabled inside block-level tags.
+ </string>
+ <key>end</key>
+ <string>(?&lt;=^&lt;/\1&gt;$\n)</string>
+ <key>name</key>
+ <string>meta.disable-markdown</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>include</key>
+ <string>text.html.basic</string>
+ </dict>
+ </array>
+ </dict>
+ <dict>
+ <key>begin</key>
+ <string>^(?=&lt;(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b)</string>
+ <key>comment</key>
+ <string>Same rule but for one line disables.</string>
+ <key>end</key>
+ <string>$\n?</string>
+ <key>name</key>
+ <string>meta.disable-markdown</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>include</key>
+ <string>text.html.basic</string>
+ </dict>
+ </array>
+ </dict>
+ <dict>
+ <key>captures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.constant.markdown</string>
+ </dict>
+ <key>10</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.end.markdown</string>
+ </dict>
+ <key>11</key>
+ <dict>
+ <key>name</key>
+ <string>string.other.link.description.title.markdown</string>
+ </dict>
+ <key>12</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.begin.markdown</string>
+ </dict>
+ <key>13</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.end.markdown</string>
+ </dict>
+ <key>2</key>
+ <dict>
+ <key>name</key>
+ <string>constant.other.reference.link.markdown</string>
+ </dict>
+ <key>3</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.constant.markdown</string>
+ </dict>
+ <key>4</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.separator.key-value.markdown</string>
+ </dict>
+ <key>5</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.link.markdown</string>
+ </dict>
+ <key>6</key>
+ <dict>
+ <key>name</key>
+ <string>markup.underline.link.markdown</string>
+ </dict>
+ <key>7</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.link.markdown</string>
+ </dict>
+ <key>8</key>
+ <dict>
+ <key>name</key>
+ <string>string.other.link.description.title.markdown</string>
+ </dict>
+ <key>9</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.begin.markdown</string>
+ </dict>
+ </dict>
+ <key>match</key>
+ <string>(?x:
+ \s* # Leading whitespace
+ (\[)(.+?)(\])(:) # Reference name
+ [ \t]* # Optional whitespace
+ (&lt;?)(\S+?)(&gt;?) # The url
+ [ \t]* # Optional whitespace
+ (?:
+ ((\().+?(\))) # Match title in quotes…
+ | ((").+?(")) # or in parens.
+ )? # Title is optional
+ \s* # Optional whitespace
+ $
+ )</string>
+ <key>name</key>
+ <string>meta.link.reference.def.markdown</string>
+ </dict>
+ <dict>
+ <key>begin</key>
+ <string>^(?=\S)(?![=-]{3,}(?=$))</string>
+ <key>end</key>
+ <string>^(?:\s*$|(?=[ ]{,3}&gt;.))|(?=[ \t]*\n)(?&lt;=^===|^====|=====|^---|^----|-----)[ \t]*\n|(?=^#)</string>
+ <key>name</key>
+ <string>meta.paragraph.markdown</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>include</key>
+ <string>#inline</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>text.html.basic</string>
+ </dict>
+ <dict>
+ <key>captures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.heading.markdown</string>
+ </dict>
+ </dict>
+ <key>match</key>
+ <string>^(={3,})(?=[ \t]*$)</string>
+ <key>name</key>
+ <string>markup.heading.1.markdown</string>
+ </dict>
+ <dict>
+ <key>captures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.heading.markdown</string>
+ </dict>
+ </dict>
+ <key>match</key>
+ <string>^(-{3,})(?=[ \t]*$)</string>
+ <key>name</key>
+ <string>markup.heading.2.markdown</string>
+ </dict>
+ </array>
+ </dict>
+ </array>
+ <key>repository</key>
+ <dict>
+ <key>ampersand</key>
+ <dict>
+ <key>comment</key>
+ <string>
+ Markdown will convert this for us. We match it so that the
+ HTML grammar will not mark it up as invalid.
+ </string>
+ <key>match</key>
+ <string>&amp;(?!([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+);)</string>
+ <key>name</key>
+ <string>meta.other.valid-ampersand.markdown</string>
+ </dict>
+ <key>block_quote</key>
+ <dict>
+ <key>begin</key>
+ <string>\G[ ]{,3}(&gt;)(?!$)[ ]?</string>
+ <key>beginCaptures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.blockquote.markdown</string>
+ </dict>
+ </dict>
+ <key>comment</key>
+ <string>
+ We terminate the block quote when seeing an empty line, a
+ separator or a line with leading &gt; characters. The latter is
+ to “reset” the quote level for quoted lines.
+ </string>
+ <key>end</key>
+ <string>(?x)^
+ (?= \s*$
+ | [ ]{,3}(?&lt;marker&gt;[-*_])([ ]{,2}\k&lt;marker&gt;){2,}[ \t]*+$
+ | [ ]{,3}&gt;.
+ )</string>
+ <key>name</key>
+ <string>markup.quote.markdown</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>begin</key>
+ <string>(?x)\G
+ (?= [ ]{,3}&gt;.
+ )</string>
+ <key>end</key>
+ <string>^</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>include</key>
+ <string>#block_quote</string>
+ </dict>
+ </array>
+ </dict>
+ <dict>
+ <key>applyEndPatternLast</key>
+ <integer>1</integer>
+ <key>begin</key>
+ <string>(?x)\G
+ (?= ([ ]{4}|\t)
+ | [#]{1,6}\s*+
+ | [ ]{,3}(?&lt;marker&gt;[-*_])([ ]{,2}\k&lt;marker&gt;){2,}[ \t]*+$
+ )</string>
+ <key>end</key>
+ <string>^</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>include</key>
+ <string>#block_raw</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#heading</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#separator</string>
+ </dict>
+ </array>
+ </dict>
+ <dict>
+ <key>begin</key>
+ <string>(?x)\G
+ (?! $
+ | [ ]{,3}&gt;.
+ | ([ ]{4}|\t)
+ | [#]{1,6}\s*+
+ | [ ]{,3}(?&lt;marker&gt;[-*_])([ ]{,2}\k&lt;marker&gt;){2,}[ \t]*+$
+ )</string>
+ <key>end</key>
+ <string>$|(?&lt;=\n)</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>include</key>
+ <string>#inline</string>
+ </dict>
+ </array>
+ </dict>
+ </array>
+ </dict>
+ <key>block_raw</key>
+ <dict>
+ <key>match</key>
+ <string>\G([ ]{4}|\t).*$\n?</string>
+ <key>name</key>
+ <string>markup.raw.block.markdown</string>
+ </dict>
+ <key>bold</key>
+ <dict>
+ <key>begin</key>
+ <string>(?x)
+ (\*\*|__)(?=\S) # Open
+ (?=
+ (
+ &lt;[^&gt;]*+&gt; # HTML tags
+ | (?&lt;raw&gt;`+)([^`]|(?!(?&lt;!`)\k&lt;raw&gt;(?!`))`)*+\k&lt;raw&gt;
+ # Raw
+ | \\[\\`*_{}\[\]()#.!+\-&gt;]?+ # Escapes
+ | \[
+ (
+ (?&lt;square&gt; # Named group
+ [^\[\]\\] # Match most chars
+ | \\. # Escaped chars
+ | \[ \g&lt;square&gt;*+ \] # Nested brackets
+ )*+
+ \]
+ (
+ ( # Reference Link
+ [ ]? # Optional space
+ \[[^\]]*+\] # Ref name
+ )
+ | ( # Inline Link
+ \( # Opening paren
+ [ \t]*+ # Optional whtiespace
+ &lt;?(.*?)&gt;? # URL
+ [ \t]*+ # Optional whtiespace
+ ( # Optional Title
+ (?&lt;title&gt;['"])
+ (.*?)
+ \k&lt;title&gt;
+ )?
+ \)
+ )
+ )
+ )
+ | (?!(?&lt;=\S)\1). # Everything besides
+ # style closer
+ )++
+ (?&lt;=\S)\1 # Close
+ )
+ </string>
+ <key>captures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.bold.markdown</string>
+ </dict>
+ </dict>
+ <key>end</key>
+ <string>(?&lt;=\S)(\1)</string>
+ <key>name</key>
+ <string>markup.bold.markdown</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>applyEndPatternLast</key>
+ <integer>1</integer>
+ <key>begin</key>
+ <string>(?=&lt;[^&gt;]*?&gt;)</string>
+ <key>end</key>
+ <string>(?&lt;=&gt;)</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>include</key>
+ <string>text.html.basic</string>
+ </dict>
+ </array>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#escape</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#ampersand</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#bracket</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#raw</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#italic</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#image-inline</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#link-inline</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#link-inet</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#link-email</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#image-ref</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#link-ref-literal</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#link-ref</string>
+ </dict>
+ </array>
+ </dict>
+ <key>bracket</key>
+ <dict>
+ <key>comment</key>
+ <string>
+ Markdown will convert this for us. We match it so that the
+ HTML grammar will not mark it up as invalid.
+ </string>
+ <key>match</key>
+ <string>&lt;(?![a-z/?\$!])</string>
+ <key>name</key>
+ <string>meta.other.valid-bracket.markdown</string>
+ </dict>
+ <key>escape</key>
+ <dict>
+ <key>match</key>
+ <string>\\[-`*_#+.!(){}\[\]\\&gt;]</string>
+ <key>name</key>
+ <string>constant.character.escape.markdown</string>
+ </dict>
+ <key>heading</key>
+ <dict>
+ <key>begin</key>
+ <string>\G(#{1,6})(?!#)\s*(?=\S)</string>
+ <key>captures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.heading.markdown</string>
+ </dict>
+ </dict>
+ <key>contentName</key>
+ <string>entity.name.section.markdown</string>
+ <key>end</key>
+ <string>\s*(#*)$\n?</string>
+ <key>name</key>
+ <string>markup.heading.markdown</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>include</key>
+ <string>#inline</string>
+ </dict>
+ </array>
+ </dict>
+ <key>image-inline</key>
+ <dict>
+ <key>captures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.begin.markdown</string>
+ </dict>
+ <key>10</key>
+ <dict>
+ <key>name</key>
+ <string>string.other.link.description.title.markdown</string>
+ </dict>
+ <key>11</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.markdown</string>
+ </dict>
+ <key>12</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.markdown</string>
+ </dict>
+ <key>13</key>
+ <dict>
+ <key>name</key>
+ <string>string.other.link.description.title.markdown</string>
+ </dict>
+ <key>14</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.markdown</string>
+ </dict>
+ <key>15</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.markdown</string>
+ </dict>
+ <key>16</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.metadata.markdown</string>
+ </dict>
+ <key>2</key>
+ <dict>
+ <key>name</key>
+ <string>string.other.link.description.markdown</string>
+ </dict>
+ <key>3</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.end.markdown</string>
+ </dict>
+ <key>5</key>
+ <dict>
+ <key>name</key>
+ <string>invalid.illegal.whitespace.markdown</string>
+ </dict>
+ <key>6</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.metadata.markdown</string>
+ </dict>
+ <key>7</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.link.markdown</string>
+ </dict>
+ <key>8</key>
+ <dict>
+ <key>name</key>
+ <string>markup.underline.link.image.markdown</string>
+ </dict>
+ <key>9</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.link.markdown</string>
+ </dict>
+ </dict>
+ <key>match</key>
+ <string>(?x:
+ \! # Images start with !
+ (\[)((?&lt;square&gt;[^\[\]\\]|\\.|\[\g&lt;square&gt;*+\])*+)(\])
+ # Match the link text.
+ ([ ])? # Space not allowed
+ (\() # Opening paren for url
+ (&lt;?)(\S+?)(&gt;?) # The url
+ [ \t]* # Optional whitespace
+ (?:
+ ((\().+?(\))) # Match title in parens…
+ | ((").+?(")) # or in quotes.
+ )? # Title is optional
+ \s* # Optional whitespace
+ (\))
+ )</string>
+ <key>name</key>
+ <string>meta.image.inline.markdown</string>
+ </dict>
+ <key>image-ref</key>
+ <dict>
+ <key>captures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.begin.markdown</string>
+ </dict>
+ <key>2</key>
+ <dict>
+ <key>name</key>
+ <string>string.other.link.description.markdown</string>
+ </dict>
+ <key>4</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.begin.markdown</string>
+ </dict>
+ <key>5</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.constant.markdown</string>
+ </dict>
+ <key>6</key>
+ <dict>
+ <key>name</key>
+ <string>constant.other.reference.link.markdown</string>
+ </dict>
+ <key>7</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.constant.markdown</string>
+ </dict>
+ </dict>
+ <key>match</key>
+ <string>\!(\[)((?&lt;square&gt;[^\[\]\\]|\\.|\[\g&lt;square&gt;*+\])*+)(\])[ ]?(\[)(.*?)(\])</string>
+ <key>name</key>
+ <string>meta.image.reference.markdown</string>
+ </dict>
+ <key>inline</key>
+ <dict>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>include</key>
+ <string>#escape</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#ampersand</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#bracket</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#raw</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#bold</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#italic</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#line-break</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#image-inline</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#link-inline</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#link-inet</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#link-email</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#image-ref</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#link-ref-literal</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#link-ref</string>
+ </dict>
+ </array>
+ </dict>
+ <key>italic</key>
+ <dict>
+ <key>begin</key>
+ <string>(?x)
+ (\*|_)(?=\S) # Open
+ (?=
+ (
+ &lt;[^&gt;]*+&gt; # HTML tags
+ | (?&lt;raw&gt;`+)([^`]|(?!(?&lt;!`)\k&lt;raw&gt;(?!`))`)*+\k&lt;raw&gt;
+ # Raw
+ | \\[\\`*_{}\[\]()#.!+\-&gt;]?+ # Escapes
+ | \[
+ (
+ (?&lt;square&gt; # Named group
+ [^\[\]\\] # Match most chars
+ | \\. # Escaped chars
+ | \[ \g&lt;square&gt;*+ \] # Nested brackets
+ )*+
+ \]
+ (
+ ( # Reference Link
+ [ ]? # Optional space
+ \[[^\]]*+\] # Ref name
+ )
+ | ( # Inline Link
+ \( # Opening paren
+ [ \t]*+ # Optional whtiespace
+ &lt;?(.*?)&gt;? # URL
+ [ \t]*+ # Optional whtiespace
+ ( # Optional Title
+ (?&lt;title&gt;['"])
+ (.*?)
+ \k&lt;title&gt;
+ )?
+ \)
+ )
+ )
+ )
+ | \1\1 # Must be bold closer
+ | (?!(?&lt;=\S)\1). # Everything besides
+ # style closer
+ )++
+ (?&lt;=\S)\1 # Close
+ )
+ </string>
+ <key>captures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.italic.markdown</string>
+ </dict>
+ </dict>
+ <key>end</key>
+ <string>(?&lt;=\S)(\1)((?!\1)|(?=\1\1))</string>
+ <key>name</key>
+ <string>markup.italic.markdown</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>applyEndPatternLast</key>
+ <integer>1</integer>
+ <key>begin</key>
+ <string>(?=&lt;[^&gt;]*?&gt;)</string>
+ <key>end</key>
+ <string>(?&lt;=&gt;)</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>include</key>
+ <string>text.html.basic</string>
+ </dict>
+ </array>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#escape</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#ampersand</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#bracket</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#raw</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#bold</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#image-inline</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#link-inline</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#link-inet</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#link-email</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#image-ref</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#link-ref-literal</string>
+ </dict>
+ <dict>
+ <key>include</key>
+ <string>#link-ref</string>
+ </dict>
+ </array>
+ </dict>
+ <key>line-break</key>
+ <dict>
+ <key>match</key>
+ <string> {2,}$</string>
+ <key>name</key>
+ <string>meta.dummy.line-break</string>
+ </dict>
+ <key>link-email</key>
+ <dict>
+ <key>captures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.link.markdown</string>
+ </dict>
+ <key>2</key>
+ <dict>
+ <key>name</key>
+ <string>markup.underline.link.markdown</string>
+ </dict>
+ <key>4</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.link.markdown</string>
+ </dict>
+ </dict>
+ <key>match</key>
+ <string>(&lt;)((?:mailto:)?[-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(&gt;)</string>
+ <key>name</key>
+ <string>meta.link.email.lt-gt.markdown</string>
+ </dict>
+ <key>link-inet</key>
+ <dict>
+ <key>captures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.link.markdown</string>
+ </dict>
+ <key>2</key>
+ <dict>
+ <key>name</key>
+ <string>markup.underline.link.markdown</string>
+ </dict>
+ <key>3</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.link.markdown</string>
+ </dict>
+ </dict>
+ <key>match</key>
+ <string>(&lt;)((?:https?|ftp)://.*?)(&gt;)</string>
+ <key>name</key>
+ <string>meta.link.inet.markdown</string>
+ </dict>
+ <key>link-inline</key>
+ <dict>
+ <key>captures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.begin.markdown</string>
+ </dict>
+ <key>10</key>
+ <dict>
+ <key>name</key>
+ <string>string.other.link.description.title.markdown</string>
+ </dict>
+ <key>11</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.begin.markdown</string>
+ </dict>
+ <key>12</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.end.markdown</string>
+ </dict>
+ <key>13</key>
+ <dict>
+ <key>name</key>
+ <string>string.other.link.description.title.markdown</string>
+ </dict>
+ <key>14</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.begin.markdown</string>
+ </dict>
+ <key>15</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.end.markdown</string>
+ </dict>
+ <key>16</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.metadata.markdown</string>
+ </dict>
+ <key>2</key>
+ <dict>
+ <key>name</key>
+ <string>string.other.link.title.markdown</string>
+ </dict>
+ <key>4</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.end.markdown</string>
+ </dict>
+ <key>5</key>
+ <dict>
+ <key>name</key>
+ <string>invalid.illegal.whitespace.markdown</string>
+ </dict>
+ <key>6</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.metadata.markdown</string>
+ </dict>
+ <key>7</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.link.markdown</string>
+ </dict>
+ <key>8</key>
+ <dict>
+ <key>name</key>
+ <string>markup.underline.link.markdown</string>
+ </dict>
+ <key>9</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.link.markdown</string>
+ </dict>
+ </dict>
+ <key>match</key>
+ <string>(?x:
+ (\[)((?&lt;square&gt;[^\[\]\\]|\\.|\[\g&lt;square&gt;*+\])*+)(\])
+ # Match the link text.
+ ([ ])? # Space not allowed
+ (\() # Opening paren for url
+ (&lt;?)(.*?)(&gt;?) # The url
+ [ \t]* # Optional whitespace
+ (?:
+ ((\().+?(\))) # Match title in parens…
+ | ((").+?(")) # or in quotes.
+ )? # Title is optional
+ \s* # Optional whitespace
+ (\))
+ )</string>
+ <key>name</key>
+ <string>meta.link.inline.markdown</string>
+ </dict>
+ <key>link-ref</key>
+ <dict>
+ <key>captures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.begin.markdown</string>
+ </dict>
+ <key>2</key>
+ <dict>
+ <key>name</key>
+ <string>string.other.link.title.markdown</string>
+ </dict>
+ <key>4</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.end.markdown</string>
+ </dict>
+ <key>5</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.constant.begin.markdown</string>
+ </dict>
+ <key>6</key>
+ <dict>
+ <key>name</key>
+ <string>constant.other.reference.link.markdown</string>
+ </dict>
+ <key>7</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.constant.end.markdown</string>
+ </dict>
+ </dict>
+ <key>match</key>
+ <string>(\[)((?&lt;square&gt;[^\[\]\\]|\\.|\[\g&lt;square&gt;*+\])*+)(\])[ ]?(\[)([^\]]*+)(\])</string>
+ <key>name</key>
+ <string>meta.link.reference.markdown</string>
+ </dict>
+ <key>link-ref-literal</key>
+ <dict>
+ <key>captures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.begin.markdown</string>
+ </dict>
+ <key>2</key>
+ <dict>
+ <key>name</key>
+ <string>string.other.link.title.markdown</string>
+ </dict>
+ <key>4</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.string.end.markdown</string>
+ </dict>
+ <key>5</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.constant.begin.markdown</string>
+ </dict>
+ <key>6</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.constant.end.markdown</string>
+ </dict>
+ </dict>
+ <key>match</key>
+ <string>(\[)((?&lt;square&gt;[^\[\]\\]|\\.|\[\g&lt;square&gt;*+\])*+)(\])[ ]?(\[)(\])</string>
+ <key>name</key>
+ <string>meta.link.reference.literal.markdown</string>
+ </dict>
+ <key>list-paragraph</key>
+ <dict>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>begin</key>
+ <string>\G\s+(?=\S)</string>
+ <key>end</key>
+ <string>^\s*$</string>
+ <key>name</key>
+ <string>meta.paragraph.list.markdown</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>include</key>
+ <string>#inline</string>
+ </dict>
+ </array>
+ </dict>
+ </array>
+ </dict>
+ <key>raw</key>
+ <dict>
+ <key>captures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.raw.markdown</string>
+ </dict>
+ <key>3</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.definition.raw.markdown</string>
+ </dict>
+ </dict>
+ <key>match</key>
+ <string>(`+)([^`]|(?!(?&lt;!`)\1(?!`))`)*+(\1)</string>
+ <key>name</key>
+ <string>markup.raw.inline.markdown</string>
+ </dict>
+ <key>separator</key>
+ <dict>
+ <key>match</key>
+ <string>\G[ ]{,3}([-*_])([ ]{,2}\1){2,}[ \t]*$\n?</string>
+ <key>name</key>
+ <string>meta.separator.markdown</string>
+ </dict>
+ </dict>
+ <key>scopeName</key>
+ <string>text.html.markdown</string>
+ <key>uuid</key>
+ <string>0A1D9874-B448-11D9-BD50-000D93B6E43C</string>
+</dict>
+</plist>
29 MarkdownBuild.py
@@ -0,0 +1,29 @@
+import sublime, sublime_plugin
+import markdown_python
+import os
+import tempfile
+
+class MarkdownBuild(sublime_plugin.WindowCommand):
+ def run(self):
+ view = self.window.active_view()
+ if not view:
+ return
+ file_name = view.file_name()
+ if not file_name:
+ return
+
+ contents = view.substr(sublime.Region(0, view.size()))
+ md = markdown_python.markdown(contents)
+ html = '<html><meta charset="UTF-8">'
+ css = os.path.join(sublime.packages_path(), 'SublimeMarkdownBuild', 'markdown.css')
+ if (os.path.isfile(css)):
+ styles = open(css, 'r').read()
+ html += '<style>' + styles + '</style>'
+ html += "<body>"
+ html += md
+ html += "</body></html>"
+ output = tempfile.NamedTemporaryFile(delete=False, suffix='.html')
+ output.write(html.encode('UTF-8'))
+ output.close()
+ os.system(output.name)
+
80 MultiMarkdown.tmLanguage
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>firstLineMatch</key>
+ <string>^Format:\s*(?i:complete)\s*$</string>
+ <key>foldingStartMarker</key>
+ <string>(?x)
+ (&lt;(?i:head|body|table|thead|tbody|tfoot|tr|div|select|fieldset|style|script|ul|ol|form|dl)\b.*?&gt;
+ |&lt;!--(?!.*--&gt;)
+ |\{\s*($|\?&gt;\s*$|//|/\*(.*\*/\s*$|(?!.*?\*/)))
+ )</string>
+ <key>foldingStopMarker</key>
+ <string>(?x)
+ (&lt;/(?i:head|body|table|thead|tbody|tfoot|tr|div|select|fieldset|style|script|ul|ol|form|dl)&gt;
+ |^\s*--&gt;
+ |(^|\s)\}
+ )</string>
+ <key>keyEquivalent</key>
+ <string>^~M</string>
+ <key>name</key>
+ <string>MultiMarkdown</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>begin</key>
+ <string>^([A-Za-z0-9]+)(:)\s*</string>
+ <key>beginCaptures</key>
+ <dict>
+ <key>1</key>
+ <dict>
+ <key>name</key>
+ <string>keyword.other.multimarkdown</string>
+ </dict>
+ <key>2</key>
+ <dict>
+ <key>name</key>
+ <string>punctuation.separator.key-value.multimarkdown</string>
+ </dict>
+ </dict>
+ <key>end</key>
+ <string>^$|^(?=[A-Za-z0-9]+:)</string>
+ <key>name</key>
+ <string>meta.header.multimarkdown</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>comment</key>
+ <string>The reason for not setting scopeName = "string.unquoted"
+ (for the parent rule) is that we do not want
+ newlines to be marked as string.unquoted</string>
+ <key>match</key>
+ <string>.+</string>
+ <key>name</key>
+ <string>string.unquoted.multimarkdown</string>
+ </dict>
+ </array>
+ </dict>
+ <dict>
+ <key>begin</key>
+ <string>^(?!=[A-Za-z0-9]+:)</string>
+ <key>end</key>
+ <string>^(?=not)possible$</string>
+ <key>name</key>
+ <string>meta.content.multimarkdown</string>
+ <key>patterns</key>
+ <array>
+ <dict>
+ <key>include</key>
+ <string>text.html.markdown</string>
+ </dict>
+ </array>
+ </dict>
+ </array>
+ <key>scopeName</key>
+ <string>text.html.markdown.multimarkdown</string>
+ <key>uuid</key>
+ <string>F5E04BF4-69A9-45AE-9205-B3F3C2B00130</string>
+</dict>
+</plist>
25 README.md
@@ -0,0 +1,25 @@
+# Sublime Markdown (version 0.5.0)
+
+This is a Sublime Text plugin for building markdown.
+
+## Installation
+
+1. Download the package from https://github.com/downloads/erinata/SublimeMarkdown/SublimeMarkdownBuild-0.5.0.zip
+2. Extract the folder SublimeMarkdownBuild
+3. Copy the SublimeMarkdownBuild folder to the package folder of SublimeText 2
+
+## Usage
+
+Originally this plugin is named "SublimeMarkdown" which features automatic bullet points, numbered lists etc. Now the bullet points functionality is extracted to a separated plugin named "SublimeBullet" <https://github.com/erinata/SublimeBullet>
+
+Press Ctrl+b to build the markdown file to html and view it in the browser. It used Python-markdown to build the html file but you do not need to have Python installed in order to use this plugin. It used the Python inside Sublime Text to get the job done.
+
+I also include a Markdown.tmLanguage file so the markdown files' syntax should be highlighted. It works well with the theme "SunBurst" but it should work for other themes too.
+
+## Operating Systems
+
+I only tested this on Windows, I hope that it works on OSX and Linux.
+
+## License
+
+Copyright (C) 2012 Tom Lam. MIT License.
107 markdown.css
@@ -0,0 +1,107 @@
+body{
+ margin: 0 auto;
+ font-family: Georgia, Palatino, serif;
+ color: #444444;
+ line-height: 1;
+ max-width: 960px;
+ padding: 30px;
+ border-width: 2px;
+ border-style: solid;
+ border-color: #999999;
+ background-color: #FFFFFF;
+}
+h1, h2, h3, h4 {
+ color: #111111;
+ font-weight: 400;
+ background-color: #FFFFFF;
+}
+h1, h2, h3, h4, h5, p {
+ margin-bottom: 24px;
+ padding: 0;
+}
+h1 {
+ font-size: 48px;
+}
+h2 {
+ font-size: 36px;
+}
+h3 {
+ font-size: 24px;
+}
+h4 {
+ font-size: 21px;
+}
+h5 {
+ font-size: 18px;
+}
+a {
+ color: #0099ff;
+ margin: 0;
+ padding: 0;
+ vertical-align: baseline;
+}
+a:hover {
+ text-decoration: none;
+ color: #ff6600;
+}
+a:visited {
+ color: #800080;
+}
+ul, ol {
+ padding: 0;
+ margin: 24px;
+}
+li {
+ line-height: 24px;
+}
+li ul, li ul {
+ margin-left: 24px;
+}
+p, ul, ol {
+ font-size: 16px;
+ line-height: 24px;
+ max-width: 540px;
+}
+pre {
+ padding: 0px 24px;
+ max-width: 800px;
+ white-space: pre-wrap;
+ background-color: #FFEECC;
+ padding: 0 4em;
+}
+code {
+ font-family: Consolas, Monaco, Andale Mono, monospace;
+ line-height: 1.5;
+ font-size: 16px;
+
+}
+aside {
+ display: block;
+ float: right;
+ width: 390px;
+}
+blockquote {
+ border-left:.5em solid #eee;
+ padding: 0 2em;
+ margin-left:0;
+ max-width: 476px;
+}
+blockquote cite {
+ font-size:14px;
+ line-height:20px;
+ color:#bfbfbf;
+}
+blockquote cite:before {
+ content: '\2014 \00A0';
+}
+
+blockquote p {
+ color: #666;
+ max-width: 460px;
+}
+hr {
+ width: 540px;
+ text-align: left;
+ margin: 0 auto 0 0;
+ color: #999;
+}
428 markdown_python/__init__.py
@@ -0,0 +1,428 @@
+"""
+Python Markdown
+===============
+
+Python Markdown converts Markdown to HTML and can be used as a library or
+called from the command line.
+
+## Basic usage as a module:
+
+ import markdown
+ html = markdown.markdown(your_text_string)
+
+See <http://www.freewisdom.org/projects/python-markdown/> for more
+information and instructions on how to extend the functionality of
+Python Markdown. Read that before you try modifying this file.
+
+## Authors and License
+
+Started by [Manfred Stienstra](http://www.dwerg.net/). Continued and
+maintained by [Yuri Takhteyev](http://www.freewisdom.org), [Waylan
+Limberg](http://achinghead.com/) and [Artem Yunusov](http://blog.splyer.com).
+
+Contact: markdown@freewisdom.org
+
+Copyright 2007-2012 The Python Markdown Project (v. 1.7 and later)
+Copyright 200? Django Software Foundation (OrderedDict implementation)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE for details).
+"""
+
+version = "2.1.1"
+version_info = (2,1,1, "final")
+
+import re
+import codecs
+import sys
+import logging
+import util
+from preprocessors import build_preprocessors
+from blockprocessors import build_block_parser
+from treeprocessors import build_treeprocessors
+from inlinepatterns import build_inlinepatterns
+from postprocessors import build_postprocessors
+from extensions import Extension
+from serializers import to_html_string, to_xhtml_string
+
+__all__ = ['Markdown', 'markdown', 'markdownFromFile']
+
+logger = logging.getLogger('MARKDOWN')
+
+
+class Markdown:
+ """Convert Markdown to HTML."""
+
+ doc_tag = "div" # Element used to wrap document - later removed
+
+ option_defaults = {
+ 'html_replacement_text' : '[HTML_REMOVED]',
+ 'tab_length' : 4,
+ 'enable_attributes' : True,
+ 'smart_emphasis' : True,
+ 'lazy_ol' : True,
+ }
+
+ output_formats = {
+ 'html' : to_html_string,
+ 'html4' : to_html_string,
+ 'html5' : to_html_string,
+ 'xhtml' : to_xhtml_string,
+ 'xhtml1': to_xhtml_string,
+ 'xhtml5': to_xhtml_string,
+ }
+
+ ESCAPED_CHARS = ['\\', '`', '*', '_', '{', '}', '[', ']',
+ '(', ')', '>', '#', '+', '-', '.', '!']
+
+ def __init__(self, *args, **kwargs):
+ """
+ Creates a new Markdown instance.
+
+ Keyword arguments:
+
+ * extensions: A list of extensions.
+ If they are of type string, the module mdx_name.py will be loaded.
+ If they are a subclass of markdown.Extension, they will be used
+ as-is.
+ * extension-configs: Configuration settingis for extensions.
+ * output_format: Format of output. Supported formats are:
+ * "xhtml1": Outputs XHTML 1.x. Default.
+ * "xhtml5": Outputs XHTML style tags of HTML 5
+ * "xhtml": Outputs latest supported version of XHTML (currently XHTML 1.1).
+ * "html4": Outputs HTML 4
+ * "html5": Outputs HTML style tags of HTML 5
+ * "html": Outputs latest supported version of HTML (currently HTML 4).
+ Note that it is suggested that the more specific formats ("xhtml1"
+ and "html4") be used as "xhtml" or "html" may change in the future
+ if it makes sense at that time.
+ * safe_mode: Disallow raw html. One of "remove", "replace" or "escape".
+ * html_replacement_text: Text used when safe_mode is set to "replace".
+ * tab_length: Length of tabs in the source. Default: 4
+ * enable_attributes: Enable the conversion of attributes. Default: True
+ * smart_emphasis: Treat `_connected_words_` intelegently Default: True
+ * lazy_ol: Ignore number of first item of ordered lists. Default: True
+
+ """
+
+ # For backward compatability, loop through old positional args
+ pos = ['extensions', 'extension_configs', 'safe_mode', 'output_format']
+ c = 0
+ for arg in args:
+ if not kwargs.has_key(pos[c]):
+ kwargs[pos[c]] = arg
+ c += 1
+ if c == len(pos):
+ # ignore any additional args
+ break
+
+ # Loop through kwargs and assign defaults
+ for option, default in self.option_defaults.items():
+ setattr(self, option, kwargs.get(option, default))
+
+ self.safeMode = kwargs.get('safe_mode', False)
+ self.registeredExtensions = []
+ self.docType = ""
+ self.stripTopLevelTags = True
+
+ self.build_parser()
+
+ self.references = {}
+ self.htmlStash = util.HtmlStash()
+ self.registerExtensions(extensions=kwargs.get('extensions', []),
+ configs=kwargs.get('extension_configs', {}))
+ self.set_output_format(kwargs.get('output_format', 'xhtml1'))
+ self.reset()
+
+ def build_parser(self):
+ """ Build the parser from the various parts. """
+ self.preprocessors = build_preprocessors(self)
+ self.parser = build_block_parser(self)
+ self.inlinePatterns = build_inlinepatterns(self)
+ self.treeprocessors = build_treeprocessors(self)
+ self.postprocessors = build_postprocessors(self)
+ return self
+
+ def registerExtensions(self, extensions, configs):
+ """
+ Register extensions with this instance of Markdown.
+
+ Keyword arguments:
+
+ * extensions: A list of extensions, which can either
+ be strings or objects. See the docstring on Markdown.
+ * configs: A dictionary mapping module names to config options.
+
+ """
+ for ext in extensions:
+ if isinstance(ext, basestring):
+ ext = self.build_extension(ext, configs.get(ext, []))
+ if isinstance(ext, Extension):
+ # might raise NotImplementedError, but that's the extension author's problem
+ ext.extendMarkdown(self, globals())
+ else:
+ raise ValueError('Extension "%s.%s" must be of type: "markdown.Extension".' \
+ % (ext.__class__.__module__, ext.__class__.__name__))
+
+ return self
+
+ def build_extension(self, ext_name, configs = []):
+ """Build extension by name, then return the module.
+
+ The extension name may contain arguments as part of the string in the
+ following format: "extname(key1=value1,key2=value2)"
+
+ """
+
+ # Parse extensions config params (ignore the order)
+ configs = dict(configs)
+ pos = ext_name.find("(") # find the first "("
+ if pos > 0:
+ ext_args = ext_name[pos+1:-1]
+ ext_name = ext_name[:pos]
+ pairs = [x.split("=") for x in ext_args.split(",")]
+ configs.update([(x.strip(), y.strip()) for (x, y) in pairs])
+
+ # Setup the module name
+ module_name = ext_name
+ if '.' not in ext_name:
+ module_name = '.'.join(['markdown.extensions', ext_name])
+
+ # Try loading the extension first from one place, then another
+ try: # New style (markdown.extensons.<extension>)
+ module = __import__(module_name, {}, {}, [module_name.rpartition('.')[0]])
+ except ImportError:
+ module_name_old_style = '_'.join(['mdx', ext_name])
+ try: # Old style (mdx_<extension>)
+ module = __import__(module_name_old_style)
+ except ImportError:
+ logger.warn("Failed loading extension '%s' from '%s' or '%s'"
+ % (ext_name, module_name, module_name_old_style))
+ # Return None so we don't try to initiate none-existant extension
+ return None
+
+ # If the module is loaded successfully, we expect it to define a
+ # function called makeExtension()
+ try:
+ return module.makeExtension(configs.items())
+ except AttributeError, e:
+ logger.warn("Failed to initiate extension '%s': %s" % (ext_name, e))
+ return None
+
+ def registerExtension(self, extension):
+ """ This gets called by the extension """
+ self.registeredExtensions.append(extension)
+ return self
+
+ def reset(self):
+ """
+ Resets all state variables so that we can start with a new text.
+ """
+ self.htmlStash.reset()
+ self.references.clear()
+
+ for extension in self.registeredExtensions:
+ if hasattr(extension, 'reset'):
+ extension.reset()
+
+ return self
+
+ def set_output_format(self, format):
+ """ Set the output format for the class instance. """
+ try:
+ self.serializer = self.output_formats[format.lower()]
+ except KeyError:
+ raise KeyError('Invalid Output Format: "%s". Use one of %s.' \
+ % (format, self.output_formats.keys()))
+ return self
+
+ def convert(self, source):
+ """
+ Convert markdown to serialized XHTML or HTML.
+
+ Keyword arguments:
+
+ * source: Source text as a Unicode string.
+
+ Markdown processing takes place in five steps:
+
+ 1. A bunch of "preprocessors" munge the input text.
+ 2. BlockParser() parses the high-level structural elements of the
+ pre-processed text into an ElementTree.
+ 3. A bunch of "treeprocessors" are run against the ElementTree. One
+ such treeprocessor runs InlinePatterns against the ElementTree,
+ detecting inline markup.
+ 4. Some post-processors are run against the text after the ElementTree
+ has been serialized into text.
+ 5. The output is written to a string.
+
+ """
+
+ # Fixup the source text
+ if not source.strip():
+ return u"" # a blank unicode string
+
+ try:
+ source = unicode(source)
+ except UnicodeDecodeError, e:
+ # Customise error message while maintaining original trackback
+ e.reason += '. -- Note: Markdown only accepts unicode input!'
+ raise
+
+ source = source.replace(util.STX, "").replace(util.ETX, "")
+ source = source.replace("\r\n", "\n").replace("\r", "\n") + "\n\n"
+ source = re.sub(r'\n\s+\n', '\n\n', source)
+ source = source.expandtabs(self.tab_length)
+
+ # Split into lines and run the line preprocessors.
+ self.lines = source.split("\n")
+ for prep in self.preprocessors.values():
+ self.lines = prep.run(self.lines)
+
+ # Parse the high-level elements.
+ root = self.parser.parseDocument(self.lines).getroot()
+
+ # Run the tree-processors
+ for treeprocessor in self.treeprocessors.values():
+ newRoot = treeprocessor.run(root)
+ if newRoot:
+ root = newRoot
+
+ # Serialize _properly_. Strip top-level tags.
+ output = self.serializer(root)
+ if self.stripTopLevelTags:
+ try:
+ start = output.index('<%s>'%self.doc_tag)+len(self.doc_tag)+2
+ end = output.rindex('</%s>'%self.doc_tag)
+ output = output[start:end].strip()
+ except ValueError:
+ if output.strip().endswith('<%s />'%self.doc_tag):
+ # We have an empty document
+ output = ''
+ else:
+ # We have a serious problem
+ raise ValueError('Markdown failed to strip top-level tags. Document=%r' % output.strip())
+
+ # Run the text post-processors
+ for pp in self.postprocessors.values():
+ output = pp.run(output)
+
+ return output.strip()
+
+ def convertFile(self, input=None, output=None, encoding=None):
+ """Converts a markdown file and returns the HTML as a unicode string.
+
+ Decodes the file using the provided encoding (defaults to utf-8),
+ passes the file content to markdown, and outputs the html to either
+ the provided stream or the file with provided name, using the same
+ encoding as the source file. The 'xmlcharrefreplace' error handler is
+ used when encoding the output.
+
+ **Note:** This is the only place that decoding and encoding of unicode
+ takes place in Python-Markdown. (All other code is unicode-in /
+ unicode-out.)
+
+ Keyword arguments:
+
+ * input: File object or path. Reads from stdin if `None`.
+ * output: File object or path. Writes to stdout if `None`.
+ * encoding: Encoding of input and output files. Defaults to utf-8.
+
+ """
+
+ encoding = encoding or "utf-8"
+
+ # Read the source
+ if input:
+ if isinstance(input, str):
+ input_file = codecs.open(input, mode="r", encoding=encoding)
+ else:
+ input_file = codecs.getreader(encoding)(input)
+ text = input_file.read()
+ input_file.close()
+ else:
+ text = sys.stdin.read()
+ if not isinstance(text, unicode):
+ text = text.decode(encoding)
+
+ text = text.lstrip('\ufeff') # remove the byte-order mark
+
+ # Convert
+ html = self.convert(text)
+
+ # Write to file or stdout
+ if output:
+ if isinstance(output, str):
+ output_file = codecs.open(output, "w",
+ encoding=encoding,
+ errors="xmlcharrefreplace")
+ output_file.write(html)
+ output_file.close()
+ else:
+ writer = codecs.getwriter(encoding)
+ output_file = writer(output, errors="xmlcharrefreplace")
+ output_file.write(html)
+ # Don't close here. User may want to write more.
+ else:
+ sys.stdout.write(html)
+
+ return self
+
+
+"""
+EXPORTED FUNCTIONS
+=============================================================================
+
+Those are the two functions we really mean to export: markdown() and
+markdownFromFile().
+"""
+
+def markdown(text, *args, **kwargs):
+ """Convert a markdown string to HTML and return HTML as a unicode string.
+
+ This is a shortcut function for `Markdown` class to cover the most
+ basic use case. It initializes an instance of Markdown, loads the
+ necessary extensions and runs the parser on the given text.
+
+ Keyword arguments:
+
+ * text: Markdown formatted text as Unicode or ASCII string.
+ * Any arguments accepted by the Markdown class.
+
+ Returns: An HTML document as a string.
+
+ """
+ md = Markdown(*args, **kwargs)
+ return md.convert(text)
+
+
+def markdownFromFile(*args, **kwargs):
+ """Read markdown code from a file and write it to a file or a stream.
+
+ This is a shortcut function which initializes an instance of Markdown,
+ and calls the convertFile method rather than convert.
+
+ Keyword arguments:
+
+ * input: a file name or readable object.
+ * output: a file name or writable object.
+ * encoding: Encoding of input and output.
+ * Any arguments accepted by the Markdown class.
+
+ """
+ # For backward compatibility loop through positional args
+ pos = ['input', 'output', 'extensions', 'encoding']
+ c = 0
+ for arg in args:
+ if not kwargs.has_key(pos[c]):
+ kwargs[pos[c]] = arg
+ c += 1
+ if c == len(pos):
+ break
+
+ md = Markdown(**kwargs)
+ md.convertFile(kwargs.get('input', None),
+ kwargs.get('output', None),
+ kwargs.get('encoding', None))
+
87 markdown_python/__main__.py
@@ -0,0 +1,87 @@
+"""
+COMMAND-LINE SPECIFIC STUFF
+=============================================================================
+
+"""
+
+import markdown
+import sys
+import optparse
+
+import logging
+from logging import DEBUG, INFO, CRITICAL
+
+logger = logging.getLogger('MARKDOWN')
+
+def parse_options():
+ """
+ Define and parse `optparse` options for command-line usage.
+ """
+ usage = """%prog [options] [INPUTFILE]
+ (STDIN is assumed if no INPUTFILE is given)"""
+ desc = "A Python implementation of John Gruber's Markdown. " \
+ "http://www.freewisdom.org/projects/python-markdown/"
+ ver = "%%prog %s" % markdown.version
+
+ parser = optparse.OptionParser(usage=usage, description=desc, version=ver)
+ parser.add_option("-f", "--file", dest="filename", default=sys.stdout,
+ help="Write output to OUTPUT_FILE. Defaults to STDOUT.",
+ metavar="OUTPUT_FILE")
+ parser.add_option("-e", "--encoding", dest="encoding",
+ help="Encoding for input and output files.",)
+ parser.add_option("-q", "--quiet", default = CRITICAL,
+ action="store_const", const=CRITICAL+10, dest="verbose",
+ help="Suppress all warnings.")
+ parser.add_option("-v", "--verbose",
+ action="store_const", const=INFO, dest="verbose",
+ help="Print all warnings.")
+ parser.add_option("-s", "--safe", dest="safe", default=False,
+ metavar="SAFE_MODE",
+ help="'replace', 'remove' or 'escape' HTML tags in input")
+ parser.add_option("-o", "--output_format", dest="output_format",
+ default='xhtml1', metavar="OUTPUT_FORMAT",
+ help="'xhtml1' (default), 'html4' or 'html5'.")
+ parser.add_option("--noisy",
+ action="store_const", const=DEBUG, dest="verbose",
+ help="Print debug messages.")
+ parser.add_option("-x", "--extension", action="append", dest="extensions",
+ help = "Load extension EXTENSION.", metavar="EXTENSION")
+ parser.add_option("-n", "--no_lazy_ol", dest="lazy_ol",
+ action='store_false', default=True,
+ help="Observe number of first item of ordered lists.")
+
+ (options, args) = parser.parse_args()
+
+ if len(args) == 0:
+ input_file = None
+ else:
+ input_file = args[0]
+
+ if not options.extensions:
+ options.extensions = []
+
+ return {'input': input_file,
+ 'output': options.filename,
+ 'safe_mode': options.safe,
+ 'extensions': options.extensions,
+ 'encoding': options.encoding,
+ 'output_format': options.output_format,
+ 'lazy_ol': options.lazy_ol}, options.verbose
+
+def run():
+ """Run Markdown from the command line."""
+
+ # Parse options and adjust logging level if necessary
+ options, logging_level = parse_options()
+ if not options: sys.exit(2)
+ logger.setLevel(logging_level)
+ logger.addHandler(logging.StreamHandler())
+
+ # Run
+ markdown.markdownFromFile(**options)
+
+if __name__ == '__main__':
+ # Support running module as a commandline command.
+ # Python 2.5 & 2.6 do: `python -m markdown.__main__ [options] [args]`.
+ # Python 2.7 & 3.x do: `python -m markdown [options] [args]`.
+ run()
97 markdown_python/blockparser.py
@@ -0,0 +1,97 @@
+
+import util
+import odict
+
+class State(list):
+ """ Track the current and nested state of the parser.
+
+ This utility class is used to track the state of the BlockParser and
+ support multiple levels if nesting. It's just a simple API wrapped around
+ a list. Each time a state is set, that state is appended to the end of the
+ list. Each time a state is reset, that state is removed from the end of
+ the list.
+
+ Therefore, each time a state is set for a nested block, that state must be
+ reset when we back out of that level of nesting or the state could be
+ corrupted.
+
+ While all the methods of a list object are available, only the three
+ defined below need be used.
+
+ """
+
+ def set(self, state):
+ """ Set a new state. """
+ self.append(state)
+
+ def reset(self):
+ """ Step back one step in nested state. """
+ self.pop()
+
+ def isstate(self, state):
+ """ Test that top (current) level is of given state. """
+ if len(self):
+ return self[-1] == state
+ else:
+ return False
+
+class BlockParser:
+ """ Parse Markdown blocks into an ElementTree object.
+
+ A wrapper class that stitches the various BlockProcessors together,
+ looping through them and creating an ElementTree object.
+ """
+
+ def __init__(self, markdown):
+ self.blockprocessors = odict.OrderedDict()
+ self.state = State()
+ self.markdown = markdown
+
+ def parseDocument(self, lines):
+ """ Parse a markdown document into an ElementTree.
+
+ Given a list of lines, an ElementTree object (not just a parent Element)
+ is created and the root element is passed to the parser as the parent.
+ The ElementTree object is returned.
+
+ This should only be called on an entire document, not pieces.
+
+ """
+ # Create a ElementTree from the lines
+ self.root = util.etree.Element(self.markdown.doc_tag)
+ self.parseChunk(self.root, '\n'.join(lines))
+ return util.etree.ElementTree(self.root)
+
+ def parseChunk(self, parent, text):
+ """ Parse a chunk of markdown text and attach to given etree node.
+
+ While the ``text`` argument is generally assumed to contain multiple
+ blocks which will be split on blank lines, it could contain only one
+ block. Generally, this method would be called by extensions when
+ block parsing is required.
+
+ The ``parent`` etree Element passed in is altered in place.
+ Nothing is returned.
+
+ """
+ self.parseBlocks(parent, text.split('\n\n'))
+
+ def parseBlocks(self, parent, blocks):
+ """ Process blocks of markdown text and attach to given etree node.
+
+ Given a list of ``blocks``, each blockprocessor is stepped through
+ until there are no blocks left. While an extension could potentially
+ call this method directly, it's generally expected to be used internally.
+
+ This is a public method as an extension may need to add/alter additional
+ BlockProcessors which call this method to recursively parse a nested
+ block.
+
+ """
+ while blocks:
+ for processor in self.blockprocessors.values():
+ if processor.test(parent, blocks[0]):
+ processor.run(parent, blocks)
+ break
+
+
555 markdown_python/blockprocessors.py
@@ -0,0 +1,555 @@
+"""
+CORE MARKDOWN BLOCKPARSER
+=============================================================================
+
+This parser handles basic parsing of Markdown blocks. It doesn't concern itself
+with inline elements such as **bold** or *italics*, but rather just catches
+blocks, lists, quotes, etc.
+
+The BlockParser is made up of a bunch of BlockProssors, each handling a
+different type of block. Extensions may add/replace/remove BlockProcessors
+as they need to alter how markdown blocks are parsed.
+
+"""
+
+import logging
+import re
+import util
+from blockparser import BlockParser
+
+logger = logging.getLogger('MARKDOWN')
+
+
+def build_block_parser(md_instance, **kwargs):
+ """ Build the default block parser used by Markdown. """
+ parser = BlockParser(md_instance)
+ parser.blockprocessors['empty'] = EmptyBlockProcessor(parser)
+ parser.blockprocessors['indent'] = ListIndentProcessor(parser)
+ parser.blockprocessors['code'] = CodeBlockProcessor(parser)
+ parser.blockprocessors['hashheader'] = HashHeaderProcessor(parser)
+ parser.blockprocessors['setextheader'] = SetextHeaderProcessor(parser)
+ parser.blockprocessors['hr'] = HRProcessor(parser)
+ parser.blockprocessors['olist'] = OListProcessor(parser)
+ parser.blockprocessors['ulist'] = UListProcessor(parser)
+ parser.blockprocessors['quote'] = BlockQuoteProcessor(parser)
+ parser.blockprocessors['paragraph'] = ParagraphProcessor(parser)
+ return parser
+
+
+class BlockProcessor:
+ """ Base class for block processors.
+
+ Each subclass will provide the methods below to work with the source and
+ tree. Each processor will need to define it's own ``test`` and ``run``
+ methods. The ``test`` method should return True or False, to indicate
+ whether the current block should be processed by this processor. If the
+ test passes, the parser will call the processors ``run`` method.
+
+ """
+
+ def __init__(self, parser):
+ self.parser = parser
+ self.tab_length = parser.markdown.tab_length
+
+ def lastChild(self, parent):
+ """ Return the last child of an etree element. """
+ if len(parent):
+ return parent[-1]
+ else:
+ return None
+
+ def detab(self, text):
+ """ Remove a tab from the front of each line of the given text. """
+ newtext = []
+ lines = text.split('\n')
+ for line in lines:
+ if line.startswith(' '*self.tab_length):
+ newtext.append(line[self.tab_length:])
+ elif not line.strip():
+ newtext.append('')
+ else:
+ break
+ return '\n'.join(newtext), '\n'.join(lines[len(newtext):])
+
+ def looseDetab(self, text, level=1):
+ """ Remove a tab from front of lines but allowing dedented lines. """
+ lines = text.split('\n')
+ for i in range(len(lines)):
+ if lines[i].startswith(' '*self.tab_length*level):
+ lines[i] = lines[i][self.tab_length*level:]
+ return '\n'.join(lines)
+
+ def test(self, parent, block):
+ """ Test for block type. Must be overridden by subclasses.
+
+ As the parser loops through processors, it will call the ``test`` method
+ on each to determine if the given block of text is of that type. This
+ method must return a boolean ``True`` or ``False``. The actual method of
+ testing is left to the needs of that particular block type. It could
+ be as simple as ``block.startswith(some_string)`` or a complex regular
+ expression. As the block type may be different depending on the parent
+ of the block (i.e. inside a list), the parent etree element is also
+ provided and may be used as part of the test.
+
+ Keywords:
+
+ * ``parent``: A etree element which will be the parent of the block.
+ * ``block``: A block of text from the source which has been split at
+ blank lines.
+ """
+ pass
+
+ def run(self, parent, blocks):
+ """ Run processor. Must be overridden by subclasses.
+
+ When the parser determines the appropriate type of a block, the parser
+ will call the corresponding processor's ``run`` method. This method
+ should parse the individual lines of the block and append them to
+ the etree.
+
+ Note that both the ``parent`` and ``etree`` keywords are pointers
+ to instances of the objects which should be edited in place. Each
+ processor must make changes to the existing objects as there is no
+ mechanism to return new/different objects to replace them.
+
+ This means that this method should be adding SubElements or adding text
+ to the parent, and should remove (``pop``) or add (``insert``) items to
+ the list of blocks.
+
+ Keywords:
+
+ * ``parent``: A etree element which is the parent of the current block.
+ * ``blocks``: A list of all remaining blocks of the document.
+ """
+ pass
+
+
+class ListIndentProcessor(BlockProcessor):
+ """ Process children of list items.
+
+ Example:
+ * a list item
+ process this part
+
+ or this part
+
+ """
+
+ ITEM_TYPES = ['li']
+ LIST_TYPES = ['ul', 'ol']
+
+ def __init__(self, *args):
+ BlockProcessor.__init__(self, *args)
+ self.INDENT_RE = re.compile(r'^(([ ]{%s})+)'% self.tab_length)
+
+ def test(self, parent, block):
+ return block.startswith(' '*self.tab_length) and \
+ not self.parser.state.isstate('detabbed') and \
+ (parent.tag in self.ITEM_TYPES or \
+ (len(parent) and parent[-1] and \
+ (parent[-1].tag in self.LIST_TYPES)
+ )
+ )
+
+ def run(self, parent, blocks):
+ block = blocks.pop(0)
+ level, sibling = self.get_level(parent, block)
+ block = self.looseDetab(block, level)
+
+ self.parser.state.set('detabbed')
+ if parent.tag in self.ITEM_TYPES:
+ # It's possible that this parent has a 'ul' or 'ol' child list
+ # with a member. If that is the case, then that should be the
+ # parent. This is intended to catch the edge case of an indented
+ # list whose first member was parsed previous to this point
+ # see OListProcessor
+ if len(parent) and parent[-1].tag in self.LIST_TYPES:
+ self.parser.parseBlocks(parent[-1], [block])
+ else:
+ # The parent is already a li. Just parse the child block.
+ self.parser.parseBlocks(parent, [block])
+ elif sibling.tag in self.ITEM_TYPES:
+ # The sibling is a li. Use it as parent.
+ self.parser.parseBlocks(sibling, [block])
+ elif len(sibling) and sibling[-1].tag in self.ITEM_TYPES:
+ # The parent is a list (``ol`` or ``ul``) which has children.
+ # Assume the last child li is the parent of this block.
+ if sibling[-1].text:
+ # If the parent li has text, that text needs to be moved to a p
+ # The p must be 'inserted' at beginning of list in the event
+ # that other children already exist i.e.; a nested sublist.
+ p = util.etree.Element('p')
+ p.text = sibling[-1].text
+ sibling[-1].text = ''
+ sibling[-1].insert(0, p)
+ self.parser.parseChunk(sibling[-1], block)
+ else:
+ self.create_item(sibling, block)
+ self.parser.state.reset()
+
+ def create_item(self, parent, block):
+ """ Create a new li and parse the block with it as the parent. """
+ li = util.etree.SubElement(parent, 'li')
+ self.parser.parseBlocks(li, [block])
+
+ def get_level(self, parent, block):
+ """ Get level of indent based on list level. """
+ # Get indent level
+ m = self.INDENT_RE.match(block)
+ if m:
+ indent_level = len(m.group(1))/self.tab_length
+ else:
+ indent_level = 0
+ if self.parser.state.isstate('list'):
+ # We're in a tightlist - so we already are at correct parent.
+ level = 1
+ else:
+ # We're in a looselist - so we need to find parent.
+ level = 0
+ # Step through children of tree to find matching indent level.
+ while indent_level > level:
+ child = self.lastChild(parent)
+ if child and (child.tag in self.LIST_TYPES or child.tag in self.ITEM_TYPES):
+ if child.tag in self.LIST_TYPES:
+ level += 1
+ parent = child
+ else:
+ # No more child levels. If we're short of indent_level,
+ # we have a code block. So we stop here.
+ break
+ return level, parent
+
+
+class CodeBlockProcessor(BlockProcessor):
+ """ Process code blocks. """
+
+ def test(self, parent, block):
+ return block.startswith(' '*self.tab_length)
+
+ def run(self, parent, blocks):
+ sibling = self.lastChild(parent)
+ block = blocks.pop(0)
+ theRest = ''
+ if sibling and sibling.tag == "pre" and len(sibling) \
+ and sibling[0].tag == "code":
+ # The previous block was a code block. As blank lines do not start
+ # new code blocks, append this block to the previous, adding back
+ # linebreaks removed from the split into a list.
+ code = sibling[0]
+ block, theRest = self.detab(block)
+ code.text = util.AtomicString('%s\n%s\n' % (code.text, block.rstrip()))
+ else:
+ # This is a new codeblock. Create the elements and insert text.
+ pre = util.etree.SubElement(parent, 'pre')
+ code = util.etree.SubElement(pre, 'code')
+ block, theRest = self.detab(block)
+ code.text = util.AtomicString('%s\n' % block.rstrip())
+ if theRest:
+ # This block contained unindented line(s) after the first indented
+ # line. Insert these lines as the first block of the master blocks
+ # list for future processing.
+ blocks.insert(0, theRest)
+
+
+class BlockQuoteProcessor(BlockProcessor):
+
+ RE = re.compile(r'(^|\n)[ ]{0,3}>[ ]?(.*)')
+
+ def test(self, parent, block):
+ return bool(self.RE.search(block))
+
+ def run(self, parent, blocks):
+ block = blocks.pop(0)
+ m = self.RE.search(block)
+ if m:
+ before = block[:m.start()] # Lines before blockquote
+ # Pass lines before blockquote in recursively for parsing forst.
+ self.parser.parseBlocks(parent, [before])
+ # Remove ``> `` from begining of each line.
+ block = '\n'.join([self.clean(line) for line in
+ block[m.start():].split('\n')])
+ sibling = self.lastChild(parent)
+ if sibling and sibling.tag == "blockquote":
+ # Previous block was a blockquote so set that as this blocks parent
+ quote = sibling
+ else:
+ # This is a new blockquote. Create a new parent element.
+ quote = util.etree.SubElement(parent, 'blockquote')
+ # Recursively parse block with blockquote as parent.
+ # change parser state so blockquotes embedded in lists use p tags
+ self.parser.state.set('blockquote')
+ self.parser.parseChunk(quote, block)
+ self.parser.state.reset()
+
+ def clean(self, line):
+ """ Remove ``>`` from beginning of a line. """
+ m = self.RE.match(line)
+ if line.strip() == ">":
+ return ""
+ elif m:
+ return m.group(2)
+ else:
+ return line
+
+class OListProcessor(BlockProcessor):
+ """ Process ordered list blocks. """
+
+ TAG = 'ol'
+ # Detect an item (``1. item``). ``group(1)`` contains contents of item.
+ RE = re.compile(r'^[ ]{0,3}\d+\.[ ]+(.*)')
+ # Detect items on secondary lines. they can be of either list type.
+ CHILD_RE = re.compile(r'^[ ]{0,3}((\d+\.)|[*+-])[ ]+(.*)')
+ # Detect indented (nested) items of either type
+ INDENT_RE = re.compile(r'^[ ]{4,7}((\d+\.)|[*+-])[ ]+.*')
+ # The integer (python string) with which the lists starts (default=1)
+ # Eg: If list is intialized as)
+ # 3. Item
+ # The ol tag will get starts="3" attribute
+ STARTSWITH = '1'
+ # List of allowed sibling tags.
+ SIBLING_TAGS = ['ol', 'ul']
+
+ def test(self, parent, block):
+ return bool(self.RE.match(block))
+
+ def run(self, parent, blocks):
+ # Check fr multiple items in one block.
+ items = self.get_items(blocks.pop(0))
+ sibling = self.lastChild(parent)
+
+ if sibling and sibling.tag in self.SIBLING_TAGS:
+ # Previous block was a list item, so set that as parent
+ lst = sibling
+ # make sure previous item is in a p- if the item has text, then it
+ # it isn't in a p
+ if lst[-1].text:
+ # since it's possible there are other children for this sibling,