diff options
Diffstat (limited to 'lib/rdoc/ri/ri_formatter.rb')
-rw-r--r-- | lib/rdoc/ri/ri_formatter.rb | 309 |
1 files changed, 287 insertions, 22 deletions
diff --git a/lib/rdoc/ri/ri_formatter.rb b/lib/rdoc/ri/ri_formatter.rb index b3024d4c6c..03fee89d8f 100644 --- a/lib/rdoc/ri/ri_formatter.rb +++ b/lib/rdoc/ri/ri_formatter.rb @@ -1,8 +1,17 @@ module RI class TextFormatter - def TextFormatter.create(options, indent) - new(options, indent) + def TextFormatter.list + "plain, bs, ansi" + end + + def TextFormatter.for(name) + case name + when /plain/i then TextFormatter + when /bs/i then OverstrikeFormatter + when /ansi/i then AnsiFormatter + else nil + end end attr_reader :indent @@ -20,7 +29,10 @@ module RI len = @width len -= (label.size+1) if label print "-"*len - print(" ", label) if label + if label + print(" ") + bold_print(label) + end puts end @@ -55,6 +67,12 @@ module RI ###################################################################### + def bold_print(txt) + print txt + end + + ###################################################################### + # convert HTML entities back to ASCII def conv_html(txt) txt. @@ -126,7 +144,7 @@ module RI else display_flow_item(item) end - end + end end ###################################################################### @@ -147,24 +165,7 @@ module RI blankline when SM::Flow::H - text = conv_html(item.text.join) - case item.level - when 1 - ul = "=" * text.length - puts - puts text.upcase - puts ul - puts - - when 2 - ul = "-" * text.length - puts - puts text - puts ul - puts - else - print "\n", @indent, text, "\n\n" - end + display_heading(conv_html(item.text.join), item.level, @indent) else fail "Unknown flow element: #{item.class}" end @@ -172,13 +173,277 @@ module RI ###################################################################### + def display_heading(text, level, indent) + case level + when 1 + ul = "=" * text.length + puts + puts text.upcase + puts ul +# puts + + when 2 + ul = "-" * text.length + puts + puts text + puts ul +# puts + else + print indent, text, "\n" + end + end + + ###################################################################### + def display_flow(flow) flow.each do |f| display_flow_item(f) end end end + + + # Handle text with attributes. We're a base class: there are + # different presentation classes (one, for example, uses overstrikes + # to handle bold and underlinig, while another using ANSI escape + # sequences + + class AttributeFormatter < TextFormatter + + BOLD = 1 + ITALIC = 2 + CODE = 4 + + ATTR_MAP = { + "b" => BOLD, + "code" => CODE, + "em" => ITALIC, + "i" => ITALIC, + "tt" => CODE + } + + # TODO: struct? + class AttrChar + attr_reader :char + attr_reader :attr + + def initialize(char, attr) + @char = char + @attr = attr + end + end + + + class AttributeString + def initialize + @txt = [] + @optr = 0 + end + + def <<(char) + @txt << char + end + + def empty? + @optr >= @txt.length + end + + # accept non space, then all following spaces + def next_word + start = @optr + len = @txt.length + + while @optr < len && @txt[@optr].char != " " + @optr += 1 + end + + while @optr < len && @txt[@optr].char == " " + @optr += 1 + end + + @txt[start...@optr] + end + end + + ###################################################################### + # overrides base class. Looks for <tt>...</tt> etc sequences + # and generates an array of AttrChars. This array is then used + # as the basis for the split + + def wrap(txt, prefix=@indent, linelen=@width) + return unless txt && !txt.empty? + + txt = add_attributes_to(txt) + + line = [] + + until txt.empty? + word = txt.next_word + if word.size + line.size > linelen - @indent.size + write_attribute_text(line) + line = [] + end + line.concat(word) + end + + write_attribute_text(line) if line.length > 0 + end + + protected + + # overridden in specific formatters + + def write_attribute_text(line) + print @indent + line.each do |achar| + print achar.char + end + puts + end + + # again, overridden + + def bold_print(txt) + print txt + end + + private + + def add_attributes_to(txt) + tokens = txt.split(%r{(</?(?:b|code|em|i|tt)>)}) + text = AttributeString.new + attributes = 0 + tokens.each do |tok| + case tok + when %r{^</(\w+)>$} then attributes &= ~(ATTR_MAP[$1]||0) + when %r{^<(\w+)>$} then attributes |= (ATTR_MAP[$1]||0) + else + tok.split(//).each {|ch| text << AttrChar.new(ch, attributes)} + end + end + text + end + + end + + + ################################################## + + # This formatter generates overstrike-style formatting, which + # works with pages such as man and less. + + class OverstrikeFormatter < AttributeFormatter + + BS = "\C-h" + + def write_attribute_text(line) + print @indent + line.each do |achar| + attr = achar.attr + if (attr & (ITALIC+CODE)) != 0 + print "_", BS + end + if (attr & BOLD) != 0 + print achar.char, BS + end + print achar.char + end + puts + end + + # draw a string in bold + def bold_print(text) + text.split(//).each do |ch| + print ch, BS, ch + end + end + end + + ################################################## + + # This formatter uses ANSI escape sequences + # to colorize stuff + # works with pages such as man and less. + + class AnsiFormatter < AttributeFormatter + + BS = "\C-h" + + def initialize(*args) + print "\033[0m" + super + end + + def write_attribute_text(line) + print @indent + curr_attr = 0 + line.each do |achar| + attr = achar.attr + if achar.attr != curr_attr + update_attributes(achar.attr) + curr_attr = achar.attr + end + print achar.char + end + update_attributes(0) unless curr_attr.zero? + puts + end + + + def bold_print(txt) + print "\033[1m#{txt}\033[m" + end + + HEADINGS = { + 1 => "\033[1;32m%s\033[m", + 2 => "\033[4;32m%s\033[m", + 3 => "\033[32m%s\033[m" + } + + def display_heading(text, level, indent) + level = 3 if level > 3 + print indent + printf(HEADINGS[level], text) + puts + end + + private + + ATTR_MAP = { + BOLD => "1", + ITALIC => "33", + CODE => "36" + } + + def update_attributes(attr) + str = "\033[" + for quality in [ BOLD, ITALIC, CODE] + unless (attr & quality).zero? + str << ATTR_MAP[quality] + end + end + print str, "m" + end + end +# options = "options" +# def options.width +# 70 +# end +# a = OverstrikeFormatter.new(options, " ") +# a.wrap( +# "The quick <b>brown</b> and <i>italic</i> dog " + +# "The quick <b>brown and <i>italic</i></b> dog " + +# "The quick <b>brown and <i>italic</i></b> dog " + +# "The quick <b>brown and <i>italic</i></b> dog " + +# "The quick <b>brown and <i>italic</i></b> dog " + +# "The quick <b>brown and <i>italic</i></b> dog " + +# "The quick <b>brown and <i>italic</i></b> dog " + +# "The quick <b>brown and <i>italic</i></b> dog " + +# "The quick <b>brown and <i>italic</i></b> dog " + +# "The quick <b>brown and <i>italic</i></b> dog " + +# "The quick <b>brown and <i>italic</i></b> dog " +# ) end |