Skip to content

Commit 0a8902f

Browse files
committed
Added syntax highlighting for verbatim sections that (probably) contain ruby.
Moved token stream HTML markup out of RDoc::AnyMethod#markup_code into RDoc::TokenStream::to_html RDoc::RubyLex raises RDoc::RubyLex::Error instead of RDoc::Error. Fixed generation of rd parsers.
1 parent d346ffc commit 0a8902f

File tree

14 files changed

+262
-68
lines changed

14 files changed

+262
-68
lines changed

History.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
* RDoc now looks for a <tt>format: parser_name</tt> magic comment to choose
3737
alternate documentation formats. The format comment must be in the first
3838
three lines of the file (to allow for a shebang or modeline).
39+
* RDoc makes an effort to syntax-highlight ruby code in verbatim sections.
40+
See RDoc::Markup@Paragraphs+and+Verbatim
3941
* Added RDoc::TopLevel#text? and RDoc::Parser::Text to indicate a
4042
parsed file contains no ruby constructs.
4143
* Added <tt>rdoc-label</tt> link scheme which allows bidirectional links.
@@ -47,6 +49,8 @@
4749
munging.
4850
* RDoc::RDoc::current is set for the entire RDoc run.
4951
* Split rdoc/markup/inline into individual files for its component classes.
52+
* Moved token stream HTML markup out of RDoc::AnyMethod#markup_code into
53+
RDoc::TokenStream::to_html
5054

5155
* Bug fixes
5256
* Markup defined by RDoc::Markup#add_special inside a <tt><tt></tt> is no

Manifest.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ test/test_rdoc_single_class.rb
212212
test/test_rdoc_stats.rb
213213
test/test_rdoc_task.rb
214214
test/test_rdoc_text.rb
215+
test/test_rdoc_token_stream.rb
215216
test/test_rdoc_tom_doc.rb
216217
test/test_rdoc_top_level.rb
217218
test/xref_data.rb

Rakefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ Depending on your version of ruby, you may need to install ruby rdoc/ri data:
4040
self.clean_globs += PARSER_FILES
4141

4242
require_ruby_version '>= 1.8.7'
43-
extra_dev_deps << ['racc', '>= 0']
43+
extra_dev_deps << ['racc', '~> 1.4']
4444
extra_dev_deps << ['minitest', '~> 2']
4545
extra_dev_deps << ['ZenTest', '~> 4']
4646

@@ -52,9 +52,9 @@ end
5252
task 'generate' => PARSER_FILES
5353

5454
rule '.rb' => '.ry' do |t|
55-
racc = File.join Gem.dir, 'bin', 'racc'
55+
racc = Gem.bin_path 'racc', 'racc'
5656

57-
sh "#{racc} -l -o #{t.name} #{t.source}"
57+
ruby "-rubygems #{racc} -l -o #{t.name} #{t.source}"
5858
end
5959

6060
# These tasks expect to have the following directory structure:

lib/rdoc/generator/markup.rb

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -112,32 +112,7 @@ def add_line_numbers(src)
112112
def markup_code
113113
return '' unless @token_stream
114114

115-
src = ""
116-
117-
@token_stream.each do |t|
118-
next unless t
119-
120-
style = case t
121-
when RDoc::RubyToken::TkCONSTANT then 'ruby-constant'
122-
when RDoc::RubyToken::TkKW then 'ruby-keyword'
123-
when RDoc::RubyToken::TkIVAR then 'ruby-ivar'
124-
when RDoc::RubyToken::TkOp then 'ruby-operator'
125-
when RDoc::RubyToken::TkId then 'ruby-identifier'
126-
when RDoc::RubyToken::TkNode then 'ruby-node'
127-
when RDoc::RubyToken::TkCOMMENT then 'ruby-comment'
128-
when RDoc::RubyToken::TkREGEXP then 'ruby-regexp'
129-
when RDoc::RubyToken::TkSTRING then 'ruby-string'
130-
when RDoc::RubyToken::TkVal then 'ruby-value'
131-
end
132-
133-
text = CGI.escapeHTML t.text
134-
135-
if style then
136-
src << "<span class=\"#{style}\">#{text}</span>"
137-
else
138-
src << text
139-
end
140-
end
115+
src = RDoc::TokenStream.to_html @token_stream
141116

142117
# dedent the source
143118
indent = src.length

