├── Snippets ├── Hard linebreak.plist ├── Insert default metadata.tmSnippet └── Insert letter metadata.tmSnippet ├── Preferences ├── Disable spell checking for raw.plist ├── Indent: Raw.plist ├── Autocomplete Image Filename.tmPreferences ├── Autocomplete Anchors.tmPreferences ├── Autocomplete XSLT Files.tmPreferences ├── Autocomplete BibTeX Citations.tmPreferences ├── Symbol List: Heading.plist ├── Typing Pairs: Disable _ for Raw.plist └── Miscellaneous.plist ├── Support ├── bin │ ├── InsertFormatHeader.rb │ └── html2text.py ├── help.markdown └── lib │ └── markdown.rb ├── DragCommands ├── Insert HTML file as Markdown.plist └── Image Tag.plist ├── Commands ├── Convert MMD to OPML.tmCommand ├── Convert Document:Selection to LaTeX.plist ├── Convert Document:Selection to HTML.plist ├── Syntax Cheat Sheet.tmCommand ├── Table - Cleanup.tmCommand ├── Convert OPML to MMD.tmCommand ├── Table - Help.tmCommand ├── Header - Help.tmCommand ├── List - Toggle Marker.tmCommand ├── Blockquote - Increase Quote Level.tmCommand ├── Header - Complete.tmCommand ├── Generate Output and open in Browser.plist ├── Convert Document : Selection to ODF.tmCommand ├── Blockquote - Decrease Quote Level.tmCommand ├── Table - Next Cell.tmCommand ├── Header - Increase Level.tmCommand ├── List - Indent Line.tmCommand ├── Blockquote - Help.tmCommand ├── List - Outdent Line.tmCommand ├── Header - Decrease Level.tmCommand ├── Reformat.tmCommand ├── List - Help.tmCommand ├── MMD Merge Document : Selection.tmCommand ├── MultiMarkdown Preview.tmCommand ├── Convert Document to PDF.tmCommand ├── Bold.tmCommand ├── Table - Previous Cell.tmCommand ├── Metadata - Help.tmCommand ├── Select Current Item.tmCommand ├── Add Numbered List Item.plist ├── Add New Sublist.tmCommand ├── Auto Complete Reference Links.tmCommand ├── Change Style.tmCommand ├── Italic.tmCommand ├── Convert Document to HTML.plist ├── Blockquote - New Line.tmCommand ├── Heading level 1 [setext] (=).plist ├── Heading level 2 [setext] (-).plist ├── Markdown preview.plist ├── Metadata - New Line.tmCommand ├── List - New Sibling.tmCommand ├── Metadata - Cleanup.tmCommand ├── Metadata - Advance to Value.tmCommand └── List - Clean-up.tmCommand ├── Tests ├── test-minimal.markdown └── test.markdown ├── Macros └── Cut Item.tmMacro ├── Syntaxes ├── MultiMarkdown.tmLanguage └── Markdown.plist ├── README.md └── info.plist /Snippets/Hard linebreak.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | 7 | 8 | keyEquivalent 9 | ^ 10 | name 11 | Hard Linebreak 12 | scope 13 | text.html.markdown -meta.disable-markdown 14 | uuid 15 | 4405912F-4AD5-40F8-93B3-A63394036ACA 16 | 17 | 18 | -------------------------------------------------------------------------------- /Preferences/Disable spell checking for raw.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Spell Checking: Disable 7 | scope 8 | text.html.markdown meta.reference, meta.link.markdown entity.name 9 | settings 10 | 11 | spellChecking 12 | 0 13 | 14 | uuid 15 | C2DBC2F2-D859-4B35-A38E-244927A8447F 16 | 17 | 18 | -------------------------------------------------------------------------------- /Preferences/Indent: Raw.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Indent: Raw Block 7 | scope 8 | markup.raw.block.markdown 9 | settings 10 | 11 | decreaseIndentPattern 12 | ^(.*\*/)?\s*\}[;\s]*$ 13 | increaseIndentPattern 14 | ^.*(\{[^}"']*|\([^)"']*)$ 15 | 16 | uuid 17 | E23C5DD2-9A36-4B4A-9729-2A769A055B92 18 | 19 | 20 | -------------------------------------------------------------------------------- /Preferences/Autocomplete Image Filename.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Autocomplete Image Filename 7 | scope 8 | meta.link.reference.def.markdown 9 | settings 10 | 11 | completionCommand 12 | cd "$TM_DIRECTORY"; ls *.png *.PNG *.jpg *.JPG *.gif *.GIF | sort|uniq 13 | disableDefaultCompletion 14 | 1 15 | 16 | uuid 17 | 7A27A176-318B-403F-9228-D40B55CC6E85 18 | 19 | 20 | -------------------------------------------------------------------------------- /Support/bin/InsertFormatHeader.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby -wKU 2 | # 3 | # This wrapper will insert a ‘Format: Complete’-header 4 | # if the document (as read from stdin) does not have a 5 | # format header already. 6 | # 7 | # This header is sort of necessary when we conver the 8 | # users document to RTF or similar where the document 9 | # encoding is specified in the header. 10 | 11 | doc = STDIN.read 12 | 13 | def parse_headers(doc) 14 | return {} unless doc =~ /\A(\w+:.+?)\n\n/m 15 | tmp = $1.scan(/^(\w+):\s+(.*)$/).collect { |pair| [pair[0].downcase, pair[1].strip] } 16 | Hash[*tmp.flatten] 17 | end 18 | 19 | headers = parse_headers(doc) 20 | unless headers.has_key?('format') 21 | puts "Format: complete" 22 | puts if headers.empty? 23 | end 24 | print doc 25 | -------------------------------------------------------------------------------- /Preferences/Autocomplete Anchors.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Autocomplete Anchors 7 | scope 8 | meta.link.reference, meta.image.reference 9 | settings 10 | 11 | completionCommand 12 | perl "${TM_MULTIMARKDOWN_PATH:-$HOME/Library/Application Support/MultiMarkdown}/Utilities/autocomplete.pl" |sort|uniq 13 | disableDefaultCompletion 14 | 1 15 | 16 | uuid 17 | 6D74AB8C-1903-4EB5-B0B6-AF16527F131C 18 | 19 | 20 | -------------------------------------------------------------------------------- /Preferences/Autocomplete XSLT Files.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Autocomplete XSLT Files 7 | scope 8 | meta.header.multimarkdown 9 | settings 10 | 11 | completionCommand 12 | cd "${TM_MULTIMARKDOWN_PATH:-$HOME/Library/Application Support/MultiMarkdown}/XSLT"; ls *.xslt | perl -pi -e "s/\.xslt$//i" |sort|uniq 13 | disableDefaultCompletion 14 | 1 15 | 16 | uuid 17 | 4A05D483-795D-4B71-8537-3417B8450AD8 18 | 19 | 20 | -------------------------------------------------------------------------------- /Preferences/Autocomplete BibTeX Citations.tmPreferences: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Autocomplete BibTeX Citations 7 | scope 8 | meta.citation.reference.multimarkdown, meta.citation.reference.literal.multimarkdown 9 | settings 10 | 11 | completionCommand 12 | cd "$TM_DIRECTORY";grep "^@" *.bib | sort | uniq | perl -pi -e "s/^.*{//" | perl -pi -e "s/,//" 13 | disableDefaultCompletion 14 | 1 15 | 16 | uuid 17 | 48600DF2-8E98-40C0-9FBD-D9B50EE73633 18 | 19 | 20 | -------------------------------------------------------------------------------- /DragCommands/Insert HTML file as Markdown.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | command 6 | python "$TM_BUNDLE_SUPPORT/bin/html2text.py" <"$TM_DROPPED_FILE"|perl -pe 's/\\/\\\\/g; s/`/\\`/g; s/\$/\\\$/g' 7 | draggedFileExtensions 8 | 9 | html 10 | htm 11 | 12 | name 13 | Insert HTML File as Markdown 14 | output 15 | insertAsSnippet 16 | scope 17 | text.html.markdown 18 | uuid 19 | DA157B9A-792F-11D9-A212-000D93B3A10E 20 | 21 | 22 | -------------------------------------------------------------------------------- /Commands/Convert MMD to OPML.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | multimarkdown -t opml 9 | 10 | fallbackInput 11 | document 12 | input 13 | selection 14 | keyEquivalent 15 | ^O 16 | name 17 | Convert Document / Selection to OPML 18 | output 19 | openAsNewDocument 20 | scope 21 | text.html.markdown.multimarkdown 22 | uuid 23 | FD6FBB48-68DF-4EFB-9A66-2C109E9FCA7E 24 | 25 | 26 | -------------------------------------------------------------------------------- /Preferences/Symbol List: Heading.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Symbol List: Heading 7 | scope 8 | text.html.markdown markup.heading.markdown 9 | settings 10 | 11 | showInSymbolList 12 | 1 13 | symbolTransformation 14 | 15 | s/\s*#*\s*\z//g; # strip trailing space and #'s 16 | s/(?<=#)#/ /g; # change all but first # to m-space 17 | s/^#( *)\s+(.*)/$1$2/; # strip first # and space before title 18 | 19 | 20 | uuid 21 | C02A37C1-E770-472F-A13E-358FF0C6AD89 22 | 23 | 24 | -------------------------------------------------------------------------------- /Commands/Convert Document:Selection to LaTeX.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | # Process the MultiMarkdown document into LaTeX 9 | 10 | multimarkdown -t latex 11 | fallbackInput 12 | document 13 | input 14 | selection 15 | keyEquivalent 16 | ^L 17 | name 18 | Convert Document / Selection to LaTeX 19 | output 20 | openAsNewDocument 21 | scope 22 | text.html.markdown.multimarkdown 23 | uuid 24 | 67EB96A4-4213-42C9-9C47-B886A4B8AC93 25 | 26 | 27 | -------------------------------------------------------------------------------- /Commands/Convert Document:Selection to HTML.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | # Process the MultiMarkdown document and display as HTML source 9 | 10 | multimarkdown 11 | fallbackInput 12 | document 13 | input 14 | selection 15 | keyEquivalent 16 | ^H 17 | name 18 | Convert Document / Selection to HTML 19 | output 20 | openAsNewDocument 21 | scope 22 | text.html.markdown.multimarkdown 23 | uuid 24 | 9F73CBC1-E9C0-41A4-891F-B2879A1852F7 25 | 26 | 27 | -------------------------------------------------------------------------------- /Commands/Syntax Cheat Sheet.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | bundleUUID 8 | D99E8C0C-792F-11D9-A212-000D93B3A10E 9 | command 10 | . "$TM_SUPPORT_PATH/lib/webpreview.sh" 11 | html_header "Markdown Cheat Sheet" 12 | Markdown.pl "$TM_BUNDLE_SUPPORT/help.markdown" 13 | html_footer 14 | input 15 | none 16 | keyEquivalent 17 | ^h 18 | name 19 | Syntax Cheat Sheet 20 | output 21 | showAsHTML 22 | scope 23 | text.html.markdown 24 | uuid 25 | FE31CF79-5F04-4FB6-B5CE-70BC781FF8B5 26 | 27 | 28 | -------------------------------------------------------------------------------- /Commands/Table - Cleanup.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | # Cleanup the spacing of MultiMarkdown tables in the selection 9 | 10 | "${TM_MULTIMARKDOWN_PATH:-$HOME/Library/Application Support/MultiMarkdown}/Utilities/table_cleanup.pl" 11 | 12 | 13 | fallbackInput 14 | scope 15 | input 16 | selection 17 | keyEquivalent 18 | ^k 19 | name 20 | Table - Cleanup 21 | output 22 | replaceSelectedText 23 | scope 24 | markup.table.multimarkdown 25 | uuid 26 | DB739633-6AF0-460A-BF34-86BAD8C22C4D 27 | 28 | 29 | -------------------------------------------------------------------------------- /Snippets/Insert default metadata.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | Title: ${1:Title} 7 | Subtitle: ${2:Subtitle} 8 | Author: $TM_FULLNAME 9 | Affiliation: ${4:$TM_ORGANIZATION_NAME} 10 | Date: ${5:`date "+%B %d, %Y"`} 11 | Copyright: ${6:`date +%Y` $TM_FULLNAME}. 12 | ${7:This work is licensed under a Creative Commons License. 13 | http://creativecommons.org/licenses/by-sa/2.5/} 14 | Keywords: $8 15 | 16 | $0 17 | keyEquivalent 18 | ~@m 19 | name 20 | Insert default metadata 21 | scope 22 | text.html.markdown 23 | tabTrigger 24 | meta 25 | uuid 26 | 8D04C38E-0187-4E53-B100-AE096CBBB984 27 | 28 | 29 | -------------------------------------------------------------------------------- /Commands/Convert OPML to MMD.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | # Requires MultiMarkdown-Support be installed 9 | 10 | cd "${TM_MULTIMARKDOWN_PATH:-$HOME/Library/Application Support/MultiMarkdown}" 11 | cd XSLT 12 | 13 | 14 | xsltproc -nonet -novalid opml2mmd.xslt - 15 | 16 | 17 | fallbackInput 18 | document 19 | input 20 | selection 21 | keyEquivalent 22 | ^O 23 | name 24 | Convert OPML to MMD 25 | output 26 | openAsNewDocument 27 | scope 28 | text.xml 29 | uuid 30 | 9BF17F3B-B5E1-4F8A-A422-1A5413D4AD75 31 | 32 | 33 | -------------------------------------------------------------------------------- /Commands/Table - Help.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | echo "CONTROL-RIGHT ARROW: Move one cell to the right. 9 | CONTROL-LEFT ARROW: Move one cell to the left. 10 | 11 | CONTROL-K: Clean up table layout. 12 | 13 | Naturally, you can reconfigure this in the Bundle Editor..." 14 | fallbackInput 15 | scope 16 | input 17 | none 18 | keyEquivalent 19 | ^h 20 | name 21 | Table - Help 22 | output 23 | showAsTooltip 24 | scope 25 | markup.table.multimarkdown 26 | uuid 27 | CA000031-1DD5-42D8-9E7E-678B006B1978 28 | 29 | 30 | -------------------------------------------------------------------------------- /Commands/Header - Help.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | echo "ENTER: append trailing \"#\"s and advance 2 lines 9 | 10 | CONTROL-RIGHT ARROW: Increase header level. 11 | CONTROL-LEFT ARROW: Decrease header level. 12 | 13 | Naturally, you can reconfigure this in the Bundle Editor..." 14 | fallbackInput 15 | scope 16 | input 17 | none 18 | keyEquivalent 19 | ^h 20 | name 21 | Header - Help 22 | output 23 | showAsTooltip 24 | scope 25 | markup.heading.markdown 26 | uuid 27 | 8557FE6C-388E-4E3A-A725-94B3A505CCD8 28 | 29 | 30 | -------------------------------------------------------------------------------- /Commands/List - Toggle Marker.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env perl 9 | 10 | $line = $ENV{'TM_CURRENT_LINE'}; 11 | 12 | if ($line =~ s/^(\s*)(\d+\.)/$1\*/) { 13 | } else{ 14 | $line =~ s/^(\s*)(\*|\+|\-)/${1}1./; 15 | } 16 | 17 | print $line; 18 | fallbackInput 19 | line 20 | input 21 | selection 22 | keyEquivalent 23 | ^t 24 | name 25 | List - Toggle Marker 26 | output 27 | replaceSelectedText 28 | scope 29 | text.html.markdown markup.list 30 | uuid 31 | BAE8ED70-CF67-4D4A-99D8-02544053131C 32 | 33 | 34 | -------------------------------------------------------------------------------- /Snippets/Insert letter metadata.tmSnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | content 6 | Title: ${1:Title} 7 | Author: ${2:$TM_FULLNAME} 8 | Date: ${3:`date "+%B %d, %Y"`} 9 | Recipient: ${4:Some Recipient} 10 | Recipient Address: ${10:Recipient Address} 11 | LaTeX XSLT: ${11:fp-letterhead} 12 | LaTeX XSLT off: ${12:fp-envelope} 13 | Graphic Signature: ${13:true} 14 | 15 | ${5:Dear }${6:${4/\s.*$//}}${7:${4/.*?(\s|\Z)/$1/}}, 16 | 17 | $0 18 | 19 | 20 | keyEquivalent 21 | ~@m 22 | name 23 | Insert letter metadata 24 | scope 25 | text.html.markdown 26 | tabTrigger 27 | letter 28 | uuid 29 | C96D5804-7FA5-4CFE-8ADC-6F2F53B0FF01 30 | 31 | 32 | -------------------------------------------------------------------------------- /Commands/Blockquote - Increase Quote Level.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env perl 9 | 10 | $line = $ENV{'TM_CURRENT_LINE'}; 11 | 12 | 13 | $index = $ENV{'TM_LINE_INDEX'}; 14 | $line =~ s/^(.{$index})/$1\$0/; 15 | $line =~ s/`/\\\`/g; 16 | 17 | print "> " . $line; 18 | fallbackInput 19 | line 20 | input 21 | selection 22 | keyEquivalent 23 | ^ 24 | name 25 | Blockquote - Increase Quote Level 26 | output 27 | insertAsSnippet 28 | scope 29 | markup.quote.markdown 30 | uuid 31 | 115BAB2F-3F19-429E-B337-B6A3BF5A061E 32 | 33 | 34 | -------------------------------------------------------------------------------- /Commands/Header - Complete.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env perl 9 | 10 | $line = $ENV{'TM_CURRENT_LINE'}; 11 | 12 | $line =~ s/^(#+)\s*(.*?)\s*(#+)?$/$1 $2 $1/; 13 | 14 | $index = $ENV{'TM_LINE_INDEX'}+1; 15 | $line.= "\n\n\$0"; 16 | $line =~ s/`/\\\`/g; 17 | 18 | print $line; 19 | fallbackInput 20 | line 21 | input 22 | selection 23 | keyEquivalent 24 | 25 | name 26 | Header - Complete 27 | output 28 | insertAsSnippet 29 | scope 30 | markup.heading.markdown 31 | uuid 32 | 69DBCB2D-ECFA-4515-A479-F96AE19FE25A 33 | 34 | 35 | -------------------------------------------------------------------------------- /Commands/Generate Output and open in Browser.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | # Process the MultiMarkdown document and open in browser 9 | 10 | TEMPFILE=`/usr/bin/mktemp -t TextMate.html | sed 's/\.[^.]*$//'` || exit 1 11 | 12 | 13 | multimarkdown > $TEMPFILE 14 | open $TEMPFILE 15 | fallbackInput 16 | document 17 | input 18 | selection 19 | keyEquivalent 20 | ^@p 21 | name 22 | Generate Output and Open in Browser 23 | output 24 | discard 25 | scope 26 | text.html.markdown.multimarkdown 27 | uuid 28 | 351451DE-C1A4-4A36-A563-99AF761D026B 29 | 30 | 31 | -------------------------------------------------------------------------------- /Commands/Convert Document : Selection to ODF.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | # Process the MultiMarkdown document into ODF 9 | 10 | 11 | TEMPFILE=`/usr/bin/mktemp -t TextMate.fodt | sed 's/\.[^.]*$//'` || exit 1 12 | 13 | multimarkdown -t odf > $TEMPFILE 14 | open $TEMPFILE 15 | 16 | fallbackInput 17 | document 18 | input 19 | selection 20 | keyEquivalent 21 | ^O 22 | name 23 | Convert Document / Selection to ODF 24 | output 25 | showAsTooltip 26 | scope 27 | text.html.markdown.multimarkdown 28 | uuid 29 | C92636B7-8795-4CE4-8F0B-0F2EB200CAA1 30 | 31 | 32 | -------------------------------------------------------------------------------- /Commands/Blockquote - Decrease Quote Level.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env perl 9 | 10 | $line = $ENV{'TM_CURRENT_LINE'}; 11 | 12 | 13 | $index = $ENV{'TM_LINE_INDEX'}; 14 | $line =~ s/^(.{$index})/$1\$0/; 15 | $line =~ s/`/\\\`/g; 16 | 17 | $line =~ s/^\>\s*//; 18 | 19 | print $line; 20 | fallbackInput 21 | line 22 | input 23 | selection 24 | keyEquivalent 25 | ^ 26 | name 27 | Blockquote - Decrease Quote Level 28 | output 29 | insertAsSnippet 30 | scope 31 | markup.quote.markdown 32 | uuid 33 | 2E3B6708-ECB7-45DE-BCEF-714038D7CC8B 34 | 35 | 36 | -------------------------------------------------------------------------------- /Commands/Table - Next Cell.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env perl 9 | 10 | # Tab forward to next cell in table, or end of line 11 | 12 | $line = <>; 13 | $index = $ENV{'TM_LINE_INDEX'}; 14 | 15 | $line =~ s/^(.{$index}.*?\|.*?)(\s*\|.*)$/$1\$0$2/; 16 | $line =~ s/`/\\\`/g; 17 | 18 | print $line; 19 | fallbackInput 20 | line 21 | input 22 | selection 23 | keyEquivalent 24 | ^ 25 | name 26 | Table - Next Cell 27 | output 28 | insertAsSnippet 29 | scope 30 | markup.table.multimarkdown 31 | uuid 32 | 34FCB7E2-516C-4ADA-9CFC-BD3D5BA6D9C7 33 | 34 | 35 | -------------------------------------------------------------------------------- /Commands/Header - Increase Level.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env perl 9 | 10 | $line = $ENV{'TM_CURRENT_LINE'}; 11 | 12 | $line =~ s/^(#{1,5})#*\s*(.*?)\s*(#+)?$/\#$1 $2 $1\#/; 13 | 14 | $index = $ENV{'TM_LINE_INDEX'}+1; 15 | $line =~ s/^(.{$index})/$1\$0/; 16 | $line =~ s/`/\\\`/g; 17 | 18 | print $line; 19 | fallbackInput 20 | line 21 | input 22 | selection 23 | keyEquivalent 24 | ^ 25 | name 26 | Header - Increase Level 27 | output 28 | insertAsSnippet 29 | scope 30 | markup.heading.markdown 31 | uuid 32 | 317FF73B-9CCC-486D-827F-839F4C7EE855 33 | 34 | 35 | -------------------------------------------------------------------------------- /Commands/List - Indent Line.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env perl 9 | 10 | $line = $ENV{'TM_CURRENT_LINE'}; 11 | 12 | $line =~ s{ 13 | ^\s*(\d)+ 14 | }{ 15 | '1'; 16 | }ex; 17 | 18 | $index = $ENV{'TM_LINE_INDEX'}; 19 | $line =~ s/^(.{$index})/$1\$0/; 20 | $line =~ s/`/\\\`/g; 21 | 22 | print "\t" . $line; 23 | fallbackInput 24 | line 25 | input 26 | selection 27 | keyEquivalent 28 | ^ 29 | name 30 | List - Indent Line 31 | output 32 | insertAsSnippet 33 | scope 34 | text.html.markdown markup.list 35 | uuid 36 | EAAF445C-947E-496B-A8B9-4FF45EEF8C5E 37 | 38 | 39 | -------------------------------------------------------------------------------- /Commands/Blockquote - Help.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | echo "ENTER: Create a new blockquote line. 9 | Enter again to end current blockquote level. 10 | 11 | CONTROL-RIGHT ARROW: Add additional level of quoting. 12 | CONTROL-LEFT ARROW: Remove a level of quoting. 13 | 14 | Naturally, you can reconfigure this in the Bundle Editor..." 15 | fallbackInput 16 | line 17 | input 18 | none 19 | keyEquivalent 20 | ^h 21 | name 22 | Blockquote - Help 23 | output 24 | showAsTooltip 25 | scope 26 | markup.quote.markdown 27 | uuid 28 | C51C8DF5-1C1A-4409-AC9B-4778280D0B1F 29 | 30 | 31 | -------------------------------------------------------------------------------- /Commands/List - Outdent Line.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env perl 9 | 10 | $line = $ENV{'TM_CURRENT_LINE'}; 11 | 12 | $index = $ENV{'TM_LINE_INDEX'}; 13 | 14 | if ($line =~ s/^(\t| )//) { 15 | $index--; 16 | } 17 | 18 | $line =~ s/^(.{$index})/$1\$0/; 19 | 20 | $line =~ s/`/\\\`/g; 21 | 22 | print $line; 23 | fallbackInput 24 | line 25 | input 26 | selection 27 | keyEquivalent 28 | ^ 29 | name 30 | List - Outdent Line 31 | output 32 | insertAsSnippet 33 | scope 34 | text.html.markdown markup.list 35 | uuid 36 | 1E8299F1-916B-445B-BC6F-1D3657901BB5 37 | 38 | 39 | -------------------------------------------------------------------------------- /Commands/Header - Decrease Level.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env perl 9 | 10 | $line = $ENV{'TM_CURRENT_LINE'}; 11 | 12 | $index = $ENV{'TM_LINE_INDEX'}; 13 | 14 | if ($line =~ s/^#(#+)\s*(.*?)\s*(#+)?$/$1 $2 $1/) { 15 | $index--; 16 | } 17 | 18 | $line =~ s/^(.{$index})/$1\$0/; 19 | $line =~ s/`/\\\`/g; 20 | 21 | print $line; 22 | fallbackInput 23 | line 24 | input 25 | selection 26 | keyEquivalent 27 | ^ 28 | name 29 | Header - Decrease Level 30 | output 31 | insertAsSnippet 32 | scope 33 | markup.heading.markdown 34 | uuid 35 | 45736A34-CE6F-4F03-93F5-EB6F348A4AF8 36 | 37 | 38 | -------------------------------------------------------------------------------- /Commands/Reformat.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby 9 | 10 | $: << ENV['TM_BUNDLE_SUPPORT'] 11 | $: << ENV['TM_SUPPORT_PATH'] 12 | 13 | require 'lib/markdown' 14 | require 'lib/escape' 15 | 16 | # get the list itself 17 | listtxt = $stdin.read() 18 | list = Markdown::List.parse(listtxt) 19 | 20 | print list.to_s() 21 | 22 | fallbackInput 23 | scope 24 | input 25 | selection 26 | keyEquivalent 27 | ^{ 28 | name 29 | Reformat 30 | output 31 | replaceSelectedText 32 | scope 33 | text.html.markdown markup.list 34 | uuid 35 | 5EFA9FF4-2246-4AF4-ABD6-2B7ADB4E9B80 36 | 37 | 38 | -------------------------------------------------------------------------------- /Commands/List - Help.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | echo "ENTER: Create a new list item. 9 | Enter again to end current list level. 10 | 11 | CONTROL-RIGHT ARROW: Indent current item one level. 12 | CONTROL-LEFT ARROW: Outdent current item one level. 13 | 14 | CONTROL-T: Toggle list item type. 15 | CONTROL-K: Clean up list layout. 16 | 17 | Naturally, you can reconfigure this in the Bundle Editor..." 18 | fallbackInput 19 | scope 20 | input 21 | none 22 | keyEquivalent 23 | ^h 24 | name 25 | List - Help 26 | output 27 | showAsTooltip 28 | scope 29 | text.html.markdown markup.list 30 | uuid 31 | 8A9993E1-CA38-49B1-92D8-ADCA4CF9C4DD 32 | 33 | 34 | -------------------------------------------------------------------------------- /Commands/MMD Merge Document : Selection.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | # Use the mmd_merge.pl script to compile multiple documents into one MMD source 9 | 10 | # The document must be saved first, in order for the script to find the referenced documents 11 | 12 | # Requires that MultiMarkdown-Support be installed 13 | 14 | cd "${TM_FILEPATH%/*}" 15 | 16 | "${TM_MULTIMARKDOWN_PATH:-$HOME/Library/Application Support/MultiMarkdown}/Utilities/mmd_merge.pl" 17 | 18 | input 19 | selection 20 | keyEquivalent 21 | ^M 22 | name 23 | MMD Merge Document / Selection 24 | output 25 | openAsNewDocument 26 | scope 27 | text.html.markdown.multimarkdown 28 | uuid 29 | CAC8BE7C-78DD-489B-97F8-2EF8D896F91C 30 | 31 | 32 | -------------------------------------------------------------------------------- /Preferences/Typing Pairs: Disable _ for Raw.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Typing Pairs: Disable _ for Raw and Links 7 | scope 8 | text.html.markdown markup.raw, text.html.markdown meta.link 9 | settings 10 | 11 | smartTypingPairs 12 | 13 | 14 | " 15 | " 16 | 17 | 18 | ( 19 | ) 20 | 21 | 22 | { 23 | } 24 | 25 | 26 | [ 27 | ] 28 | 29 | 30 | 31 | 32 | 33 | 34 | ` 35 | ` 36 | 37 | 38 | 39 | uuid 40 | 146B2643-D903-49A8-9586-BE9C509D65B1 41 | 42 | 43 | -------------------------------------------------------------------------------- /Commands/MultiMarkdown Preview.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | bundleUUID 8 | D99E8C0C-792F-11D9-A212-000D93B3A10E 9 | command 10 | # Process the MultiMarkdown document and display as a web page 11 | 12 | 13 | # This really should go after xml declaration, but 14 | # TM seems ok with it 15 | 16 | if [[ -f "$TM_FILEPATH" ]]; then 17 | echo "<base href='tm-file://${TM_FILEPATH// /%20}'>" 18 | fi 19 | 20 | 21 | multimarkdown 22 | fallbackInput 23 | document 24 | input 25 | selection 26 | keyEquivalent 27 | ^~@p 28 | name 29 | Preview 30 | output 31 | showAsHTML 32 | scope 33 | text.html.markdown.multimarkdown 34 | uuid 35 | 7CCF064C-BC8F-437B-A339-0E2156D8B2C3 36 | 37 | 38 | -------------------------------------------------------------------------------- /Commands/Convert Document to PDF.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | # Process the MultiMarkdown document into LaTeX, and then 9 | # Process the LaTeX into a PDF 10 | 11 | # Requires that the document be saved first 12 | 13 | # This may or may not work for your file, and is not "officially" 14 | # supported. 15 | 16 | # Use at your own risk 17 | 18 | 19 | cd "${TM_FILEPATH%/*}" 20 | 21 | mmd2pdf "${TM_FILEPATH}" 22 | 23 | open "${TM_FILEPATH%.*}.pdf" 24 | fallbackInput 25 | document 26 | input 27 | document 28 | keyEquivalent 29 | ^~@p 30 | name 31 | Convert Document to PDF 32 | output 33 | discard 34 | scope 35 | text.html.markdown.multimarkdown 36 | uuid 37 | 4F20AFC6-53B0-4789-8007-8FC84F2B1874 38 | 39 | 40 | -------------------------------------------------------------------------------- /Commands/Bold.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby 9 | $: << ENV['TM_SUPPORT_PATH'] + '/lib' 10 | require 'escape' 11 | def esc(str) 12 | e_sn(str).gsub(/\}/, '\\}') # escaping inside a placeholder 13 | end 14 | 15 | s = STDIN.read 16 | if s.empty? then 17 | print "**$1**" 18 | elsif s =~ /^\*{2}(.*)\*{2}$/ then 19 | print "${1:#{esc $1}}" 20 | elsif ENV.has_key? 'TM_SELECTED_TEXT' 21 | print "${1:**#{esc s}**}" 22 | else 23 | print "**#{e_sn s}**" 24 | end 25 | fallbackInput 26 | word 27 | input 28 | selection 29 | keyEquivalent 30 | @b 31 | name 32 | Bold 33 | output 34 | insertAsSnippet 35 | scope 36 | text.html.markdown -meta.disable-markdown 37 | uuid 38 | 31614C02-1FED-4644-9518-2C2DEF0D7A2C 39 | 40 | 41 | -------------------------------------------------------------------------------- /DragCommands/Image Tag.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | command 6 | base=${TM_DROPPED_FILE##*/} 7 | alt=$(tr <<<${base%.*} '[_-]' ' '|perl -pe 's/(\w+)/\u$1/g') 8 | if [ -n "$TM_DROPPED_FILE_STRIP_ROOT" ] 9 | then 10 | file=$(sed -e "s|^$TM_DROPPED_FILE_STRIP_ROOT||" <<< $TM_DROPPED_FILE); 11 | else 12 | file=${TM_DROPPED_FILE}; 13 | fi 14 | echo -n "![\${1:$alt}]($file)" 15 | draggedFileExtensions 16 | 17 | png 18 | PNG 19 | jpeg 20 | JPEG 21 | jpg 22 | JPG 23 | gif 24 | GIF 25 | pdf 26 | PDF 27 | 28 | name 29 | Insert Image Tag 30 | output 31 | insertAsSnippet 32 | scope 33 | text.html.markdown -meta.disable-markdown 34 | uuid 35 | DA18D8BE-792F-11D9-A212-000D93B3A10E 36 | 37 | 38 | -------------------------------------------------------------------------------- /Commands/Table - Previous Cell.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env perl 9 | 10 | # Tab forward to next cell in table, or end of line 11 | 12 | $line = <>; 13 | $index = $ENV{'TM_LINE_INDEX'}; 14 | $original = $line; 15 | 16 | $line =~ s/^(.{$index})//; 17 | $line =~ s/`/\\\`/g; 18 | $beginning = $1; 19 | 20 | if ($beginning =~ s/(.*[^\s])(\s*\|.*?)$/$1\$0$2/) { 21 | $beginning .= $line; 22 | print $beginning; 23 | } else { 24 | $original =~ s/^(.*?)(\s*\|.*)$/$1\$0$2/; 25 | print $original; 26 | } 27 | fallbackInput 28 | line 29 | input 30 | selection 31 | keyEquivalent 32 | ^ 33 | name 34 | Table - Previous Cell 35 | output 36 | insertAsSnippet 37 | scope 38 | markup.table.multimarkdown 39 | uuid 40 | 3F7582D4-F2C3-44B8-944E-CDA2F069A818 41 | 42 | 43 | -------------------------------------------------------------------------------- /Preferences/Miscellaneous.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Typing Pairs: Defaults 7 | scope 8 | text.html.markdown 9 | settings 10 | 11 | smartTypingPairs 12 | 13 | 14 | " 15 | " 16 | 17 | 18 | ( 19 | ) 20 | 21 | 22 | { 23 | } 24 | 25 | 26 | [ 27 | ] 28 | 29 | 30 | 31 | 32 | 33 | 34 | ` 35 | ` 36 | 37 | 38 | _ 39 | _ 40 | 41 | 42 | < 43 | > 44 | 45 | 46 | 47 | uuid 48 | 15E0B3D5-8523-40EF-B767-5AF153FFD11E 49 | 50 | 51 | -------------------------------------------------------------------------------- /Commands/Metadata - Help.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | echo "ENTER: Create a new indented row to continue current metadata item. 9 | Enter again to move to left margin for new metadata item. 10 | Enter again to leave metadata section and begin document. 11 | 12 | TAB: Hit tab after typing a metadata key, and you will be advanced the 13 | appropriate number of tabs to align the value. In addition, other 14 | lines will be cleaned up. 15 | 16 | CONTROL-K: Clean up spacing and align metadata values. 17 | 18 | Naturally, you can reconfigure this in the Bundle Editor..." 19 | fallbackInput 20 | line 21 | input 22 | none 23 | keyEquivalent 24 | ^h 25 | name 26 | Metadata - Help 27 | output 28 | showAsTooltip 29 | scope 30 | meta.header.multimarkdown 31 | uuid 32 | 6AE91BD7-4E3B-49CD-B175-E52E76512176 33 | 34 | 35 | -------------------------------------------------------------------------------- /Commands/Select Current Item.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby 9 | 10 | $: << ENV['TM_BUNDLE_SUPPORT'] 11 | $: << ENV['TM_SUPPORT_PATH'] 12 | 13 | require 'lib/markdown' 14 | require 'lib/escape' 15 | 16 | # get the list itself 17 | listtxt = $stdin.read() 18 | list = Markdown::List.parse(listtxt) 19 | 20 | # now we need to figure out where we were when we hit enter 21 | offsetline = ENV['TM_LINE_NUMBER'].to_i() - ENV['TM_INPUT_START_LINE'].to_i() 22 | index = ENV['TM_LINE_INDEX'].to_i() 23 | 24 | list.select(offsetline) { |l| e_sn(l) } 25 | print list.to_s() 26 | 27 | fallbackInput 28 | scope 29 | input 30 | selection 31 | keyEquivalent 32 | @ 33 | name 34 | Select Item 35 | output 36 | insertAsSnippet 37 | scope 38 | text.html.markdown markup.list 39 | uuid 40 | ADEF8E57-BF21-487A-9115-E1D1146142CD 41 | 42 | 43 | -------------------------------------------------------------------------------- /Commands/Add Numbered List Item.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby 9 | 10 | $: << ENV['TM_BUNDLE_SUPPORT'] 11 | $: << ENV['TM_SUPPORT_PATH'] 12 | 13 | require 'lib/markdown' 14 | require 'lib/escape' 15 | 16 | # get the list itself 17 | listtxt = $stdin.read() 18 | list = Markdown::List.parse(listtxt) 19 | 20 | # now we need to figure out where we were when we hit enter 21 | offsetline = ENV['TM_LINE_NUMBER'].to_i() - ENV['TM_INPUT_START_LINE'].to_i() 22 | index = ENV['TM_LINE_INDEX'].to_i() 23 | 24 | list.break(offsetline, index) { |l| e_sn(l) } 25 | print list.to_s() 26 | 27 | fallbackInput 28 | scope 29 | input 30 | selection 31 | keyEquivalent 32 |  33 | name 34 | New Item 35 | output 36 | insertAsSnippet 37 | scope 38 | text.html.markdown markup.list 39 | uuid 40 | 622F0B69-EB98-4EB9-8DC8-2AC56FF2501E 41 | 42 | 43 | -------------------------------------------------------------------------------- /Commands/Add New Sublist.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby 9 | 10 | $: << ENV['TM_BUNDLE_SUPPORT'] 11 | $: << ENV['TM_SUPPORT_PATH'] 12 | 13 | require 'lib/markdown' 14 | require 'lib/escape' 15 | 16 | # get the list itself 17 | listtxt = $stdin.read() 18 | list = Markdown::List.parse(listtxt) 19 | 20 | # now we need to figure out where we were when we hit enter 21 | offsetline = ENV['TM_LINE_NUMBER'].to_i() - ENV['TM_INPUT_START_LINE'].to_i() 22 | index = ENV['TM_LINE_INDEX'].to_i() 23 | 24 | list.break(offsetline, index, "$0", true) { |l| e_sn(l) } 25 | print list.to_s() 26 | 27 | fallbackInput 28 | scope 29 | input 30 | selection 31 | keyEquivalent 32 | $ 33 | name 34 | New Subitem 35 | output 36 | insertAsSnippet 37 | scope 38 | text.html.markdown markup.list 39 | uuid 40 | 000B399B-FB71-49EF-B799-A1200A3865AB 41 | 42 | 43 | -------------------------------------------------------------------------------- /Commands/Auto Complete Reference Links.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby -wKU 9 | 10 | require ENV['TM_SUPPORT_PATH'] + '/lib/ui' 11 | require ENV['TM_SUPPORT_PATH'] + '/lib/exit_codes' 12 | 13 | word = ENV['TM_CURRENT_WORD'] 14 | word = '' if word =~ /[\[\]]/ 15 | links = [] 16 | link_regex = /^ {0,3}\[(.+)\]:/ 17 | 18 | STDIN.read.each { |ln| links << $1 if ln =~ link_regex } 19 | 20 | TextMate.exit_show_tool_tip( "No links found." ) if links.empty? 21 | 22 | TextMate::UI.complete(links, :initial_filter => word, :extra_chars => '_-') 23 | 24 | 25 | fallbackInput 26 | word 27 | input 28 | document 29 | keyEquivalent 30 | ~ 31 | name 32 | Auto Complete Reference Link 33 | output 34 | discard 35 | scope 36 | meta.link.reference.literal.markdown, meta.link.reference.markdown 37 | uuid 38 | C70F0881-D108-47B1-A06F-09C74954E5C2 39 | 40 | 41 | -------------------------------------------------------------------------------- /Commands/Change Style.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby 9 | 10 | $: << ENV['TM_BUNDLE_SUPPORT'] 11 | $: << ENV['TM_SUPPORT_PATH'] 12 | 13 | require 'lib/markdown' 14 | require 'lib/escape' 15 | 16 | # get the list itself 17 | listtxt = $stdin.read() 18 | list = Markdown::List.parse(listtxt) 19 | 20 | # now we need to figure out where we were when we hit enter 21 | offsetline = ENV['TM_LINE_NUMBER'].to_i() - ENV['TM_INPUT_START_LINE'].to_i() 22 | index = ENV['TM_LINE_INDEX'].to_i() 23 | 24 | list.get_entry(offsetline) do |e, l, n| 25 | l.numbered = !l.numbered 26 | end 27 | print list.to_s() 28 | 29 | fallbackInput 30 | scope 31 | input 32 | selection 33 | keyEquivalent 34 | ^* 35 | name 36 | Change Style 37 | output 38 | replaceSelectedText 39 | scope 40 | text.html.markdown markup.list 41 | uuid 42 | 39A74FF2-46EF-4178-9E3A-7D4DB3968E05 43 | 44 | 45 | -------------------------------------------------------------------------------- /Commands/Italic.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env ruby 9 | $: << ENV['TM_SUPPORT_PATH'] + '/lib' 10 | require 'escape' 11 | def esc(str) 12 | e_sn(str).gsub(/\}/, '\\}') # escaping inside a placeholder 13 | end 14 | 15 | s = STDIN.read 16 | if s.empty? then 17 | print "*$1*" 18 | elsif s =~ /^(\*+)(.*[^\*])\*+$/ then 19 | m, s = $1, $2 20 | case m.length 21 | when 1 then print "${1:#{esc s}}" 22 | when 2 then print "${1:***#{esc s}***}" 23 | else print "${1:**#{esc s}**}" 24 | end 25 | elsif ENV.has_key? 'TM_SELECTED_TEXT' 26 | print "${1:*#{esc s}*}" 27 | else 28 | print "*#{e_sn s}*" 29 | end 30 | fallbackInput 31 | word 32 | input 33 | selection 34 | keyEquivalent 35 | @i 36 | name 37 | Italic 38 | output 39 | insertAsSnippet 40 | scope 41 | text.html.markdown -meta.disable-markdown 42 | uuid 43 | F56525A1-C879-4A7C-9584-4DB28AFC58C2 44 | 45 | 46 | -------------------------------------------------------------------------------- /Commands/Convert Document to HTML.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/bin/bash 9 | # This command works well when you use the TextMate service from a 10 | # web-log editor like Ecto or MarsEdit. You can write in markdown 11 | # and then convert back to html before save and close. 12 | 13 | "${TM_MARKDOWN:-Markdown.pl}"|"${TM_SMARTYPANTS:-SmartyPants.pl}"|perl -pe ' 14 | # make <h1>Header</h1> into <h1 id="header">Header</h1> 15 | # so that we can link to page#header 16 | if(($tag, $title) = /<(h[1-6])>(.*?)<\/\1>/) { 17 | $_ = $title; 18 | s/<[^>]+>|&\w+;//g; # remove tag and entities 19 | s/[^-_ \/\w]//g; # remove all but word and separators 20 | s/[-_ \/]+/_/g; # collapse all separators into _ 21 | $_ = "<$tag id=\"" . (lc $_) . "\">$title</$tag>\n"; 22 | }' 23 | 24 | fallbackInput 25 | document 26 | input 27 | selection 28 | keyEquivalent 29 | ^H 30 | name 31 | Convert Document / Selection to HTML 32 | output 33 | replaceSelectedText 34 | scope 35 | text.html.markdown 36 | uuid 37 | 966B0E57-799A-4B91-84B4-75695A78F7B8 38 | 39 | 40 | -------------------------------------------------------------------------------- /Commands/Blockquote - New Line.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env perl 9 | 10 | $line = $ENV{'TM_CURRENT_LINE'}; 11 | $old_line = $line; 12 | $original = $old_line; 13 | 14 | # Strip Marker 15 | $old_line =~ s/^(\>*\s*)*//; 16 | 17 | if ($old_line !~ /^\s*$/) { 18 | # The item was not empty 19 | 20 | if ($line =~ s/^((\>*\s*)*).*/$1/) { 21 | # Line was a blockquote 22 | } else { 23 | # Not quote 24 | $line = ""; 25 | } 26 | 27 | $index = $ENV{'TM_LINE_INDEX'}; 28 | $original =~ s/^(.{$index})/$1\n$line\$0/; 29 | 30 | $original =~ s/`/\\\`/g; 31 | print $original; 32 | } else { 33 | # The item was empty, so end the current quote level 34 | 35 | if ($line =~ s/^((\>*\s*)*).*/$1/) { 36 | # Line was a blockquote 37 | $line =~ s/(\>\s*)$//; 38 | } else { 39 | # Not quote 40 | $line = ""; 41 | } 42 | print $line . "\n" . $line; 43 | } 44 | fallbackInput 45 | line 46 | input 47 | selection 48 | keyEquivalent 49 | 50 | name 51 | Blockquote - New Line 52 | output 53 | insertAsSnippet 54 | scope 55 | markup.quote.markdown 56 | uuid 57 | BC6D1959-6343-4620-8EEA-1463C3D240C8 58 | 59 | 60 | -------------------------------------------------------------------------------- /Commands/Heading level 1 [setext] (=).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | captureFormatString 8 | $3 9 | capturePattern 10 | ^([^:]*):([^:]*):(.*)$ 11 | command 12 | #!/usr/bin/env ruby -wKU 13 | 14 | require 'jcode' 15 | require ENV['TM_SUPPORT_PATH'] + '/lib/textmate' 16 | 17 | begin 18 | # Split document into lines. Get current line number minus one for 19 | # previous, minus another for ruby being 0 based. 20 | lines = STDIN.readlines 21 | line = ENV['TM_LINE_NUMBER'].to_i - 2 22 | 23 | # Get length of previous line, using jlength for unicode 24 | length = lines[line].rstrip.jlength 25 | 26 | # Print same number of = 27 | length.times { print "=" } 28 | rescue 29 | TextMate.exit_show_tool_tip("Use this command on the line following a string to turn it into setext-style heading.") 30 | end 31 | fileCaptureRegister 32 | 1 33 | input 34 | document 35 | lineCaptureRegister 36 | 2 37 | name 38 | Level 1 [setext] 39 | output 40 | afterSelectedText 41 | scope 42 | text.html.markdown 43 | tabTrigger 44 | = 45 | uuid 46 | F3A754C3-CE6B-11D9-9C17-000A95C0F626 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Heading level 2 [setext] (-).plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | captureFormatString 8 | $3 9 | capturePattern 10 | ^([^:]*):([^:]*):(.*)$ 11 | command 12 | #!/usr/bin/env ruby -wKU 13 | 14 | require 'jcode' 15 | require ENV['TM_SUPPORT_PATH'] + '/lib/textmate' 16 | 17 | begin 18 | # Split document into lines. Get current line number minus one for 19 | # previous, minus another for ruby being 0 based. 20 | lines = STDIN.readlines 21 | line = ENV['TM_LINE_NUMBER'].to_i - 2 22 | 23 | # Get length of previous line, using jlength for unicode 24 | length = lines[line].rstrip.jlength 25 | 26 | # Print same number of - 27 | length.times { print "-" } 28 | rescue 29 | TextMate.exit_show_tool_tip("Use this command on the line following a string to turn it into setext-style heading.") 30 | end 31 | fileCaptureRegister 32 | 1 33 | input 34 | document 35 | lineCaptureRegister 36 | 2 37 | name 38 | Level 2 [setext] 39 | output 40 | afterSelectedText 41 | scope 42 | text.html.markdown 43 | tabTrigger 44 | - 45 | uuid 46 | 724FCFF6-CE6B-11D9-9C17-000A95C0F626 47 | 48 | 49 | -------------------------------------------------------------------------------- /Commands/Markdown preview.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | . "$TM_SUPPORT_PATH/lib/webpreview.sh" 9 | html_header "Markdown Preview" "${TM_FILENAME:-}" 10 | 11 | if [[ -f "$TM_FILEPATH" ]]; then 12 | echo "<base href='tm-file://${TM_FILEPATH// /%20}'>" 13 | fi 14 | 15 | # Convert to html then make one of the html tags above caret 16 | # into a link that we scroll down to 17 | "${TM_MARKDOWN:-Markdown.pl}"|"${TM_SMARTYPANTS:-SmartyPants.pl}"|ruby -e ' 18 | lines = STDIN.read.split("\n") 19 | n = [ENV["TM_LINE_NUMBER"].to_i, lines.length].min - 7 20 | 21 | while n > 0 && !lines[n].match(/<(h\d|p|ul|li|blockquote|pre|div|img|code|table|tr)>/i) 22 | n -= 1 23 | end 24 | 25 | if n > 0 && m = lines[n].match(/<(h\d|p|ul|li|blockquote|pre|div|img|code|table|tr)>(.*)$/i) 26 | lines[n] = "<#{m[1]} id=\"scroll_to_here\" >#{m[2]}" 27 | end 28 | 29 | puts lines.join("\n") 30 | puts "\n<script>window.location.hash = \"scroll_to_here\";</script>" 31 | ' 32 | html_footer 33 | input 34 | document 35 | keyEquivalent 36 | ^~@p 37 | name 38 | Preview 39 | output 40 | showAsHTML 41 | scope 42 | text.html.markdown 43 | uuid 44 | B52DEA16-8480-11D9-BE59-000D93B3A10E 45 | 46 | 47 | -------------------------------------------------------------------------------- /Commands/Metadata - New Line.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env perl 9 | 10 | $line = $ENV{'TM_CURRENT_LINE'}; 11 | 12 | $old_line = $line; 13 | $original = $old_line; 14 | 15 | if ($line =~ /^\s*$/) { 16 | # empty line 17 | 18 | print ""; 19 | } elsif ($line =~ /^(\s+)/) { 20 | $leader = $1; 21 | $index = $ENV{'TM_LINE_INDEX'}; 22 | $line =~ s/^(.{$index})/$1\n$leader\$0/; 23 | $line =~ s/\$/\\\$/g; 24 | $line =~ s/\\\$0/\$0/s; 25 | 26 | print $line; # . "\n" . $1; 27 | } else { 28 | # Need to find leading width, and replicate it 29 | $leader = $line; 30 | $leader =~ s/^([a-zA-Z0-9][0-9a-zA-Z _-]+?:)(\s*).*/$2/; 31 | 32 | $leader = sprintf("%*s", int(length($1)/$ENV{'TM_TAB_SIZE'})*$ENV{'TM_TAB_SIZE'}, "") . $leader; 33 | 34 | $leader =~ s{ 35 | \t 36 | }{ 37 | sprintf("%*s", $ENV{'TM_TAB_SIZE'}, ""); 38 | }xmge; 39 | $leader =~ s/[^ ]/ /g; 40 | 41 | $leader =~ s/(.*?) {$ENV{'TM_TAB_SIZE'}}/$1\t/g; 42 | 43 | $index = $ENV{'TM_LINE_INDEX'}; 44 | $line =~ s/^(.{$index})/$1\n$leader\$0/; 45 | $line =~ s/\$/\\\$/g; 46 | $line =~ s/\\\$0/\$0/s; 47 | 48 | print $line; # . "\n" . $leader; 49 | } 50 | fallbackInput 51 | line 52 | input 53 | selection 54 | keyEquivalent 55 | 56 | name 57 | Metadata - New Line 58 | output 59 | insertAsSnippet 60 | scope 61 | meta.header.multimarkdown 62 | uuid 63 | 442001A7-0503-46F3-96BF-4740E3BC2F16 64 | 65 | 66 | -------------------------------------------------------------------------------- /Commands/List - New Sibling.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env perl 9 | 10 | # New, cleaned up, improved list sibling command 11 | # Thanks to Allan Odgaard and Brian H for finding and 12 | # helping to fix problem with special characters in list items 13 | 14 | 15 | # get current line, and break into what is left and right of caret 16 | 17 | $line = $ENV{'TM_CURRENT_LINE'}; 18 | 19 | $index = $ENV{'TM_LINE_INDEX'}; 20 | $line =~ /^(.{$index})(.*)$/; 21 | $left = $1; 22 | $right = $2; 23 | 24 | 25 | # Escape special characters since we will paste as snippet 26 | $left =~ s/(?=[\$`\\])/\\/g; 27 | $right =~ s/(?=[\$`\\])/\\/g; 28 | 29 | # Now, figure out what to paste back 30 | 31 | if ($left =~ /^(\s*(\*|\+|\-|\d+\.)\s*)\S+/) { 32 | # We appear to have a list item with content, so create a new sibling 33 | 34 | $marker = $1; # What was used as a list item marker? 35 | 36 | # If the marker included a counter, increment it 37 | $marker =~ s{ 38 | (\d+) 39 | }{ 40 | $1+1; 41 | }ex; 42 | 43 | print "$left\n$marker$right\$0"; 44 | } else { 45 | # Not a list item with content, so strip marker (if any) and add a newline 46 | $left =~ s/^\s*((\*|\+|\-|\d+\.)\s*)//; 47 | print "$left\n$right\$0"; 48 | } 49 | 50 | fallbackInput 51 | line 52 | input 53 | selection 54 | keyEquivalent 55 | 56 | name 57 | List - New Sibling 58 | output 59 | insertAsSnippet 60 | scope 61 | text.html.markdown markup.list 62 | uuid 63 | 5C692A38-2045-42F7-973B-E5D0C2558B03 64 | 65 | 66 | -------------------------------------------------------------------------------- /Tests/test-minimal.markdown: -------------------------------------------------------------------------------- 1 | Inline styles 2 | =============== 3 | 4 | _italic_ 5 | 6 | _italic one_ not italic _italic two_ 7 | 8 | _italic\__ 9 | 10 | _italic \__ 11 | 12 | stuff * not italic* 13 | 14 | *italic__* 15 | 16 | _all _ italic_ 17 | 18 | _italic 19 | end italic_ 20 | 21 | \\\\_italic\\_ 22 | 23 | \\\\_italic\\\_\\\\_ 24 | 25 | \\\\_italic\\_ 26 | 27 | \_ not italic _ 28 | 29 | _not italic _ 30 | 31 | \\\\_not italic\_ 32 | 33 | _not italic \_ 34 | 35 | \\\_not italic\\_ 36 | 37 | _not italic 38 | 39 | not end italic_ 40 | 41 | __bold__ 42 | 43 | **bold\*** 44 | 45 | `raw more` 46 | 47 | ``dobule ` raw`` 48 | 49 | `raw \` more` 50 | 51 | Headings 52 | ================ 53 | 54 | heading 2 55 | ---------- 56 | 57 | ## heading 2 58 | 59 | ### heading 3 60 | 61 | ###### heading 6 62 | 63 | Horizontal lines 64 | ================= 65 | 66 | *** 67 | 68 | * * * 69 | 70 | ___ 71 | 72 | __ __ __ 73 | 74 | - - - 75 | 76 | ---------------- 77 | 78 | 79 | Block formatting 80 | ================ 81 | 82 | Lists 83 | ---------------- 84 | 85 | * This *is a list!* 86 | * This is another list item. 87 | But this one spans *two* lines. 88 | * Another list item with __inline__ formatting 89 | * This one is tricky 90 | * *This is a list* 91 | 92 | Because this should still be a list item. 93 | 94 | 1. This is a list item too 95 | 2. This list is numbered 96 | 97 | 1986\. This shouldn't be a list. 98 | 99 | Code block 100 | --------------- 101 | 102 | asdfsdafasdf 103 | This is code. 104 | Isn't it pretty! 105 | 106 | Quotes 107 | --------------- 108 | 109 | > Here is a quote block 110 | This quote continues on. Line breaking is OK in markdown 111 | > Here it is again 112 | > Lah-di-dah 113 | > I should really match headings in here too: 114 | > ## This is a heading in a block quote 115 | 116 | Things that don't work currently 117 | ================================ -------------------------------------------------------------------------------- /Commands/Metadata - Cleanup.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env perl 9 | 10 | local $/; 11 | $text = <>; 12 | 13 | $g_max_width = 0; 14 | 15 | while ($text =~ /^([a-zA-Z0-9][0-9a-zA-Z _-]+?:)/mg) { 16 | # Find widest header label 17 | if (length($1) > $g_max_width) { 18 | $g_max_width = length($1); 19 | } 20 | } 21 | 22 | # Find the necessary width to allow all headers and 1 space 23 | $g_max_width++; 24 | $g_tabs = int(0.9999 + $g_max_width/$ENV{'TM_TAB_SIZE'}); 25 | $g_max_width = $g_tabs * $ENV{'TM_TAB_SIZE'}; 26 | 27 | # Now add appropriate numbers of tabs 28 | $text =~ s{ 29 | ^([a-zA-Z0-9][0-9a-zA-Z _-]+?:)[ \t]*(.*)$ 30 | }{ 31 | my $key = $1; 32 | my $value= $2; 33 | my $space = $g_max_width - length($key) - 1; 34 | 35 | $tabs = $space / $ENV{'TM_TAB_SIZE'}; 36 | $tabs ++; # Everybody gets at least 1 37 | 38 | my $result = $key; 39 | 40 | for ($i = 1; $i <= $tabs;$i++){ 41 | $result.="\t"; 42 | } 43 | $result.= $value; # For debugging . " " . length($key) . " $space $tabs"; 44 | 45 | $result; 46 | }xmge; 47 | 48 | # Now, add appropriate numbers of leading tabs for multi-line values 49 | 50 | $text =~ s{ 51 | ^\s+(.*) 52 | }{ 53 | my $result; 54 | for ($i = 1; $i <= $g_tabs;$i++){ 55 | $result.="\t"; 56 | } 57 | $result .$1; 58 | }xmge; 59 | 60 | $text =~ s{ 61 | ^(\S[^\:]*)$ 62 | }{ 63 | my $result; 64 | for ($i = 1; $i <= $g_tabs;$i++){ 65 | $result.="\t"; 66 | } 67 | $result .$1; 68 | }xmge; 69 | 70 | 71 | print $text; 72 | fallbackInput 73 | scope 74 | input 75 | selection 76 | keyEquivalent 77 | ^k 78 | name 79 | Metadata - Cleanup 80 | output 81 | replaceSelectedText 82 | scope 83 | meta.header.multimarkdown 84 | uuid 85 | B4A1CDF4-8759-45D4-B6B6-6CB44356B633 86 | 87 | 88 | -------------------------------------------------------------------------------- /Support/help.markdown: -------------------------------------------------------------------------------- 1 | ## Phrase Emphasis ## 2 | 3 | *italic* **bold** 4 | _italic_ __bold__ 5 | 6 | 7 | ## Links ## 8 | 9 | Inline: 10 | 11 | An [example](http://url.com/ "Title") 12 | 13 | Reference-style labels (titles are optional): 14 | 15 | An [example][id]. Then, anywhere 16 | else in the doc, define the link: 17 | 18 | [id]: http://example.com/ "Title" 19 | 20 | 21 | ## Images ## 22 | 23 | Inline (titles are optional): 24 | 25 | ![alt text](/path/img.jpg "Title") 26 | 27 | Reference-style: 28 | 29 | ![alt text][id] 30 | 31 | [id]: /url/to/img.jpg "Title" 32 | 33 | 34 | ## Headers ## 35 | 36 | Setext-style: 37 | 38 | Header 1 39 | ======== 40 | 41 | Header 2 42 | -------- 43 | 44 | atx-style (closing #'s are optional): 45 | 46 | # Header 1 # 47 | 48 | ## Header 2 ## 49 | 50 | ###### Header 6 51 | 52 | 53 | ## Lists ## 54 | 55 | Ordered, without paragraphs: 56 | 57 | 1. Foo 58 | 2. Bar 59 | 60 | Unordered, with paragraphs: 61 | 62 | * A list item. 63 | 64 | With multiple paragraphs. 65 | 66 | * Bar 67 | 68 | You can nest them: 69 | 70 | * Abacus 71 | * answer 72 | * Bubbles 73 | 1. bunk 74 | 2. bupkis 75 | * BELITTLER 76 | 3. burper 77 | * Cunning 78 | 79 | 80 | ## Blockquotes ## 81 | 82 | > Email-style angle brackets 83 | > are used for blockquotes. 84 | 85 | > > And, they can be nested. 86 | 87 | > #### Headers in blockquotes 88 | > 89 | > * You can quote a list. 90 | > * Etc. 91 | 92 | 93 | ## Code Spans ## 94 | 95 | `` spans are delimited 96 | by backticks. 97 | 98 | You can include literal backticks 99 | like `` `this` ``. 100 | 101 | 102 | ## Preformatted Code Blocks ## 103 | 104 | Indent every line of a code block by at least 4 spaces or 1 tab. 105 | 106 | This is a normal paragraph. 107 | 108 | This is a preformatted 109 | code block. 110 | 111 | 112 | ## Horizontal Rules ## 113 | 114 | Three or more dashes or asterisks: 115 | 116 | --- 117 | 118 | * * * 119 | 120 | - - - - 121 | 122 | 123 | ## Manual Line Breaks ## 124 | 125 | End a line with two or more spaces: 126 | 127 | Roses are red, 128 | Violets are blue. -------------------------------------------------------------------------------- /Commands/Metadata - Advance to Value.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env perl 9 | 10 | local $/; 11 | $text = <>; 12 | 13 | $cur_line = $ENV{'TM_CURRENT_LINE'}; 14 | $new_cur_line = $cur_line; 15 | if ($new_cur_line =~ s/(\t)+(.*)$/:$1\${1:$2}/m) { 16 | } else { 17 | $new_cur_line.= ": \$0"; 18 | } 19 | 20 | $replacement = ""; 21 | 22 | $g_max_width = 0; 23 | 24 | $text =~ s/^$cur_line$/$new_cur_line/m; 25 | 26 | $text =~ s{ 27 | ^(([a-zA-Z0-9][0-9a-zA-Z _-]*?:).*$) 28 | }{ 29 | my $line = $1; 30 | my $key = $2; 31 | my $result = ""; 32 | 33 | # Find widest header label 34 | if (length($key) > $g_max_width) { 35 | $g_max_width = length($key); 36 | } 37 | 38 | $line; 39 | }mgex; 40 | 41 | # Find the necessary width to allow all headers and 1 space 42 | $g_max_width++; 43 | $g_tabs = int(0.9999 + $g_max_width/$ENV{'TM_TAB_SIZE'}); 44 | $g_max_width = $g_tabs * $ENV{'TM_TAB_SIZE'}; 45 | 46 | # Now add appropriate numbers of tabs 47 | $text =~ s{ 48 | ^([a-zA-Z0-9][0-9a-zA-Z _-]*?:)[ \t]*(.*)$ 49 | }{ 50 | my $key = $1; 51 | my $value= $2; 52 | my $space = $g_max_width - length($key) - 1; 53 | 54 | $tabs = $space / $ENV{'TM_TAB_SIZE'}; 55 | $tabs ++; # Everybody gets at least 1 56 | 57 | my $result = $key; 58 | 59 | for ($i = 1; $i <= $tabs;$i++){ 60 | $result.="\t"; 61 | } 62 | $result.= $value; # For debugging . " " . length($key) . " $space $tabs"; 63 | 64 | $result; 65 | }xmge; 66 | 67 | # Now, add appropriate numbers of leading tabs for multi-line values 68 | 69 | $text =~ s{ 70 | ^\s+(.*) 71 | }{ 72 | my $result; 73 | for ($i = 1; $i <= $g_tabs;$i++){ 74 | $result.="\t"; 75 | } 76 | $result .$1; 77 | }xmge; 78 | 79 | $text =~ s{ 80 | ^(\S[^\:]*)$ 81 | }{ 82 | my $result; 83 | for ($i = 1; $i <= $g_tabs;$i++){ 84 | $result.="\t"; 85 | } 86 | $result .$1; 87 | }xmge; 88 | 89 | $text =~ s/\$/\\\$/g; 90 | $text =~ s/\\\$0/\$0/s; 91 | $text =~ s/\\\${1/\${1/s; 92 | 93 | print $text; 94 | 95 | 96 | fallbackInput 97 | scope 98 | input 99 | selection 100 | name 101 | Metadata - Advance to Value 102 | output 103 | insertAsSnippet 104 | scope 105 | meta.header.multimarkdown 106 | tabTrigger 107 | : 108 | uuid 109 | AF23DB79-1CCB-47EA-87A6-6727524BBA9A 110 | 111 | 112 | -------------------------------------------------------------------------------- /Commands/List - Clean-up.tmCommand: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beforeRunningCommand 6 | nop 7 | command 8 | #!/usr/bin/env perl 9 | 10 | $result = ""; 11 | %last_marker = (); # Store last marker used for each list depth 12 | $last_leading_space = ""; 13 | $g_tab_width = $ENV{'TM_TAB_SIZE'}; 14 | 15 | $g_list_level = 0; 16 | 17 | while ($line = <>) { 18 | $line =~ /^([ \t]*)([\*\+\_]|\d+\.)(\.?\s*)(.*)/; 19 | $leading_space = $1; 20 | $marker = $2; 21 | $item = " " . $4; 22 | 23 | $leading_space =~ s/\t/ /g; # Convert tabs to spaces 24 | 25 | if ( $line !~ /^([ \t]*)([\*\+\_]|\d+\.)/) { 26 | #$result .= "a"; 27 | # not a list line 28 | $result .= $line; 29 | $marker = $last_marker{$g_list_level}; 30 | } elsif (length($leading_space) > length($last_leading_space)+3) { 31 | # New list level 32 | #$result .= "b"; 33 | $g_list_level++; 34 | 35 | $marker =~ s{ 36 | (\d+) 37 | }{ 38 | # Reset count 39 | "1"; 40 | }ex; 41 | 42 | $last_leading_space = $leading_space; 43 | 44 | $result .= "\t" x $g_list_level; 45 | $result .= $marker . $item . "\n"; 46 | } elsif (length($leading_space)+3 < length($last_leading_space)) { 47 | #$result .= "c"; 48 | # back to prior list level 49 | $g_list_level = length($leading_space) / 4; 50 | 51 | # update marker 52 | $marker = $last_marker{$g_list_level}; 53 | $marker =~ s{ 54 | (\d+) 55 | }{ 56 | $1+1; 57 | }ex; 58 | 59 | $last_leading_space = $leading_space; 60 | 61 | $result .= "\t" x $g_list_level; 62 | $result .= $marker . $item . "\n"; 63 | } else { 64 | # No change in level 65 | #$result .= "d"; 66 | 67 | # update marker if it exists 68 | if ($last_marker{$g_list_level} ne "") { 69 | $marker = $last_marker{$g_list_level}; 70 | $marker =~ s{ 71 | (\d+) 72 | }{ 73 | $1+1; 74 | }ex; 75 | } 76 | 77 | 78 | $last_leading_space = $leading_space; 79 | 80 | $result .= "\t" x $g_list_level; 81 | $result .= $marker . $item . "\n"; 82 | } 83 | 84 | $last_marker{$g_list_level} = $marker; 85 | } 86 | 87 | print $result; 88 | fallbackInput 89 | scope 90 | input 91 | selection 92 | keyEquivalent 93 | ^k 94 | name 95 | List - Clean-up 96 | output 97 | replaceSelectedText 98 | scope 99 | text.html.markdown markup.list 100 | uuid 101 | 4D051505-F739-4A2F-AC49-649A4ABA4271 102 | 103 | 104 | -------------------------------------------------------------------------------- /Macros/Cut Item.tmMacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | commands 6 | 7 | 8 | argument 9 | 10 | beforeRunningCommand 11 | nop 12 | command 13 | #!/usr/bin/env ruby 14 | 15 | $: << ENV['TM_BUNDLE_SUPPORT'] 16 | $: << ENV['TM_SUPPORT_PATH'] 17 | 18 | require 'lib/markdown' 19 | require 'lib/escape' 20 | 21 | # get the list itself 22 | listtxt = $stdin.read() 23 | list = Markdown::List.parse(listtxt) 24 | 25 | # now we need to figure out where we were when we hit enter 26 | offsetline = ENV['TM_LINE_NUMBER'].to_i() - ENV['TM_INPUT_START_LINE'].to_i() 27 | index = ENV['TM_LINE_INDEX'].to_i() 28 | 29 | list.select(offsetline) { |l| e_sn(l) } 30 | print list.to_s() 31 | 32 | fallbackInput 33 | scope 34 | input 35 | selection 36 | keyEquivalent 37 | @ 38 | name 39 | Select Current Item 40 | output 41 | insertAsSnippet 42 | scope 43 | markup.list 44 | uuid 45 | ADEF8E57-BF21-487A-9115-E1D1146142CD 46 | 47 | command 48 | executeCommandWithOptions: 49 | 50 | 51 | command 52 | selectWord: 53 | 54 | 55 | command 56 | cut: 57 | 58 | 59 | command 60 | selectHardLine: 61 | 62 | 63 | command 64 | deleteBackward: 65 | 66 | 67 | argument 68 | 69 | beforeRunningCommand 70 | nop 71 | command 72 | #!/usr/bin/env ruby 73 | 74 | $: << ENV['TM_BUNDLE_SUPPORT'] 75 | $: << ENV['TM_SUPPORT_PATH'] 76 | 77 | require 'lib/markdown' 78 | require 'lib/escape' 79 | 80 | # get the list itself 81 | listtxt = $stdin.read() 82 | list = Markdown::List.parse(listtxt) 83 | 84 | print list.to_s() 85 | 86 | fallbackInput 87 | scope 88 | input 89 | selection 90 | keyEquivalent 91 | ^~@l 92 | name 93 | Reformat 94 | output 95 | replaceSelectedText 96 | scope 97 | markup.list 98 | uuid 99 | 5EFA9FF4-2246-4AF4-ABD6-2B7ADB4E9B80 100 | 101 | command 102 | executeCommandWithOptions: 103 | 104 | 105 | keyEquivalent 106 | $@ 107 | name 108 | Cut Item 109 | scope 110 | text.html.markdown markup.list 111 | useGlobalClipboard 112 | 113 | uuid 114 | 2E75B4D8-E6E8-4E3C-969D-FFC650092A39 115 | 116 | 117 | -------------------------------------------------------------------------------- /Syntaxes/MultiMarkdown.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fileTypes 6 | 7 | md 8 | markdown 9 | mdown 10 | markdn 11 | mmd 12 | 13 | firstLineMatch 14 | ^\S.*?:\s*\S.*?\s*$ 15 | foldingStartMarker 16 | (?x) 17 | (<(?i:head|body|table|thead|tbody|tfoot|tr|div|select|fieldset|style|script|ul|ol|form|dl)\b.*?> 18 | |<!--(?!.*-->) 19 | |\{\s*($|\?>\s*$|//|/\*(.*\*/\s*$|(?!.*?\*/))) 20 | ) 21 | foldingStopMarker 22 | (?x) 23 | (</(?i:head|body|table|thead|tbody|tfoot|tr|div|select|fieldset|style|script|ul|ol|form|dl)> 24 | |^\s*--> 25 | |(^|\s)\} 26 | ) 27 | keyEquivalent 28 | ^~M 29 | name 30 | MultiMarkdown 31 | patterns 32 | 33 | 34 | begin 35 | ^([A-Za-z0-9][A-Za-z0-9 ]*):\s* 36 | beginCaptures 37 | 38 | 1 39 | 40 | name 41 | keyword.other.multimarkdown 42 | 43 | 44 | end 45 | ^$|^(?=[A-Za-z0-9]+:) 46 | name 47 | meta.header.multimarkdown 48 | patterns 49 | 50 | 51 | comment 52 | The reason for not setting scopeName = "string.unquoted" 53 | (for the parent rule) is that we do not want 54 | newlines to be marked as string.unquoted 55 | match 56 | .+ 57 | name 58 | string.unquoted.multimarkdown 59 | 60 | 61 | 62 | 63 | begin 64 | ^(?!=[A-Za-z0-9]+:) 65 | end 66 | ^(?=not)possible$ 67 | name 68 | meta.content.multimarkdown 69 | patterns 70 | 71 | 72 | begin 73 | ^[ ]{0,3}\[\^(.+?)\]:[ \t]*(.*?)$\n 74 | captures 75 | 76 | 1 77 | 78 | name 79 | constant.other.reference.footnote.multimarkdown 80 | 81 | 2 82 | 83 | name 84 | markup.footnote.multimarkdown 85 | 86 | 87 | end 88 | ^$ 89 | name 90 | meta.footnote.reference.def.multimarkdown 91 | patterns 92 | 93 | 94 | include 95 | text.html.markdown 96 | 97 | 98 | 99 | 100 | begin 101 | ^[ ]{0,3}\[\#(.+?)\]:[ \t]*(.*?)$\n 102 | captures 103 | 104 | 1 105 | 106 | name 107 | constant.other.reference.citation.multimarkdown 108 | 109 | 2 110 | 111 | name 112 | markup.citation.multimarkdown 113 | 114 | 115 | end 116 | ^$ 117 | name 118 | meta.citation.reference.def.multimarkdown 119 | 120 | 121 | match 122 | \[\#.*\] 123 | name 124 | meta.citation.reference.literal.multimarkdown 125 | 126 | 127 | captures 128 | 129 | 1 130 | 131 | name 132 | constant.other.reference.link.markdown 133 | 134 | 2 135 | 136 | name 137 | markup.underline.link.markdown 138 | 139 | 3 140 | 141 | name 142 | string.other.link.description.title.markdown 143 | 144 | 4 145 | 146 | name 147 | string.other.link.description.attributes.markdown 148 | 149 | 150 | match 151 | (?x: 152 | \s* # Leading whitespace 153 | \[(.+?)\]: # Reference name 154 | [ \t]* # Optional whitespace 155 | <?(\S+?)>? # The url 156 | [ \t]* # Optional whitespace 157 | (?: 158 | ["(](.+?)[")] # Match title in quotes or parens 159 | [ \t]* 160 | )? # Title is optional 161 | ( 162 | (?<=\s) # Match attributes 163 | (([ \t]*\n)?[ \t]* # Leading whitespace 164 | (\S+=\S+)|(\S+=".*?") # Match the attributes 165 | )* 166 | )?[ \t]* # Attributes are optional 167 | \s* # Optional whitespace 168 | $\n? 169 | ) 170 | name 171 | meta.link.reference.def.markdown 172 | 173 | 174 | begin 175 | ^([ ]{0,3})[^\s\*].*?\|.*|\[.*?\](\[.*?\])?[ \t]*$\n? 176 | end 177 | ^(?!((.*\|.*)|\[.*\]|$)) 178 | name 179 | markup.table.multimarkdown 180 | patterns 181 | 182 | 183 | include 184 | text.html.markdown 185 | 186 | 187 | 188 | 189 | include 190 | text.html.markdown 191 | 192 | 193 | 194 | 195 | scopeName 196 | text.html.markdown.multimarkdown 197 | uuid 198 | F5E04BF4-69A9-45AE-9205-B3F3C2B00130 199 | 200 | 201 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Title: MultiMarkdown Bundle for TextMate 2 | Author: Fletcher T. Penney 3 | 4 | 5 | # Introduction # 6 | 7 | [TextMate](http://macromates.com) is a wonderfully useful text editor for Mac 8 | OS X. Of particular interest to me is the ability to extend it with add-on 9 | Bundles for particular uses, either programming languages or document types. 10 | Allan Odgaard (and others) created a Bundle for Markdown, and included some 11 | basic support for MultiMarkdown. 12 | 13 | To me, however, the job felt halfway done. First - the support for 14 | MultiMarkdown was outdated, so at the very least it needed to be updated with 15 | newer versions of the MultiMarkdown software. More importantly, however, the 16 | Bundle didn't take advantage of all the features that TextMate offered that 17 | could be used to make document creation and publishing easier. And that was 18 | the whole reason for creating MultiMarkdown in the first place. 19 | 20 | 21 | # Where can you get a copy # 22 | 23 | You can download a copy of the latest version from my github repository: 24 | 25 | * [markdown.tmbundle](https://github.com/fletcher/markdown.tmbundle) 26 | 27 | 28 | # Installation # 29 | 30 | To install, you download the .zip file, and after unzipping it, rename the 31 | folder as `markdown.tmbundle`. After that, you can double-click the newly 32 | renamed folder and it should open in TextMate and be installed to the proper 33 | location. 34 | 35 | If you are using MultiMarkdown 2.0 (the perl version), then you will want to 36 | use the latest release of this plugin tagged as version 2 on the [downloads] 37 | page. If you use this, you should probably also set the TextMate Shell 38 | Variable `TM_MULTIMARKDOWN_PATH` to match your installation directory --- for 39 | example, `/Users/yourname/Library/Application Support/MultiMarkdown`. 40 | 41 | If you are using MultiMarkdown 3.0, you probably need to add `/usr/local/bin` 42 | to your `PATH` variable in the TextMate preferences. If you don't this, you 43 | will see an error message about the multimarkdown command not being found. 44 | 45 | Of course, you need a working installation of MultiMarkdown. A few of the more 46 | advanced features require that you also install the `MultiMarkdown-Support` 47 | package, but the basics work without it. 48 | 49 | You can also install my MultiMarkdown TextMate [theme] as well. 50 | 51 | 52 | [downloads]: https://github.com/fletcher/markdown.tmbundle/downloads 53 | [theme]: http://files.fletcherpenney.net/MultiMarkdown.tmTheme.zip 54 | 55 | 56 | # What's the difference between this Bundle and the Markdown Bundle? # 57 | 58 | The basic Markdown bundle that is included with TextMate is great, and I was 59 | pleased when I learned that they added MultiMarkdown support. The problem was 60 | that even I couldn't get a pdf to compile using it. The MultiMarkdown support 61 | was limited, and didn't take full advantage of the features that TextMate had 62 | to offer. 63 | 64 | So I wrote a new bundle to add those features back. More recently (July 2009), 65 | I have forked a git repository of the original bundle that adds my improved 66 | support. Perhaps these changes will get pulled back into the original copy.... 67 | This should make it easier for me to keep my version up to date until that 68 | happens. 69 | 70 | If you just use regular Markdown, the other bundle may be sufficient. But if 71 | you use MultiMarkdown, I believe you'll find this version to be indispensable. 72 | 73 | 74 | # Features # 75 | 76 | 77 | ## Metadata ## 78 | 79 | * Automatically clean up metadata section to align the data 80 | 81 | * hitting return aligns you to continue entering metadata within the same key. 82 | hit return again to enter a new key. hit return again to insert a blank line 83 | and begin the body 84 | 85 | * hitting tab after typing the colon for the key aligns you to the right tab 86 | width to start entering data 87 | 88 | * If using the *Memoir* class, you can set the `chapterstyle` and `pagestyle` 89 | in the metadata within the document, or as part of your command using 90 | `addmetadata.pl`. See the companion style example. 91 | 92 | * When creating a new document, you can pre-populate it with default metadata 93 | using the `Insert default metadata` or `Insert letter metadata` snippet. 94 | Both of these can be customized to your fit your needs. The advantage of the 95 | snippet approach is that you can tab between all of the values to easily 96 | make changes. 97 | 98 | 99 | ## Headers ## 100 | 101 | * you can use a keystroke to increase or decrease the level of the header 102 | * hitting enter automatically adds trailing #'s to the header and skips some 103 | space 104 | 105 | 106 | ## Lists ## 107 | 108 | * indent and outdent with a keystroke 109 | * convert from numbered to unnumbered list with a keystroke 110 | * clean up the spacing of your list automatically with a single keystroke 111 | 112 | 113 | ## Blockquotes ## 114 | 115 | * hitting return automatically starts the next line with the proper level of ">" 116 | * use a keystroke to increase or decrease quote level 117 | 118 | 119 | ## Tables ## 120 | 121 | * Clean up ascii spacing of tables automatically 122 | * navigate left and right across cells with a single keystroke 123 | 124 | 125 | ## Text Formatting ## 126 | 127 | Key commands to toggle italics and bold 128 | 129 | 130 | ## Completions ## 131 | 132 | Automatically complete: 133 | 134 | * links by reference 135 | * citations 136 | * footnotes 137 | * automatic cross-refs 138 | * equation labels 139 | * table labels 140 | * autocomplete image filenames located in same folder as your document 141 | * autocomplete BibTeX cite keys from .bib files located in the same folder as 142 | your document 143 | 144 | 145 | ## Document Conversion ## 146 | 147 | Run the following with one menu selection (or keystroke): 148 | 149 | * Preview XHTML - run MultiMarkdownMath (optionally), MultiMarkdown, 150 | SmartyPants 151 | * View XHTML source 152 | * Convert XHTML into LaTeX using article, memoir, report, science or other 153 | XSLT file of your choice 154 | * Convert to RTF (though I recommend using Google Docs instead to create an 155 | RTF file) 156 | 157 | **Note**: You can convert either the entire document or just a selection. If 158 | you choose to convert just a section, make sure that the section begins with a 159 | blank line in order to differentiate it from the metadata that will be added 160 | automatically. If this doesn't make sense, just stick with previewing the 161 | entire document until it does. ;) 162 | 163 | 164 | ## Image Preview ## 165 | 166 | Thanks to a suggestion from Andrew Nanton, images now work properly when XHTML 167 | is previewed within TextMate. 168 | 169 | 170 | # Limitations # 171 | 172 | 173 | ## Language Grammar ## 174 | 175 | There are a few situations where the language matching grammar is too limited 176 | to properly match MultiMarkdown documents: 177 | 178 | * TextMate can't tell the difference between an anchor by reference on a line 179 | by itself, and the caption and optional label at the start of a table. If 180 | you are trying to use an anchor, you may need to add some non-whitespace 181 | characters to the end of the line to force the scope to change. I am open to 182 | suggestions on how to improve this. 183 | 184 | * TextMate doesn't include the character after a scope as part of the scope. 185 | For example, Markdown anchors can consist of square brackets surrounding a 186 | label. The only way to allow customized autocompletion to work properly on 187 | the label is if you include the brackets in the scope of interest. I would 188 | like the cursor at the end of a scope to be considered part of that scope, 189 | until one types a character that is no longer part of that scope. (This idea 190 | makes sense to me as a type it, but I will be quite surprised if many people 191 | understood the gibberish I just typed :) 192 | 193 | 194 | ## Completions Limitations ## 195 | 196 | Unfortunately, completions are apparently case sensitive. So if you have a 197 | header `Introduction`, it will not show up as a completion for `i`. I suppose 198 | you can make the best of this and label all references with lower case, and 199 | use upper case for headers, allowing you to restrict your completion search by 200 | using upper or lower case, but this seems like a limitation of TextMate. 201 | -------------------------------------------------------------------------------- /Support/lib/markdown.rb: -------------------------------------------------------------------------------- 1 | class String 2 | 3 | def add_newline() 4 | if self !~ /\n$/m 5 | self + "\n" 6 | else 7 | self 8 | end 9 | end 10 | 11 | end 12 | 13 | 14 | module Markdown 15 | 16 | class Insert 17 | 18 | def initialize(str) 19 | @str = str 20 | end 21 | 22 | 23 | def length 24 | @str.length 25 | end 26 | 27 | 28 | def to_s 29 | @str.to_s 30 | end 31 | end 32 | 33 | 34 | class ListLine 35 | attr_accessor :line, :indent 36 | 37 | 38 | def initialize(line, indent, str) 39 | @line = line 40 | @indent = indent 41 | @str = [str] 42 | end 43 | 44 | 45 | def [](arg) 46 | if arg.kind_of?(Range) 47 | # adjust the range by the indent 48 | if (arg.begin >= 0 and arg.begin < @indent.length) and (arg.end >= 0 and arg.end < @indent.length) 49 | return "" 50 | end 51 | 52 | newbegin = if arg.begin >= 0 then [arg.begin - @indent.length, 0].max() else arg.begin end 53 | newend = if arg.end >= 0 then [arg.end - @indent.length, 0].max() else arg.end end 54 | return self.to_s()[Range.new(newbegin, newend, arg.exclude_end?)] 55 | elsif arg.kind_of?(Integer) 56 | if arg < 0 57 | return self.to_s()[arg] 58 | else 59 | return self.to_s()[[arg - @indent.length(), 0].max()] 60 | end 61 | else 62 | return self.to_s()[arg] 63 | end 64 | end 65 | 66 | 67 | def str=(newstr) 68 | @str = [newstr] 69 | end 70 | 71 | 72 | def str() 73 | to_s() 74 | end 75 | 76 | 77 | def rawstr() 78 | @str 79 | end 80 | 81 | 82 | def rawstr=(newrawstr) 83 | @str = newrawstr 84 | end 85 | 86 | 87 | def insert(pos, insert) 88 | index = 0 89 | newstr = [] 90 | @str.each() do |s| 91 | if s.kind_of?(Insert) 92 | newstr << s 93 | next 94 | end 95 | 96 | if index + s.length < pos 97 | index += s.length 98 | newstr << s 99 | elsif index <= pos and index + s.length >= pos 100 | pos -= index 101 | newstr << s[0...pos] 102 | newstr << Insert.new(insert) 103 | newstr << s[pos..-1] 104 | else 105 | newstr << s 106 | end 107 | end 108 | @str = newstr 109 | 110 | self 111 | end 112 | 113 | 114 | # returns the length of the str portions only 115 | def length() 116 | @str.select { |s| s.kind_of?(String) }.join.length() 117 | end 118 | 119 | 120 | def to_s() 121 | @str.map { |s| s.to_s }.join() 122 | end 123 | end 124 | 125 | 126 | class List 127 | class SubList < StandardError 128 | end 129 | 130 | 131 | attr_accessor :line, :indent, :numbered 132 | attr_reader :entries 133 | 134 | 135 | @@sublistregex = /^\s+([0-9]+\.|\*)\s/ 136 | 137 | # This should never be called unless you know what you are doing. It is used 138 | # internally to create sublists. Generally you will want to call List.parse(str) 139 | # instead 140 | def initialize(line=nil, indent=nil, numbered=nil, entries = []) 141 | @line = line 142 | @indent = indent 143 | @numbered = numbered 144 | @entries = [] 145 | entries.each() do |e| 146 | @entries << e 147 | end 148 | end 149 | 150 | 151 | def add(entry) 152 | @entries << entry 153 | self 154 | end 155 | 156 | 157 | def <<(entry) 158 | add(entry) 159 | self 160 | end 161 | 162 | 163 | def length() 164 | @entries.inject(0) { |t, e| t + e.inject(0) { |t, l| if l.kind_of?(List) then t + l.length else t + 1 end } } 165 | end 166 | 167 | 168 | def [](index) 169 | @entries[index] 170 | end 171 | 172 | 173 | # yields each str in turn to &block and replaces the result. Also 174 | # performs pending insertions after the yield (to avoid escaping insertions) 175 | def map!(&block) 176 | @entries.each() do |e| 177 | e.each_index() do |i| 178 | l = e[i] 179 | if l.kind_of?(ListLine) 180 | newrawstr = [] 181 | l.rawstr.each() do |s| 182 | if s.kind_of?(String) 183 | s = yield(s) 184 | end 185 | newrawstr << s 186 | end 187 | e[i].rawstr = newrawstr 188 | else 189 | l.map!(&block) 190 | end 191 | end 192 | end 193 | 194 | self 195 | end 196 | 197 | 198 | def get_entry(line, &block) 199 | curline = 0 200 | @entries.each_index() do |i| 201 | @entries[i].each_index do |li| 202 | l = @entries[i][li] 203 | if l.kind_of?(ListLine) 204 | if l.line == line 205 | yield(@entries[i], self, i) 206 | break 207 | end 208 | elsif l.line <= line and l.line + l.length >= line 209 | l.get_entry(line - l.line, &block) 210 | end 211 | end 212 | end 213 | end 214 | 215 | 216 | def select(line, &block) 217 | get_entry(line) do |e, list, num| 218 | e[0].insert(0, "${1:") 219 | last_line(e).insert(e[-1].length-1, "}") 220 | end 221 | 222 | self.map!(&block) 223 | end 224 | 225 | 226 | # deletes the entry at i 227 | def delete_at(i) 228 | @entries.delete_at(i) 229 | end 230 | 231 | 232 | # indents the item marked by the original input line and returns the new list 233 | def indent_entry(line) 234 | get_entry(line) do |e, list, num| 235 | # can't indent the first item in a list 236 | if num == 0 237 | return self 238 | end 239 | 240 | newindent = increase_indent(list.indent) 241 | newentry = List.new(-1, newindent, list.numbered, [e]) 242 | 243 | list[num - 1] << newentry 244 | list.delete_at(num) 245 | end 246 | 247 | # a bit of slight of hand, we turn the list back into 248 | # a string and parse it back into itself to clear up 249 | # any internal discrepencies that may have been created - 250 | # mostly handles merging lists 251 | @entries = List.parse(self.to_s).entries() 252 | 253 | self 254 | end 255 | 256 | 257 | # breaks the list at line, pos in the original input 258 | # inserts insert at the break point and filters everything 259 | # else through block. If aslist is true, then the break 260 | # item is inserted as a new list 261 | def break(line, pos, insert = "$0", aslist = false, &block) 262 | curline = 0 263 | @entries.each_index() do |i| 264 | @entries[i].each_index do |li| 265 | l = @entries[i][li] 266 | if l.kind_of?(ListLine) 267 | if l.line == line 268 | breakentry = @entries[i] 269 | breakline = @entries[i][li] 270 | newentries = [] 271 | 272 | firstpart = breakentry[0...li] << ListLine.new(-1, breakline.indent, (breakline[0...pos].add_newline())) 273 | newentries << firstpart 274 | 275 | secondpart = [ListLine.new(-1, breakline.indent, breakline[pos..-1].to_s.lstrip().add_newline())] + breakentry[li+1..-1] 276 | 277 | if firstpart.map { |l| l.to_s() }.join().strip == "" and secondpart.map { |l| l.to_s() }.join().strip() != "" 278 | firstpart[-1].insert(0, " " + insert) 279 | secondpart[0].insert(0, " ") 280 | else 281 | secondpart[0].insert(0, " " + insert) 282 | end 283 | 284 | if aslist 285 | newindent = increase_indent(self.indent) 286 | secondpart = List.new(-1, newindent, self.numbered, [secondpart]) 287 | firstpart << secondpart 288 | else 289 | newentries << secondpart 290 | end 291 | 292 | @entries = @entries[0...i] + newentries + @entries[i+1..-1] 293 | break 294 | end 295 | elsif l.line <= line and l.line + l.length >= line 296 | l.break(line - l.line, pos, insert, aslist) 297 | end 298 | end 299 | end 300 | 301 | if block 302 | self.map!(&block) 303 | end 304 | 305 | self 306 | end 307 | 308 | 309 | # parses the list into a full structure 310 | def List.parse(str, line = 0) 311 | list = List.new() 312 | list.indent = str[/^(\s*)/, 1].to_s() 313 | list.numbered = /^\s*([0-9])/.match(str.to_a[0]) 314 | list.line = line 315 | itemregex = /^(#{Regexp.escape(list.indent)}#{if list.numbered then "[0-9]+\\." else "\\*" end})(\s.*)/ 316 | 317 | entry = [] 318 | linenumber = -1 319 | begin 320 | lines = str.to_a() 321 | lines.each_index() do |i| 322 | line = lines[i] 323 | linenumber += 1 324 | 325 | # we might be in an indented sublist, if the indent goes down, and the line isn't blank, return the list and the remainder 326 | if list.indent.length > 0 && line[/^(\s*)/, 1].to_s.length < list.indent.length && line.strip() != "" 327 | list << entry 328 | return [list, lines[i..-1].join()] 329 | end 330 | 331 | if itemregex.match(line) 332 | if entry.length > 0 333 | list << entry 334 | end 335 | entry = [ListLine.new(linenumber, $1, $2 + "\n")] 336 | else 337 | if @@sublistregex.match(line) 338 | sublist, str = List.parse(lines[i..-1].join(), linenumber) 339 | entry << sublist 340 | linenumber += sublist.length - 1 341 | raise SubList 342 | else 343 | entry << ListLine.new(linenumber, "", line) 344 | end 345 | end 346 | end 347 | list << entry 348 | rescue SubList 349 | retry 350 | end 351 | 352 | list 353 | end 354 | 355 | 356 | def to_s() 357 | str = "" 358 | @entries.each_index() do |i| 359 | str << @indent 360 | if @numbered 361 | str << "#{i+1}." 362 | else 363 | str << "*" 364 | end 365 | 366 | str << @entries[i].map { |e| e.to_s() }.join() 367 | end 368 | 369 | str 370 | end 371 | 372 | 373 | private 374 | 375 | 376 | # returns the last line of an entry 377 | def last_line(entry) 378 | last = entry[-1] 379 | if last.kind_of?(List) 380 | last_line(last[-1]) 381 | else 382 | last 383 | end 384 | end 385 | 386 | 387 | # creates a new, deper indent based on indent 388 | def increase_indent(indent) 389 | if ENV['TM_SOFT_TABS'] == 'NO' 390 | "\t#{indent}" 391 | else 392 | " " * ENV['TM_TAB_SIZE'].to_i + indent 393 | end 394 | end 395 | end 396 | 397 | end 398 | -------------------------------------------------------------------------------- /info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | contactEmailRot13 6 | syrgpure@syrgpurecraarl.arg 7 | contactName 8 | Fletcher T. Penney 9 | deleted 10 | 11 | 58434A58-85E8-11D9-9CD0-000D93B3A10E 12 | 15D9BCDD-1140-49B1-A054-5D9D57DC29A4 13 | B6E4F67F-D9E2-4866-A958-A96C063549DB 14 | D548EAB4-08E6-449B-89DF-CE8BAAEF7BBA 15 | 70F80DF8-3FFE-46E3-A1A7-5E480E2623BD 16 | AC737304-8B70-49F4-9442-AB824D8D911C 17 | 6A1D4980-B41C-11D9-95E7-000D93B6E43C 18 | 485F0ABF-7A7D-4432-8AB6-702414D6ADBD 19 | 4AB16529-60A5-4CE7-8E97-B0785CAF87C4 20 | 3BAE5ECF-9006-43D0-9AEB-28FAFE526840 21 | 401A3DB4-7032-4046-A2B6-6021C20F4DE5 22 | DB5085DA-3E95-4020-8521-C9702168F160 23 | E57A1B41-D70E-44C9-9512-45026C0A32F2 24 | F05719F8-89F2-48F0-88F6-8CFAEEF5BA91 25 | D9118E94-4E23-4B75-88D7-6BFEBAA70D1B 26 | 27 | description 28 | <a href="http://daringfireball.net/projects/markdown/">Markdown</a> allows you to write using an easy-to-read, easy-to-write plain text format, then convert it to structurally valid XHTML. This bundle provides preview functionality, syntax highlighting, and several useful commands. Improved support for <a href="http://fletcherpenney.net/multimarkdown/">MultiMarkdown</a> has been added. 29 | mainMenu 30 | 31 | items 32 | 33 | B52DEA16-8480-11D9-BE59-000D93B3A10E 34 | 966B0E57-799A-4B91-84B4-75695A78F7B8 35 | FE31CF79-5F04-4FB6-B5CE-70BC781FF8B5 36 | C70F0881-D108-47B1-A06F-09C74954E5C2 37 | ------------------------------------ 38 | 49B1C71D-A748-4F99-9503-95444E8FF7BE 39 | B8AD0BAA-18C9-4BBA-8217-E915544812E6 40 | 624C68E4-F786-4DBF-8A2E-B9E09651A0C5 41 | ------------------------------------ 42 | 914B78B7-3C9E-4630-8BFC-665A358FB49B 43 | ------------------------------------ 44 | C17369F1-F47C-475E-A84A-C849A308F702 45 | A6E74A5E-FFE9-43FA-8936-970F3CE47DCB 46 | 350477DF-B66B-49E8-8A31-CF26C2AD745D 47 | ------------------------------------ 48 | 4405912F-4AD5-40F8-93B3-A63394036ACA 49 | CAC8BE7C-78DD-489B-97F8-2EF8D896F91C 50 | 51 | submenus 52 | 53 | 350477DF-B66B-49E8-8A31-CF26C2AD745D 54 | 55 | items 56 | 57 | 622F0B69-EB98-4EB9-8DC8-2AC56FF2501E 58 | 000B399B-FB71-49EF-B799-A1200A3865AB 59 | ------------------------------------ 60 | 2E75B4D8-E6E8-4E3C-969D-FFC650092A39 61 | ADEF8E57-BF21-487A-9115-E1D1146142CD 62 | ------------------------------------ 63 | 5EFA9FF4-2246-4AF4-ABD6-2B7ADB4E9B80 64 | 39A74FF2-46EF-4178-9E3A-7D4DB3968E05 65 | ------------------------------------ 66 | 5C692A38-2045-42F7-973B-E5D0C2558B03 67 | BAE8ED70-CF67-4D4A-99D8-02544053131C 68 | EAAF445C-947E-496B-A8B9-4FF45EEF8C5E 69 | 1E8299F1-916B-445B-BC6F-1D3657901BB5 70 | 4D051505-F739-4A2F-AC49-649A4ABA4271 71 | 8A9993E1-CA38-49B1-92D8-ADCA4CF9C4DD 72 | 73 | name 74 | Lists 75 | 76 | 49B1C71D-A748-4F99-9503-95444E8FF7BE 77 | 78 | items 79 | 80 | 7CCF064C-BC8F-437B-A339-0E2156D8B2C3 81 | 351451DE-C1A4-4A36-A563-99AF761D026B 82 | ------------------------------------ 83 | 9F73CBC1-E9C0-41A4-891F-B2879A1852F7 84 | 67EB96A4-4213-42C9-9C47-B886A4B8AC93 85 | C92636B7-8795-4CE4-8F0B-0F2EB200CAA1 86 | FD6FBB48-68DF-4EFB-9A66-2C109E9FCA7E 87 | 9BF17F3B-B5E1-4F8A-A422-1A5413D4AD75 88 | ------------------------------------ 89 | 90 | name 91 | MultiMarkdown 92 | 93 | 624C68E4-F786-4DBF-8A2E-B9E09651A0C5 94 | 95 | items 96 | 97 | DB739633-6AF0-460A-BF34-86BAD8C22C4D 98 | 34FCB7E2-516C-4ADA-9CFC-BD3D5BA6D9C7 99 | 3F7582D4-F2C3-44B8-944E-CDA2F069A818 100 | CA000031-1DD5-42D8-9E7E-678B006B1978 101 | 102 | name 103 | Tables 104 | 105 | 914B78B7-3C9E-4630-8BFC-665A358FB49B 106 | 107 | items 108 | 109 | 31614C02-1FED-4644-9518-2C2DEF0D7A2C 110 | F56525A1-C879-4A7C-9584-4DB28AFC58C2 111 | 112 | name 113 | Format 114 | 115 | A6E74A5E-FFE9-43FA-8936-970F3CE47DCB 116 | 117 | items 118 | 119 | F3A754C3-CE6B-11D9-9C17-000A95C0F626 120 | 724FCFF6-CE6B-11D9-9C17-000A95C0F626 121 | ------------------------------------ 122 | 317FF73B-9CCC-486D-827F-839F4C7EE855 123 | 69DBCB2D-ECFA-4515-A479-F96AE19FE25A 124 | 45736A34-CE6F-4F03-93F5-EB6F348A4AF8 125 | 8557FE6C-388E-4E3A-A725-94B3A505CCD8 126 | 127 | name 128 | Headings 129 | 130 | B8AD0BAA-18C9-4BBA-8217-E915544812E6 131 | 132 | items 133 | 134 | 8D04C38E-0187-4E53-B100-AE096CBBB984 135 | C96D5804-7FA5-4CFE-8ADC-6F2F53B0FF01 136 | ------------------------------------ 137 | B4A1CDF4-8759-45D4-B6B6-6CB44356B633 138 | 442001A7-0503-46F3-96BF-4740E3BC2F16 139 | AF23DB79-1CCB-47EA-87A6-6727524BBA9A 140 | 6AE91BD7-4E3B-49CD-B175-E52E76512176 141 | 142 | name 143 | Metadata 144 | 145 | C17369F1-F47C-475E-A84A-C849A308F702 146 | 147 | items 148 | 149 | BC6D1959-6343-4620-8EEA-1463C3D240C8 150 | 115BAB2F-3F19-429E-B337-B6A3BF5A061E 151 | 2E3B6708-ECB7-45DE-BCEF-714038D7CC8B 152 | C51C8DF5-1C1A-4409-AC9B-4778280D0B1F 153 | 154 | name 155 | Blockquotes 156 | 157 | 158 | 159 | name 160 | Markdown 161 | ordering 162 | 163 | B52DEA16-8480-11D9-BE59-000D93B3A10E 164 | 966B0E57-799A-4B91-84B4-75695A78F7B8 165 | FE31CF79-5F04-4FB6-B5CE-70BC781FF8B5 166 | F3A754C3-CE6B-11D9-9C17-000A95C0F626 167 | 724FCFF6-CE6B-11D9-9C17-000A95C0F626 168 | 9F73CBC1-E9C0-41A4-891F-B2879A1852F7 169 | 67EB96A4-4213-42C9-9C47-B886A4B8AC93 170 | C92636B7-8795-4CE4-8F0B-0F2EB200CAA1 171 | FD6FBB48-68DF-4EFB-9A66-2C109E9FCA7E 172 | 4F20AFC6-53B0-4789-8007-8FC84F2B1874 173 | 9BF17F3B-B5E1-4F8A-A422-1A5413D4AD75 174 | 351451DE-C1A4-4A36-A563-99AF761D026B 175 | CAC8BE7C-78DD-489B-97F8-2EF8D896F91C 176 | 7CCF064C-BC8F-437B-A339-0E2156D8B2C3 177 | 622F0B69-EB98-4EB9-8DC8-2AC56FF2501E 178 | 000B399B-FB71-49EF-B799-A1200A3865AB 179 | ADEF8E57-BF21-487A-9115-E1D1146142CD 180 | 2E75B4D8-E6E8-4E3C-969D-FFC650092A39 181 | 5EFA9FF4-2246-4AF4-ABD6-2B7ADB4E9B80 182 | 39A74FF2-46EF-4178-9E3A-7D4DB3968E05 183 | 31614C02-1FED-4644-9518-2C2DEF0D7A2C 184 | F56525A1-C879-4A7C-9584-4DB28AFC58C2 185 | B4A1CDF4-8759-45D4-B6B6-6CB44356B633 186 | 442001A7-0503-46F3-96BF-4740E3BC2F16 187 | AF23DB79-1CCB-47EA-87A6-6727524BBA9A 188 | 6AE91BD7-4E3B-49CD-B175-E52E76512176 189 | BC6D1959-6343-4620-8EEA-1463C3D240C8 190 | 115BAB2F-3F19-429E-B337-B6A3BF5A061E 191 | 2E3B6708-ECB7-45DE-BCEF-714038D7CC8B 192 | C51C8DF5-1C1A-4409-AC9B-4778280D0B1F 193 | 5C692A38-2045-42F7-973B-E5D0C2558B03 194 | BAE8ED70-CF67-4D4A-99D8-02544053131C 195 | EAAF445C-947E-496B-A8B9-4FF45EEF8C5E 196 | 1E8299F1-916B-445B-BC6F-1D3657901BB5 197 | 4D051505-F739-4A2F-AC49-649A4ABA4271 198 | 8A9993E1-CA38-49B1-92D8-ADCA4CF9C4DD 199 | 317FF73B-9CCC-486D-827F-839F4C7EE855 200 | 69DBCB2D-ECFA-4515-A479-F96AE19FE25A 201 | 45736A34-CE6F-4F03-93F5-EB6F348A4AF8 202 | 8557FE6C-388E-4E3A-A725-94B3A505CCD8 203 | DB739633-6AF0-460A-BF34-86BAD8C22C4D 204 | 34FCB7E2-516C-4ADA-9CFC-BD3D5BA6D9C7 205 | 3F7582D4-F2C3-44B8-944E-CDA2F069A818 206 | CA000031-1DD5-42D8-9E7E-678B006B1978 207 | DA157B9A-792F-11D9-A212-000D93B3A10E 208 | DA18D8BE-792F-11D9-A212-000D93B3A10E 209 | 4405912F-4AD5-40F8-93B3-A63394036ACA 210 | 8D04C38E-0187-4E53-B100-AE096CBBB984 211 | C96D5804-7FA5-4CFE-8ADC-6F2F53B0FF01 212 | 0A1D9874-B448-11D9-BD50-000D93B6E43C 213 | F5E04BF4-69A9-45AE-9205-B3F3C2B00130 214 | E23C5DD2-9A36-4B4A-9729-2A769A055B92 215 | 15E0B3D5-8523-40EF-B767-5AF153FFD11E 216 | 146B2643-D903-49A8-9586-BE9C509D65B1 217 | C2DBC2F2-D859-4B35-A38E-244927A8447F 218 | C02A37C1-E770-472F-A13E-358FF0C6AD89 219 | 6D74AB8C-1903-4EB5-B0B6-AF16527F131C 220 | 4A05D483-795D-4B71-8537-3417B8450AD8 221 | 48600DF2-8E98-40C0-9FBD-D9B50EE73633 222 | 7A27A176-318B-403F-9228-D40B55CC6E85 223 | C70F0881-D108-47B1-A06F-09C74954E5C2 224 | 225 | uuid 226 | D99E8C0C-792F-11D9-A212-000D93B3A10E 227 | 228 | 229 | -------------------------------------------------------------------------------- /Support/bin/html2text.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """html2text: Turn HTML into equivalent Markdown-structured text.""" 3 | __version__ = "2.35" 4 | __author__ = "Aaron Swartz (me@aaronsw.com)" 5 | __copyright__ = "(C) 2004-2008 Aaron Swartz. GNU GPL 3." 6 | __contributors__ = ["Martin 'Joey' Schulze", "Ricardo Reyes"] 7 | 8 | # TODO: 9 | # Support decoded entities with unifiable. 10 | # Relative URL resolution 11 | 12 | if not hasattr(__builtins__, 'True'): True, False = 1, 0 13 | import re, sys, urllib, htmlentitydefs, codecs, StringIO, types 14 | import sgmllib 15 | sgmllib.charref = re.compile('&#([xX]?[0-9a-fA-F]+)[^0-9a-fA-F]') 16 | 17 | try: from textwrap import wrap 18 | except: pass 19 | 20 | # Use Unicode characters instead of their ascii psuedo-replacements 21 | UNICODE_SNOB = 0 22 | 23 | # Put the links after each paragraph instead of at the end. 24 | LINKS_EACH_PARAGRAPH = 0 25 | 26 | # Wrap long lines at position. 0 for no wrapping. (Requires Python 2.3.) 27 | BODY_WIDTH = 78 28 | 29 | # Don't show internal links (href="#local-anchor") -- corresponding link targets 30 | # won't be visible in the plain text file anyway. 31 | SKIP_INTERNAL_LINKS = False 32 | 33 | ### Entity Nonsense ### 34 | 35 | def name2cp(k): 36 | if k == 'apos': return ord("'") 37 | if hasattr(htmlentitydefs, "name2codepoint"): # requires Python 2.3 38 | return htmlentitydefs.name2codepoint[k] 39 | else: 40 | k = htmlentitydefs.entitydefs[k] 41 | if k.startswith("&#") and k.endswith(";"): return int(k[2:-1]) # not in latin-1 42 | return ord(codecs.latin_1_decode(k)[0]) 43 | 44 | unifiable = {'rsquo':"'", 'lsquo':"'", 'rdquo':'"', 'ldquo':'"', 45 | 'copy':'(C)', 'mdash':'--', 'nbsp':' ', 'rarr':'->', 'larr':'<-', 'middot':'*', 46 | 'ndash':'-', 'oelig':'oe', 'aelig':'ae', 47 | 'agrave':'a', 'aacute':'a', 'acirc':'a', 'atilde':'a', 'auml':'a', 'aring':'a', 48 | 'egrave':'e', 'eacute':'e', 'ecirc':'e', 'euml':'e', 49 | 'igrave':'i', 'iacute':'i', 'icirc':'i', 'iuml':'i', 50 | 'ograve':'o', 'oacute':'o', 'ocirc':'o', 'otilde':'o', 'ouml':'o', 51 | 'ugrave':'u', 'uacute':'u', 'ucirc':'u', 'uuml':'u'} 52 | 53 | unifiable_n = {} 54 | 55 | for k in unifiable.keys(): 56 | unifiable_n[name2cp(k)] = unifiable[k] 57 | 58 | def charref(name): 59 | if name[0] in ['x','X']: 60 | c = int(name[1:], 16) 61 | else: 62 | c = int(name) 63 | 64 | if not UNICODE_SNOB and c in unifiable_n.keys(): 65 | return unifiable_n[c] 66 | else: 67 | return unichr(c) 68 | 69 | def entityref(c): 70 | if not UNICODE_SNOB and c in unifiable.keys(): 71 | return unifiable[c] 72 | else: 73 | try: name2cp(c) 74 | except KeyError: return "&" + c 75 | else: return unichr(name2cp(c)) 76 | 77 | def replaceEntities(s): 78 | s = s.group(1) 79 | if s[0] == "#": 80 | return charref(s[1:]) 81 | else: return entityref(s) 82 | 83 | r_unescape = re.compile(r"&(#?[xX]?(?:[0-9a-fA-F]+|\w{1,8}));") 84 | def unescape(s): 85 | return r_unescape.sub(replaceEntities, s) 86 | 87 | def fixattrs(attrs): 88 | # Fix bug in sgmllib.py 89 | if not attrs: return attrs 90 | newattrs = [] 91 | for attr in attrs: 92 | newattrs.append((attr[0], unescape(attr[1]))) 93 | return newattrs 94 | 95 | ### End Entity Nonsense ### 96 | 97 | def onlywhite(line): 98 | """Return true if the line does only consist of whitespace characters.""" 99 | for c in line: 100 | if c is not ' ' and c is not ' ': 101 | return c is ' ' 102 | return line 103 | 104 | def optwrap(text): 105 | """Wrap all paragraphs in the provided text.""" 106 | if not BODY_WIDTH: 107 | return text 108 | 109 | assert wrap, "Requires Python 2.3." 110 | result = '' 111 | newlines = 0 112 | for para in text.split("\n"): 113 | if len(para) > 0: 114 | if para[0] is not ' ' and para[0] is not '-' and para[0] is not '*': 115 | for line in wrap(para, BODY_WIDTH): 116 | result += line + "\n" 117 | result += "\n" 118 | newlines = 2 119 | else: 120 | if not onlywhite(para): 121 | result += para + "\n" 122 | newlines = 1 123 | else: 124 | if newlines < 2: 125 | result += "\n" 126 | newlines += 1 127 | return result 128 | 129 | def hn(tag): 130 | if tag[0] == 'h' and len(tag) == 2: 131 | try: 132 | n = int(tag[1]) 133 | if n in range(1, 10): return n 134 | except ValueError: return 0 135 | 136 | class _html2text(sgmllib.SGMLParser): 137 | def __init__(self, out=sys.stdout.write): 138 | sgmllib.SGMLParser.__init__(self) 139 | 140 | if out is None: self.out = self.outtextf 141 | else: self.out = out 142 | self.outtext = u'' 143 | self.quiet = 0 144 | self.p_p = 0 145 | self.outcount = 0 146 | self.start = 1 147 | self.space = 0 148 | self.a = [] 149 | self.astack = [] 150 | self.acount = 0 151 | self.list = [] 152 | self.blockquote = 0 153 | self.pre = 0 154 | self.startpre = 0 155 | self.lastWasNL = 0 156 | self.abbr_title = None # current abbreviation definition 157 | self.abbr_data = None # last inner HTML (for abbr being defined) 158 | self.abbr_list = {} # stack of abbreviations to write later 159 | 160 | def outtextf(self, s): 161 | self.outtext += s 162 | 163 | def close(self): 164 | sgmllib.SGMLParser.close(self) 165 | 166 | self.pbr() 167 | self.o('', 0, 'end') 168 | 169 | return self.outtext 170 | 171 | def handle_charref(self, c): 172 | self.o(charref(c)) 173 | 174 | def handle_entityref(self, c): 175 | self.o(entityref(c)) 176 | 177 | def unknown_starttag(self, tag, attrs): 178 | self.handle_tag(tag, attrs, 1) 179 | 180 | def unknown_endtag(self, tag): 181 | self.handle_tag(tag, None, 0) 182 | 183 | def previousIndex(self, attrs): 184 | """ returns the index of certain set of attributes (of a link) in the 185 | self.a list 186 | 187 | If the set of attributes is not found, returns None 188 | """ 189 | if not attrs.has_key('href'): return None 190 | 191 | i = -1 192 | for a in self.a: 193 | i += 1 194 | match = 0 195 | 196 | if a.has_key('href') and a['href'] == attrs['href']: 197 | if a.has_key('title') or attrs.has_key('title'): 198 | if (a.has_key('title') and attrs.has_key('title') and 199 | a['title'] == attrs['title']): 200 | match = True 201 | else: 202 | match = True 203 | 204 | if match: return i 205 | 206 | def handle_tag(self, tag, attrs, start): 207 | attrs = fixattrs(attrs) 208 | 209 | if hn(tag): 210 | self.p() 211 | if start: self.o(hn(tag)*"#" + ' ') 212 | 213 | if tag in ['p', 'div']: self.p() 214 | 215 | if tag == "br" and start: self.o(" \n") 216 | 217 | if tag == "hr" and start: 218 | self.p() 219 | self.o("* * *") 220 | self.p() 221 | 222 | if tag in ["head", "style", 'script']: 223 | if start: self.quiet += 1 224 | else: self.quiet -= 1 225 | 226 | if tag in ["body"]: 227 | self.quiet = 0 # sites like 9rules.com never close 228 | 229 | if tag == "blockquote": 230 | if start: 231 | self.p(); self.o('> ', 0, 1); self.start = 1 232 | self.blockquote += 1 233 | else: 234 | self.blockquote -= 1 235 | self.p() 236 | 237 | if tag in ['em', 'i', 'u']: self.o("_") 238 | if tag in ['strong', 'b']: self.o("**") 239 | if tag == "code" and not self.pre: self.o('`') #TODO: `` `this` `` 240 | if tag == "abbr": 241 | if start: 242 | attrsD = {} 243 | for (x, y) in attrs: attrsD[x] = y 244 | attrs = attrsD 245 | 246 | self.abbr_title = None 247 | self.abbr_data = '' 248 | if attrs.has_key('title'): 249 | self.abbr_title = attrs['title'] 250 | else: 251 | if self.abbr_title != None: 252 | self.abbr_list[self.abbr_data] = self.abbr_title 253 | self.abbr_title = None 254 | self.abbr_data = '' 255 | 256 | if tag == "a": 257 | if start: 258 | attrsD = {} 259 | for (x, y) in attrs: attrsD[x] = y 260 | attrs = attrsD 261 | if attrs.has_key('href') and not (SKIP_INTERNAL_LINKS and attrs['href'].startswith('#')): 262 | self.astack.append(attrs) 263 | self.o("[") 264 | else: 265 | self.astack.append(None) 266 | else: 267 | if self.astack: 268 | a = self.astack.pop() 269 | if a: 270 | i = self.previousIndex(a) 271 | if i is not None: 272 | a = self.a[i] 273 | else: 274 | self.acount += 1 275 | a['count'] = self.acount 276 | a['outcount'] = self.outcount 277 | self.a.append(a) 278 | self.o("][" + `a['count']` + "]") 279 | 280 | if tag == "img" and start: 281 | attrsD = {} 282 | for (x, y) in attrs: attrsD[x] = y 283 | attrs = attrsD 284 | if attrs.has_key('src'): 285 | attrs['href'] = attrs['src'] 286 | alt = attrs.get('alt', '') 287 | i = self.previousIndex(attrs) 288 | if i is not None: 289 | attrs = self.a[i] 290 | else: 291 | self.acount += 1 292 | attrs['count'] = self.acount 293 | attrs['outcount'] = self.outcount 294 | self.a.append(attrs) 295 | self.o("![") 296 | self.o(alt) 297 | self.o("]["+`attrs['count']`+"]") 298 | 299 | if tag == 'dl' and start: self.p() 300 | if tag == 'dt' and not start: self.pbr() 301 | if tag == 'dd' and start: self.o(' ') 302 | if tag == 'dd' and not start: self.pbr() 303 | 304 | if tag in ["ol", "ul"]: 305 | if start: 306 | self.list.append({'name':tag, 'num':0}) 307 | else: 308 | if self.list: self.list.pop() 309 | 310 | self.p() 311 | 312 | if tag == 'li': 313 | if start: 314 | self.pbr() 315 | if self.list: li = self.list[-1] 316 | else: li = {'name':'ul', 'num':0} 317 | self.o(" "*len(self.list)) #TODO: line up
  1. s > 9 correctly. 318 | if li['name'] == "ul": self.o("* ") 319 | elif li['name'] == "ol": 320 | li['num'] += 1 321 | self.o(`li['num']`+". ") 322 | self.start = 1 323 | else: 324 | self.pbr() 325 | 326 | if tag in ["table", "tr"] and start: self.p() 327 | if tag == 'td': self.pbr() 328 | 329 | if tag == "pre": 330 | if start: 331 | self.startpre = 1 332 | self.pre = 1 333 | else: 334 | self.pre = 0 335 | self.p() 336 | 337 | def pbr(self): 338 | if self.p_p == 0: self.p_p = 1 339 | 340 | def p(self): self.p_p = 2 341 | 342 | def o(self, data, puredata=0, force=0): 343 | if self.abbr_data is not None: self.abbr_data += data 344 | 345 | if not self.quiet: 346 | if puredata and not self.pre: 347 | data = re.sub('\s+', ' ', data) 348 | if data and data[0] == ' ': 349 | self.space = 1 350 | data = data[1:] 351 | if not data and not force: return 352 | 353 | if self.startpre: 354 | #self.out(" :") #TODO: not output when already one there 355 | self.startpre = 0 356 | 357 | bq = (">" * self.blockquote) 358 | if not (force and data and data[0] == ">") and self.blockquote: bq += " " 359 | 360 | if self.pre: 361 | bq += " " 362 | data = data.replace("\n", "\n"+bq) 363 | 364 | if self.start: 365 | self.space = 0 366 | self.p_p = 0 367 | self.start = 0 368 | 369 | if force == 'end': 370 | # It's the end. 371 | self.p_p = 0 372 | self.out("\n") 373 | self.space = 0 374 | 375 | 376 | if self.p_p: 377 | self.out(('\n'+bq)*self.p_p) 378 | self.space = 0 379 | 380 | if self.space: 381 | if not self.lastWasNL: self.out(' ') 382 | self.space = 0 383 | 384 | if self.a and ((self.p_p == 2 and LINKS_EACH_PARAGRAPH) or force == "end"): 385 | if force == "end": self.out("\n") 386 | 387 | newa = [] 388 | for link in self.a: 389 | if self.outcount > link['outcount']: 390 | self.out(" ["+`link['count']`+"]: " + link['href']) #TODO: base href 391 | if link.has_key('title'): self.out(" ("+link['title']+")") 392 | self.out("\n") 393 | else: 394 | newa.append(link) 395 | 396 | if self.a != newa: self.out("\n") # Don't need an extra line when nothing was done. 397 | 398 | self.a = newa 399 | 400 | if self.abbr_list and force == "end": 401 | for abbr, definition in self.abbr_list.items(): 402 | self.out(" *[" + abbr + "]: " + definition + "\n") 403 | 404 | self.p_p = 0 405 | self.out(data) 406 | self.lastWasNL = data and data[-1] == '\n' 407 | self.outcount += 1 408 | 409 | def handle_data(self, data): 410 | if r'\/script>' in data: self.quiet -= 1 411 | self.o(data, 1) 412 | 413 | def unknown_decl(self, data): pass 414 | 415 | def wrapwrite(text): sys.stdout.write(text.encode('utf8')) 416 | 417 | def html2text_file(html, out=wrapwrite): 418 | h = _html2text(out) 419 | h.feed(html) 420 | h.feed("") 421 | return h.close() 422 | 423 | def html2text(html): 424 | return optwrap(html2text_file(html, None)) 425 | 426 | if __name__ == "__main__": 427 | if sys.argv[1:]: 428 | arg = sys.argv[1] 429 | if arg.startswith('http://'): 430 | j = urllib.urlopen(arg) 431 | try: 432 | from feedparser import _getCharacterEncoding as enc 433 | except ImportError: 434 | enc = lambda x, y: ('utf-8', 1) 435 | text = j.read() 436 | encoding = enc(j.headers, text)[0] 437 | if encoding == 'us-ascii': encoding = 'utf-8' 438 | data = text.decode(encoding) 439 | 440 | else: 441 | encoding = 'utf8' 442 | if len(sys.argv) > 2: 443 | encoding = sys.argv[2] 444 | data = open(arg, 'r').read().decode(encoding) 445 | else: 446 | data = sys.stdin.read().decode('utf8') 447 | wrapwrite(html2text(data)) 448 | 449 | -------------------------------------------------------------------------------- /Tests/test.markdown: -------------------------------------------------------------------------------- 1 | Markdown: Syntax 2 | ================ 3 | 4 | 11 | 12 | * [Overview](#overview) 13 | * [Philosophy](#philosophy) 14 | * [Inline HTML](#html) 15 | * [Automatic Escaping for Special Characters](#autoescape) 16 | * [Block Elements](#block) 17 | * [Paragraphs and Line Breaks](#p) 18 | * [Headers](#header) 19 | * [Blockquotes](#blockquote) 20 | * [Lists](#list) 21 | * [Code Blocks](#precode) 22 | * [Horizontal Rules](#hr) 23 | * [Span Elements](#span) 24 | * [Links](#link) 25 | * [Emphasis](#em) 26 | * [Code](#code) 27 | * [Images](#img) 28 | * [Miscellaneous](#misc) 29 | * [Backslash Escapes](#backslash) 30 | * [Automatic Links](#autolink) 31 | 32 | 33 | 34 | **Note:** This document is itself written using Markdown; you 35 | can [see the source for it by adding '.text' to the URL][src]. 36 | 37 | [src]: /projects/markdown/syntax.text 38 | 39 | * * * 40 | 41 |

    Overview

    42 | 43 |

    Philosophy

    44 | 45 | Markdown is intended to be as easy-to-read and easy-to-write as is feasible. 46 | 47 | Readability, however, is emphasized above all else. A Markdown-formatted 48 | document should be publishable as-is, as plain text, without looking 49 | like it's been marked up with tags or formatting instructions. While 50 | Markdown's syntax has been influenced by several existing text-to-HTML 51 | filters -- including [Setext] [1], [atx] [2], [Textile] [3], [reStructuredText] [4], 52 | [Grutatext] [5], and [EtText] [6] -- the single biggest source of 53 | inspiration for Markdown's syntax is the format of plain text email. 54 | 55 | [1]: http://docutils.sourceforge.net/mirror/setext.html 56 | [2]: http://www.aaronsw.com/2002/atx/ 57 | [3]: http://textism.com/tools/textile/ 58 | [4]: http://docutils.sourceforge.net/rst.html 59 | [5]: http://www.triptico.com/software/grutatxt.html 60 | [6]: http://ettext.taint.org/doc/ 61 | 62 | To this end, Markdown's syntax is comprised entirely of punctuation 63 | characters, which punctuation characters have been carefully chosen so 64 | as to look like what they mean. E.g., asterisks around a word actually 65 | look like \*emphasis\*. Markdown lists look like, well, lists. Even 66 | blockquotes look like quoted passages of text, assuming you've ever 67 | used email. 68 | 69 | 70 |

    Inline HTML

    71 | 72 | Markdown's syntax is intended for one purpose: to be used as a 73 | format for *writing* for the web. 74 | 75 | Markdown is not a replacement for HTML, or even close to it. Its 76 | syntax is very small, corresponding only to a very small subset of 77 | HTML tags. The idea is *not* to create a syntax that makes it easier 78 | to insert HTML tags. In my opinion, HTML tags are already easy to 79 | insert. The idea for Markdown is to make it easy to read, write, and 80 | edit prose. HTML is a *publishing* format; Markdown is a *writing* 81 | format. Thus, Markdown's formatting syntax only addresses issues that 82 | can be conveyed in plain text. 83 | 84 | For any markup that is not covered by Markdown's syntax, you simply 85 | use HTML itself. There's no need to preface it or delimit it to 86 | indicate that you're switching from Markdown to HTML; you just use 87 | the tags. 88 | 89 | The only restrictions are that block-level HTML elements -- e.g. `
    `, 90 | ``, `
    `, `

    `, etc. -- must be separated from surrounding 91 | content by blank lines, and the start and end tags of the block should 92 | not be indented with tabs or spaces. Markdown is smart enough not 93 | to add extra (unwanted) `

    ` tags around HTML block-level tags. 94 | 95 | For example, to add an HTML table to a Markdown article: 96 | 97 | This is a regular paragraph. 98 | 99 |

    100 | 101 | 102 | 103 |
    Foo
    104 | 105 | This is another regular paragraph. 106 | 107 | Note that Markdown formatting syntax is not processed within block-level 108 | HTML tags. E.g., you can't use Markdown-style `*emphasis*` inside an 109 | HTML block. 110 | 111 | Span-level HTML tags -- e.g. ``, ``, or `` -- can be 112 | used anywhere in a Markdown paragraph, list item, or header. If you 113 | want, you can even use HTML tags instead of Markdown formatting; e.g. if 114 | you'd prefer to use HTML `` or `` tags instead of Markdown's 115 | link or image syntax, go right ahead. 116 | 117 | Unlike block-level HTML tags, Markdown syntax *is* processed within 118 | span-level tags. 119 | 120 | 121 |

    Automatic Escaping for Special Characters

    122 | 123 | In HTML, there are two characters that demand special treatment: `<` 124 | and `&`. Left angle brackets are used to start tags; ampersands are 125 | used to denote HTML entities. If you want to use them as literal 126 | characters, you must escape them as entities, e.g. `<`, and 127 | `&`. 128 | 129 | Ampersands in particular are bedeviling for web writers. If you want to 130 | write about 'AT&T', you need to write '`AT&T`'. You even need to 131 | escape ampersands within URLs. Thus, if you want to link to: 132 | 133 | http://images.google.com/images?num=30&q=larry+bird 134 | 135 | you need to encode the URL as: 136 | 137 | http://images.google.com/images?num=30&q=larry+bird 138 | 139 | in your anchor tag `href` attribute. Needless to say, this is easy to 140 | forget, and is probably the single most common source of HTML validation 141 | errors in otherwise well-marked-up web sites. 142 | 143 | Markdown allows you to use these characters naturally, taking care of 144 | all the necessary escaping for you. If you use an ampersand as part of 145 | an HTML entity, it remains unchanged; otherwise it will be translated 146 | into `&`. 147 | 148 | So, if you want to include a copyright symbol in your article, you can write: 149 | 150 | © 151 | 152 | and Markdown will leave it alone. But if you write: 153 | 154 | AT&T 155 | 156 | Markdown will translate it to: 157 | 158 | AT&T 159 | 160 | Similarly, because Markdown supports [inline HTML](#html), if you use 161 | angle brackets as delimiters for HTML tags, Markdown will treat them as 162 | such. But if you write: 163 | 164 | 4 < 5 165 | 166 | Markdown will translate it to: 167 | 168 | 4 < 5 169 | 170 | However, inside Markdown code spans and blocks, angle brackets and 171 | ampersands are *always* encoded automatically. This makes it easy to use 172 | Markdown to write about HTML code. (As opposed to raw HTML, which is a 173 | terrible format for writing about HTML syntax, because every single `<` 174 | and `&` in your example code needs to be escaped.) 175 | 176 | 177 | * * * 178 | 179 | 180 |

    Block Elements

    181 | 182 | 183 |

    Paragraphs and Line Breaks

    184 | 185 | A paragraph is simply one or more consecutive lines of text, separated 186 | by one or more blank lines. (A blank line is any line that looks like a 187 | blank line -- a line containing nothing but spaces or tabs is considered 188 | blank.) Normal paragraphs should not be intended with spaces or tabs. 189 | 190 | The implication of the "one or more consecutive lines of text" rule is 191 | that Markdown supports "hard-wrapped" text paragraphs. This differs 192 | significantly from most other text-to-HTML formatters (including Movable 193 | Type's "Convert Line Breaks" option) which translate every line break 194 | character in a paragraph into a `
    ` tag. 195 | 196 | When you *do* want to insert a `
    ` break tag using Markdown, you 197 | end a line with two or more spaces, then type return. 198 | 199 | Yes, this takes a tad more effort to create a `
    `, but a simplistic 200 | "every line break is a `
    `" rule wouldn't work for Markdown. 201 | Markdown's email-style [blockquoting][bq] and multi-paragraph [list items][l] 202 | work best -- and look better -- when you format them with hard breaks. 203 | 204 | [bq]: #blockquote 205 | [l]: #list 206 | 207 | 208 | 209 | 210 | 211 | Markdown supports two styles of headers, [Setext] [1] and [atx] [2]. 212 | 213 | Setext-style headers are "underlined" using equal signs (for first-level 214 | headers) and dashes (for second-level headers). For example: 215 | 216 | This is an H1 217 | ============= 218 | 219 | This is an H2 220 | ------------- 221 | 222 | Any number of underlining `=`'s or `-`'s will work. 223 | 224 | Atx-style headers use 1-6 hash characters at the start of the line, 225 | corresponding to header levels 1-6. For example: 226 | 227 | # This is an H1 228 | 229 | ## This is an H2 230 | 231 | ###### This is an H6 232 | 233 | Optionally, you may "close" atx-style headers. This is purely 234 | cosmetic -- you can use this if you think it looks better. The 235 | closing hashes don't even need to match the number of hashes 236 | used to open the header. (The number of opening hashes 237 | determines the header level.) : 238 | 239 | # This is an H1 # 240 | 241 | ## This is an H2 ## 242 | 243 | ### This is an H3 ###### 244 | 245 | 246 |

    Blockquotes

    247 | 248 | Markdown uses email-style `>` characters for blockquoting. If you're 249 | familiar with quoting passages of text in an email message, then you 250 | know how to create a blockquote in Markdown. It looks best if you hard 251 | wrap the text and put a `>` before every line: 252 | 253 | > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, 254 | > consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. 255 | > Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. 256 | > 257 | > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse 258 | > id sem consectetuer libero luctus adipiscing. 259 | 260 | Markdown allows you to be lazy and only put the `>` before the first 261 | line of a hard-wrapped paragraph: 262 | 263 | > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, 264 | consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. 265 | Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. 266 | 267 | > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse 268 | id sem consectetuer libero luctus adipiscing. 269 | 270 | Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by 271 | adding additional levels of `>`: 272 | 273 | > This is the first level of quoting. 274 | > 275 | > > This is nested blockquote. 276 | > 277 | > Back to the first level. 278 | 279 | Blockquotes can contain other Markdown elements, including headers, lists, 280 | and code blocks: 281 | 282 | > ## This is a header. 283 | > 284 | > 1. This is the first list item. 285 | > 2. This is the second list item. 286 | > 287 | > Here's some example code: 288 | > 289 | > return shell_exec("echo $input | $markdown_script"); 290 | 291 | Any decent text editor should make email-style quoting easy. For 292 | example, with BBEdit, you can make a selection and choose Increase 293 | Quote Level from the Text menu. 294 | 295 | 296 |

    Lists

    297 | 298 | Markdown supports ordered (numbered) and unordered (bulleted) lists. 299 | 300 | Unordered lists use asterisks, pluses, and hyphens -- interchangably 301 | -- as list markers: 302 | 303 | * Red 304 | * Green 305 | * Blue 306 | 307 | is equivalent to: 308 | 309 | + Red 310 | + Green 311 | + Blue 312 | 313 | and: 314 | 315 | - Red 316 | - Green 317 | - Blue 318 | 319 | Ordered lists use numbers followed by periods: 320 | 321 | 1. Bird 322 | 2. McHale 323 | 3. Parish 324 | 325 | It's important to note that the actual numbers you use to mark the 326 | list have no effect on the HTML output Markdown produces. The HTML 327 | Markdown produces from the above list is: 328 | 329 |
      330 |
    1. Bird
    2. 331 |
    3. McHale
    4. 332 |
    5. Parish
    6. 333 |
    334 | 335 | If you instead wrote the list in Markdown like this: 336 | 337 | 1. Bird 338 | 1. McHale 339 | 1. Parish 340 | 341 | or even: 342 | 343 | 3. Bird 344 | 1. McHale 345 | 8. Parish 346 | 347 | you'd get the exact same HTML output. The point is, if you want to, 348 | you can use ordinal numbers in your ordered Markdown lists, so that 349 | the numbers in your source match the numbers in your published HTML. 350 | But if you want to be lazy, you don't have to. 351 | 352 | If you do use lazy list numbering, however, you should still start the 353 | list with the number 1. At some point in the future, Markdown may support 354 | starting ordered lists at an arbitrary number. 355 | 356 | List markers typically start at the left margin, but may be indented by 357 | up to three spaces. List markers must be followed by one or more spaces 358 | or a tab. 359 | 360 | To make lists look nice, you can wrap items with hanging indents: 361 | 362 | * Lorem ipsum dolor sit amet, consectetuer adipiscing elit. 363 | Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, 364 | viverra nec, fringilla in, laoreet vitae, risus. 365 | * Donec sit amet nisl. Aliquam semper ipsum sit amet velit. 366 | Suspendisse id sem consectetuer libero luctus adipiscing. 367 | 368 | But if you want to be lazy, you don't have to: 369 | 370 | * Lorem ipsum dolor sit amet, consectetuer adipiscing elit. 371 | Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, 372 | viverra nec, fringilla in, laoreet vitae, risus. 373 | * Donec sit amet nisl. Aliquam semper ipsum sit amet velit. 374 | Suspendisse id sem consectetuer libero luctus adipiscing. 375 | 376 | If list items are separated by blank lines, Markdown will wrap the 377 | items in `

    ` tags in the HTML output. For example, this input: 378 | 379 | * Bird 380 | * Magic 381 | 382 | will turn into: 383 | 384 |

      385 |
    • Bird
    • 386 |
    • Magic
    • 387 |
    388 | 389 | But this: 390 | 391 | * Bird 392 | 393 | * Magic 394 | 395 | will turn into: 396 | 397 |
      398 |
    • Bird

    • 399 |
    • Magic

    • 400 |
    401 | 402 | List items may consist of multiple paragraphs. Each subsequent 403 | paragraph in a list item must be intended by either 4 spaces 404 | or one tab: 405 | 406 | 1. This is a list item with two paragraphs. Lorem ipsum dolor 407 | sit amet, consectetuer adipiscing elit. Aliquam hendrerit 408 | mi posuere lectus. 409 | 410 | Vestibulum enim wisi, viverra nec, fringilla in, laoreet 411 | vitae, risus. Donec sit amet nisl. Aliquam semper ipsum 412 | sit amet velit. 413 | 414 | 2. Suspendisse id sem consectetuer libero luctus adipiscing. 415 | 416 | It looks nice if you indent every line of the subsequent 417 | paragraphs, but here again, Markdown will allow you to be 418 | lazy: 419 | 420 | * This is a list item with two paragraphs. 421 | 422 | This is the second paragraph in the list item. You're 423 | only required to indent the first line. Lorem ipsum dolor 424 | sit amet, consectetuer adipiscing elit. 425 | 426 | * Another item in the same list. 427 | 428 | To put a blockquote within a list item, the blockquote's `>` 429 | delimiters need to be indented: 430 | 431 | * A list item with a blockquote: 432 | 433 | > This is a blockquote 434 | > inside a list item. 435 | 436 | To put a code block within a list item, the code block needs 437 | to be indented *twice* -- 8 spaces or two tabs: 438 | 439 | * A list item with a code block: 440 | 441 | 442 | 443 | 444 | It's worth noting that it's possible to trigger an ordered list by 445 | accident, by writing something like this: 446 | 447 | 1986. What a great season. 448 | 449 | In other words, a *number-period-space* sequence at the beginning of a 450 | line. To avoid this, you can backslash-escape the period: 451 | 452 | 1986\. What a great season. 453 | 454 | 455 | 456 |

    Code Blocks

    457 | 458 | Pre-formatted code blocks are used for writing about programming or 459 | markup source code. Rather than forming normal paragraphs, the lines 460 | of a code block are interpreted literally. Markdown wraps a code block 461 | in both `
    ` and `` tags.
    462 | 
    463 | To produce a code block in Markdown, simply indent every line of the
    464 | block by at least 4 spaces or 1 tab. For example, given this input:
    465 | 
    466 |     This is a normal paragraph:
    467 | 
    468 |         This is a code block.
    469 | 
    470 | Markdown will generate:
    471 | 
    472 |     

    This is a normal paragraph:

    473 | 474 |
    This is a code block.
    475 |     
    476 | 477 | One level of indentation -- 4 spaces or 1 tab -- is removed from each 478 | line of the code block. For example, this: 479 | 480 | Here is an example of AppleScript: 481 | 482 | tell application "Foo" 483 | beep 484 | end tell 485 | 486 | will turn into: 487 | 488 |

    Here is an example of AppleScript:

    489 | 490 |
    tell application "Foo"
    491 |         beep
    492 |     end tell
    493 |     
    494 | 495 | A code block continues until it reaches a line that is not indented 496 | (or the end of the article). 497 | 498 | Within a code block, ampersands (`&`) and angle brackets (`<` and `>`) 499 | are automatically converted into HTML entities. This makes it very 500 | easy to include example HTML source code using Markdown -- just paste 501 | it and indent it, and Markdown will handle the hassle of encoding the 502 | ampersands and angle brackets. For example, this: 503 | 504 | 507 | 508 | will turn into: 509 | 510 |
    <div class="footer">
    511 |         &copy; 2004 Foo Corporation
    512 |     </div>
    513 |     
    514 | 515 | Regular Markdown syntax is not processed within code blocks. E.g., 516 | asterisks are just literal asterisks within a code block. This means 517 | it's also easy to use Markdown to write about Markdown's own syntax. 518 | 519 | 520 | 521 |

    Horizontal Rules

    522 | 523 | You can produce a horizontal rule tag (`
    `) by placing three or 524 | more hyphens, asterisks, or underscores on a line by themselves. If you 525 | wish, you may use spaces between the hyphens or asterisks. Each of the 526 | following lines will produce a horizontal rule: 527 | 528 | * * * 529 | 530 | *** 531 | 532 | ***** 533 | 534 | - - - 535 | 536 | --------------------------------------- 537 | 538 | _ _ _ 539 | 540 | 541 | * * * 542 | 543 |

    Span Elements

    544 | 545 | 546 | 547 | Markdown supports two style of links: *inline* and *reference*. 548 | 549 | In both styles, the link text is delimited by [square brackets]. 550 | 551 | To create an inline link, use a set of regular parentheses immediately 552 | after the link text's closing square bracket. Inside the parentheses, 553 | put the URL where you want the link to point, along with an *optional* 554 | title for the link, surrounded in quotes. For example: 555 | 556 | This is [an example](http://example.com/ "Title") inline link. 557 | 558 | [This link](http://example.net/) has no title attribute. 559 | 560 | Will produce: 561 | 562 |

    This is 563 | an example inline link.

    564 | 565 |

    This link has no 566 | title attribute.

    567 | 568 | If you're referring to a local resource on the same server, you can 569 | use relative paths: 570 | 571 | See my [About](/about/) page for details. 572 | 573 | Reference-style links use a second set of square brackets, inside 574 | which you place a label of your choosing to identify the link: 575 | 576 | This is [an example][id] reference-style link. 577 | 578 | You can optionally use a space to separate the sets of brackets: 579 | 580 | This is [an example] [id] reference-style link. 581 | 582 | Then, anywhere in the document, you define your link label like this, 583 | on a line by itself: 584 | 585 | [id]: http://example.com/ "Optional Title Here" 586 | 587 | That is: 588 | 589 | * Square brackets containing the link identifier (optionally 590 | indented from the left margin using spaces or tabs); 591 | * followed by a colon; 592 | * followed by one or more spaces (or tabs); 593 | * followed by the URL for the link; 594 | * optionally followed by a title attribute for the link, enclosed 595 | in double or single quotes. 596 | 597 | The link URL may, optionally, be surrounded by angle brackets: 598 | 599 | [id]: "Optional Title Here" 600 | 601 | You can put the title attribute on the next line and use extra spaces 602 | or tabs for padding, which tends to look better with longer URLs: 603 | 604 | [id]: http://example.com/longish/path/to/resource/here 605 | "Optional Title Here" 606 | 607 | Link definitions are only used for creating links during Markdown 608 | processing, and are stripped from your document in the HTML output. 609 | 610 | Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are *not* case sensitive. E.g. these two links: 611 | 612 | [link text][a] 613 | [link text][A] 614 | 615 | are equivalent. 616 | 617 | The *implicit link name* shortcut allows you to omit the name of the 618 | link, in which case the link text itself is used as the name. 619 | Just use an empty set of square brackets -- e.g., to link the word 620 | "Google" to the google.com web site, you could simply write: 621 | 622 | [Google][] 623 | 624 | And then define the link: 625 | 626 | [Google]: http://google.com/ 627 | 628 | Because link names may contain spaces, this shortcut even works for 629 | multiple words in the link text: 630 | 631 | Visit [Daring Fireball][] for more information. 632 | 633 | And then define the link: 634 | 635 | [Daring Fireball]: http://daringfireball.net/ 636 | 637 | Link definitions can be placed anywhere in your Markdown document. I 638 | tend to put them immediately after each paragraph in which they're 639 | used, but if you want, you can put them all at the end of your 640 | document, sort of like footnotes. 641 | 642 | Here's an example of reference links in action: 643 | 644 | I get 10 times more traffic from [Google] [1] than from 645 | [Yahoo] [2] or [MSN] [3]. 646 | 647 | [1]: http://google.com/ "Google" 648 | [2]: http://search.yahoo.com/ "Yahoo Search" 649 | [3]: http://search.msn.com/ "MSN Search" 650 | 651 | Using the implicit link name shortcut, you could instead write: 652 | 653 | I get 10 times more traffic from [Google][] than from 654 | [Yahoo][] or [MSN][]. 655 | 656 | [google]: http://google.com/ "Google" 657 | [yahoo]: http://search.yahoo.com/ "Yahoo Search" 658 | [msn]: http://search.msn.com/ "MSN Search" 659 | 660 | Both of the above examples will produce the following HTML output: 661 | 662 |

    I get 10 times more traffic from Google than from 664 | Yahoo 665 | or MSN.

    666 | 667 | For comparison, here is the same paragraph written using 668 | Markdown's inline link style: 669 | 670 | I get 10 times more traffic from [Google](http://google.com/ "Google") 671 | than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or 672 | [MSN](http://search.msn.com/ "MSN Search"). 673 | 674 | The point of reference-style links is not that they're easier to 675 | write. The point is that with reference-style links, your document 676 | source is vastly more readable. Compare the above examples: using 677 | reference-style links, the paragraph itself is only 81 characters 678 | long; with inline-style links, it's 176 characters; and as raw HTML, 679 | it's 234 characters. In the raw HTML, there's more markup than there 680 | is text. 681 | 682 | With Markdown's reference-style links, a source document much more 683 | closely resembles the final output, as rendered in a browser. By 684 | allowing you to move the markup-related metadata out of the paragraph, 685 | you can add links without interrupting the narrative flow of your 686 | prose. 687 | 688 | 689 |

    Emphasis

    690 | 691 | Markdown treats asterisks (`*`) and underscores (`_`) as indicators of 692 | emphasis. Text wrapped with one `*` or `_` will be wrapped with an 693 | HTML `` tag; double `*`'s or `_`'s will be wrapped with an HTML 694 | `` tag. E.g., this input: 695 | 696 | *single asterisks* 697 | 698 | _single underscores_ 699 | 700 | **double asterisks** 701 | 702 | __double underscores__ 703 | 704 | will produce: 705 | 706 | single asterisks 707 | 708 | single underscores 709 | 710 | double asterisks 711 | 712 | double underscores 713 | 714 | You can use whichever style you prefer; the lone restriction is that 715 | the same character must be used to open and close an emphasis span. 716 | 717 | Emphasis can be used in the middle of a word: 718 | 719 | un*fucking*believable 720 | 721 | But if you surround an `*` or `_` with spaces, it'll be treated as a 722 | literal asterisk or underscore. 723 | 724 | To produce a literal asterisk or underscore at a position where it 725 | would otherwise be used as an emphasis delimiter, you can backslash 726 | escape it: 727 | 728 | \\*this text is surrounded by literal asterisks\\* 729 | 730 | 731 | 732 |

    Code

    733 | 734 | To indicate a span of code, wrap it with backtick quotes (`` ` ``). 735 | Unlike a pre-formatted code block, a code span indicates code within a 736 | normal paragraph. For example: 737 | 738 | Use the `printf()` function. 739 | 740 | will produce: 741 | 742 |

    Use the printf() function.

    743 | 744 | To include a literal backtick character within a code span, you can 745 | backslash escape it: 746 | 747 | `There is a literal backtick (\`) here.` 748 | 749 | Or, if you prefer, you can use multiple backticks as the opening and 750 | closing delimiters: 751 | 752 | ``There is a literal backtick (`) here.`` 753 | 754 | Both of the previous two examples will produce this: 755 | 756 |

    There is a literal backtick (`) here.

    757 | 758 | With a code span, ampersands and angle brackets are encoded as HTML 759 | entities automatically, which makes it easy to include example HTML 760 | tags. Markdown will turn this: 761 | 762 | Please don't use any `` tags. 763 | 764 | into: 765 | 766 |

    Please don't use any <blink> tags.

    767 | 768 | You can write this: 769 | 770 | `—` is the decimal-encoded equivalent of `—`. 771 | 772 | to produce: 773 | 774 |

    &#8212; is the decimal-encoded 775 | equivalent of &mdash;.

    776 | 777 | 778 | 779 |

    Images

    780 | 781 | Admittedly, it's fairly difficult to devise a "natural" syntax for 782 | placing images into a plain text document format. 783 | 784 | Markdown uses an image syntax that is intended to resemble the syntax 785 | for links, allowing for two styles: *inline* and *reference*. 786 | 787 | Inline image syntax looks like this: 788 | 789 | ![Alt text](/path/to/img.jpg) 790 | 791 | ![Alt text](/path/to/img.jpg "Optional title") 792 | 793 | That is: 794 | 795 | * An exclamation mark: `!`; 796 | * followed by a set of square brackets, containing the `alt` 797 | attribute text for the image; 798 | * followed by a set of parentheses, containing the URL or path to 799 | the image, and an optional `title` attribute enclosed in double 800 | or single quotes. 801 | 802 | Reference-style image syntax looks like this: 803 | 804 | ![Alt text][id] 805 | 806 | Where "id" is the name of a defined image reference. Image references 807 | are defined using syntax identical to link references: 808 | 809 | [id]: url/to/image "Optional title attribute" 810 | 811 | As of this writing, Markdown has no syntax for specifying the 812 | dimensions of an image; if this is important to you, you can simply 813 | use regular HTML `` tags. 814 | 815 | 816 | * * * 817 | 818 | 819 |

    Miscellaneous

    820 | 821 | 822 | 823 | Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this: 824 | 825 | 826 | 827 | Markdown will turn this into: 828 | 829 | http://example.com/ 830 | 831 | Automatic links for email addresses work similarly, except that 832 | Markdown will also perform a bit of randomized decimal and hex 833 | entity-encoding to help obscure your address from address-harvesting 834 | spambots. For example, Markdown will turn this: 835 | 836 | 837 | 838 | into something like this: 839 | 840 | address@exa 843 | mple.com 844 | 845 | which will render in a browser as a clickable link to "address@example.com". 846 | 847 | (This sort of entity-encoding trick will indeed fool many, if not 848 | most, address-harvesting bots, but it definitely won't fool all of 849 | them. It's better than nothing, but an address published in this way 850 | will probably eventually start receiving spam.) 851 | 852 | 853 | 854 |

    Backslash Escapes

    855 | 856 | Markdown allows you to use backslash escapes to generate literal 857 | characters which would otherwise have special meaning in Markdown's 858 | formatting syntax. For example, if you wanted to surround a word with 859 | literal asterisks (instead of an HTML `` tag), you can backslashes 860 | before the asterisks, like this: 861 | 862 | \*literal asterisks\* 863 | 864 | Markdown provides backslash escapes for the following characters: 865 | 866 | \ backslash 867 | ` backtick 868 | * asterisk 869 | _ underscore 870 | {} curly braces 871 | [] square brackets 872 | () parentheses 873 | # hash mark 874 | . dot 875 | ! exclamation mark 876 | 877 | -------------------------------------------------------------------------------- /Syntaxes/Markdown.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fileTypes 6 | 7 | mdown 8 | markdown 9 | markdn 10 | md 11 | 12 | foldingStartMarker 13 | (?x) 14 | (<(?i:head|body|table|thead|tbody|tfoot|tr|div|select|fieldset|style|script|ul|ol|form|dl)\b.*?> 15 | |<!--(?!.*-->) 16 | |\{\s*($|\?>\s*$|//|/\*(.*\*/\s*$|(?!.*?\*/))) 17 | ) 18 | foldingStopMarker 19 | (?x) 20 | (</(?i:head|body|table|thead|tbody|tfoot|tr|div|select|fieldset|style|script|ul|ol|form|dl)> 21 | |^\s*--> 22 | |(^|\s)\} 23 | ) 24 | keyEquivalent 25 | ^~M 26 | name 27 | Markdown 28 | patterns 29 | 30 | 31 | begin 32 | (?x)^ 33 | (?= [ ]{,3}>. 34 | | ([ ]{4}|\t)(?!$) 35 | | [#]{1,6}\s*+ 36 | | [ ]{,3}(?<marker>[-*_])([ ]{,2}\k<marker>){2,}[ \t]*+$ 37 | ) 38 | comment 39 | 40 | We could also use an empty end match and set 41 | applyEndPatternLast, but then we must be sure that the begin 42 | pattern will only match stuff matched by the sub-patterns. 43 | 44 | end 45 | (?x)^ 46 | (?! [ ]{,3}>. 47 | | ([ ]{4}|\t) 48 | | [#]{1,6}\s*+ 49 | | [ ]{,3}(?<marker>[-*_])([ ]{,2}\k<marker>){2,}[ \t]*+$ 50 | ) 51 | name 52 | meta.block-level.markdown 53 | patterns 54 | 55 | 56 | include 57 | #block_quote 58 | 59 | 60 | include 61 | #block_raw 62 | 63 | 64 | include 65 | #heading 66 | 67 | 68 | include 69 | #separator 70 | 71 | 72 | 73 | 74 | begin 75 | ^[ ]{0,3}([*+-])(?=\s) 76 | captures 77 | 78 | 1 79 | 80 | name 81 | punctuation.definition.list_item.markdown 82 | 83 | 84 | end 85 | ^(?=\S) 86 | name 87 | markup.list.unnumbered.markdown 88 | patterns 89 | 90 | 91 | include 92 | #list-paragraph 93 | 94 | 95 | 96 | 97 | begin 98 | ^[ ]{0,3}([0-9]+\.)(?=\s) 99 | captures 100 | 101 | 1 102 | 103 | name 104 | punctuation.definition.list_item.markdown 105 | 106 | 107 | end 108 | ^(?=\S) 109 | name 110 | markup.list.numbered.markdown 111 | patterns 112 | 113 | 114 | include 115 | #list-paragraph 116 | 117 | 118 | 119 | 120 | begin 121 | ^(?=<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b)(?!.*?</\1>) 122 | comment 123 | 124 | Markdown formatting is disabled inside block-level tags. 125 | 126 | end 127 | (?<=^</\1>$\n) 128 | name 129 | meta.disable-markdown 130 | patterns 131 | 132 | 133 | include 134 | text.html.basic 135 | 136 | 137 | 138 | 139 | begin 140 | ^(?=<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b) 141 | comment 142 | Same rule but for one line disables. 143 | end 144 | $\n? 145 | name 146 | meta.disable-markdown 147 | patterns 148 | 149 | 150 | include 151 | text.html.basic 152 | 153 | 154 | 155 | 156 | captures 157 | 158 | 1 159 | 160 | name 161 | punctuation.definition.constant.markdown 162 | 163 | 10 164 | 165 | name 166 | punctuation.definition.string.end.markdown 167 | 168 | 11 169 | 170 | name 171 | string.other.link.description.title.markdown 172 | 173 | 12 174 | 175 | name 176 | punctuation.definition.string.begin.markdown 177 | 178 | 13 179 | 180 | name 181 | punctuation.definition.string.end.markdown 182 | 183 | 2 184 | 185 | name 186 | constant.other.reference.link.markdown 187 | 188 | 3 189 | 190 | name 191 | punctuation.definition.constant.markdown 192 | 193 | 4 194 | 195 | name 196 | punctuation.separator.key-value.markdown 197 | 198 | 5 199 | 200 | name 201 | punctuation.definition.link.markdown 202 | 203 | 6 204 | 205 | name 206 | markup.underline.link.markdown 207 | 208 | 7 209 | 210 | name 211 | punctuation.definition.link.markdown 212 | 213 | 8 214 | 215 | name 216 | string.other.link.description.title.markdown 217 | 218 | 9 219 | 220 | name 221 | punctuation.definition.string.begin.markdown 222 | 223 | 224 | match 225 | (?x: 226 | \s* # Leading whitespace 227 | (\[)(.+?)(\])(:) # Reference name 228 | [ \t]* # Optional whitespace 229 | (<?)(\S+?)(>?) # The url 230 | [ \t]* # Optional whitespace 231 | (?: 232 | ((\().+?(\))) # Match title in quotes… 233 | | ((").+?(")) # or in parens. 234 | )? # Title is optional 235 | \s* # Optional whitespace 236 | $ 237 | ) 238 | name 239 | meta.link.reference.def.markdown 240 | 241 | 242 | begin 243 | ^(?=\S)(?![=-]{3,}(?=$)) 244 | end 245 | ^(?:\s*$|(?=[ ]{,3}>.))|(?=[ \t]*\n)(?<=^===|^====|=====|^---|^----|-----)[ \t]*\n|(?=^#) 246 | name 247 | meta.paragraph.markdown 248 | patterns 249 | 250 | 251 | include 252 | #inline 253 | 254 | 255 | include 256 | text.html.basic 257 | 258 | 259 | captures 260 | 261 | 1 262 | 263 | name 264 | punctuation.definition.heading.markdown 265 | 266 | 267 | match 268 | ^(={3,})(?=[ \t]*$) 269 | name 270 | markup.heading.1.markdown 271 | 272 | 273 | captures 274 | 275 | 1 276 | 277 | name 278 | punctuation.definition.heading.markdown 279 | 280 | 281 | match 282 | ^(-{3,})(?=[ \t]*$) 283 | name 284 | markup.heading.2.markdown 285 | 286 | 287 | 288 | 289 | repository 290 | 291 | ampersand 292 | 293 | comment 294 | 295 | Markdown will convert this for us. We match it so that the 296 | HTML grammar will not mark it up as invalid. 297 | 298 | match 299 | &(?!([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+);) 300 | name 301 | meta.other.valid-ampersand.markdown 302 | 303 | block_quote 304 | 305 | begin 306 | \G[ ]{,3}(>)(?!$)[ ]? 307 | beginCaptures 308 | 309 | 1 310 | 311 | name 312 | punctuation.definition.blockquote.markdown 313 | 314 | 315 | comment 316 | 317 | We terminate the block quote when seeing an empty line, a 318 | separator or a line with leading > characters. The latter is 319 | to “reset” the quote level for quoted lines. 320 | 321 | end 322 | (?x)^ 323 | (?= \s*$ 324 | | [ ]{,3}(?<marker>[-*_])([ ]{,2}\k<marker>){2,}[ \t]*+$ 325 | | [ ]{,3}>. 326 | ) 327 | name 328 | markup.quote.markdown 329 | patterns 330 | 331 | 332 | begin 333 | (?x)\G 334 | (?= [ ]{,3}>. 335 | ) 336 | end 337 | ^ 338 | patterns 339 | 340 | 341 | include 342 | #block_quote 343 | 344 | 345 | 346 | 347 | applyEndPatternLast 348 | 1 349 | begin 350 | (?x)\G 351 | (?= ([ ]{4}|\t) 352 | | [#]{1,6}\s*+ 353 | | [ ]{,3}(?<marker>[-*_])([ ]{,2}\k<marker>){2,}[ \t]*+$ 354 | ) 355 | end 356 | ^ 357 | patterns 358 | 359 | 360 | include 361 | #block_raw 362 | 363 | 364 | include 365 | #heading 366 | 367 | 368 | include 369 | #separator 370 | 371 | 372 | 373 | 374 | begin 375 | (?x)\G 376 | (?! $ 377 | | [ ]{,3}>. 378 | | ([ ]{4}|\t) 379 | | [#]{1,6}\s*+ 380 | | [ ]{,3}(?<marker>[-*_])([ ]{,2}\k<marker>){2,}[ \t]*+$ 381 | ) 382 | end 383 | $|(?<=\n) 384 | patterns 385 | 386 | 387 | include 388 | #inline 389 | 390 | 391 | 392 | 393 | 394 | block_raw 395 | 396 | match 397 | \G([ ]{4}|\t).*$\n? 398 | name 399 | markup.raw.block.markdown 400 | 401 | bold 402 | 403 | begin 404 | (?x) 405 | (\*\*|__)(?=\S) # Open 406 | (?= 407 | ( 408 | <[^>]*+> # HTML tags 409 | | (?<raw>`+)([^`]|(?!(?<!`)\k<raw>(?!`))`)*+\k<raw> 410 | # Raw 411 | | \\[\\`*_{}\[\]()#.!+\->]?+ # Escapes 412 | | \[ 413 | ( 414 | (?<square> # Named group 415 | [^\[\]\\] # Match most chars 416 | | \\. # Escaped chars 417 | | \[ \g<square>*+ \] # Nested brackets 418 | )*+ 419 | \] 420 | ( 421 | ( # Reference Link 422 | [ ]? # Optional space 423 | \[[^\]]*+\] # Ref name 424 | ) 425 | | ( # Inline Link 426 | \( # Opening paren 427 | [ \t]*+ # Optional whtiespace 428 | <?(.*?)>? # URL 429 | [ \t]*+ # Optional whtiespace 430 | ( # Optional Title 431 | (?<title>['"]) 432 | (.*?) 433 | \k<title> 434 | )? 435 | \) 436 | ) 437 | ) 438 | ) 439 | | (?!(?<=\S)\1). # Everything besides 440 | # style closer 441 | )++ 442 | (?<=\S)\1 # Close 443 | ) 444 | 445 | captures 446 | 447 | 1 448 | 449 | name 450 | punctuation.definition.bold.markdown 451 | 452 | 453 | end 454 | (?<=\S)(\1) 455 | name 456 | markup.bold.markdown 457 | patterns 458 | 459 | 460 | applyEndPatternLast 461 | 1 462 | begin 463 | (?=<[^>]*?>) 464 | end 465 | (?<=>) 466 | patterns 467 | 468 | 469 | include 470 | text.html.basic 471 | 472 | 473 | 474 | 475 | include 476 | #escape 477 | 478 | 479 | include 480 | #ampersand 481 | 482 | 483 | include 484 | #bracket 485 | 486 | 487 | include 488 | #raw 489 | 490 | 491 | include 492 | #italic 493 | 494 | 495 | include 496 | #image-inline 497 | 498 | 499 | include 500 | #link-inline 501 | 502 | 503 | include 504 | #link-inet 505 | 506 | 507 | include 508 | #link-email 509 | 510 | 511 | include 512 | #image-ref 513 | 514 | 515 | include 516 | #link-ref-literal 517 | 518 | 519 | include 520 | #link-ref 521 | 522 | 523 | 524 | bracket 525 | 526 | comment 527 | 528 | Markdown will convert this for us. We match it so that the 529 | HTML grammar will not mark it up as invalid. 530 | 531 | match 532 | <(?![a-z/?\$!]) 533 | name 534 | meta.other.valid-bracket.markdown 535 | 536 | escape 537 | 538 | match 539 | \\[-`*_#+.!(){}\[\]\\>] 540 | name 541 | constant.character.escape.markdown 542 | 543 | heading 544 | 545 | begin 546 | \G(#{1,6})(?!#)\s*(?=\S) 547 | captures 548 | 549 | 1 550 | 551 | name 552 | punctuation.definition.heading.markdown 553 | 554 | 555 | contentName 556 | entity.name.section.markdown 557 | end 558 | \s*(#*)$\n? 559 | name 560 | markup.heading.markdown 561 | patterns 562 | 563 | 564 | include 565 | #inline 566 | 567 | 568 | 569 | image-inline 570 | 571 | captures 572 | 573 | 1 574 | 575 | name 576 | punctuation.definition.string.begin.markdown 577 | 578 | 10 579 | 580 | name 581 | string.other.link.description.title.markdown 582 | 583 | 11 584 | 585 | name 586 | punctuation.definition.string.markdown 587 | 588 | 12 589 | 590 | name 591 | punctuation.definition.string.markdown 592 | 593 | 13 594 | 595 | name 596 | string.other.link.description.title.markdown 597 | 598 | 14 599 | 600 | name 601 | punctuation.definition.string.markdown 602 | 603 | 15 604 | 605 | name 606 | punctuation.definition.string.markdown 607 | 608 | 16 609 | 610 | name 611 | punctuation.definition.metadata.markdown 612 | 613 | 2 614 | 615 | name 616 | string.other.link.description.markdown 617 | 618 | 3 619 | 620 | name 621 | punctuation.definition.string.end.markdown 622 | 623 | 5 624 | 625 | name 626 | invalid.illegal.whitespace.markdown 627 | 628 | 6 629 | 630 | name 631 | punctuation.definition.metadata.markdown 632 | 633 | 7 634 | 635 | name 636 | punctuation.definition.link.markdown 637 | 638 | 8 639 | 640 | name 641 | markup.underline.link.image.markdown 642 | 643 | 9 644 | 645 | name 646 | punctuation.definition.link.markdown 647 | 648 | 649 | match 650 | (?x: 651 | \! # Images start with ! 652 | (\[)((?<square>[^\[\]\\]|\\.|\[\g<square>*+\])*+)(\]) 653 | # Match the link text. 654 | ([ ])? # Space not allowed 655 | (\() # Opening paren for url 656 | (<?)(\S+?)(>?) # The url 657 | [ \t]* # Optional whitespace 658 | (?: 659 | ((\().+?(\))) # Match title in parens… 660 | | ((").+?(")) # or in quotes. 661 | )? # Title is optional 662 | \s* # Optional whitespace 663 | (\)) 664 | ) 665 | name 666 | meta.image.inline.markdown 667 | 668 | image-ref 669 | 670 | captures 671 | 672 | 1 673 | 674 | name 675 | punctuation.definition.string.begin.markdown 676 | 677 | 2 678 | 679 | name 680 | string.other.link.description.markdown 681 | 682 | 4 683 | 684 | name 685 | punctuation.definition.string.begin.markdown 686 | 687 | 5 688 | 689 | name 690 | punctuation.definition.constant.markdown 691 | 692 | 6 693 | 694 | name 695 | constant.other.reference.link.markdown 696 | 697 | 7 698 | 699 | name 700 | punctuation.definition.constant.markdown 701 | 702 | 703 | match 704 | \!(\[)((?<square>[^\[\]\\]|\\.|\[\g<square>*+\])*+)(\])[ ]?(\[)(.*?)(\]) 705 | name 706 | meta.image.reference.markdown 707 | 708 | inline 709 | 710 | patterns 711 | 712 | 713 | include 714 | #escape 715 | 716 | 717 | include 718 | #ampersand 719 | 720 | 721 | include 722 | #bracket 723 | 724 | 725 | include 726 | #raw 727 | 728 | 729 | include 730 | #bold 731 | 732 | 733 | include 734 | #italic 735 | 736 | 737 | include 738 | #line-break 739 | 740 | 741 | include 742 | #image-inline 743 | 744 | 745 | include 746 | #link-inline 747 | 748 | 749 | include 750 | #link-inet 751 | 752 | 753 | include 754 | #link-email 755 | 756 | 757 | include 758 | #image-ref 759 | 760 | 761 | include 762 | #link-ref-literal 763 | 764 | 765 | include 766 | #link-ref 767 | 768 | 769 | 770 | italic 771 | 772 | begin 773 | (?x) 774 | (\*|_)(?=\S) # Open 775 | (?= 776 | ( 777 | <[^>]*+> # HTML tags 778 | | (?<raw>`+)([^`]|(?!(?<!`)\k<raw>(?!`))`)*+\k<raw> 779 | # Raw 780 | | \\[\\`*_{}\[\]()#.!+\->]?+ # Escapes 781 | | \[ 782 | ( 783 | (?<square> # Named group 784 | [^\[\]\\] # Match most chars 785 | | \\. # Escaped chars 786 | | \[ \g<square>*+ \] # Nested brackets 787 | )*+ 788 | \] 789 | ( 790 | ( # Reference Link 791 | [ ]? # Optional space 792 | \[[^\]]*+\] # Ref name 793 | ) 794 | | ( # Inline Link 795 | \( # Opening paren 796 | [ \t]*+ # Optional whtiespace 797 | <?(.*?)>? # URL 798 | [ \t]*+ # Optional whtiespace 799 | ( # Optional Title 800 | (?<title>['"]) 801 | (.*?) 802 | \k<title> 803 | )? 804 | \) 805 | ) 806 | ) 807 | ) 808 | | \1\1 # Must be bold closer 809 | | (?!(?<=\S)\1). # Everything besides 810 | # style closer 811 | )++ 812 | (?<=\S)\1 # Close 813 | ) 814 | 815 | captures 816 | 817 | 1 818 | 819 | name 820 | punctuation.definition.italic.markdown 821 | 822 | 823 | end 824 | (?<=\S)(\1)((?!\1)|(?=\1\1)) 825 | name 826 | markup.italic.markdown 827 | patterns 828 | 829 | 830 | applyEndPatternLast 831 | 1 832 | begin 833 | (?=<[^>]*?>) 834 | end 835 | (?<=>) 836 | patterns 837 | 838 | 839 | include 840 | text.html.basic 841 | 842 | 843 | 844 | 845 | include 846 | #escape 847 | 848 | 849 | include 850 | #ampersand 851 | 852 | 853 | include 854 | #bracket 855 | 856 | 857 | include 858 | #raw 859 | 860 | 861 | include 862 | #bold 863 | 864 | 865 | include 866 | #image-inline 867 | 868 | 869 | include 870 | #link-inline 871 | 872 | 873 | include 874 | #link-inet 875 | 876 | 877 | include 878 | #link-email 879 | 880 | 881 | include 882 | #image-ref 883 | 884 | 885 | include 886 | #link-ref-literal 887 | 888 | 889 | include 890 | #link-ref 891 | 892 | 893 | 894 | line-break 895 | 896 | match 897 | {2,}$ 898 | name 899 | meta.dummy.line-break 900 | 901 | link-email 902 | 903 | captures 904 | 905 | 1 906 | 907 | name 908 | punctuation.definition.link.markdown 909 | 910 | 2 911 | 912 | name 913 | markup.underline.link.markdown 914 | 915 | 4 916 | 917 | name 918 | punctuation.definition.link.markdown 919 | 920 | 921 | match 922 | (<)((?:mailto:)?[-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(>) 923 | name 924 | meta.link.email.lt-gt.markdown 925 | 926 | link-inet 927 | 928 | captures 929 | 930 | 1 931 | 932 | name 933 | punctuation.definition.link.markdown 934 | 935 | 2 936 | 937 | name 938 | markup.underline.link.markdown 939 | 940 | 3 941 | 942 | name 943 | punctuation.definition.link.markdown 944 | 945 | 946 | match 947 | (<)((?:https?|ftp)://.*?)(>) 948 | name 949 | meta.link.inet.markdown 950 | 951 | link-inline 952 | 953 | captures 954 | 955 | 1 956 | 957 | name 958 | punctuation.definition.string.begin.markdown 959 | 960 | 10 961 | 962 | name 963 | string.other.link.description.title.markdown 964 | 965 | 11 966 | 967 | name 968 | punctuation.definition.string.begin.markdown 969 | 970 | 12 971 | 972 | name 973 | punctuation.definition.string.end.markdown 974 | 975 | 13 976 | 977 | name 978 | string.other.link.description.title.markdown 979 | 980 | 14 981 | 982 | name 983 | punctuation.definition.string.begin.markdown 984 | 985 | 15 986 | 987 | name 988 | punctuation.definition.string.end.markdown 989 | 990 | 16 991 | 992 | name 993 | punctuation.definition.metadata.markdown 994 | 995 | 2 996 | 997 | name 998 | string.other.link.title.markdown 999 | 1000 | 4 1001 | 1002 | name 1003 | punctuation.definition.string.end.markdown 1004 | 1005 | 5 1006 | 1007 | name 1008 | invalid.illegal.whitespace.markdown 1009 | 1010 | 6 1011 | 1012 | name 1013 | punctuation.definition.metadata.markdown 1014 | 1015 | 7 1016 | 1017 | name 1018 | punctuation.definition.link.markdown 1019 | 1020 | 8 1021 | 1022 | name 1023 | markup.underline.link.markdown 1024 | 1025 | 9 1026 | 1027 | name 1028 | punctuation.definition.link.markdown 1029 | 1030 | 1031 | match 1032 | (?x: 1033 | (\[)((?<square>[^\[\]\\]|\\.|\[\g<square>*+\])*+)(\]) 1034 | # Match the link text. 1035 | ([ ])? # Space not allowed 1036 | (\() # Opening paren for url 1037 | (<?)(.*?)(>?) # The url 1038 | [ \t]* # Optional whitespace 1039 | (?: 1040 | ((\().+?(\))) # Match title in parens… 1041 | | ((").+?(")) # or in quotes. 1042 | )? # Title is optional 1043 | \s* # Optional whitespace 1044 | (\)) 1045 | ) 1046 | name 1047 | meta.link.inline.markdown 1048 | 1049 | link-ref 1050 | 1051 | captures 1052 | 1053 | 1 1054 | 1055 | name 1056 | punctuation.definition.string.begin.markdown 1057 | 1058 | 2 1059 | 1060 | name 1061 | string.other.link.title.markdown 1062 | 1063 | 4 1064 | 1065 | name 1066 | punctuation.definition.string.end.markdown 1067 | 1068 | 5 1069 | 1070 | name 1071 | punctuation.definition.constant.begin.markdown 1072 | 1073 | 6 1074 | 1075 | name 1076 | constant.other.reference.link.markdown 1077 | 1078 | 7 1079 | 1080 | name 1081 | punctuation.definition.constant.end.markdown 1082 | 1083 | 1084 | match 1085 | (\[)((?<square>[^\[\]\\]|\\.|\[\g<square>*+\])*+)(\])[ ]?(\[)([^\]]*+)(\]) 1086 | name 1087 | meta.link.reference.markdown 1088 | 1089 | link-ref-literal 1090 | 1091 | captures 1092 | 1093 | 1 1094 | 1095 | name 1096 | punctuation.definition.string.begin.markdown 1097 | 1098 | 2 1099 | 1100 | name 1101 | string.other.link.title.markdown 1102 | 1103 | 4 1104 | 1105 | name 1106 | punctuation.definition.string.end.markdown 1107 | 1108 | 5 1109 | 1110 | name 1111 | punctuation.definition.constant.begin.markdown 1112 | 1113 | 6 1114 | 1115 | name 1116 | punctuation.definition.constant.end.markdown 1117 | 1118 | 1119 | match 1120 | (\[)((?<square>[^\[\]\\]|\\.|\[\g<square>*+\])*+)(\])[ ]?(\[)(\]) 1121 | name 1122 | meta.link.reference.literal.markdown 1123 | 1124 | list-paragraph 1125 | 1126 | patterns 1127 | 1128 | 1129 | begin 1130 | \G\s+(?=\S) 1131 | end 1132 | ^\s*$ 1133 | name 1134 | meta.paragraph.list.markdown 1135 | patterns 1136 | 1137 | 1138 | include 1139 | #inline 1140 | 1141 | 1142 | captures 1143 | 1144 | 1 1145 | 1146 | name 1147 | punctuation.definition.list_item.markdown 1148 | 1149 | 1150 | comment 1151 | Match the list punctuation 1152 | match 1153 | ^\s*([*+-]|[0-9]+\.) 1154 | 1155 | 1156 | 1157 | 1158 | 1159 | raw 1160 | 1161 | captures 1162 | 1163 | 1 1164 | 1165 | name 1166 | punctuation.definition.raw.markdown 1167 | 1168 | 3 1169 | 1170 | name 1171 | punctuation.definition.raw.markdown 1172 | 1173 | 1174 | match 1175 | (`+)([^`]|(?!(?<!`)\1(?!`))`)*+(\1) 1176 | name 1177 | markup.raw.inline.markdown 1178 | 1179 | separator 1180 | 1181 | match 1182 | \G[ ]{,3}([-*_])([ ]{,2}\1){2,}[ \t]*$\n? 1183 | name 1184 | meta.separator.markdown 1185 | 1186 | 1187 | scopeName 1188 | text.html.markdown 1189 | uuid 1190 | 0A1D9874-B448-11D9-BD50-000D93B6E43C 1191 | 1192 | 1193 | --------------------------------------------------------------------------------