diff options
author | dave <dave@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2003-12-24 04:24:29 +0000 |
---|---|---|
committer | dave <dave@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2003-12-24 04:24:29 +0000 |
commit | 036fdff6b9283255b1f5e1763ff27f02041f44f1 (patch) | |
tree | c945829da8f2e7555a6b4cb7e11601dfafdc4d78 /lib/rdoc/ri | |
parent | c107984009f575f5988ca02274195d6da411e6c1 (diff) | |
download | ruby-036fdff6b9283255b1f5e1763ff27f02041f44f1.tar.gz ruby-036fdff6b9283255b1f5e1763ff27f02041f44f1.tar.xz ruby-036fdff6b9283255b1f5e1763ff27f02041f44f1.zip |
Forgot to save buffer.... sigh
git-svn-id: http://svn.ruby-lang.org/repos/ruby/trunk@5272 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/rdoc/ri')
-rw-r--r-- | lib/rdoc/ri/ri_cache.rb | 6 | ||||
-rw-r--r-- | lib/rdoc/ri/ri_formatter.rb | 309 | ||||
-rw-r--r-- | lib/rdoc/ri/ri_options.rb | 55 | ||||
-rw-r--r-- | lib/rdoc/ri/ri_reader.rb | 14 |
4 files changed, 353 insertions, 31 deletions
diff --git a/lib/rdoc/ri/ri_cache.rb b/lib/rdoc/ri/ri_cache.rb index 9e8c897d3..8d7c98240 100644 --- a/lib/rdoc/ri/ri_cache.rb +++ b/lib/rdoc/ri/ri_cache.rb @@ -53,6 +53,10 @@ module RI @inferior_classes.find_all {|c| c.name[name]} end + def classes_and_modules + @inferior_classes + end + # Return an exact match to a particular name def contained_class_named(name) @inferior_classes.find {|c| c.name == name} @@ -60,7 +64,7 @@ module RI # return the list of local methods matching name # We're split into two because we need distinct behavior - # when called from the toplevel + # when called from the _toplevel_ def methods_matching(name, is_class_method) local_methods_matching(name, is_class_method) end diff --git a/lib/rdoc/ri/ri_formatter.rb b/lib/rdoc/ri/ri_formatter.rb index b3024d4c6..03fee89d8 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 diff --git a/lib/rdoc/ri/ri_options.rb b/lib/rdoc/ri/ri_options.rb index 3ec6d4657..9b0704d42 100644 --- a/lib/rdoc/ri/ri_options.rb +++ b/lib/rdoc/ri/ri_options.rb @@ -18,13 +18,24 @@ module RI # The width of the output line attr_reader :width - + + # the formatting we apply to the output + attr_reader :formatter + module OptionList OPTION_LIST = [ [ "--help", "-h", nil, "you're looking at it" ], - + + [ "--format", "-f", "<name>", + "Format to use when displaying output:\n" + + " " + RI::TextFormatter.list + "\n" + + "Use 'bs' (backspace) with most pager programs.\n" + + "To use ANSI, either also use the -T option, or\n\n" + + "tell your pager to allow control characters\n" + + "(for example using the -R option to less)"], + [ "--no-pager", "-T", nil, "Send output directly to stdout." ], @@ -63,7 +74,7 @@ module RI # Show usage and exit - def OptionList.usage + def OptionList.usage(short_form=false) puts puts(RI::VERSION_STRING) @@ -96,12 +107,15 @@ module RI containing puncuation: ri 'Array.[]' - ri compact\! - - Options: + ri compact\\! EOT - + + if short_form + class_list + puts "For help, type 'ri -h'" + else + puts "Options:\n\n" OPTION_LIST.each do |long, short, arg, desc| opt = sprintf("%20s", "#{long}, #{short}") oparg = sprintf("%-7s", arg) @@ -120,6 +134,23 @@ module RI exit 0 end + end + + def OptionList.class_list + paths = RI::Paths::PATH + if paths.empty? + puts "Before using ri, you need to generate documentation" + puts "using 'rdoc' with the --ri option" + else + @ri_reader = RI::RiReader.new(RI::RiCache.new(paths)) + puts + puts "Classes and modules I know about:" + puts + puts @ri_reader.class_names.sort.join(", ") + puts + end + end + end # Parse command line options. @@ -128,7 +159,8 @@ module RI @use_stdout = !STDOUT.tty? @width = 72 - + @formatter = RI::TextFormatter.for("plain") + begin go = GetoptLong.new(*OptionList.options) @@ -138,6 +170,13 @@ module RI case opt when "--help" then OptionList.usage when "--no-pager" then @use_stdout = true + when "--format" + @formatter = RI::TextFormatter.for(arg) + unless @formatter + $stderr.print "Invalid formatter (should be one of " + $stderr.puts RI::TextFormatter.list + ")" + exit 1 + end when "--width" begin @width = Integer(arg) diff --git a/lib/rdoc/ri/ri_reader.rb b/lib/rdoc/ri/ri_reader.rb index dd647b3f8..ddce38f10 100644 --- a/lib/rdoc/ri/ri_reader.rb +++ b/lib/rdoc/ri/ri_reader.rb @@ -52,5 +52,19 @@ module RI File.open(path) {|f| RI::Description.deserialize(f) } end + # return the names of all classes and modules + def class_names + res = [] + find_classes_in(res, @cache.toplevel) + end + + def find_classes_in(res, klass) + classes = klass.classes_and_modules + for c in classes + res << c.name + find_classes_in(res, c) + end + res + end end end |