lib/rdoc/generator/template/darkfish/rdoc.css

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,13 +474,26 @@ ul.link-list .type {
474474

475475
/* @group Ruby keyword styles */
476476

477+
.description pre,
478+
.method-description pre {
479+
overflow: auto;
480+
background: #262626;
481+
color: #efefef;
482+
border: 1px dashed #999;
483+
padding: 0.5em;
484+
}
485+
486+
.description pre {
487+
margin: 0 0.4em;
488+
}
489+
477490
.ruby-constant { color: #7fffd4; background: transparent; }
478491
.ruby-keyword { color: #00ffff; background: transparent; }
479492
.ruby-ivar { color: #eedd82; background: transparent; }
480493
.ruby-operator { color: #00ffee; background: transparent; }
481494
.ruby-identifier { color: #ffdead; background: transparent; }
482495
.ruby-node { color: #ffa07a; background: transparent; }
483-
.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
496+
.ruby-comment { color: #dc0000; font-weight: bold; background: transparent; }
484497
.ruby-regexp { color: #ffa07a; background: transparent; }
485498
.ruby-value { color: #7fffd4; background: transparent; }
486499

lib/rdoc/markup.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@
9393
# have been removed. In addition, the verbatim text has been shifted
9494
# left, so the amount of indentation of verbatim text is unimportant.
9595
#
96+
# For HTML output RDoc makes a small effort to determine if a verbatim section
97+
# contains ruby source code. If so, the verbatim block will be marked up as
98+
# HTML. Triggers include "def", "class", "module", "require", the "hash
99+
# rocket"# (=>) or a block call with a parameter.
100+
#
96101
# === Headers
97102
#
98103
# A line starting with an equal sign (=) is treated as a
@@ -266,7 +271,6 @@
266271
# verbatim text outside of the list (the list is therefore closed)
267272
# regular paragraph after the list
268273
#
269-
#
270274
# == Text Markup
271275
#
272276
# === Bold, Italic, Typewriter Text

lib/rdoc/markup/to_html.rb

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,24 @@ def accept_paragraph(paragraph)
187187
##
188188
# Adds +verbatim+ to the output
189189

190-
def accept_verbatim(verbatim)
191-
@res << "\n<pre>"
192-
@res << CGI.escapeHTML(verbatim.text.rstrip)
193-
@res << "</pre>\n"
190+
def accept_verbatim verbatim
191+
text = verbatim.text.rstrip
192+
193+
@res << if parseable? text then
194+
options = RDoc::RDoc.current.options if RDoc::RDoc.current
195+
196+
begin
197+
tokens = RDoc::RubyLex.tokenize text, options
198+
199+
"\n<pre class=\"ruby\">" \
200+
"#{RDoc::TokenStream.to_html tokens}" \
201+
"</pre>\n"
202+
rescue RDoc::RubyLex::Error
203+
"\n<pre>#{CGI.escapeHTML text}</pre>\n"
204+
end
205+
else
206+
"\n<pre>#{CGI.escapeHTML text}</pre>\n"
207+
end
194208
end
195209

196210
##
@@ -361,6 +375,13 @@ def list_end_for(list_type)
361375
end
362376
end
363377

378+
##
379+
# Returns true if Ripper is available it can create a sexp from +text+
380+
381+
def parseable? text
382+
text =~ /\b(def|class|module|require)\b|=>|\{\s?\||do \|/
383+
end
384+
364385
##
365386
# Converts +item+ to HTML using RDoc::Text#to_html
366387

lib/rdoc/ruby_lex.rb

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ class RDoc::RubyLex
2222

2323
# :stopdoc:
2424

25+
##
26+
# Raised upon invalid input
27+
28+
class Error < RDoc::Error
29+
end
30+
2531
extend Exception2MessageMapper
2632

2733
def_exception(:AlreadyDefinedToken, "Already defined token(%s)")
@@ -50,6 +56,19 @@ def self.debug?
5056

5157
self.debug_level = 0
5258

59+
def self.tokenize text, options
60+
tokens = []
61+
62+
scanner = RDoc::RubyLex.new text, options
63+
scanner.exception_on_syntax_error = true
64+
65+
while token = scanner.token do
66+
tokens << token
67+
end
68+
69+
tokens
70+
end
71+
5372
def initialize(content, options)
5473
lex_init
5574

@@ -322,7 +341,7 @@ def token
322341
tk = @OP.match(self)
323342
@space_seen = tk.kind_of?(TkSPACE)
324343
rescue SyntaxError => e
325-
raise RDoc::Error, "syntax error: #{e.message}" if
344+
raise Error, "syntax error: #{e.message}" if
326345
@exception_on_syntax_error
327346

328347
tk = TkError.new(@seek, @line_no, @char_no)
@@ -1004,7 +1023,7 @@ def identify_quotation
10041023
elsif ch =~ /\W/
10051024
lt = "\""
10061025
else
1007-
raise RDoc::Error, "unknown type of %string #{ch.inspect}"
1026+
raise Error, "unknown type of %string #{ch.inspect}"
10081027
end
10091028
# if ch !~ /\W/
10101029
# ungetc
@@ -1039,7 +1058,7 @@ def identify_number(op = "")
10391058
when /[0-7]/
10401059
match = /[0-7_]/
10411060
when /[89]/
1042-
raise RDoc::Error, "Illegal octal digit"
1061+
raise Error, "Illegal octal digit"
10431062
else
10441063
return Token(TkINTEGER, num)
10451064
end
@@ -1053,7 +1072,7 @@ def identify_number(op = "")
10531072
if match =~ ch
10541073
if ch == "_"
10551074
if non_digit
1056-
raise RDoc::Error, "trailing `#{ch}' in number"
1075+
raise Error, "trailing `#{ch}' in number"
10571076
else
10581077
non_digit = ch
10591078
end
@@ -1065,10 +1084,10 @@ def identify_number(op = "")
10651084
ungetc
10661085
num[-1, 1] = ''
10671086
if len0
1068-
raise RDoc::Error, "numeric literal without digits"
1087+
raise Error, "numeric literal without digits"
10691088
end
10701089
if non_digit
1071-
raise RDoc::Error, "trailing `#{non_digit}' in number"
1090+
raise Error, "trailing `#{non_digit}' in number"
10721091
end
10731092
break
10741093
end
@@ -1089,7 +1108,7 @@ def identify_number(op = "")
10891108
non_digit = ch
10901109
when allow_point && "."
10911110
if non_digit
1092-
raise RDoc::Error, "trailing `#{non_digit}' in number"
1111+
raise Error, "trailing `#{non_digit}' in number"
10931112
end
10941113
type = TkFLOAT
10951114
if peek(0) !~ /[0-9]/
@@ -1101,7 +1120,7 @@ def identify_number(op = "")
11011120
allow_point = false
11021121
when allow_e && "e", allow_e && "E"
11031122
if non_digit
1104-
raise RDoc::Error, "trailing `#{non_digit}' in number"
1123+
raise Error, "trailing `#{non_digit}' in number"
11051124
end
11061125
type = TkFLOAT
11071126
if peek(0) =~ /[+-]/
@@ -1112,7 +1131,7 @@ def identify_number(op = "")
11121131
non_digit = ch
11131132
else
11141133
if non_digit
1115-
raise RDoc::Error, "trailing `#{non_digit}' in number"
1134+
raise Error, "trailing `#{non_digit}' in number"
11161135
end
11171136
ungetc
11181137
num[-1, 1] = ''

lib/rdoc/ruby_token.rb

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ def set_text(text)
6060
self
6161
end
6262

63+
def inspect # :nodoc:
64+
klass = self.class.name.split('::').last
65+
"{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @text]
66+
end
67+
6368
end
6469

6570
class TkNode < Token
@@ -83,6 +88,12 @@ def set_text text
8388
end
8489

8590
alias text node
91+
92+
def inspect # :nodoc:
93+
klass = self.class.name.split('::').last
94+
"{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @node]
95+
end
96+
8697
end
8798

8899
class TkId < Token
@@ -105,6 +116,12 @@ def set_text text
105116
end
106117

107118
alias text name
119+
120+
def inspect # :nodoc:
121+
klass = self.class.name.split('::').last
122+
"{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @name]
123+
end
124+
108125
end
109126

110127
class TkKW < TkId
@@ -130,6 +147,12 @@ def set_text text
130147
end
131148

132149
alias text value
150+
151+
def inspect # :nodoc:
152+
klass = self.class.name.split('::').last
153+
"{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @value]
154+
end
155+
133156
end
134157

135158
class TkOp < Token
@@ -153,6 +176,12 @@ def set_text text
153176
end
154177

155178
alias text name
179+
180+
def inspect # :nodoc:
181+
klass = self.class.name.split('::').last
182+
"{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @name]
183+
end
184+
156185
end
157186

158187
class TkOPASGN < TkOp
@@ -175,6 +204,12 @@ def ==(other)
175204
def text
176205
@text ||= "#{TkToken2Reading[op]}="
177206
end
207+
208+
def inspect # :nodoc:
209+
klass = self.class.name.split('::').last
210+
"{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @op]
211+
end
212+
178213
end
179214

180215
class TkUnknownChar < Token
@@ -197,6 +232,12 @@ def set_text text
197232
end
198233

199234
alias text name
235+
236+
def inspect # :nodoc:
237+
klass = self.class.name.split('::').last
238+
"{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @name]
239+
end
240+
200241
end
201242

202243
class TkError < Token

0 commit comments

Comments
 (0)