summaryrefslogtreecommitdiff
path: root/lib/rdoc/ri
diff options
context:
space:
mode:
authordave <dave@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-12-24 04:24:29 +0000
committerdave <dave@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-12-24 04:24:29 +0000
commitf0346bd249ae29cdf4d9c2e88b09e63c41ff1ce8 (patch)
treec945829da8f2e7555a6b4cb7e11601dfafdc4d78 /lib/rdoc/ri
parent52975bb7a77b3a6409e50609b4baeafade035b3d (diff)
Forgot to save buffer.... sigh
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@5272 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/rdoc/ri')
-rw-r--r--lib/rdoc/ri/ri_cache.rb6
-rw-r--r--lib/rdoc/ri/ri_formatter.rb309
-rw-r--r--lib/rdoc/ri/ri_options.rb55
-rw-r--r--lib/rdoc/ri/ri_reader.rb14
4 files changed, 353 insertions, 31 deletions
diff --git a/lib/rdoc/ri/ri_cache.rb b/lib/rdoc/ri/ri_cache.rb
index 9e8c897d36..8d7c982409 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 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
diff --git a/lib/rdoc/ri/ri_options.rb b/lib/rdoc/ri/ri_options.rb
index 3ec6d4657c..9b0704d421 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 dd647b3f89..ddce38f101 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