1# :markup: markdown 2 3## 4# Outputs parsed markup as Markdown 5 6class RDoc::Markup::ToMarkdown < RDoc::Markup::ToRdoc 7 8 ## 9 # Creates a new formatter that will output Markdown format text 10 11 def initialize markup = nil 12 super 13 14 @headings[1] = ['# ', ''] 15 @headings[2] = ['## ', ''] 16 @headings[3] = ['### ', ''] 17 @headings[4] = ['#### ', ''] 18 @headings[5] = ['##### ', ''] 19 @headings[6] = ['###### ', ''] 20 21 add_special_RDOCLINK 22 add_special_TIDYLINK 23 24 @hard_break = " \n" 25 end 26 27 ## 28 # Maps attributes to HTML sequences 29 30 def init_tags 31 add_tag :BOLD, '**', '**' 32 add_tag :EM, '*', '*' 33 add_tag :TT, '`', '`' 34 end 35 36 ## 37 # Adds a newline to the output 38 39 def handle_special_HARD_BREAK special 40 " \n" 41 end 42 43 ## 44 # Finishes consumption of `list` 45 46 def accept_list_end list 47 @res << "\n" 48 49 super 50 end 51 52 ## 53 # Finishes consumption of `list_item` 54 55 def accept_list_item_end list_item 56 width = case @list_type.last 57 when :BULLET then 58 4 59 when :NOTE, :LABEL then 60 use_prefix 61 62 4 63 else 64 @list_index[-1] = @list_index.last.succ 65 4 66 end 67 68 @indent -= width 69 end 70 71 ## 72 # Prepares the visitor for consuming `list_item` 73 74 def accept_list_item_start list_item 75 type = @list_type.last 76 77 case type 78 when :NOTE, :LABEL then 79 bullets = Array(list_item.label).map do |label| 80 attributes(label).strip 81 end.join "\n" 82 83 bullets << "\n:" 84 85 @prefix = ' ' * @indent 86 @indent += 4 87 @prefix << bullets + (' ' * (@indent - 1)) 88 else 89 bullet = type == :BULLET ? '*' : @list_index.last.to_s + '.' 90 @prefix = (' ' * @indent) + bullet.ljust(4) 91 92 @indent += 4 93 end 94 end 95 96 ## 97 # Prepares the visitor for consuming `list` 98 99 def accept_list_start list 100 case list.type 101 when :BULLET, :LABEL, :NOTE then 102 @list_index << nil 103 when :LALPHA, :NUMBER, :UALPHA then 104 @list_index << 1 105 else 106 raise RDoc::Error, "invalid list type #{list.type}" 107 end 108 109 @list_width << 4 110 @list_type << list.type 111 end 112 113 ## 114 # Adds `rule` to the output 115 116 def accept_rule rule 117 use_prefix or @res << ' ' * @indent 118 @res << '-' * 3 119 @res << "\n" 120 end 121 122 ## 123 # Outputs `verbatim` indented 4 columns 124 125 def accept_verbatim verbatim 126 indent = ' ' * (@indent + 4) 127 128 verbatim.parts.each do |part| 129 @res << indent unless part == "\n" 130 @res << part 131 end 132 133 @res << "\n" unless @res =~ /\n\z/ 134 end 135 136 ## 137 # Creates a Markdown-style URL from +url+ with +text+. 138 139 def gen_url url, text 140 scheme, url, = parse_url url 141 142 "[#{text.sub(%r{^#{scheme}:/*}i, '')}](#{url})" 143 end 144 145 ## 146 # Handles <tt>rdoc-</tt> type links for footnotes. 147 148 def handle_rdoc_link url 149 case url 150 when /\Ardoc-ref:/ then 151 $' 152 when /\Ardoc-label:footmark-(\d+)/ then 153 "[^#{$1}]:" 154 when /\Ardoc-label:foottext-(\d+)/ then 155 "[^#{$1}]" 156 when /\Ardoc-label:label-/ then 157 gen_url url, $' 158 when /\Ardoc-[a-z]+:/ then 159 $' 160 end 161 end 162 163 ## 164 # Converts the RDoc markup tidylink into a Markdown.style link. 165 166 def handle_special_TIDYLINK special 167 text = special.text 168 169 return text unless text =~ /\{(.*?)\}\[(.*?)\]/ or text =~ /(\S+)\[(.*?)\]/ 170 171 label = $1 172 url = $2 173 174 if url =~ /^rdoc-label:foot/ then 175 handle_rdoc_link url 176 else 177 gen_url url, label 178 end 179 end 180 181 ## 182 # Converts the rdoc-...: links into a Markdown.style links. 183 184 def handle_special_RDOCLINK special 185 handle_rdoc_link special.text 186 end 187 188end 189 190