1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/lib/rdoc/markup/to_html.rb
nagachika 2a70d21484 merge revision(s) b1c73f239fe9af97de837331849f55d67c27561e,bb570ce6d80d28cfc7131dcb72885eed2f989b30,b88d1e6b44164bca0c2b85ea6639469813e1e1d8,127f735c1e5e0771076caf2a74390757a42fb177,f3f1a666c77f8c528b0adc9ccf78e4b9910bd6e0,fa048a0f8523cefde5428805dd334691486319e6,d5d1c41728d65acfb8aa2cf95f2d8ac88f271cd1,52ebaf718e6a78297ceb0dff49815eeed28eae45,7fe22152fc28084f4395fece84ff6e5eb2d6b288,19e6d271266eca5925e66fc8ec39b251a2fa6bcd,05898c5b9001c0b1e8bd7bf0d12b42a8e7c388b8,3651f678a719ae3a35825bcb4e0dabbc7c60d8df,10b082064e6ab0943cce4ef43e567d8044c7096d,de8e6218a3257fe19b46ff0aa157e66f452ac8b7,971a0cd246db6578e1ea8760a903e1a23e3681f3,61a29a41e1d0d11a9963315aa86d25ed690124c0,ff9a00887161840eb8a34d53749a7d7962181cfe,fad3412d475b57055f426cf4e86eafeab516672b,54aa11efa8b1be2c5d20402890d6d2fa90aa19a8,e84d275fe6d0c14ba58ce73b13323879c060b7ae,61e1cf23ac0d122fba3ad4cbaa402c7c94ad54d3,a6948329f8f89fb390215086fe4a888915fd589e,64b991b0cd98ee8f23266b8cbea0fa34bdaab1ec,b1c73f239fe9af97de837331849f55d67c27561e,0ee24b4fab1a1faef600a42c29863e1c3edd8c61: [Backport #17877]
Synchronize rdoc with upstream version v6.3.1.

	[ruby/rdoc] Use File.open to fix the OS Command Injection
	 vulnerability in CVE-2021-31799

	a7f5d6ab88
	---
	 lib/rdoc/rdoc.rb            |  2 +-
	 test/rdoc/test_rdoc_rdoc.rb | 12 ++++++++++++
	 2 files changed, 13 insertions(+), 1 deletion(-)

	[ruby/rdoc] Support ChangeLog generated by `git log`

	5e0a123ca1
	---
	 lib/rdoc/parser/changelog.rb            | 35 +++++++++++++++++++++
	 test/rdoc/test_rdoc_parser_changelog.rb | 56 +++++++++++++++++++++++++++++++++
	 2 files changed, 91 insertions(+)

	[ruby/rdoc] Make each commit entries h3

	11eefb2ae9
	---
	 lib/rdoc/parser/changelog.rb            | 12 ++++++------
	 test/rdoc/test_rdoc_parser_changelog.rb | 12 ++++--------
	 2 files changed, 10 insertions(+), 14 deletions(-)

	[ruby/rdoc] Tweak log entry markdown

	* add 3 levels to headings
	* prefix commit log to labels to make unique IDs

	5074c13209
	---
	 lib/rdoc/parser/changelog.rb            | 20 +++++++++++++++++-
	 test/rdoc/test_rdoc_parser_changelog.rb | 36 ++++++++++++++++++++++++++++++++-
	 2 files changed, 54 insertions(+), 2 deletions(-)

	[ruby/rdoc] Shorten commit hashes

	5d3e153963
	---
	 lib/rdoc/parser/changelog.rb            | 2 +-
	 test/rdoc/test_rdoc_parser_changelog.rb | 2 +-
	 2 files changed, 2 insertions(+), 2 deletions(-)

	[ruby/rdoc] Add links to the commits

	1821628076
	---
	 lib/rdoc/parser/changelog.rb            | 107 +++++++++++++++++++++++++-------
	 test/rdoc/test_rdoc_parser_changelog.rb |  36 ++++++-----
	 2 files changed, 107 insertions(+), 36 deletions(-)

	[ruby/rdoc] Sort by CommitDate if available

	455715e930
	---
	 lib/rdoc/parser/changelog.rb            | 11 ++++++---
	 test/rdoc/test_rdoc_parser_changelog.rb | 40 +++++++++++++++++++++++++++++++++
	 2 files changed, 48 insertions(+), 3 deletions(-)

	[ruby/rdoc] Skip non-date logs by git-log

	`RDoc::Parser::ChangeLog` mis-parses ChangeLog generated by
	git-log, because of too heuristic `Time.parse`.

	For instance, "commit 8187228de0"
	results in "8187-08-16", that is, day 228 in the year 8187.

	9711e6f6d9
	---
	 lib/rdoc/parser/changelog.rb            | 36 ++++++++++++++++++++-------------
	 test/rdoc/test_rdoc_parser_changelog.rb |  2 ++
	 2 files changed, 24 insertions(+), 14 deletions(-)

	[ruby/rdoc] Support other date formats in git-log

	ad8cf37d72
	---
	 lib/rdoc/parser/changelog.rb            |  6 +++---
	 test/rdoc/test_rdoc_parser_changelog.rb | 22 ++++++++++++++++++++++
	 2 files changed, 25 insertions(+), 3 deletions(-)

	[ruby/rdoc] Support iso-strict format in git-log

	2a6c22da63
	---
	 lib/rdoc/parser/changelog.rb            |  6 +++---
	 test/rdoc/test_rdoc_parser_changelog.rb | 11 +++++++++++
	 2 files changed, 14 insertions(+), 3 deletions(-)

	[ruby/rdoc] Update Rdoc.css sidebar panel.

	Updates css so the sidebar look like a panel instead of looking like chopped edges.

	b0098c6d72
	---
	 lib/rdoc/generator/template/darkfish/css/rdoc.css | 1 +
	 1 file changed, 1 insertion(+)

	[ruby/rdoc] Support GFM table

	9dc933df16
	---
	 lib/rdoc/markdown.rb                    | 349 +++++++++++++++++++++++++++++++-
	 lib/rdoc/markup.rb                      |   1 +
	 lib/rdoc/markup/table.rb                |  47 +++++
	 lib/rdoc/markup/to_html.rb              |  23 +++
	 lib/rdoc/markup/to_joined_paragraph.rb  |   1 +
	 lib/rdoc/markup/to_rdoc.rb              |  28 +++
	 lib/rdoc/markup/to_table_of_contents.rb |   1 +
	 test/rdoc/test_rdoc_markdown.rb         |  23 +++
	 8 files changed, 471 insertions(+), 2 deletions(-)
	 create mode 100644 lib/rdoc/markup/table.rb

	[ruby/rdoc] Add table style

	2219c5ae80
	---
	 lib/rdoc/generator/template/darkfish/css/rdoc.css | 19 +++++++++++++++++++
	 1 file changed, 19 insertions(+)

	[ruby/rdoc] Fixed CodeFence without blank lines

	Currently a fenced code block needs a preceding blank line, it
	should not be required, as:
	https://github.github.com/gfm/#fenced-code-blocks
	> A fenced code block may interrupt a paragraph, and does not
	> require a blank line either before or after.

	Just recommended:
	https://docs.github.com/en/github/writing-on-github/creating-and-highlighting-code-blocks
	> We recommend placing a blank line before and after code blocks
	> to make the raw formatting easier to read.

	0e1776caf3
	---
	 lib/rdoc/markdown.rb            | 447 +++++++---------------------------------
	 test/rdoc/test_rdoc_markdown.rb |  36 +++-
	 2 files changed, 112 insertions(+), 371 deletions(-)

	[ruby/rdoc] Allow partial default values to be overridden with
	 .rdoc_options

	e14800891f
	---
	 lib/rdoc/options.rb         | 34 +++++++++++++++++++++++++++++++++-
	 lib/rdoc/rdoc.rb            |  7 ++++++-
	 test/rdoc/test_rdoc_rdoc.rb | 12 ++++++++++++
	 3 files changed, 51 insertions(+), 2 deletions(-)

	[ruby/rdoc] Allow empty .rdoc_options

	0c8cb25b50
	---
	 lib/rdoc/rdoc.rb            |  2 ++
	 test/rdoc/test_rdoc_rdoc.rb | 11 +++++++++++
	 2 files changed, 13 insertions(+)

	[ruby/rdoc] Suppress unused variable warning of "text"

	3a4120b155
	---
	 lib/rdoc/markdown.rb | 345 ++++++++++++++++++++++++++++++++++++++++++++++++++-
	 1 file changed, 343 insertions(+), 2 deletions(-)

	[ruby/rdoc] Get rid of a trailing space

	7b7b91768e
	---
	 lib/rdoc/markdown.rb | 7 +++----
	 1 file changed, 3 insertions(+), 4 deletions(-)

	[ruby/rdoc] Disable other notations in <code> tags

	0cd3b55210
	---
	 lib/rdoc/markup/attr_span.rb                    |  10 ++-
	 lib/rdoc/markup/attribute_manager.rb            | 102 ++++++++++++++++++------
	 test/rdoc/test_rdoc_markup_attribute_manager.rb |  24 +++++-
	 test/rdoc/test_rdoc_markup_to_html.rb           |   6 ++
	 4 files changed, 114 insertions(+), 28 deletions(-)

	[ruby/rdoc] Treat other tags as word boundaries

	8222f85a17
	---
	 lib/rdoc/markup/attribute_manager.rb  | 17 +++++++++++++----
	 test/rdoc/test_rdoc_markup_to_html.rb |  5 +++++
	 2 files changed, 18 insertions(+), 4 deletions(-)

	[ruby/rdoc] Treat emphasis tags as excluding other notations

	And exclusive notations don't exclude other exclusive notations.

	b8baa9a435
	---
	 lib/rdoc/markup/attr_span.rb                    |  2 +-
	 lib/rdoc/markup/attribute_manager.rb            | 10 +++++-----
	 test/rdoc/test_rdoc_markup_attribute_manager.rb |  1 +
	 3 files changed, 7 insertions(+), 6 deletions(-)

	[ruby/rdoc] Clarify that dots in URL are replaced

	The dots in all path components from the document root are
	replaced with underscores, not only in the basename.

	7a3417ea4c
	---
	 test/rdoc/test_rdoc_top_level.rb | 3 +++
	 1 file changed, 3 insertions(+)

	[ruby/rdoc] Links to document texts without "rdoc-ref:" prefix

	While links to generated HTML from RDoc file needs to be prefixed
	by "rdoc-ref:" currently, in case of explicit references this
	seems just redundant.

	Also GitHub RDoc support does not work with this prefix.

	This patch lets links to such document texts (".rb", ".rdoc" and
	".md" now) refer URLs generated by `RDoc::TopLevel#http_url`
	without the prefix.

	f18b27b69d
	---
	 lib/rdoc/markup/to_html.rb            |  4 ++++
	 test/rdoc/test_rdoc_markup_to_html.rb | 21 +++++++++++++++++++++
	 2 files changed, 25 insertions(+)

	[ruby/rdoc] Use File.open to fix the OS Command Injection
	 vulnerability in CVE-2021-31799

	a7f5d6ab88
	---
	 lib/rdoc/rdoc.rb            |  2 +-
	 test/rdoc/test_rdoc_rdoc.rb | 12 ++++++++++++
	 2 files changed, 13 insertions(+), 1 deletion(-)

	[ruby/rdoc] Version 6.3.1

	9307f932b7
	---
	 lib/rdoc/version.rb | 2 +-
	 1 file changed, 1 insertion(+), 1 deletion(-)
2021-05-22 14:51:55 +09:00

444 lines
9.7 KiB
Ruby

# frozen_string_literal: true
require 'cgi'
##
# Outputs RDoc markup as HTML.
class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
include RDoc::Text
# :section: Utilities
##
# Maps RDoc::Markup::Parser::LIST_TOKENS types to HTML tags
LIST_TYPE_TO_HTML = {
:BULLET => ['<ul>', '</ul>'],
:LABEL => ['<dl class="rdoc-list label-list">', '</dl>'],
:LALPHA => ['<ol style="list-style-type: lower-alpha">', '</ol>'],
:NOTE => ['<dl class="rdoc-list note-list">', '</dl>'],
:NUMBER => ['<ol>', '</ol>'],
:UALPHA => ['<ol style="list-style-type: upper-alpha">', '</ol>'],
}
attr_reader :res # :nodoc:
attr_reader :in_list_entry # :nodoc:
attr_reader :list # :nodoc:
##
# The RDoc::CodeObject HTML is being generated for. This is used to
# generate namespaced URI fragments
attr_accessor :code_object
##
# Path to this document for relative links
attr_accessor :from_path
# :section:
##
# Creates a new formatter that will output HTML
def initialize options, markup = nil
super
@code_object = nil
@from_path = ''
@in_list_entry = nil
@list = nil
@th = nil
@hard_break = "<br>\n"
init_regexp_handlings
init_tags
end
# :section: Regexp Handling
#
# These methods are used by regexp handling markup added by RDoc::Markup#add_regexp_handling.
##
# Adds regexp handlings.
def init_regexp_handlings
# external links
@markup.add_regexp_handling(/(?:link:|https?:|mailto:|ftp:|irc:|www\.)\S+\w/,
:HYPERLINK)
init_link_notation_regexp_handlings
end
##
# Adds regexp handlings about link notations.
def init_link_notation_regexp_handlings
add_regexp_handling_RDOCLINK
add_regexp_handling_TIDYLINK
end
def handle_RDOCLINK url # :nodoc:
case url
when /^rdoc-ref:/
$'
when /^rdoc-label:/
text = $'
text = case text
when /\Alabel-/ then $'
when /\Afootmark-/ then $'
when /\Afoottext-/ then $'
else text
end
gen_url url, text
when /^rdoc-image:/
"<img src=\"#{$'}\">"
else
url =~ /\Ardoc-[a-z]+:/
$'
end
end
##
# +target+ is a <code><br></code>
def handle_regexp_HARD_BREAK target
'<br>'
end
##
# +target+ is a potential link. The following schemes are handled:
#
# <tt>mailto:</tt>::
# Inserted as-is.
# <tt>http:</tt>::
# Links are checked to see if they reference an image. If so, that image
# gets inserted using an <tt><img></tt> tag. Otherwise a conventional
# <tt><a href></tt> is used.
# <tt>link:</tt>::
# Reference to a local file relative to the output directory.
def handle_regexp_HYPERLINK(target)
url = target.text
gen_url url, url
end
##
# +target+ is an rdoc-schemed link that will be converted into a hyperlink.
#
# For the +rdoc-ref+ scheme the named reference will be returned without
# creating a link.
#
# For the +rdoc-label+ scheme the footnote and label prefixes are stripped
# when creating a link. All other contents will be linked verbatim.
def handle_regexp_RDOCLINK target
handle_RDOCLINK target.text
end
##
# This +target+ is a link where the label is different from the URL
# <tt>label[url]</tt> or <tt>{long label}[url]</tt>
def handle_regexp_TIDYLINK(target)
text = target.text
return text unless
text =~ /^\{(.*)\}\[(.*?)\]$/ or text =~ /^(\S+)\[(.*?)\]$/
label = $1
url = $2
label = handle_RDOCLINK label if /^rdoc-image:/ =~ label
gen_url url, label
end
# :section: Visitor
#
# These methods implement the HTML visitor.
##
# Prepares the visitor for HTML generation
def start_accepting
@res = []
@in_list_entry = []
@list = []
end
##
# Returns the generated output
def end_accepting
@res.join
end
##
# Adds +block_quote+ to the output
def accept_block_quote block_quote
@res << "\n<blockquote>"
block_quote.parts.each do |part|
part.accept self
end
@res << "</blockquote>\n"
end
##
# Adds +paragraph+ to the output
def accept_paragraph paragraph
@res << "\n<p>"
text = paragraph.text @hard_break
text = text.gsub(/\r?\n/, ' ')
@res << to_html(text)
@res << "</p>\n"
end
##
# Adds +verbatim+ to the output
def accept_verbatim verbatim
text = verbatim.text.rstrip
klass = nil
content = if verbatim.ruby? or parseable? text then
begin
tokens = RDoc::Parser::RipperStateLex.parse text
klass = ' class="ruby"'
result = RDoc::TokenStream.to_html tokens
result = result + "\n" unless "\n" == result[-1]
result
rescue
CGI.escapeHTML text
end
else
CGI.escapeHTML text
end
if @options.pipe then
@res << "\n<pre><code>#{CGI.escapeHTML text}\n</code></pre>\n"
else
@res << "\n<pre#{klass}>#{content}</pre>\n"
end
end
##
# Adds +rule+ to the output
def accept_rule rule
@res << "<hr>\n"
end
##
# Prepares the visitor for consuming +list+
def accept_list_start(list)
@list << list.type
@res << html_list_name(list.type, true)
@in_list_entry.push false
end
##
# Finishes consumption of +list+
def accept_list_end(list)
@list.pop
if tag = @in_list_entry.pop
@res << tag
end
@res << html_list_name(list.type, false) << "\n"
end
##
# Prepares the visitor for consuming +list_item+
def accept_list_item_start(list_item)
if tag = @in_list_entry.last
@res << tag
end
@res << list_item_start(list_item, @list.last)
end
##
# Finishes consumption of +list_item+
def accept_list_item_end(list_item)
@in_list_entry[-1] = list_end_for(@list.last)
end
##
# Adds +blank_line+ to the output
def accept_blank_line(blank_line)
# @res << annotate("<p />") << "\n"
end
##
# Adds +heading+ to the output. The headings greater than 6 are trimmed to
# level 6.
def accept_heading heading
level = [6, heading.level].min
label = heading.label @code_object
@res << if @options.output_decoration
"\n<h#{level} id=\"#{label}\">"
else
"\n<h#{level}>"
end
@res << to_html(heading.text)
unless @options.pipe then
@res << "<span><a href=\"##{label}\">&para;</a>"
@res << " <a href=\"#top\">&uarr;</a></span>"
end
@res << "</h#{level}>\n"
end
##
# Adds +raw+ to the output
def accept_raw raw
@res << raw.parts.join("\n")
end
##
# Adds +table+ to the output
def accept_table header, body, aligns
@res << "\n<table role=\"table\">\n<thead>\n<tr>\n"
header.zip(aligns) do |text, align|
@res << '<th'
@res << ' align="' << align << '"' if align
@res << '>' << CGI.escapeHTML(text) << "</th>\n"
end
@res << "</tr>\n</thead>\n<tbody>\n"
body.each do |row|
@res << "<tr>\n"
row.zip(aligns) do |text, align|
@res << '<td'
@res << ' align="' << align << '"' if align
@res << '>' << CGI.escapeHTML(text) << "</td>\n"
end
@res << "</tr>\n"
end
@res << "</tbody>\n</table>\n"
end
# :section: Utilities
##
# CGI-escapes +text+
def convert_string(text)
CGI.escapeHTML text
end
##
# Generate a link to +url+ with content +text+. Handles the special cases
# for img: and link: described under handle_regexp_HYPERLINK
def gen_url url, text
scheme, url, id = parse_url url
if %w[http https link].include?(scheme) and
url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then
"<img src=\"#{url}\" />"
else
if scheme != 'link' and /\.(?:rb|rdoc|md)\z/i =~ url
url = url.sub(%r%\A([./]*)(.*)\z%) { "#$1#{$2.tr('.', '_')}.html" }
end
text = text.sub %r%^#{scheme}:/*%i, ''
text = text.sub %r%^[*\^](\d+)$%, '\1'
link = "<a#{id} href=\"#{url}\">#{text}</a>"
link = "<sup>#{link}</sup>" if /"foot/ =~ id
link
end
end
##
# Determines the HTML list element for +list_type+ and +open_tag+
def html_list_name(list_type, open_tag)
tags = LIST_TYPE_TO_HTML[list_type]
raise RDoc::Error, "Invalid list type: #{list_type.inspect}" unless tags
tags[open_tag ? 0 : 1]
end
##
# Maps attributes to HTML tags
def init_tags
add_tag :BOLD, "<strong>", "</strong>"
add_tag :TT, "<code>", "</code>"
add_tag :EM, "<em>", "</em>"
end
##
# Returns the HTML tag for +list_type+, possible using a label from
# +list_item+
def list_item_start(list_item, list_type)
case list_type
when :BULLET, :LALPHA, :NUMBER, :UALPHA then
"<li>"
when :LABEL, :NOTE then
Array(list_item.label).map do |label|
"<dt>#{to_html label}\n"
end.join << "<dd>"
else
raise RDoc::Error, "Invalid list type: #{list_type.inspect}"
end
end
##
# Returns the HTML end-tag for +list_type+
def list_end_for(list_type)
case list_type
when :BULLET, :LALPHA, :NUMBER, :UALPHA then
"</li>"
when :LABEL, :NOTE then
"</dd>"
else
raise RDoc::Error, "Invalid list type: #{list_type.inspect}"
end
end
##
# Returns true if text is valid ruby syntax
def parseable? text
verbose, $VERBOSE = $VERBOSE, nil
eval("BEGIN {return true}\n#{text}")
rescue SyntaxError
false
ensure
$VERBOSE = verbose
end
##
# Converts +item+ to HTML using RDoc::Text#to_html
def to_html item
super convert_flow @am.flow item
end
end