diff options
Diffstat (limited to 'lib/rdoc')
114 files changed, 2727 insertions, 1713 deletions
diff --git a/lib/rdoc/alias.rb b/lib/rdoc/alias.rb index 858e053049..446cf9ccb4 100644 --- a/lib/rdoc/alias.rb +++ b/lib/rdoc/alias.rb @@ -109,4 +109,3 @@ class RDoc::Alias < RDoc::CodeObject end end - diff --git a/lib/rdoc/anon_class.rb b/lib/rdoc/anon_class.rb index d02a38c2cf..3c2f0e1877 100644 --- a/lib/rdoc/anon_class.rb +++ b/lib/rdoc/anon_class.rb @@ -8,4 +8,3 @@ class RDoc::AnonClass < RDoc::ClassModule end - diff --git a/lib/rdoc/any_method.rb b/lib/rdoc/any_method.rb index 562e68461c..465c4a4fb2 100644 --- a/lib/rdoc/any_method.rb +++ b/lib/rdoc/any_method.rb @@ -26,6 +26,9 @@ class RDoc::AnyMethod < RDoc::MethodAttr attr_accessor :c_function + # The section title of the method (if defined in a C file via +:category:+) + attr_accessor :section_title + # Parameters for this method attr_accessor :params @@ -113,6 +116,13 @@ class RDoc::AnyMethod < RDoc::MethodAttr end ## + # Whether the method has a call-seq. + + def has_call_seq? + !!(@call_seq || is_alias_for&._call_seq) + end + + ## # Loads is_alias_for from the internal name. Returns nil if the alias # cannot be found. @@ -294,6 +304,14 @@ class RDoc::AnyMethod < RDoc::MethodAttr end ## + # Whether to skip the method description, true for methods that have + # aliases with a call-seq that doesn't include the method name. + + def skip_description? + has_call_seq? && call_seq.nil? && !!(is_alias_for || !aliases.empty?) + end + + ## # Sets the store for this method and its referenced code objects. def store= store @@ -347,15 +365,15 @@ class RDoc::AnyMethod < RDoc::MethodAttr ignore << is_alias_for.name ignore.concat is_alias_for.aliases.map(&:name) end - ignore.map! { |n| n =~ /\A\[/ ? n[0, 1] : n} + ignore.map! { |n| n =~ /\A\[/ ? /\[.*\]/ : n} ignore.delete(method_name) ignore = Regexp.union(ignore) matching = entries.reject do |entry| - entry =~ /^\w*\.?#{ignore}/ or + entry =~ /^\w*\.?#{ignore}[$\(\s]/ or entry =~ /\s#{ignore}\s/ end - matching.join "\n" + matching.empty? ? nil : matching.join("\n") end end diff --git a/lib/rdoc/attr.rb b/lib/rdoc/attr.rb index f780b3b976..a403235933 100644 --- a/lib/rdoc/attr.rb +++ b/lib/rdoc/attr.rb @@ -173,4 +173,3 @@ class RDoc::Attr < RDoc::MethodAttr end end - diff --git a/lib/rdoc/class_module.rb b/lib/rdoc/class_module.rb index 7609080fbf..c69e14b5e4 100644 --- a/lib/rdoc/class_module.rb +++ b/lib/rdoc/class_module.rb @@ -799,4 +799,3 @@ class RDoc::ClassModule < RDoc::Context end end - diff --git a/lib/rdoc/code_objects.rb b/lib/rdoc/code_objects.rb index 434a25ac7f..d5f2f920ad 100644 --- a/lib/rdoc/code_objects.rb +++ b/lib/rdoc/code_objects.rb @@ -2,5 +2,4 @@ # This file was used to load all the RDoc::CodeObject subclasses at once. Now # autoload handles this. -require 'rdoc' - +require_relative '../rdoc' diff --git a/lib/rdoc/comment.rb b/lib/rdoc/comment.rb index 9e90999eac..04ec226436 100644 --- a/lib/rdoc/comment.rb +++ b/lib/rdoc/comment.rb @@ -6,8 +6,8 @@ # Each comment may have a different markup format set by #format=. By default # 'rdoc' is used. The :markup: directive tells RDoc which format to use. # -# See RDoc::Markup@Other+directives for instructions on adding an alternate -# format. +# See RDoc::MarkupReference@Directive+for+Specifying+RDoc+Source+Format. + class RDoc::Comment @@ -97,42 +97,26 @@ class RDoc::Comment # comment. The difficulty is to make sure not to match lines starting # with ARGF at the same indent, but that are after the first description # paragraph. - if @text =~ /^\s*:?call-seq:(.*?(?:\S).*?)^\s*$/m then + if /^(?<S> ((?!\n)\s)*+ (?# whitespaces except newline)) + :?call-seq: + (?<B> \g<S>(?<N>\n|\z) (?# trailing spaces))? + (?<seq> + (\g<S>(?!\w)\S.*\g<N>)* + (?> + (?<H> \g<S>\w+ (?# ' # ARGF' in the example above)) + .*\g<N>)? + (\g<S>\S.*\g<N> (?# other non-blank line))*+ + (\g<B>+(\k<H>.*\g<N> (?# ARGF.to_a lines))++)*+ + ) + (?m:^\s*$|\z) + /x =~ @text + seq = $~[:seq] + all_start, all_stop = $~.offset(0) - seq_start, seq_stop = $~.offset(1) - - # we get the following lines that start with the leading word at the - # same indent, even if they have blank lines before - if $1 =~ /(^\s*\n)+^(\s*\w+)/m then - leading = $2 # ' * ARGF' in the example above - re = %r% - \A( - (^\s*\n)+ - (^#{Regexp.escape leading}.*?\n)+ - )+ - ^\s*$ - %xm - - if @text[seq_stop..-1] =~ re then - all_stop = seq_stop + $~.offset(0).last - seq_stop = seq_stop + $~.offset(1).last - end - end - - seq = @text[seq_start..seq_stop] - seq.gsub!(/^\s*(\S|\n)/m, '\1') @text.slice! all_start...all_stop - method.call_seq = seq.chomp - - else - regexp = /^\s*:?call-seq:(.*?)(^\s*$|\z)/m - if regexp =~ @text then - @text = @text.sub(regexp, '') - seq = $1 - seq.gsub!(/^\s*/, '') - method.call_seq = seq - end + seq.gsub!(/^\s*/, '') + method.call_seq = seq end method @@ -149,12 +133,7 @@ class RDoc::Comment # HACK dubious def encode! encoding - # TODO: Remove this condition after Ruby 2.2 EOL - if RUBY_VERSION < '2.3.0' - @text = @text.force_encoding encoding - else - @text = String.new @text, encoding: encoding - end + @text = String.new @text, encoding: encoding self end diff --git a/lib/rdoc/constant.rb b/lib/rdoc/constant.rb index 0c3d7505a1..12b8be775c 100644 --- a/lib/rdoc/constant.rb +++ b/lib/rdoc/constant.rb @@ -184,4 +184,3 @@ class RDoc::Constant < RDoc::CodeObject end end - diff --git a/lib/rdoc/context.rb b/lib/rdoc/context.rb index b3caa53aa1..c688d562c3 100644 --- a/lib/rdoc/context.rb +++ b/lib/rdoc/context.rb @@ -1,6 +1,4 @@ # frozen_string_literal: true -require 'cgi' - ## # A Context is something that can hold modules, classes, methods, attributes, # aliases, requires, and includes. Classes, modules, and files are all @@ -712,7 +710,7 @@ class RDoc::Context < RDoc::CodeObject # This method exists to make it easy to work with Context subclasses that # aren't part of RDoc. - def each_ancestor # :nodoc: + def each_ancestor(&_) # :nodoc: end ## @@ -1261,6 +1259,6 @@ class RDoc::Context < RDoc::CodeObject klass end - autoload :Section, 'rdoc/context/section' + autoload :Section, "#{__dir__}/context/section" end diff --git a/lib/rdoc/context/section.rb b/lib/rdoc/context/section.rb index 5fef4a9ffc..aecd4e0213 100644 --- a/lib/rdoc/context/section.rb +++ b/lib/rdoc/context/section.rb @@ -1,4 +1,6 @@ # frozen_string_literal: true +require 'cgi/util' + ## # A section of documentation like: # @@ -229,4 +231,3 @@ class RDoc::Context::Section end end - diff --git a/lib/rdoc/cross_reference.rb b/lib/rdoc/cross_reference.rb index 99a64cd99a..4e011219e8 100644 --- a/lib/rdoc/cross_reference.rb +++ b/lib/rdoc/cross_reference.rb @@ -1,4 +1,7 @@ # frozen_string_literal: true + +require_relative 'markup/attribute_manager' # for PROTECT_ATTR + ## # RDoc::CrossReference is a reusable way to create cross references for names. @@ -15,11 +18,24 @@ class RDoc::CrossReference CLASS_REGEXP_STR = '\\\\?((?:\:{2})?[A-Z]\w*(?:\:\:\w+)*)' ## + # Regular expression to match a single method argument. + + METHOD_ARG_REGEXP_STR = '[\w.+*/=<>-]+' + + ## + # Regular expression to match method arguments. + + METHOD_ARGS_REGEXP_STR = /(?:\((?:#{METHOD_ARG_REGEXP_STR}(?:,\s*#{METHOD_ARG_REGEXP_STR})*)?\))?/.source + + ## # Regular expression to match method references. # # See CLASS_REGEXP_STR - METHOD_REGEXP_STR = '([a-z]\w*[!?=]?|%|===|\[\]=?|<<|>>|\+@|-@|-|\+|\*)(?:\([\w.+*/=<>-]*\))?' + METHOD_REGEXP_STR = /( + (?!\d)[\w#{RDoc::Markup::AttributeManager::PROTECT_ATTR}]+[!?=]?| + %|=(?:==?|~)|![=~]|\[\]=?|<(?:<|=>?)?|>[>=]?|[-+!]@?|\*\*?|[\/%\`|&^~] + )#{METHOD_ARGS_REGEXP_STR}/.source.delete("\n ").freeze ## # Regular expressions matching text that should potentially have @@ -34,12 +50,6 @@ class RDoc::CrossReference # A::B::C.meth #{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR} - # Stand-alone method (preceded by a #) - | \\?\##{METHOD_REGEXP_STR} - - # Stand-alone method (preceded by ::) - | ::#{METHOD_REGEXP_STR} - # A::B::C # The stuff after CLASS_REGEXP_STR is a # nasty hack. CLASS_REGEXP_STR unfortunately matches @@ -56,6 +66,12 @@ class RDoc::CrossReference # marker. | #{CLASS_REGEXP_STR}(?=[@\s).?!,;<\000]|\z) + # Stand-alone method (preceded by a #) + | \\?\##{METHOD_REGEXP_STR} + + # Stand-alone method (preceded by ::) + | ::#{METHOD_REGEXP_STR} + # Things that look like filenames # The key thing is that there must be at least # one special character (period, slash, or @@ -82,12 +98,12 @@ class RDoc::CrossReference # A::B::C.meth #{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR} - # Stand-alone method - | \\?#{METHOD_REGEXP_STR} - # A::B::C | #{CLASS_REGEXP_STR}(?=[@\s).?!,;<\000]|\z) + # Stand-alone method + | \\?#{METHOD_REGEXP_STR} + # Things that look like filenames | (?:\.\.\/)*[-\/\w]+[_\/.][-\w\/.]+ @@ -116,14 +132,10 @@ class RDoc::CrossReference end ## - # Returns a reference to +name+. - # - # If the reference is found and +name+ is not documented +text+ will be - # returned. If +name+ is escaped +name+ is returned. If +name+ is not - # found +text+ is returned. + # Returns a method reference to +name+. - def resolve name, text - return @seen[name] if @seen.include? name + def resolve_method name + ref = nil if /#{CLASS_REGEXP_STR}([.#]|::)#{METHOD_REGEXP_STR}/o =~ name then type = $2 @@ -165,12 +177,27 @@ class RDoc::CrossReference end end + ref + end + + ## + # Returns a reference to +name+. + # + # If the reference is found and +name+ is not documented +text+ will be + # returned. If +name+ is escaped +name+ is returned. If +name+ is not + # found +text+ is returned. + + def resolve name, text + return @seen[name] if @seen.include? name + ref = case name when /^\\(#{CLASS_REGEXP_STR})$/o then @context.find_symbol $1 else @context.find_symbol name - end unless ref + end + + ref = resolve_method name unless ref # Try a page name ref = @store.page name if not ref and name =~ /^[\w.]+$/ @@ -199,4 +226,3 @@ class RDoc::CrossReference end end - diff --git a/lib/rdoc/encoding.rb b/lib/rdoc/encoding.rb index cf60badd24..67e190f782 100644 --- a/lib/rdoc/encoding.rb +++ b/lib/rdoc/encoding.rb @@ -86,17 +86,6 @@ module RDoc::Encoding nil end - def self.remove_frozen_string_literal string - string =~ /\A(?:#!.*\n)?(.*\n)/ - first_line = $1 - - if first_line =~ /\A# +frozen[-_]string[-_]literal[=:].+$/i - string = string.sub first_line, '' - end - - string - end - ## # Detects the encoding of +string+ based on the magic comment @@ -124,12 +113,7 @@ module RDoc::Encoding if text.kind_of? RDoc::Comment text.encode! encoding else - # TODO: Remove this condition after Ruby 2.2 EOL - if RUBY_VERSION < '2.3.0' - text.force_encoding encoding - else - String.new text, encoding: encoding - end + String.new text, encoding: encoding end end diff --git a/lib/rdoc/erb_partial.rb b/lib/rdoc/erb_partial.rb index d6e3f41b7e..043d763db1 100644 --- a/lib/rdoc/erb_partial.rb +++ b/lib/rdoc/erb_partial.rb @@ -16,4 +16,3 @@ class RDoc::ERBPartial < ERB end end - diff --git a/lib/rdoc/erbio.rb b/lib/rdoc/erbio.rb index 0d5f96e133..0f98eaedee 100644 --- a/lib/rdoc/erbio.rb +++ b/lib/rdoc/erbio.rb @@ -20,12 +20,8 @@ class RDoc::ERBIO < ERB ## # Defaults +eoutvar+ to 'io', otherwise is identical to ERB's initialize - def initialize str, safe_level = nil, legacy_trim_mode = nil, legacy_eoutvar = 'io', trim_mode: nil, eoutvar: 'io' - if RUBY_VERSION >= '2.6' - super(str, trim_mode: trim_mode, eoutvar: eoutvar) - else - super(str, safe_level, legacy_trim_mode, legacy_eoutvar) - end + def initialize str, trim_mode: nil, eoutvar: 'io' + super(str, trim_mode: trim_mode, eoutvar: eoutvar) end ## @@ -39,4 +35,3 @@ class RDoc::ERBIO < ERB end end - diff --git a/lib/rdoc/extend.rb b/lib/rdoc/extend.rb index e1b182902e..7d57433de6 100644 --- a/lib/rdoc/extend.rb +++ b/lib/rdoc/extend.rb @@ -7,4 +7,3 @@ class RDoc::Extend < RDoc::Mixin end - diff --git a/lib/rdoc/generator.rb b/lib/rdoc/generator.rb index 340dcbf7ae..a769cf8ac0 100644 --- a/lib/rdoc/generator.rb +++ b/lib/rdoc/generator.rb @@ -41,11 +41,11 @@ module RDoc::Generator - autoload :Markup, 'rdoc/generator/markup' + autoload :Markup, "#{__dir__}/generator/markup" - autoload :Darkfish, 'rdoc/generator/darkfish' - autoload :JsonIndex, 'rdoc/generator/json_index' - autoload :RI, 'rdoc/generator/ri' - autoload :POT, 'rdoc/generator/pot' + autoload :Darkfish, "#{__dir__}/generator/darkfish" + autoload :JsonIndex, "#{__dir__}/generator/json_index" + autoload :RI, "#{__dir__}/generator/ri" + autoload :POT, "#{__dir__}/generator/pot" end diff --git a/lib/rdoc/generator/darkfish.rb b/lib/rdoc/generator/darkfish.rb index b46861d009..1b408a6f8e 100644 --- a/lib/rdoc/generator/darkfish.rb +++ b/lib/rdoc/generator/darkfish.rb @@ -220,8 +220,8 @@ class RDoc::Generator::Darkfish install_rdoc_static_file @template_dir + item, "./#{item}", options end - @options.template_stylesheets.each do |stylesheet| - FileUtils.cp stylesheet, '.', options + unless @options.template_stylesheets.empty? + FileUtils.cp @options.template_stylesheets, '.', **options end Dir[(@template_dir + "{js,images}/**/*").to_s].each do |path| @@ -610,7 +610,7 @@ class RDoc::Generator::Darkfish @classes = @store.all_classes_and_modules.sort @files = @store.all_files.sort - @methods = @classes.map { |m| m.method_list }.flatten.sort + @methods = @classes.flat_map { |m| m.method_list }.sort @modsort = get_sorted_module_list @classes end @@ -778,11 +778,7 @@ class RDoc::Generator::Darkfish erbout = "_erbout_#{file_var}" end - if RUBY_VERSION >= '2.6' - template = klass.new template, trim_mode: '-', eoutvar: erbout - else - template = klass.new template, nil, '-', erbout - end + template = klass.new template, trim_mode: '-', eoutvar: erbout @template_cache[file] = template template end diff --git a/lib/rdoc/generator/json_index.rb b/lib/rdoc/generator/json_index.rb index 3a1000033d..c454910d5c 100644 --- a/lib/rdoc/generator/json_index.rb +++ b/lib/rdoc/generator/json_index.rb @@ -230,9 +230,9 @@ class RDoc::Generator::JsonIndex def index_methods debug_msg " generating method search index" - list = @classes.uniq.map do |klass| + list = @classes.uniq.flat_map do |klass| klass.method_list - end.flatten.sort_by do |method| + end.sort_by do |method| [method.name, method.parent.full_name] end diff --git a/lib/rdoc/generator/markup.rb b/lib/rdoc/generator/markup.rb index 41e132450d..76b7d458aa 100644 --- a/lib/rdoc/generator/markup.rb +++ b/lib/rdoc/generator/markup.rb @@ -109,7 +109,7 @@ class RDoc::MethodAttr lines.shift if src =~ /\A.*#\ *File/i # remove '# File' comment lines.each do |line| if line =~ /^ *(?=\S)/ - n = $&.length + n = $~.end(0) indent = n if n < indent break if n == 0 end @@ -157,4 +157,3 @@ class RDoc::TopLevel end end - diff --git a/lib/rdoc/generator/pot.rb b/lib/rdoc/generator/pot.rb index bee1133b07..b0b7c07179 100644 --- a/lib/rdoc/generator/pot.rb +++ b/lib/rdoc/generator/pot.rb @@ -81,6 +81,7 @@ class RDoc::Generator::POT end end + # :nodoc: def class_dir nil end diff --git a/lib/rdoc/generator/ri.rb b/lib/rdoc/generator/ri.rb index 0eef1d03f5..1c2f018f97 100644 --- a/lib/rdoc/generator/ri.rb +++ b/lib/rdoc/generator/ri.rb @@ -28,4 +28,3 @@ class RDoc::Generator::RI end end - diff --git a/lib/rdoc/generator/template/darkfish/_head.rhtml b/lib/rdoc/generator/template/darkfish/_head.rhtml index e61fce1b9a..d5aed3e9ef 100644 --- a/lib/rdoc/generator/template/darkfish/_head.rhtml +++ b/lib/rdoc/generator/template/darkfish/_head.rhtml @@ -3,20 +3,18 @@ <title><%= h @title %></title> <script type="text/javascript"> - var rdoc_rel_prefix = "<%= asset_rel_prefix %>/"; - var index_rel_prefix = "<%= rel_prefix %>/"; + var rdoc_rel_prefix = "<%= h asset_rel_prefix %>/"; + var index_rel_prefix = "<%= h rel_prefix %>/"; </script> -<script src="<%= asset_rel_prefix %>/js/navigation.js" defer></script> -<script src="<%= asset_rel_prefix %>/js/search.js" defer></script> -<script src="<%= asset_rel_prefix %>/js/search_index.js" defer></script> -<script src="<%= asset_rel_prefix %>/js/searcher.js" defer></script> -<script src="<%= asset_rel_prefix %>/js/darkfish.js" defer></script> +<script src="<%= h asset_rel_prefix %>/js/navigation.js" defer></script> +<script src="<%= h asset_rel_prefix %>/js/search.js" defer></script> +<script src="<%= h asset_rel_prefix %>/js/search_index.js" defer></script> +<script src="<%= h asset_rel_prefix %>/js/searcher.js" defer></script> +<script src="<%= h asset_rel_prefix %>/js/darkfish.js" defer></script> -<link href="<%= asset_rel_prefix %>/css/fonts.css" rel="stylesheet"> -<link href="<%= asset_rel_prefix %>/css/rdoc.css" rel="stylesheet"> -<%- if @options.template_stylesheets.flatten.any? then -%> -<%- @options.template_stylesheets.flatten.each do |stylesheet| -%> -<link href="<%= asset_rel_prefix %>/<%= File.basename stylesheet %>" rel="stylesheet"> -<%- end -%> +<link href="<%= h asset_rel_prefix %>/css/fonts.css" rel="stylesheet"> +<link href="<%= h asset_rel_prefix %>/css/rdoc.css" rel="stylesheet"> +<%- @options.template_stylesheets.each do |stylesheet| -%> +<link href="<%= h asset_rel_prefix %>/<%= File.basename stylesheet %>" rel="stylesheet"> <%- end -%> diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml index 530f25c762..d3d8da4017 100644 --- a/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml +++ b/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml @@ -1,9 +1,33 @@ <div id="classindex-section" class="nav-section"> <h3>Class and Module Index</h3> + <%- + all_classes = @classes.group_by do |klass| + klass.full_name[/\A[^:]++(?:::[^:]++(?=::))*+(?=::[^:]*+\z)/] + end.delete_if do |_, klasses| + !klasses.any?(&:display?) + end + link = proc do |index_klass, display = index_klass.display?| + if display + -%><code><a href="<%= rel_prefix %>/<%= index_klass.path %>"><%= index_klass.name %></a></code><%- + else + -%><code><%= index_klass.name %></code><%- + end + end + if top = all_classes[nil] + solo = top.one? {|klass| klass.display?} + traverse = proc do |klasses| -%> <ul class="link-list"> - <%- @modsort.each do |index_klass| -%> - <li><a href="<%= rel_prefix %>/<%= index_klass.path %>"><%= index_klass.full_name %></a> + <%- klasses.each do |index_klass| -%> + <%- if children = all_classes[index_klass.full_name] -%> + <li><details<% if solo; solo = false %> open<% end %>><summary><% link.call(index_klass) %></summary> + <%- traverse.call(children) -%> + </ul></details> + <%- elsif index_klass.display? -%> + <li><% link.call(index_klass, true) %> + <%- end -%> + <%- end -%> + <%- end -%> + <%- traverse.call(top) -%> <%- end -%> - </ul> </div> diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml index 8ec83abda2..3f68f0c0dc 100644 --- a/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +++ b/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml @@ -1,11 +1,31 @@ <%- simple_files = @files.select { |f| f.text? } %> +<%- if defined?(current) -%> + <%- dir = current.full_name[%r{\A[^/]+(?=/)}] || current.page_name -%> +<%- end -%> <%- unless simple_files.empty? then -%> <div id="fileindex-section" class="nav-section"> <h3>Pages</h3> <ul class="link-list"> - <%- simple_files.each do |f| -%> - <li><a href="<%= rel_prefix %>/<%= f.path %>"><%= h f.page_name %></a> + <%- simple_files.group_by do |f| -%> + <%- f.full_name[%r{\A[^/]+(?=/)}] || f.page_name -%> + <%- end.each do |n, files| -%> + <%- f = files.shift -%> + <%- if files.empty? -%> + <li><a href="<%= rel_prefix %>/<%= h f.path %>"><%= h f.page_name %></a> + <%- next -%> + <%- end -%> + <li><details<% if dir == n %> open<% end %>><summary><% + if n == f.page_name + %><a href="<%= rel_prefix %>/<%= h f.path %>"><%= h n %></a><% + else + %><%= h n %><% files.unshift(f) + end %></summary> + <ul class="link-list"> + <%- files.each do |f| -%> + <li><a href="<%= rel_prefix %>/<%= h f.path %>"><%= h f.page_name %></a> + <%- end -%> + </ul></details> <%- end -%> </ul> </div> diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml index 9c49b31376..afc7f7b88d 100644 --- a/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml +++ b/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml @@ -3,7 +3,7 @@ <div id="search-field-wrapper"> <input id="search-field" role="combobox" aria-label="Search" aria-autocomplete="list" aria-controls="search-results" - type="text" name="search" placeholder="Search" spellcheck="false" + type="text" name="search" placeholder="Search (/) for a class, method, ..." spellcheck="false" title="Type to search, Up and Down to navigate, Enter to load"> </div> diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml index bf70819f64..b1e047b5f7 100644 --- a/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +++ b/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml @@ -3,16 +3,37 @@ else current.comment end - table = current.parse(comment).table_of_contents + table = current.parse(comment).table_of_contents.dup if table.length > 1 then %> <div class="nav-section"> <h3>Table of Contents</h3> + <%- display_link = proc do |heading| -%> + <a href="#<%= heading.label current %>"><%= heading.plain_html %></a> + <%- end -%> + + <%- list_siblings = proc do -%> + <%- level = table.first&.level -%> + <%- while table.first && table.first.level >= level -%> + <%- heading = table.shift -%> + <%- if table.first.nil? || table.first.level <= heading.level -%> + <li><% display_link.call heading -%> + <%- else -%> + <li> + <details open> + <summary><%- display_link.call heading -%></summary> + <ul class="link-list" role="directory"> + <% list_siblings.call %> + </ul> + </details> + </li> + <%- end -%> + <%- end -%> + <%- end -%> + <ul class="link-list" role="directory"> -<%- table.each do |heading| -%> - <li><a href="#<%= heading.label current %>"><%= heading.plain_html %></a> -<%- end -%> + <% list_siblings.call %> </ul> </div> <%- end -%> diff --git a/lib/rdoc/generator/template/darkfish/class.rhtml b/lib/rdoc/generator/template/darkfish/class.rhtml index 5d7b6a1b80..d6510336df 100644 --- a/lib/rdoc/generator/template/darkfish/class.rhtml +++ b/lib/rdoc/generator/template/darkfish/class.rhtml @@ -98,29 +98,36 @@ <%- methods.each do |method| -%> <div id="<%= method.aref %>" class="method-detail <%= method.is_alias_for ? "method-alias" : '' %>"> - <%- if (call_seq = method.call_seq) then -%> - <%- call_seq.strip.split("\n").each_with_index do |call_seq, i| -%> - <div class="method-heading"> - <span class="method-callseq"> - <%= h(call_seq.strip. - gsub( /^\w+\./m, '')). - gsub(/(.*)[-=]>/, '\1→') %> - </span> - <%- if i == 0 and method.token_stream then -%> - <span class="method-click-advice">click to toggle source</span> - <%- end -%> - </div> - <%- end -%> - <%- else -%> - <div class="method-heading"> - <span class="method-name"><%= h method.name %></span><span - class="method-args"><%= h method.param_seq %></span> - <%- if method.token_stream then -%> - <span class="method-click-advice">click to toggle source</span> + <div class="method-header"> + <%- if (call_seq = method.call_seq) then -%> + <%- call_seq.strip.split("\n").each_with_index do |call_seq, i| -%> + <div class="method-heading"> + <span class="method-callseq"> + <%= h(call_seq.strip. + gsub( /^\w+\./m, '')). + gsub(/(.*)[-=]>/, '\1→') %> + </span> + <%- if i == 0 and method.token_stream then -%> + <span class="method-click-advice">click to toggle source</span> + <%- end -%> + </div> + <%- end -%> + <%- elsif method.has_call_seq? then -%> + <div class="method-heading"> + <span class="method-name"><%= h method.name %></span> + </div> + <%- else -%> + <div class="method-heading"> + <span class="method-name"><%= h method.name %></span><span + class="method-args"><%= h method.param_seq %></span> + <%- if method.token_stream then -%> + <span class="method-click-advice">click to toggle source</span> + <%- end -%> + </div> <%- end -%> </div> - <%- end -%> + <%- unless method.skip_description? then -%> <div class="method-description"> <%- if method.comment then -%> <%= method.description.strip %> @@ -143,6 +150,7 @@ </div> <%- end -%> </div> + <%- end -%> <%- unless method.aliases.empty? then -%> <div class="aliases"> diff --git a/lib/rdoc/generator/template/darkfish/css/rdoc.css b/lib/rdoc/generator/template/darkfish/css/rdoc.css index ebe2e93af6..2cc55e03b1 100644 --- a/lib/rdoc/generator/template/darkfish/css/rdoc.css +++ b/lib/rdoc/generator/template/darkfish/css/rdoc.css @@ -17,6 +17,14 @@ body { background: #fafafa; font-family: Lato, sans-serif; font-weight: 300; + + /* Layout */ + display: grid; + grid-template-columns: auto 1fr; +} + +body > :last-child { + grid-column: 1 / 3; } h1 span, @@ -79,6 +87,17 @@ pre { border-radius: 0.2em; } +em { + text-decoration-color: rgba(52, 48, 64, 0.25); + text-decoration-line: underline; + text-decoration-style: dotted; +} + +strong, +em { + background-color: rgba(158, 178, 255, 0.1); +} + table { margin: 0; border-spacing: 0; @@ -181,17 +200,25 @@ table tr:nth-child(even) td { /* @group Top-Level Structure */ nav { - float: left; - width: 260px; font-family: Helvetica, sans-serif; font-size: 14px; border-right: 1px solid #ccc; + position: sticky; + top: 0; + overflow: auto; + + /* Layout */ + width: 260px; /* fallback */ + width: max(50px, 20vw); + min-width: 50px; + max-width: 80vw; + height: calc(100vh - 100px); /* reduce the footer height */ + resize: horizontal; } main { display: block; - margin: 0 2em 5em 260px; - padding-left: 20px; + margin: 1em; min-width: 340px; font-size: 16px; } @@ -210,7 +237,6 @@ main h6 { } #validator-badges { - clear: both; margin: 1em 1em 2em; font-size: smaller; } @@ -305,6 +331,28 @@ dl.note-list dt { background: url(../images/arrow_up.png) no-repeat right center; } +.nav-section details > summary { + display: block; +} + +.nav-section details > summary::-webkit-details-marker { + display: none; +} + +.nav-section details > summary::before { + content: ""; +} + +.nav-section details > summary::after { + content: "\25B6"; /* BLACK RIGHT-POINTING TRIANGLE */ + font-size: 0.8em; + margin-left: 0.4em; +} + +.nav-section details[open] > summary::after { + content: "\25BD"; /* WHITE DOWN-POINTING TRIANGLE */ +} + /* @end */ /* @group Documentation Section */ @@ -482,7 +530,7 @@ main header h3 { main .method-source-code { max-height: 0; - overflow: hidden; + overflow: auto; transition-duration: 200ms; transition-delay: 0ms; transition-property: all; @@ -530,7 +578,7 @@ main .method-click-advice { line-height: 20px; background: url(../images/zoom.png) no-repeat right top; } -main .method-heading:hover .method-click-advice { +main .method-header:hover .method-click-advice { visibility: visible; } diff --git a/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Bold.ttf b/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Bold.ttf Binary files differindex 61e3090c1c..dd00982d49 100644 --- a/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Bold.ttf +++ b/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Bold.ttf diff --git a/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Regular.ttf b/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Regular.ttf Binary files differindex 85686d967d..1decfb95af 100644 --- a/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Regular.ttf +++ b/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Regular.ttf diff --git a/lib/rdoc/generator/template/darkfish/index.rhtml b/lib/rdoc/generator/template/darkfish/index.rhtml index 13fa3dcc7f..423e225b68 100644 --- a/lib/rdoc/generator/template/darkfish/index.rhtml +++ b/lib/rdoc/generator/template/darkfish/index.rhtml @@ -17,6 +17,6 @@ main_page = @files.find { |f| f.full_name == @options.main_page } then %> <%= main_page.description %> <%- else -%> -<p>This is the API documentation for <%= @title %>. +<p>This is the API documentation for <%= h @title %>. <%- end -%> </main> diff --git a/lib/rdoc/generator/template/darkfish/js/darkfish.js b/lib/rdoc/generator/template/darkfish/js/darkfish.js index 111bbf8eb9..19a85c54e1 100644 --- a/lib/rdoc/generator/template/darkfish/js/darkfish.js +++ b/lib/rdoc/generator/template/darkfish/js/darkfish.js @@ -54,7 +54,7 @@ function hookSearch() { var html = ''; // TODO add relative path to <script> per-page - html += '<p class="search-match"><a href="' + index_rel_prefix + result.path + '">' + this.hlt(result.title); + html += '<p class="search-match"><a href="' + index_rel_prefix + this.escapeHTML(result.path) + '">' + this.hlt(result.title); if (result.params) html += '<span class="params">' + result.params + '</span>'; html += '</a>'; @@ -78,7 +78,20 @@ function hookSearch() { search.scrollIntoView = search.scrollInWindow; }; +function hookFocus() { + document.addEventListener("keydown", (event) => { + if (document.activeElement.tagName === 'INPUT') { + return; + } + if (event.key === "/") { + event.preventDefault(); + document.querySelector('#search-field').focus(); + } + }); +} + document.addEventListener('DOMContentLoaded', function() { hookSourceViews(); hookSearch(); + hookFocus(); }); diff --git a/lib/rdoc/generator/template/darkfish/js/search.js b/lib/rdoc/generator/template/darkfish/js/search.js index b558ca5b4f..d3cded1d57 100644 --- a/lib/rdoc/generator/template/darkfish/js/search.js +++ b/lib/rdoc/generator/template/darkfish/js/search.js @@ -15,9 +15,9 @@ Search.prototype = Object.assign({}, Navigation, new function() { this.init = function() { var _this = this; var observer = function(e) { - switch(e.keyCode) { - case 38: // Event.KEY_UP - case 40: // Event.KEY_DOWN + switch(e.key) { + case 'ArrowUp': + case 'ArrowDown': return; } _this.search(_this.input.value); @@ -101,7 +101,7 @@ Search.prototype = Object.assign({}, Navigation, new function() { } this.escapeHTML = function(html) { - return html.replace(/[&<>]/g, function(c) { + return html.replace(/[&<>"`']/g, function(c) { return '&#' + c.charCodeAt(0) + ';'; }); } diff --git a/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml b/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml index 303d7016cc..54a376c9e5 100644 --- a/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +++ b/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml @@ -8,14 +8,14 @@ <ul> <%- simple_files.sort.each do |file| -%> <li class="file"> - <a href="<%= file.path %>"><%= h file.page_name %></a> + <a href="<%= h file.path %>"><%= h file.page_name %></a> <% # HACK table_of_contents should not exist on Document table = file.parse(file.comment).table_of_contents unless table.empty? then %> <ul> <%- table.each do |heading| -%> - <li><a href="<%= file.path %>#<%= heading.aref %>"><%= heading.plain_html %></a> + <li><a href="<%= h file.path %>#<%= heading.aref %>"><%= heading.plain_html %></a> <%- end -%> </ul> <%- end -%> @@ -36,8 +36,9 @@ unless table.empty? then %> <ul> <%- table.each do |item| -%> - <li><a href="<%= klass.path %>#<%= item.aref %>"><%= item.plain_html %></a> -<%- end -%> +<%- label = item.respond_to?(:label) ? item.label(klass) : item.aref -%> + <li><a href="<%= klass.path %>#<%= label %>"><%= item.plain_html %></a> +<%- end -%> </ul> <%- end -%> </li> @@ -46,9 +47,9 @@ <h2 id="methods">Methods</h2> <ul> -<%- @store.all_classes_and_modules.map do |mod| +<%- @store.all_classes_and_modules.flat_map do |mod| mod.method_list - end.flatten.sort.each do |method| %> + end.sort.each do |method| %> <li class="method"> <a href="<%= method.path %>"><%= h method.pretty_name %></a> — diff --git a/lib/rdoc/generator/template/json_index/js/navigation.js b/lib/rdoc/generator/template/json_index/js/navigation.js index dfad74b1ae..137e3a0038 100644 --- a/lib/rdoc/generator/template/json_index/js/navigation.js +++ b/lib/rdoc/generator/template/json_index/js/navigation.js @@ -23,24 +23,24 @@ Navigation = new function() { this.onkeydown = function(e) { if (!this.navigationActive) return; - switch(e.keyCode) { - case 37: //Event.KEY_LEFT: + switch(e.key) { + case 'ArrowLeft': if (this.moveLeft()) e.preventDefault(); break; - case 38: //Event.KEY_UP: - if (e.keyCode == 38 || e.ctrlKey) { + case 'ArrowUp': + if (e.key == 'ArrowUp' || e.ctrlKey) { if (this.moveUp()) e.preventDefault(); } break; - case 39: //Event.KEY_RIGHT: + case 'ArrowRight': if (this.moveRight()) e.preventDefault(); break; - case 40: //Event.KEY_DOWN: - if (e.keyCode == 40 || e.ctrlKey) { + case 'ArrowDown': + if (e.key == 'ArrowDown' || e.ctrlKey) { if (this.moveDown()) e.preventDefault(); } break; - case 13: //Event.KEY_RETURN: + case 'Enter': if (this.current) e.preventDefault(); this.select(this.current); break; diff --git a/lib/rdoc/ghost_method.rb b/lib/rdoc/ghost_method.rb index 2488feb9d7..25f951e35e 100644 --- a/lib/rdoc/ghost_method.rb +++ b/lib/rdoc/ghost_method.rb @@ -4,4 +4,3 @@ class RDoc::GhostMethod < RDoc::AnyMethod end - diff --git a/lib/rdoc/i18n.rb b/lib/rdoc/i18n.rb index a32fd848a0..f209a9a6f6 100644 --- a/lib/rdoc/i18n.rb +++ b/lib/rdoc/i18n.rb @@ -4,7 +4,7 @@ module RDoc::I18n - autoload :Locale, 'rdoc/i18n/locale' + autoload :Locale, "#{__dir__}/i18n/locale" require_relative 'i18n/text' end diff --git a/lib/rdoc/include.rb b/lib/rdoc/include.rb index b3ad610649..c3e0d45e47 100644 --- a/lib/rdoc/include.rb +++ b/lib/rdoc/include.rb @@ -7,4 +7,3 @@ class RDoc::Include < RDoc::Mixin end - diff --git a/lib/rdoc/known_classes.rb b/lib/rdoc/known_classes.rb index 4d7f4aa995..3e8752bbde 100644 --- a/lib/rdoc/known_classes.rb +++ b/lib/rdoc/known_classes.rb @@ -25,6 +25,7 @@ module RDoc "rb_cObject" => "Object", "rb_cProc" => "Proc", "rb_cRange" => "Range", + "rb_cRefinement" => "Refinement", "rb_cRegexp" => "Regexp", "rb_cRubyVM" => "RubyVM", "rb_cSocket" => "Socket", @@ -35,7 +36,7 @@ module RDoc "rb_cTime" => "Time", "rb_cTrueClass" => "TrueClass", - "rb_eArgError" => "ArgError", + "rb_eArgError" => "ArgumentError", "rb_eEOFError" => "EOFError", "rb_eException" => "Exception", "rb_eFatal" => "fatal", @@ -45,8 +46,8 @@ module RDoc "rb_eInterrupt" => "Interrupt", "rb_eLoadError" => "LoadError", "rb_eNameError" => "NameError", - "rb_eNoMemError" => "NoMemError", - "rb_eNotImpError" => "NotImpError", + "rb_eNoMemError" => "NoMemoryError", + "rb_eNotImpError" => "NotImplementedError", "rb_eRangeError" => "RangeError", "rb_eRuntimeError" => "RuntimeError", "rb_eScriptError" => "ScriptError", @@ -57,7 +58,7 @@ module RDoc "rb_eSystemCallError" => "SystemCallError", "rb_eSystemExit" => "SystemExit", "rb_eTypeError" => "TypeError", - "rb_eZeroDivError" => "ZeroDivError", + "rb_eZeroDivError" => "ZeroDivisionError", "rb_mComparable" => "Comparable", "rb_mEnumerable" => "Enumerable", diff --git a/lib/rdoc/markdown.rb b/lib/rdoc/markdown.rb index 15beaefcca..5c72a5f224 100644 --- a/lib/rdoc/markdown.rb +++ b/lib/rdoc/markdown.rb @@ -175,7 +175,7 @@ # [dingus]: http://daringfireball.net/projects/markdown/dingus # [GFM]: https://github.github.com/gfm/ # [pegmarkdown]: https://github.com/jgm/peg-markdown -# [PHPE]: http://michelf.com/projects/php-markdown/extra/#def-list +# [PHPE]: https://michelf.ca/projects/php-markdown/extra/#def-list # [syntax]: http://daringfireball.net/projects/markdown/syntax #-- # Last updated to jgm/peg-markdown commit 8f8fc22ef0 @@ -199,6 +199,7 @@ class RDoc::Markdown @result = nil @failed_rule = nil @failing_rule_offset = -1 + @line_offsets = nil setup_foreign_grammar end @@ -208,30 +209,75 @@ class RDoc::Markdown attr_accessor :result, :pos def current_column(target=pos) - if c = string.rindex("\n", target-1) - return target - c - 1 + if string[target] == "\n" && (c = string.rindex("\n", target-1) || -1) + return target - c + elsif c = string.rindex("\n", target) + return target - c end target + 1 end - def current_line(target=pos) - cur_offset = 0 - cur_line = 0 + def position_line_offsets + unless @position_line_offsets + @position_line_offsets = [] + total = 0 + string.each_line do |line| + total += line.size + @position_line_offsets << total + end + end + @position_line_offsets + end + + if [].respond_to? :bsearch_index + def current_line(target=pos) + if line = position_line_offsets.bsearch_index {|x| x > target } + return line + 1 + end + raise "Target position #{target} is outside of string" + end + else + def current_line(target=pos) + if line = position_line_offsets.index {|x| x > target } + return line + 1 + end - string.each_line do |line| - cur_line += 1 - cur_offset += line.size - return cur_line if cur_offset >= target + raise "Target position #{target} is outside of string" end + end - -1 + def current_character(target=pos) + if target < 0 || target >= string.size + raise "Target position #{target} is outside of string" + end + string[target, 1] + end + + KpegPosInfo = Struct.new(:pos, :lno, :col, :line, :char) + + def current_pos_info(target=pos) + l = current_line target + c = current_column target + ln = get_line(l-1) + chr = string[target,1] + KpegPosInfo.new(target, l, c, ln, chr) end def lines - lines = [] - string.each_line { |l| lines << l } - lines + string.lines + end + + def get_line(no) + loff = position_line_offsets + if no < 0 + raise "Line No is out of range: #{no} < 0" + elsif no >= loff.size + raise "Line No is out of range: #{no} >= #{loff.size}" + end + lend = loff[no]-1 + lstart = no > 0 ? loff[no-1] : 0 + string[lstart..lend] end @@ -245,6 +291,7 @@ class RDoc::Markdown @string = string @string_size = string ? string.size : 0 @pos = pos + @position_line_offsets = nil end def show_pos @@ -269,30 +316,22 @@ class RDoc::Markdown end def failure_caret - l = current_line @failing_rule_offset - c = current_column @failing_rule_offset - - line = lines[l-1] - "#{line}\n#{' ' * (c - 1)}^" + p = current_pos_info @failing_rule_offset + "#{p.line.chomp}\n#{' ' * (p.col - 1)}^" end def failure_character - l = current_line @failing_rule_offset - c = current_column @failing_rule_offset - lines[l-1][c-1, 1] + current_character @failing_rule_offset end def failure_oneline - l = current_line @failing_rule_offset - c = current_column @failing_rule_offset - - char = lines[l-1][c-1, 1] + p = current_pos_info @failing_rule_offset if @failed_rule.kind_of? Symbol info = self.class::Rules[@failed_rule] - "@#{l}:#{c} failed rule '#{info.name}', got '#{char}'" + "@#{p.lno}:#{p.col} failed rule '#{info.name}', got '#{p.char}'" else - "@#{l}:#{c} failed rule '#{@failed_rule}', got '#{char}'" + "@#{p.lno}:#{p.col} failed rule '#{@failed_rule}', got '#{p.char}'" end end @@ -305,10 +344,9 @@ class RDoc::Markdown def show_error(io=STDOUT) error_pos = @failing_rule_offset - line_no = current_line(error_pos) - col_no = current_column(error_pos) + p = current_pos_info(error_pos) - io.puts "On line #{line_no}, column #{col_no}:" + io.puts "On line #{p.lno}, column #{p.col}:" if @failed_rule.kind_of? Symbol info = self.class::Rules[@failed_rule] @@ -317,10 +355,9 @@ class RDoc::Markdown io.puts "Failed to match rule '#{@failed_rule}'" end - io.puts "Got: #{string[error_pos,1].inspect}" - line = lines[line_no-1] - io.puts "=> #{line}" - io.print(" " * (col_no + 3)) + io.puts "Got: #{p.char.inspect}" + io.puts "=> #{p.line}" + io.print(" " * (p.col + 2)) io.puts "^" end @@ -344,9 +381,8 @@ class RDoc::Markdown end def scan(reg) - if m = reg.match(@string[@pos..-1]) - width = m.end(0) - @pos += width + if m = reg.match(@string, @pos) + @pos = m.end(0) return true end @@ -430,6 +466,7 @@ class RDoc::Markdown end def apply_with_args(rule, *args) + @result = nil memo_key = [rule, args] if m = @memoizations[memo_key][@pos] @pos = m.pos @@ -463,6 +500,7 @@ class RDoc::Markdown end def apply(rule) + @result = nil if m = @memoizations[rule][@pos] @pos = m.pos if !m.set @@ -534,11 +572,11 @@ class RDoc::Markdown - require 'rdoc' - require 'rdoc/markup/to_joined_paragraph' - require 'rdoc/markdown/entities' + require_relative '../rdoc' + require_relative 'markup/to_joined_paragraph' + require_relative 'markdown/entities' - require 'rdoc/markdown/literals' + require_relative 'markdown/literals' ## # Supported extensions @@ -796,7 +834,7 @@ class RDoc::Markdown @note_order.each_with_index do |ref, index| label = index + 1 - note = @footnotes[ref] + note = @footnotes[ref] or raise ParseError, "footnote [^#{ref}] not found" link = "{^#{label}}[rdoc-label:footmark-#{label}:foottext-#{label}] " note.parts.unshift link @@ -1060,7 +1098,7 @@ class RDoc::Markdown self.pos = _save3 break end - _tmp = scan(/\A(?-mix:#*)/) + _tmp = scan(/\G(?-mix:#*)/) unless _tmp self.pos = _save3 break @@ -1100,7 +1138,7 @@ class RDoc::Markdown _save = self.pos while true # sequence _text_start = self.pos - _tmp = scan(/\A(?-mix:\#{1,6})/) + _tmp = scan(/\G(?-mix:\#{1,6})/) if _tmp text = get_text(_text_start) end @@ -1165,7 +1203,7 @@ class RDoc::Markdown self.pos = _save3 break end - _tmp = scan(/\A(?-mix:#*)/) + _tmp = scan(/\G(?-mix:#*)/) unless _tmp self.pos = _save3 break @@ -1225,7 +1263,7 @@ class RDoc::Markdown _save = self.pos while true # sequence - _tmp = scan(/\A(?-mix:={1,})/) + _tmp = scan(/\G(?-mix:={1,})/) unless _tmp self.pos = _save break @@ -1246,7 +1284,7 @@ class RDoc::Markdown _save = self.pos while true # sequence - _tmp = scan(/\A(?-mix:-{1,})/) + _tmp = scan(/\G(?-mix:-{1,})/) unless _tmp self.pos = _save break @@ -2130,7 +2168,7 @@ class RDoc::Markdown self.pos = _save break end - _tmp = scan(/\A(?-mix:[+*-])/) + _tmp = scan(/\G(?-mix:[+*-])/) unless _tmp self.pos = _save break @@ -9385,7 +9423,7 @@ class RDoc::Markdown self.pos = _save7 break end - _tmp = scan(/\A(?-mix:[^`\n]*$)/) + _tmp = scan(/\G(?-mix:[^`\n]*$)/) unless _tmp self.pos = _save7 end @@ -9476,7 +9514,7 @@ class RDoc::Markdown self.pos = _save15 break end - _tmp = scan(/\A(?-mix:[^`\n]*$)/) + _tmp = scan(/\G(?-mix:[^`\n]*$)/) unless _tmp self.pos = _save15 end @@ -9725,7 +9763,7 @@ class RDoc::Markdown _save3 = self.pos while true # sequence - _tmp = scan(/\A(?-mix:_+)/) + _tmp = scan(/\G(?-mix:_+)/) unless _tmp self.pos = _save3 break @@ -9755,7 +9793,7 @@ class RDoc::Markdown _save6 = self.pos while true # sequence - _tmp = scan(/\A(?-mix:_+)/) + _tmp = scan(/\G(?-mix:_+)/) unless _tmp self.pos = _save6 break @@ -9818,7 +9856,7 @@ class RDoc::Markdown break end _text_start = self.pos - _tmp = scan(/\A(?-mix:[:\\`|*_{}\[\]()#+.!><-])/) + _tmp = scan(/\G(?-mix:[:\\`|*_{}\[\]()#+.!><-])/) if _tmp text = get_text(_text_start) end @@ -9944,7 +9982,7 @@ class RDoc::Markdown self.pos = _save5 break end - _tmp = scan(/\A(?-mix:={1,}|-{1,})/) + _tmp = scan(/\G(?-mix:={1,}|-{1,})/) unless _tmp self.pos = _save5 break @@ -10096,7 +10134,7 @@ class RDoc::Markdown _save1 = self.pos while true # sequence _text_start = self.pos - _tmp = scan(/\A(?-mix:\*{4,})/) + _tmp = scan(/\G(?-mix:\*{4,})/) if _tmp text = get_text(_text_start) end @@ -10126,7 +10164,7 @@ class RDoc::Markdown self.pos = _save3 break end - _tmp = scan(/\A(?-mix:\*+)/) + _tmp = scan(/\G(?-mix:\*+)/) unless _tmp self.pos = _save3 break @@ -10173,7 +10211,7 @@ class RDoc::Markdown _save1 = self.pos while true # sequence _text_start = self.pos - _tmp = scan(/\A(?-mix:_{4,})/) + _tmp = scan(/\G(?-mix:_{4,})/) if _tmp text = get_text(_text_start) end @@ -10203,7 +10241,7 @@ class RDoc::Markdown self.pos = _save3 break end - _tmp = scan(/\A(?-mix:_+)/) + _tmp = scan(/\G(?-mix:_+)/) unless _tmp self.pos = _save3 break @@ -11564,7 +11602,7 @@ class RDoc::Markdown _save1 = self.pos while true # sequence - _tmp = scan(/\A(?-mix:[A-Za-z]+)/) + _tmp = scan(/\G(?-mix:[A-Za-z]+)/) unless _tmp self.pos = _save1 break @@ -11689,7 +11727,7 @@ class RDoc::Markdown _save2 = self.pos while true # sequence - _tmp = scan(/\A(?i-mx:[\w+.\/!%~$-]+)/) + _tmp = scan(/\G(?i-mx:[\w+.\/!%~$-]+)/) unless _tmp self.pos = _save2 break @@ -12553,7 +12591,7 @@ class RDoc::Markdown self.pos = _save10 break end - _tmp = scan(/\A(?-mix:`+)/) + _tmp = scan(/\G(?-mix:`+)/) unless _tmp self.pos = _save10 end @@ -12690,7 +12728,7 @@ class RDoc::Markdown self.pos = _save24 break end - _tmp = scan(/\A(?-mix:`+)/) + _tmp = scan(/\G(?-mix:`+)/) unless _tmp self.pos = _save24 end @@ -12867,7 +12905,7 @@ class RDoc::Markdown self.pos = _save40 break end - _tmp = scan(/\A(?-mix:`+)/) + _tmp = scan(/\G(?-mix:`+)/) unless _tmp self.pos = _save40 end @@ -13004,7 +13042,7 @@ class RDoc::Markdown self.pos = _save54 break end - _tmp = scan(/\A(?-mix:`+)/) + _tmp = scan(/\G(?-mix:`+)/) unless _tmp self.pos = _save54 end @@ -13181,7 +13219,7 @@ class RDoc::Markdown self.pos = _save70 break end - _tmp = scan(/\A(?-mix:`+)/) + _tmp = scan(/\G(?-mix:`+)/) unless _tmp self.pos = _save70 end @@ -13318,7 +13356,7 @@ class RDoc::Markdown self.pos = _save84 break end - _tmp = scan(/\A(?-mix:`+)/) + _tmp = scan(/\G(?-mix:`+)/) unless _tmp self.pos = _save84 end @@ -13495,7 +13533,7 @@ class RDoc::Markdown self.pos = _save100 break end - _tmp = scan(/\A(?-mix:`+)/) + _tmp = scan(/\G(?-mix:`+)/) unless _tmp self.pos = _save100 end @@ -13632,7 +13670,7 @@ class RDoc::Markdown self.pos = _save114 break end - _tmp = scan(/\A(?-mix:`+)/) + _tmp = scan(/\G(?-mix:`+)/) unless _tmp self.pos = _save114 end @@ -13809,7 +13847,7 @@ class RDoc::Markdown self.pos = _save130 break end - _tmp = scan(/\A(?-mix:`+)/) + _tmp = scan(/\G(?-mix:`+)/) unless _tmp self.pos = _save130 end @@ -13946,7 +13984,7 @@ class RDoc::Markdown self.pos = _save144 break end - _tmp = scan(/\A(?-mix:`+)/) + _tmp = scan(/\G(?-mix:`+)/) unless _tmp self.pos = _save144 end @@ -14598,7 +14636,7 @@ class RDoc::Markdown _save = self.pos while true # choice - _tmp = scan(/\A(?-mix:[~*_`&\[\]()<!#\\'"])/) + _tmp = scan(/\G(?-mix:[~*_`&\[\]()<!#\\'"])/) break if _tmp self.pos = _save _tmp = _ExtendedSpecialChar() @@ -14703,13 +14741,13 @@ class RDoc::Markdown _save = self.pos while true # sequence - _tmp = scan(/\A(?i-mx:&#x)/) + _tmp = scan(/\G(?i-mx:&#x)/) unless _tmp self.pos = _save break end _text_start = self.pos - _tmp = scan(/\A(?-mix:[0-9a-fA-F]+)/) + _tmp = scan(/\G(?-mix:[0-9a-fA-F]+)/) if _tmp text = get_text(_text_start) end @@ -14745,7 +14783,7 @@ class RDoc::Markdown break end _text_start = self.pos - _tmp = scan(/\A(?-mix:[0-9]+)/) + _tmp = scan(/\G(?-mix:[0-9]+)/) if _tmp text = get_text(_text_start) end @@ -14781,7 +14819,7 @@ class RDoc::Markdown break end _text_start = self.pos - _tmp = scan(/\A(?-mix:[A-Za-z0-9]+)/) + _tmp = scan(/\G(?-mix:[A-Za-z0-9]+)/) if _tmp text = get_text(_text_start) end @@ -14813,14 +14851,14 @@ class RDoc::Markdown # NonindentSpace = / {0,3}/ def _NonindentSpace - _tmp = scan(/\A(?-mix: {0,3})/) + _tmp = scan(/\G(?-mix: {0,3})/) set_failed_rule :_NonindentSpace unless _tmp return _tmp end # Indent = /\t| / def _Indent - _tmp = scan(/\A(?-mix:\t| )/) + _tmp = scan(/\G(?-mix:\t| )/) set_failed_rule :_Indent unless _tmp return _tmp end @@ -14919,7 +14957,7 @@ class RDoc::Markdown return _tmp end - # RawLine = (< (!"\r" !"\n" .)* @Newline > | < .+ > @Eof) { text } + # RawLine = (< /[^\r\n]*/ @Newline > | < .+ > @Eof) { text } def _RawLine _save = self.pos @@ -14931,36 +14969,7 @@ class RDoc::Markdown _save2 = self.pos while true # sequence - while true - - _save4 = self.pos - while true # sequence - _save5 = self.pos - _tmp = match_string("\r") - _tmp = _tmp ? nil : true - self.pos = _save5 - unless _tmp - self.pos = _save4 - break - end - _save6 = self.pos - _tmp = match_string("\n") - _tmp = _tmp ? nil : true - self.pos = _save6 - unless _tmp - self.pos = _save4 - break - end - _tmp = get_byte - unless _tmp - self.pos = _save4 - end - break - end # end sequence - - break unless _tmp - end - _tmp = true + _tmp = scan(/\G(?-mix:[^\r\n]*)/) unless _tmp self.pos = _save2 break @@ -14978,10 +14987,10 @@ class RDoc::Markdown break if _tmp self.pos = _save1 - _save7 = self.pos + _save3 = self.pos while true # sequence _text_start = self.pos - _save8 = self.pos + _save4 = self.pos _tmp = get_byte if _tmp while true @@ -14990,18 +14999,18 @@ class RDoc::Markdown end _tmp = true else - self.pos = _save8 + self.pos = _save4 end if _tmp text = get_text(_text_start) end unless _tmp - self.pos = _save7 + self.pos = _save3 break end _tmp = _Eof() unless _tmp - self.pos = _save7 + self.pos = _save3 end break end # end sequence @@ -15547,7 +15556,7 @@ class RDoc::Markdown return _tmp end - # RawNoteBlock = @StartList:a (!@BlankLine OptionallyIndentedLine:l { a << l })+ < @BlankLine* > { a << text } { a } + # RawNoteBlock = @StartList:a (!@BlankLine !RawNoteReference OptionallyIndentedLine:l { a << l })+ < @BlankLine* > { a << text } { a } def _RawNoteBlock _save = self.pos @@ -15570,6 +15579,14 @@ class RDoc::Markdown self.pos = _save2 break end + _save4 = self.pos + _tmp = apply(:_RawNoteReference) + _tmp = _tmp ? nil : true + self.pos = _save4 + unless _tmp + self.pos = _save2 + break + end _tmp = apply(:_OptionallyIndentedLine) l = @result unless _tmp @@ -15587,26 +15604,34 @@ class RDoc::Markdown if _tmp while true - _save4 = self.pos + _save5 = self.pos while true # sequence - _save5 = self.pos + _save6 = self.pos _tmp = _BlankLine() _tmp = _tmp ? nil : true - self.pos = _save5 + self.pos = _save6 unless _tmp - self.pos = _save4 + self.pos = _save5 + break + end + _save7 = self.pos + _tmp = apply(:_RawNoteReference) + _tmp = _tmp ? nil : true + self.pos = _save7 + unless _tmp + self.pos = _save5 break end _tmp = apply(:_OptionallyIndentedLine) l = @result unless _tmp - self.pos = _save4 + self.pos = _save5 break end @result = begin; a << l ; end _tmp = true unless _tmp - self.pos = _save4 + self.pos = _save5 end break end # end sequence @@ -15762,7 +15787,7 @@ class RDoc::Markdown self.pos = _save11 break end - _tmp = scan(/\A(?-mix:`+)/) + _tmp = scan(/\G(?-mix:`+)/) unless _tmp self.pos = _save11 end @@ -15843,7 +15868,7 @@ class RDoc::Markdown self.pos = _save19 break end - _tmp = scan(/\A(?-mix:`+)/) + _tmp = scan(/\G(?-mix:`+)/) unless _tmp self.pos = _save19 end @@ -15908,7 +15933,7 @@ class RDoc::Markdown return _tmp end - # Table = &{ github? } TableRow:header TableLine:line TableRow+:body { table = RDoc::Markup::Table.new(header, line, body) } + # Table = &{ github? } TableHead:header TableLine:line TableRow+:body { table = RDoc::Markup::Table.new(header, line, body) } def _Table _save = self.pos @@ -15920,7 +15945,7 @@ class RDoc::Markdown self.pos = _save break end - _tmp = apply(:_TableRow) + _tmp = apply(:_TableHead) header = @result unless _tmp self.pos = _save @@ -15964,18 +15989,18 @@ class RDoc::Markdown return _tmp end - # TableRow = TableItem+:row "|" @Newline { row } - def _TableRow + # TableHead = TableItem2+:items "|"? @Newline { items } + def _TableHead _save = self.pos while true # sequence _save1 = self.pos _ary = [] - _tmp = apply(:_TableItem) + _tmp = apply(:_TableItem2) if _tmp _ary << @result while true - _tmp = apply(:_TableItem) + _tmp = apply(:_TableItem2) _ary << @result if _tmp break unless _tmp end @@ -15984,13 +16009,18 @@ class RDoc::Markdown else self.pos = _save1 end - row = @result + items = @result unless _tmp self.pos = _save break end + _save2 = self.pos _tmp = match_string("|") unless _tmp + _tmp = true + self.pos = _save2 + end + unless _tmp self.pos = _save break end @@ -15999,7 +16029,7 @@ class RDoc::Markdown self.pos = _save break end - @result = begin; row ; end + @result = begin; items ; end _tmp = true unless _tmp self.pos = _save @@ -16007,90 +16037,92 @@ class RDoc::Markdown break end # end sequence - set_failed_rule :_TableRow unless _tmp + set_failed_rule :_TableHead unless _tmp return _tmp end - # TableItem = "|" < (!"|" !@Newline .)+ > { text.strip } - def _TableItem + # TableRow = ((TableItem:item1 TableItem2*:items { [item1, *items] }):row | TableItem2+:row) "|"? @Newline { row } + def _TableRow _save = self.pos while true # sequence - _tmp = match_string("|") - unless _tmp - self.pos = _save - break - end - _text_start = self.pos + _save1 = self.pos + while true # choice - _save2 = self.pos - while true # sequence - _save3 = self.pos - _tmp = match_string("|") - _tmp = _tmp ? nil : true - self.pos = _save3 - unless _tmp - self.pos = _save2 + _save2 = self.pos + while true # sequence + _tmp = apply(:_TableItem) + item1 = @result + unless _tmp + self.pos = _save2 + break + end + _ary = [] + while true + _tmp = apply(:_TableItem2) + _ary << @result if _tmp + break unless _tmp + end + _tmp = true + @result = _ary + items = @result + unless _tmp + self.pos = _save2 + break + end + @result = begin; [item1, *items] ; end + _tmp = true + unless _tmp + self.pos = _save2 + end break - end + end # end sequence + + row = @result + break if _tmp + self.pos = _save1 _save4 = self.pos - _tmp = _Newline() - _tmp = _tmp ? nil : true - self.pos = _save4 - unless _tmp - self.pos = _save2 - break - end - _tmp = get_byte - unless _tmp - self.pos = _save2 + _ary = [] + _tmp = apply(:_TableItem2) + if _tmp + _ary << @result + while true + _tmp = apply(:_TableItem2) + _ary << @result if _tmp + break unless _tmp + end + _tmp = true + @result = _ary + else + self.pos = _save4 end + row = @result + break if _tmp + self.pos = _save1 break - end # end sequence - - if _tmp - while true - - _save5 = self.pos - while true # sequence - _save6 = self.pos - _tmp = match_string("|") - _tmp = _tmp ? nil : true - self.pos = _save6 - unless _tmp - self.pos = _save5 - break - end - _save7 = self.pos - _tmp = _Newline() - _tmp = _tmp ? nil : true - self.pos = _save7 - unless _tmp - self.pos = _save5 - break - end - _tmp = get_byte - unless _tmp - self.pos = _save5 - end - break - end # end sequence + end # end choice - break unless _tmp - end + unless _tmp + self.pos = _save + break + end + _save5 = self.pos + _tmp = match_string("|") + unless _tmp _tmp = true - else - self.pos = _save1 + self.pos = _save5 end - if _tmp - text = get_text(_text_start) + unless _tmp + self.pos = _save + break end + _tmp = _Newline() unless _tmp self.pos = _save break end - @result = begin; text.strip ; end + @result = begin; row ; end _tmp = true unless _tmp self.pos = _save @@ -16098,46 +16130,46 @@ class RDoc::Markdown break end # end sequence - set_failed_rule :_TableItem unless _tmp + set_failed_rule :_TableRow unless _tmp return _tmp end - # TableLine = TableColumn+:line "|" @Newline { line } - def _TableLine + # TableItem2 = "|" TableItem + def _TableItem2 _save = self.pos while true # sequence - _save1 = self.pos - _ary = [] - _tmp = apply(:_TableColumn) - if _tmp - _ary << @result - while true - _tmp = apply(:_TableColumn) - _ary << @result if _tmp - break unless _tmp - end - _tmp = true - @result = _ary - else - self.pos = _save1 - end - line = @result + _tmp = match_string("|") unless _tmp self.pos = _save break end - _tmp = match_string("|") + _tmp = apply(:_TableItem) unless _tmp self.pos = _save - break end - _tmp = _Newline() + break + end # end sequence + + set_failed_rule :_TableItem2 unless _tmp + return _tmp + end + + # TableItem = < /(?:\\.|[^|\n])+/ > { text.strip.gsub(/\\(.)/, '\1') } + def _TableItem + + _save = self.pos + while true # sequence + _text_start = self.pos + _tmp = scan(/\G(?-mix:(?:\\.|[^|\n])+)/) + if _tmp + text = get_text(_text_start) + end unless _tmp self.pos = _save break end - @result = begin; line ; end + @result = begin; text.strip.gsub(/\\(.)/, '\1') ; end _tmp = true unless _tmp self.pos = _save @@ -16145,80 +16177,136 @@ class RDoc::Markdown break end # end sequence - set_failed_rule :_TableLine unless _tmp + set_failed_rule :_TableItem unless _tmp return _tmp end - # TableColumn = "|" < ("-"+ ":"? | ":" "-"*) > { text.start_with?(":") ? :left : text.end_with?(":") ? :right : nil } - def _TableColumn + # TableLine = ((TableAlign:align1 TableAlign2*:aligns {[align1, *aligns] }):line | TableAlign2+:line) "|"? @Newline { line } + def _TableLine _save = self.pos while true # sequence - _tmp = match_string("|") - unless _tmp - self.pos = _save - break - end - _text_start = self.pos _save1 = self.pos while true # choice _save2 = self.pos while true # sequence - _save3 = self.pos - _tmp = match_string("-") - if _tmp - while true - _tmp = match_string("-") - break unless _tmp - end - _tmp = true - else - self.pos = _save3 - end + _tmp = apply(:_TableAlign) + align1 = @result unless _tmp self.pos = _save2 break end - _save4 = self.pos - _tmp = match_string(":") + _ary = [] + while true + _tmp = apply(:_TableAlign2) + _ary << @result if _tmp + break unless _tmp + end + _tmp = true + @result = _ary + aligns = @result unless _tmp - _tmp = true - self.pos = _save4 + self.pos = _save2 + break end + @result = begin; [align1, *aligns] ; end + _tmp = true unless _tmp self.pos = _save2 end break end # end sequence + line = @result break if _tmp self.pos = _save1 - - _save5 = self.pos - while true # sequence - _tmp = match_string(":") - unless _tmp - self.pos = _save5 - break - end + _save4 = self.pos + _ary = [] + _tmp = apply(:_TableAlign2) + if _tmp + _ary << @result while true - _tmp = match_string("-") + _tmp = apply(:_TableAlign2) + _ary << @result if _tmp break unless _tmp end _tmp = true - unless _tmp - self.pos = _save5 - end - break - end # end sequence - + @result = _ary + else + self.pos = _save4 + end + line = @result break if _tmp self.pos = _save1 break end # end choice + unless _tmp + self.pos = _save + break + end + _save5 = self.pos + _tmp = match_string("|") + unless _tmp + _tmp = true + self.pos = _save5 + end + unless _tmp + self.pos = _save + break + end + _tmp = _Newline() + unless _tmp + self.pos = _save + break + end + @result = begin; line ; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_TableLine unless _tmp + return _tmp + end + + # TableAlign2 = "|" @Sp TableAlign + def _TableAlign2 + + _save = self.pos + while true # sequence + _tmp = match_string("|") + unless _tmp + self.pos = _save + break + end + _tmp = _Sp() + unless _tmp + self.pos = _save + break + end + _tmp = apply(:_TableAlign) + unless _tmp + self.pos = _save + end + break + end # end sequence + + set_failed_rule :_TableAlign2 unless _tmp + return _tmp + end + + # TableAlign = < /:?-+:?/ > @Sp { text.start_with?(":") ? (text.end_with?(":") ? :center : :left) : (text.end_with?(":") ? :right : nil) } + def _TableAlign + + _save = self.pos + while true # sequence + _text_start = self.pos + _tmp = scan(/\G(?-mix::?-+:?)/) if _tmp text = get_text(_text_start) end @@ -16226,8 +16314,15 @@ class RDoc::Markdown self.pos = _save break end - @result = begin; text.start_with?(":") ? :left : - text.end_with?(":") ? :right : nil + _tmp = _Sp() + unless _tmp + self.pos = _save + break + end + @result = begin; + text.start_with?(":") ? + (text.end_with?(":") ? :center : :left) : + (text.end_with?(":") ? :right : nil) ; end _tmp = true unless _tmp @@ -16236,7 +16331,7 @@ class RDoc::Markdown break end # end sequence - set_failed_rule :_TableColumn unless _tmp + set_failed_rule :_TableAlign unless _tmp return _tmp end @@ -16350,12 +16445,12 @@ class RDoc::Markdown return _tmp end - # DefinitionListLabel = StrChunk:label @Sp @Newline { label } + # DefinitionListLabel = Inline:label @Sp @Newline { label } def _DefinitionListLabel _save = self.pos while true # sequence - _tmp = apply(:_StrChunk) + _tmp = apply(:_Inline) label = @result unless _tmp self.pos = _save @@ -16662,7 +16757,7 @@ class RDoc::Markdown Rules[:_OptionallyIndentedLine] = rule_info("OptionallyIndentedLine", "Indent? Line") Rules[:_StartList] = rule_info("StartList", "&. { [] }") Rules[:_Line] = rule_info("Line", "@RawLine:a { a }") - Rules[:_RawLine] = rule_info("RawLine", "(< (!\"\\r\" !\"\\n\" .)* @Newline > | < .+ > @Eof) { text }") + Rules[:_RawLine] = rule_info("RawLine", "(< /[^\\r\\n]*/ @Newline > | < .+ > @Eof) { text }") Rules[:_SkipBlock] = rule_info("SkipBlock", "(HtmlBlock | (!\"\#\" !SetextBottom1 !SetextBottom2 !@BlankLine @RawLine)+ @BlankLine* | @BlankLine+ | @RawLine)") Rules[:_ExtendedSpecialChar] = rule_info("ExtendedSpecialChar", "&{ notes? } \"^\"") Rules[:_NoteReference] = rule_info("NoteReference", "&{ notes? } RawNoteReference:ref { note_for ref }") @@ -16670,16 +16765,19 @@ class RDoc::Markdown Rules[:_Note] = rule_info("Note", "&{ notes? } @NonindentSpace RawNoteReference:ref \":\" @Sp @StartList:a RawNoteBlock:i { a.concat i } (&Indent RawNoteBlock:i { a.concat i })* { @footnotes[ref] = paragraph a nil }") Rules[:_InlineNote] = rule_info("InlineNote", "&{ notes? } \"^[\" @StartList:a (!\"]\" Inline:l { a << l })+ \"]\" { ref = [:inline, @note_order.length] @footnotes[ref] = paragraph a note_for ref }") Rules[:_Notes] = rule_info("Notes", "(Note | SkipBlock)*") - Rules[:_RawNoteBlock] = rule_info("RawNoteBlock", "@StartList:a (!@BlankLine OptionallyIndentedLine:l { a << l })+ < @BlankLine* > { a << text } { a }") + Rules[:_RawNoteBlock] = rule_info("RawNoteBlock", "@StartList:a (!@BlankLine !RawNoteReference OptionallyIndentedLine:l { a << l })+ < @BlankLine* > { a << text } { a }") Rules[:_CodeFence] = rule_info("CodeFence", "&{ github? } Ticks3 (@Sp StrChunk:format)? Spnl < ((!\"`\" Nonspacechar)+ | !Ticks3 /`+/ | Spacechar | @Newline)+ > Ticks3 @Sp @Newline* { verbatim = RDoc::Markup::Verbatim.new text verbatim.format = format.intern if format.instance_of?(String) verbatim }") - Rules[:_Table] = rule_info("Table", "&{ github? } TableRow:header TableLine:line TableRow+:body { table = RDoc::Markup::Table.new(header, line, body) }") - Rules[:_TableRow] = rule_info("TableRow", "TableItem+:row \"|\" @Newline { row }") - Rules[:_TableItem] = rule_info("TableItem", "\"|\" < (!\"|\" !@Newline .)+ > { text.strip }") - Rules[:_TableLine] = rule_info("TableLine", "TableColumn+:line \"|\" @Newline { line }") - Rules[:_TableColumn] = rule_info("TableColumn", "\"|\" < (\"-\"+ \":\"? | \":\" \"-\"*) > { text.start_with?(\":\") ? :left : text.end_with?(\":\") ? :right : nil }") + Rules[:_Table] = rule_info("Table", "&{ github? } TableHead:header TableLine:line TableRow+:body { table = RDoc::Markup::Table.new(header, line, body) }") + Rules[:_TableHead] = rule_info("TableHead", "TableItem2+:items \"|\"? @Newline { items }") + Rules[:_TableRow] = rule_info("TableRow", "((TableItem:item1 TableItem2*:items { [item1, *items] }):row | TableItem2+:row) \"|\"? @Newline { row }") + Rules[:_TableItem2] = rule_info("TableItem2", "\"|\" TableItem") + Rules[:_TableItem] = rule_info("TableItem", "< /(?:\\\\.|[^|\\n])+/ > { text.strip.gsub(/\\\\(.)/, '\\1') }") + Rules[:_TableLine] = rule_info("TableLine", "((TableAlign:align1 TableAlign2*:aligns {[align1, *aligns] }):line | TableAlign2+:line) \"|\"? @Newline { line }") + Rules[:_TableAlign2] = rule_info("TableAlign2", "\"|\" @Sp TableAlign") + Rules[:_TableAlign] = rule_info("TableAlign", "< /:?-+:?/ > @Sp { text.start_with?(\":\") ? (text.end_with?(\":\") ? :center : :left) : (text.end_with?(\":\") ? :right : nil) }") Rules[:_DefinitionList] = rule_info("DefinitionList", "&{ definition_lists? } DefinitionListItem+:list { RDoc::Markup::List.new :NOTE, *list.flatten }") Rules[:_DefinitionListItem] = rule_info("DefinitionListItem", "DefinitionListLabel+:label DefinitionListDefinition+:defns { list_items = [] list_items << RDoc::Markup::ListItem.new(label, defns.shift) list_items.concat defns.map { |defn| RDoc::Markup::ListItem.new nil, defn } unless list_items.empty? list_items }") - Rules[:_DefinitionListLabel] = rule_info("DefinitionListLabel", "StrChunk:label @Sp @Newline { label }") + Rules[:_DefinitionListLabel] = rule_info("DefinitionListLabel", "Inline:label @Sp @Newline { label }") Rules[:_DefinitionListDefinition] = rule_info("DefinitionListDefinition", "@NonindentSpace \":\" @Space Inlines:a @BlankLine+ { paragraph a }") # :startdoc: end diff --git a/lib/rdoc/markdown/entities.rb b/lib/rdoc/markdown/entities.rb index d2cf610293..265c2eb3f3 100644 --- a/lib/rdoc/markdown/entities.rb +++ b/lib/rdoc/markdown/entities.rb @@ -2129,4 +2129,3 @@ RDoc::Markdown::HTML_ENTITIES = { "zwj" => [0x0200D], "zwnj" => [0x0200C], } - diff --git a/lib/rdoc/markdown/literals.rb b/lib/rdoc/markdown/literals.rb index 31cd237f12..c5c15d3100 100644 --- a/lib/rdoc/markdown/literals.rb +++ b/lib/rdoc/markdown/literals.rb @@ -3,7 +3,6 @@ # :markup: markdown ## -#-- # This set of literals is for Ruby 1.9 regular expressions and gives full # unicode support. # @@ -29,6 +28,7 @@ class RDoc::Markdown::Literals @result = nil @failed_rule = nil @failing_rule_offset = -1 + @line_offsets = nil setup_foreign_grammar end @@ -38,30 +38,75 @@ class RDoc::Markdown::Literals attr_accessor :result, :pos def current_column(target=pos) - if c = string.rindex("\n", target-1) - return target - c - 1 + if string[target] == "\n" && (c = string.rindex("\n", target-1) || -1) + return target - c + elsif c = string.rindex("\n", target) + return target - c end target + 1 end - def current_line(target=pos) - cur_offset = 0 - cur_line = 0 + def position_line_offsets + unless @position_line_offsets + @position_line_offsets = [] + total = 0 + string.each_line do |line| + total += line.size + @position_line_offsets << total + end + end + @position_line_offsets + end - string.each_line do |line| - cur_line += 1 - cur_offset += line.size - return cur_line if cur_offset >= target + if [].respond_to? :bsearch_index + def current_line(target=pos) + if line = position_line_offsets.bsearch_index {|x| x > target } + return line + 1 + end + raise "Target position #{target} is outside of string" end + else + def current_line(target=pos) + if line = position_line_offsets.index {|x| x > target } + return line + 1 + end + + raise "Target position #{target} is outside of string" + end + end + + def current_character(target=pos) + if target < 0 || target >= string.size + raise "Target position #{target} is outside of string" + end + string[target, 1] + end + + KpegPosInfo = Struct.new(:pos, :lno, :col, :line, :char) - -1 + def current_pos_info(target=pos) + l = current_line target + c = current_column target + ln = get_line(l-1) + chr = string[target,1] + KpegPosInfo.new(target, l, c, ln, chr) end def lines - lines = [] - string.each_line { |l| lines << l } - lines + string.lines + end + + def get_line(no) + loff = position_line_offsets + if no < 0 + raise "Line No is out of range: #{no} < 0" + elsif no >= loff.size + raise "Line No is out of range: #{no} >= #{loff.size}" + end + lend = loff[no]-1 + lstart = no > 0 ? loff[no-1] : 0 + string[lstart..lend] end @@ -75,6 +120,7 @@ class RDoc::Markdown::Literals @string = string @string_size = string ? string.size : 0 @pos = pos + @position_line_offsets = nil end def show_pos @@ -99,30 +145,22 @@ class RDoc::Markdown::Literals end def failure_caret - l = current_line @failing_rule_offset - c = current_column @failing_rule_offset - - line = lines[l-1] - "#{line}\n#{' ' * (c - 1)}^" + p = current_pos_info @failing_rule_offset + "#{p.line.chomp}\n#{' ' * (p.col - 1)}^" end def failure_character - l = current_line @failing_rule_offset - c = current_column @failing_rule_offset - lines[l-1][c-1, 1] + current_character @failing_rule_offset end def failure_oneline - l = current_line @failing_rule_offset - c = current_column @failing_rule_offset - - char = lines[l-1][c-1, 1] + p = current_pos_info @failing_rule_offset if @failed_rule.kind_of? Symbol info = self.class::Rules[@failed_rule] - "@#{l}:#{c} failed rule '#{info.name}', got '#{char}'" + "@#{p.lno}:#{p.col} failed rule '#{info.name}', got '#{p.char}'" else - "@#{l}:#{c} failed rule '#{@failed_rule}', got '#{char}'" + "@#{p.lno}:#{p.col} failed rule '#{@failed_rule}', got '#{p.char}'" end end @@ -135,10 +173,9 @@ class RDoc::Markdown::Literals def show_error(io=STDOUT) error_pos = @failing_rule_offset - line_no = current_line(error_pos) - col_no = current_column(error_pos) + p = current_pos_info(error_pos) - io.puts "On line #{line_no}, column #{col_no}:" + io.puts "On line #{p.lno}, column #{p.col}:" if @failed_rule.kind_of? Symbol info = self.class::Rules[@failed_rule] @@ -147,10 +184,9 @@ class RDoc::Markdown::Literals io.puts "Failed to match rule '#{@failed_rule}'" end - io.puts "Got: #{string[error_pos,1].inspect}" - line = lines[line_no-1] - io.puts "=> #{line}" - io.print(" " * (col_no + 3)) + io.puts "Got: #{p.char.inspect}" + io.puts "=> #{p.line}" + io.print(" " * (p.col + 2)) io.puts "^" end @@ -174,9 +210,8 @@ class RDoc::Markdown::Literals end def scan(reg) - if m = reg.match(@string[@pos..-1]) - width = m.end(0) - @pos += width + if m = reg.match(@string, @pos) + @pos = m.end(0) return true end @@ -260,6 +295,7 @@ class RDoc::Markdown::Literals end def apply_with_args(rule, *args) + @result = nil memo_key = [rule, args] if m = @memoizations[memo_key][@pos] @pos = m.pos @@ -293,6 +329,7 @@ class RDoc::Markdown::Literals end def apply(rule) + @result = nil if m = @memoizations[rule][@pos] @pos = m.pos if !m.set @@ -366,14 +403,14 @@ class RDoc::Markdown::Literals # Alphanumeric = /\p{Word}/ def _Alphanumeric - _tmp = scan(/\A(?-mix:\p{Word})/) + _tmp = scan(/\G(?-mix:\p{Word})/) set_failed_rule :_Alphanumeric unless _tmp return _tmp end # AlphanumericAscii = /[A-Za-z0-9]/ def _AlphanumericAscii - _tmp = scan(/\A(?-mix:[A-Za-z0-9])/) + _tmp = scan(/\G(?-mix:[A-Za-z0-9])/) set_failed_rule :_AlphanumericAscii unless _tmp return _tmp end @@ -387,21 +424,21 @@ class RDoc::Markdown::Literals # Newline = /\n|\r\n?|\p{Zl}|\p{Zp}/ def _Newline - _tmp = scan(/\A(?-mix:\n|\r\n?|\p{Zl}|\p{Zp})/) + _tmp = scan(/\G(?-mix:\n|\r\n?|\p{Zl}|\p{Zp})/) set_failed_rule :_Newline unless _tmp return _tmp end # NonAlphanumeric = /\p{^Word}/ def _NonAlphanumeric - _tmp = scan(/\A(?-mix:\p{^Word})/) + _tmp = scan(/\G(?-mix:\p{^Word})/) set_failed_rule :_NonAlphanumeric unless _tmp return _tmp end # Spacechar = /\t|\p{Zs}/ def _Spacechar - _tmp = scan(/\A(?-mix:\t|\p{Zs})/) + _tmp = scan(/\G(?-mix:\t|\p{Zs})/) set_failed_rule :_Spacechar unless _tmp return _tmp end diff --git a/lib/rdoc/markup.rb b/lib/rdoc/markup.rb index 92aed757cf..6e93030965 100644 --- a/lib/rdoc/markup.rb +++ b/lib/rdoc/markup.rb @@ -97,638 +97,7 @@ # # = \RDoc Markup Reference # -# == Block Markup -# -# === Paragraphs and Verbatim -# -# The markup engine looks for a document's natural left margin. This is -# used as the initial margin for the document. -# -# Consecutive lines starting at this margin are considered to be a -# paragraph. Empty lines separate paragraphs. -# -# Any line that starts to the right of the current margin is treated -# as verbatim text. This is useful for code listings: -# -# 3.times { puts "Ruby" } -# -# In verbatim text, two or more blank lines are collapsed into one, -# and trailing blank lines are removed: -# -# This is the first line -# -# -# This is the second non-blank line, -# after 2 blank lines in the source markup. -# -# -# There were two trailing blank lines right above this paragraph, that -# have been removed. In addition, the verbatim text has been shifted -# left, so the amount of indentation of verbatim text is unimportant. -# -# For HTML output RDoc makes a small effort to determine if a verbatim section -# contains Ruby source code. If so, the verbatim block will be marked up as -# HTML. Triggers include "def", "class", "module", "require", the "hash -# rocket"# (=>) or a block call with a parameter. -# -# === Headers -# -# A line starting with an equal sign (=) is treated as a -# heading. Level one headings have one equals sign, level two headings -# have two, and so on until level six, which is the maximum -# (seven hyphens or more result in a level six heading). -# -# For example, the above header was obtained with: -# -# === Headers -# -# In HTML output headers have an id matching their name. The above example's -# HTML is: -# -# <h3 id="label-Headers">Headers</h3> -# -# If a heading is inside a method body the id will be prefixed with the -# method's id. If the above header where in the documentation for a method -# such as: -# -# ## -# # This method does fun things -# # -# # = Example -# # -# # Example of fun things goes here ... -# -# def do_fun_things -# end -# -# The header's id would be: -# -# <h1 id="method-i-do_fun_things-label-Example">Example</h1> -# -# The label can be linked-to using <tt>SomeClass@Headers</tt>. See -# {Links}[RDoc::Markup@Links] for further details. -# -# === Rules -# -# A line starting with three or more hyphens (at the current indent) -# generates a horizontal rule. -# -# --- -# -# produces: -# -# --- -# -# === Simple Lists -# -# If a paragraph starts with a "*", "-", "<digit>." or "<letter>.", -# then it is taken to be the start of a list. The margin is increased to be -# the first non-space following the list start flag. Subsequent lines -# should be indented to this new margin until the list ends. For example: -# -# * this is a list with three paragraphs in -# the first item. This is the first paragraph. -# -# And this is the second paragraph. -# -# 1. This is an indented, numbered list. -# 2. This is the second item in that list -# -# This is the third conventional paragraph in the -# first list item. -# -# * This is the second item in the original list -# -# produces: -# -# * this is a list with three paragraphs in -# the first item. This is the first paragraph. -# -# And this is the second paragraph. -# -# 1. This is an indented, numbered list. -# 2. This is the second item in that list -# -# This is the third conventional paragraph in the -# first list item. -# -# * This is the second item in the original list -# -# === Labeled Lists -# -# You can also construct labeled lists, sometimes called description -# or definition lists. Do this by putting the label in square brackets -# and indenting the list body: -# -# [cat] a small furry mammal -# that seems to sleep a lot -# -# [ant] a little insect that is known -# to enjoy picnics -# -# produces: -# -# [cat] a small furry mammal -# that seems to sleep a lot -# -# [ant] a little insect that is known -# to enjoy picnics -# -# If you want the list bodies to line up to the left of the labels, -# use two colons: -# -# cat:: a small furry mammal -# that seems to sleep a lot -# -# ant:: a little insect that is known -# to enjoy picnics -# -# produces: -# -# cat:: a small furry mammal -# that seems to sleep a lot -# -# ant:: a little insect that is known -# to enjoy picnics -# -# Notice that blank lines right after the label are ignored in labeled lists: -# -# [one] -# -# definition 1 -# -# [two] -# -# definition 2 -# -# produces the same output as -# -# [one] definition 1 -# [two] definition 2 -# -# -# === Lists and Verbatim -# -# If you want to introduce a verbatim section right after a list, it has to be -# less indented than the list item bodies, but more indented than the list -# label, letter, digit or bullet. For instance: -# -# * point 1 -# -# * point 2, first paragraph -# -# point 2, second paragraph -# verbatim text inside point 2 -# point 2, third paragraph -# verbatim text outside of the list (the list is therefore closed) -# regular paragraph after the list -# -# produces: -# -# * point 1 -# -# * point 2, first paragraph -# -# point 2, second paragraph -# verbatim text inside point 2 -# point 2, third paragraph -# verbatim text outside of the list (the list is therefore closed) -# regular paragraph after the list -# -# == Text Markup -# -# === Bold, Italic, Typewriter Text -# -# You can use markup within text (except verbatim) to change the -# appearance of parts of that text. Out of the box, RDoc::Markup -# supports word-based and general markup. -# -# Word-based markup uses flag characters around individual words: -# -# <tt>\*_word_\*</tt>:: displays _word_ in a *bold* font -# <tt>\__word_\_</tt>:: displays _word_ in an _emphasized_ font -# <tt>\+_word_\+</tt>:: displays _word_ in a +code+ font -# -# General markup affects text between a start delimiter and an end -# delimiter. Not surprisingly, these delimiters look like HTML markup. -# -# <tt>\<b>_text_</b></tt>:: displays _text_ in a *bold* font -# <tt>\<em>_text_</em></tt>:: displays _text_ in an _emphasized_ font -# (alternate tag: <tt>\<i></tt>) -# <tt>\<tt>_text_\</tt></tt>:: displays _text_ in a +code+ font -# (alternate tag: <tt>\<code></tt>) -# -# Unlike conventional Wiki markup, general markup can cross line -# boundaries. You can turn off the interpretation of markup by -# preceding the first character with a backslash (see <i>Escaping -# Text Markup</i>, below). -# -# === Links -# -# Links to starting with +http:+, +https:+, +mailto:+, +ftp:+ or +www.+ -# are recognized. An HTTP url that references an external image is converted -# into an inline image element. -# -# Classes and methods will be automatically linked to their definition. For -# example, <tt>RDoc::Markup</tt> will link to this documentation. By default -# methods will only be automatically linked if they contain an <tt>_</tt> (all -# methods can be automatically linked through the <tt>--hyperlink-all</tt> -# command line option). -# -# Single-word methods can be linked by using the <tt>#</tt> character for -# instance methods or <tt>::</tt> for class methods. For example, -# <tt>#convert</tt> links to #convert. A class or method may be combined like -# <tt>RDoc::Markup#convert</tt>. -# -# A heading inside the documentation can be linked by following the class -# or method by an <tt>@</tt> then the heading name. -# <tt>RDoc::Markup@Links</tt> will link to this section like this: -# RDoc::Markup@Links. Spaces in headings with multiple words must be escaped -# with <tt>+</tt> like <tt>RDoc::Markup@Escaping+Text+Markup</tt>. -# Punctuation and other special characters must be escaped like CGI.escape. -# -# The <tt>@</tt> can also be used to link to sections. If a section and a -# heading share the same name the section is preferred for the link. -# -# Links can also be of the form <tt>label[url]</tt>, in which case +label+ is -# used in the displayed text, and +url+ is used as the target. If +label+ -# contains multiple words, put it in braces: <tt>{multi word label}[url]</tt>. -# The +url+ may be an +http:+-type link or a cross-reference to a class, -# module or method with a label. -# -# Links with the <code>rdoc-image:</code> scheme will create an image tag for -# HTML output. Only fully-qualified URLs are supported. -# -# Links with the <tt>rdoc-ref:</tt> scheme will link to the referenced class, -# module, method, file, etc. If the referenced item is does not exist -# no link will be generated and <tt>rdoc-ref:</tt> will be removed from the -# resulting text. -# -# Links starting with <tt>rdoc-label:label_name</tt> will link to the -# +label_name+. You can create a label for the current link (for -# bidirectional links) by supplying a name for the current link like -# <tt>rdoc-label:label-other:label-mine</tt>. -# -# Links starting with +link:+ refer to local files whose path is relative to -# the <tt>--op</tt> directory. Use <tt>rdoc-ref:</tt> instead of -# <tt>link:</tt> to link to files generated by RDoc as the link target may -# be different across RDoc generators. -# -# Example links: -# -# https://github.com/ruby/rdoc -# mailto:user@example.com -# {RDoc Documentation}[http://rdoc.rubyforge.org] -# {RDoc Markup}[rdoc-ref:RDoc::Markup] -# -# === Escaping Text Markup -# -# Text markup can be escaped with a backslash, as in \<tt>, which was obtained -# with <tt>\\<tt></tt>. Except in verbatim sections and between \<tt> tags, -# to produce a backslash you have to double it unless it is followed by a -# space, tab or newline. Otherwise, the HTML formatter will discard it, as it -# is used to escape potential links: -# -# * The \ must be doubled if not followed by white space: \\. -# * But not in \<tt> tags: in a Regexp, <tt>\S</tt> matches non-space. -# * This is a link to {ruby-lang}[www.ruby-lang.org]. -# * This is not a link, however: \{ruby-lang.org}[www.ruby-lang.org]. -# * This will not be linked to \RDoc::RDoc#document -# -# generates: -# -# * The \ must be doubled if not followed by white space: \\. -# * But not in \<tt> tags: in a Regexp, <tt>\S</tt> matches non-space. -# * This is a link to {ruby-lang}[www.ruby-lang.org] -# * This is not a link, however: \{ruby-lang.org}[www.ruby-lang.org] -# * This will not be linked to \RDoc::RDoc#document -# -# Inside \<tt> tags, more precisely, leading backslashes are removed only if -# followed by a markup character (<tt><*_+</tt>), a backslash, or a known link -# reference (a known class or method). So in the example above, the backslash -# of <tt>\S</tt> would be removed if there was a class or module named +S+ in -# the current context. -# -# This behavior is inherited from RDoc version 1, and has been kept for -# compatibility with existing RDoc documentation. -# -# === Conversion of characters -# -# HTML will convert two/three dashes to an em-dash. Other common characters are -# converted as well: -# -# em-dash:: -- or --- -# ellipsis:: ... -# -# single quotes:: 'text' or `text' -# double quotes:: "text" or ``text'' -# -# copyright:: (c) -# registered trademark:: (r) -# -# produces: -# -# em-dash:: -- or --- -# ellipsis:: ... -# -# single quotes:: 'text' or `text' -# double quotes:: "text" or ``text'' -# -# copyright:: (c) -# registered trademark:: (r) -# -# -# == Documenting Source Code -# -# Comment blocks can be written fairly naturally, either using <tt>#</tt> on -# successive lines of the comment, or by including the comment in -# a <tt>=begin</tt>/<tt>=end</tt> block. If you use the latter form, -# the <tt>=begin</tt> line _must_ be flagged with an +rdoc+ tag: -# -# =begin rdoc -# Documentation to be processed by RDoc. -# -# ... -# =end -# -# RDoc stops processing comments if it finds a comment line starting -# with <tt>--</tt> right after the <tt>#</tt> character (otherwise, -# it will be treated as a rule if it has three dashes or more). -# This can be used to separate external from internal comments, -# or to stop a comment being associated with a method, class, or module. -# Commenting can be turned back on with a line that starts with <tt>++</tt>. -# -# ## -# # Extract the age and calculate the date-of-birth. -# #-- -# # FIXME: fails if the birthday falls on February 29th -# #++ -# # The DOB is returned as a Time object. -# -# def get_dob(person) -# # ... -# end -# -# Names of classes, files, and any method names containing an underscore or -# preceded by a hash character are automatically linked from comment text to -# their description. This linking works inside the current class or module, -# and with ancestor methods (in included modules or in the superclass). -# -# Method parameter lists are extracted and displayed with the method -# description. If a method calls +yield+, then the parameters passed to yield -# will also be displayed: -# -# def fred -# ... -# yield line, address -# -# This will get documented as: -# -# fred() { |line, address| ... } -# -# You can override this using a comment containing ':yields: ...' immediately -# after the method definition -# -# def fred # :yields: index, position -# # ... -# -# yield line, address -# -# which will get documented as -# -# fred() { |index, position| ... } -# -# +:yields:+ is an example of a documentation directive. These appear -# immediately after the start of the document element they are modifying. -# -# RDoc automatically cross-references words with underscores or camel-case. -# To suppress cross-references, prefix the word with a \ character. To -# include special characters like "<tt>\n</tt>", you'll need to use -# two \ characters in normal text, but only one in \<tt> text: -# -# "\\n" or "<tt>\n</tt>" -# -# produces: -# -# "\\n" or "<tt>\n</tt>" -# -# == Directives -# -# Directives are keywords surrounded by ":" characters. -# -# === Controlling what is documented -# -# [+:nodoc:+ / <tt>:nodoc: all</tt>] -# This directive prevents documentation for the element from -# being generated. For classes and modules, methods, aliases, -# constants, and attributes directly within the affected class or -# module also will be omitted. By default, though, modules and -# classes within that class or module _will_ be documented. This is -# turned off by adding the +all+ modifier. -# -# module MyModule # :nodoc: -# class Input -# end -# end -# -# module OtherModule # :nodoc: all -# class Output -# end -# end -# -# In the above code, only class <tt>MyModule::Input</tt> will be documented. -# -# The +:nodoc:+ directive, like +:enddoc:+, +:stopdoc:+ and +:startdoc:+ -# presented below, is local to the current file: if you do not want to -# document a module that appears in several files, specify +:nodoc:+ on each -# appearance, at least once per file. -# -# [+:stopdoc:+ / +:startdoc:+] -# Stop and start adding new documentation elements to the current container. -# For example, if a class has a number of constants that you don't want to -# document, put a +:stopdoc:+ before the first, and a +:startdoc:+ after the -# last. If you don't specify a +:startdoc:+ by the end of the container, -# disables documentation for the rest of the current file. -# -# [+:doc:+] -# Forces a method or attribute to be documented even if it wouldn't be -# otherwise. Useful if, for example, you want to include documentation of a -# particular private method. -# -# [+:enddoc:+] -# Document nothing further at the current level: directives +:startdoc:+ and -# +:doc:+ that appear after this will not be honored for the current container -# (file, class or module), in the current file. -# -# [+:notnew:+ / +:not_new:+ / +:not-new:+ ] -# Only applicable to the +initialize+ instance method. Normally RDoc -# assumes that the documentation and parameters for +initialize+ are -# actually for the +new+ method, and so fakes out a +new+ for the class. -# The +:notnew:+ directive stops this. Remember that +initialize+ is private, -# so you won't see the documentation unless you use the +-a+ command line -# option. -# -# === Method arguments -# -# [+:arg:+ or +:args:+ _parameters_] -# Overrides the default argument handling with exactly these parameters. -# -# ## -# # :args: a, b -# -# def some_method(*a) -# end -# -# [+:yield:+ or +:yields:+ _parameters_] -# Overrides the default yield discovery with these parameters. -# -# ## -# # :yields: key, value -# -# def each_thing &block -# @things.each(&block) -# end -# -# [+:call-seq:+] -# Lines up to the next blank line or lines with a common prefix in the -# comment are treated as the method's calling sequence, overriding the -# default parsing of method parameters and yield arguments. -# -# Multiple lines may be used. -# -# # :call-seq: -# # ARGF.readlines(sep=$/) -> array -# # ARGF.readlines(limit) -> array -# # ARGF.readlines(sep, limit) -> array -# # -# # ARGF.to_a(sep=$/) -> array -# # ARGF.to_a(limit) -> array -# # ARGF.to_a(sep, limit) -> array -# # -# # The remaining lines are documentation ... -# -# === Sections -# -# Sections allow you to group methods in a class into sensible containers. If -# you use the sections 'Public', 'Internal' and 'Deprecated' (the three -# allowed method statuses from TomDoc) the sections will be displayed in that -# order placing the most useful methods at the top. Otherwise, sections will -# be displayed in alphabetical order. -# -# [+:category:+ _section_] -# Adds this item to the named +section+ overriding the current section. Use -# this to group methods by section in RDoc output while maintaining a -# sensible ordering (like alphabetical). -# -# # :category: Utility Methods -# # -# # CGI escapes +text+ -# -# def convert_string text -# CGI.escapeHTML text -# end -# -# An empty category will place the item in the default category: -# -# # :category: -# # -# # This method is in the default category -# -# def some_method -# # ... -# end -# -# Unlike the :section: directive, :category: is not sticky. The category -# only applies to the item immediately following the comment. -# -# Use the :section: directive to provide introductory text for a section of -# documentation. -# -# [+:section:+ _title_] -# Provides section introductory text in RDoc output. The title following -# +:section:+ is used as the section name and the remainder of the comment -# containing the section is used as introductory text. A section's comment -# block must be separated from following comment blocks. Use an empty title -# to switch to the default section. -# -# The :section: directive is sticky, so subsequent methods, aliases, -# attributes, and classes will be contained in this section until the -# section is changed. The :category: directive will override the :section: -# directive. -# -# A :section: comment block may have one or more lines before the :section: -# directive. These will be removed, and any identical lines at the end of -# the block are also removed. This allows you to add visual cues to the -# section. -# -# Example: -# -# # ---------------------------------------- -# # :section: My Section -# # This is the section that I wrote. -# # See it glisten in the noon-day sun. -# # ---------------------------------------- -# -# ## -# # Comment for some_method -# -# def some_method -# # ... -# end -# -# === Other directives -# -# [+:markup:+ _type_] -# Overrides the default markup type for this comment with the specified -# markup type. For Ruby files, if the first comment contains this directive -# it is applied automatically to all comments in the file. -# -# Unless you are converting between markup formats you should use a -# <code>.rdoc_options</code> file to specify the default documentation -# format for your entire project. See RDoc::Options@Saved+Options for -# instructions. -# -# At the top of a file the +:markup:+ directive applies to the entire file: -# -# # coding: UTF-8 -# # :markup: TomDoc -# -# # TomDoc comment here ... -# -# class MyClass -# # ... -# -# For just one comment: -# -# # ... -# end -# -# # :markup: RDoc -# # -# # This is a comment in RDoc markup format ... -# -# def some_method -# # ... -# -# See Markup@CONTRIBUTING for instructions on adding a new markup format. -# -# [+:include:+ _filename_] -# Include the contents of the named file at this point. This directive -# must appear alone on one line, possibly preceded by spaces. In this -# position, it can be escaped with a \ in front of the first colon. -# -# The file will be searched for in the directories listed by the +--include+ -# option, or in the current directory by default. The contents of the file -# will be shifted to have the same indentation as the ':' at the start of -# the +:include:+ directive. -# -# [+:title:+ _text_] -# Sets the title for the document. Equivalent to the <tt>--title</tt> -# command line parameter. (The command line parameter overrides any :title: -# directive in the source). -# -# [+:main:+ _name_] -# Equivalent to the <tt>--main</tt> command line parameter. +# See RDoc::MarkupReference. # #-- # Original Author:: Dave Thomas, dave@pragmaticprogrammer.com @@ -822,46 +191,45 @@ https://github.com/ruby/rdoc/issues document.accept formatter end - autoload :Parser, 'rdoc/markup/parser' - autoload :PreProcess, 'rdoc/markup/pre_process' + autoload :Parser, "#{__dir__}/markup/parser" + autoload :PreProcess, "#{__dir__}/markup/pre_process" # Inline markup classes - autoload :AttrChanger, 'rdoc/markup/attr_changer' - autoload :AttrSpan, 'rdoc/markup/attr_span' - autoload :Attributes, 'rdoc/markup/attributes' - autoload :AttributeManager, 'rdoc/markup/attribute_manager' - autoload :RegexpHandling, 'rdoc/markup/regexp_handling' + autoload :AttrChanger, "#{__dir__}/markup/attr_changer" + autoload :AttrSpan, "#{__dir__}/markup/attr_span" + autoload :Attributes, "#{__dir__}/markup/attributes" + autoload :AttributeManager, "#{__dir__}/markup/attribute_manager" + autoload :RegexpHandling, "#{__dir__}/markup/regexp_handling" # RDoc::Markup AST - autoload :BlankLine, 'rdoc/markup/blank_line' - autoload :BlockQuote, 'rdoc/markup/block_quote' - autoload :Document, 'rdoc/markup/document' - autoload :HardBreak, 'rdoc/markup/hard_break' - autoload :Heading, 'rdoc/markup/heading' - autoload :Include, 'rdoc/markup/include' - autoload :IndentedParagraph, 'rdoc/markup/indented_paragraph' - autoload :List, 'rdoc/markup/list' - autoload :ListItem, 'rdoc/markup/list_item' - autoload :Paragraph, 'rdoc/markup/paragraph' - autoload :Table, 'rdoc/markup/table' - autoload :Raw, 'rdoc/markup/raw' - autoload :Rule, 'rdoc/markup/rule' - autoload :Verbatim, 'rdoc/markup/verbatim' + autoload :BlankLine, "#{__dir__}/markup/blank_line" + autoload :BlockQuote, "#{__dir__}/markup/block_quote" + autoload :Document, "#{__dir__}/markup/document" + autoload :HardBreak, "#{__dir__}/markup/hard_break" + autoload :Heading, "#{__dir__}/markup/heading" + autoload :Include, "#{__dir__}/markup/include" + autoload :IndentedParagraph, "#{__dir__}/markup/indented_paragraph" + autoload :List, "#{__dir__}/markup/list" + autoload :ListItem, "#{__dir__}/markup/list_item" + autoload :Paragraph, "#{__dir__}/markup/paragraph" + autoload :Table, "#{__dir__}/markup/table" + autoload :Raw, "#{__dir__}/markup/raw" + autoload :Rule, "#{__dir__}/markup/rule" + autoload :Verbatim, "#{__dir__}/markup/verbatim" # Formatters - autoload :Formatter, 'rdoc/markup/formatter' - - autoload :ToAnsi, 'rdoc/markup/to_ansi' - autoload :ToBs, 'rdoc/markup/to_bs' - autoload :ToHtml, 'rdoc/markup/to_html' - autoload :ToHtmlCrossref, 'rdoc/markup/to_html_crossref' - autoload :ToHtmlSnippet, 'rdoc/markup/to_html_snippet' - autoload :ToLabel, 'rdoc/markup/to_label' - autoload :ToMarkdown, 'rdoc/markup/to_markdown' - autoload :ToRdoc, 'rdoc/markup/to_rdoc' - autoload :ToTableOfContents, 'rdoc/markup/to_table_of_contents' - autoload :ToTest, 'rdoc/markup/to_test' - autoload :ToTtOnly, 'rdoc/markup/to_tt_only' + autoload :Formatter, "#{__dir__}/markup/formatter" + + autoload :ToAnsi, "#{__dir__}/markup/to_ansi" + autoload :ToBs, "#{__dir__}/markup/to_bs" + autoload :ToHtml, "#{__dir__}/markup/to_html" + autoload :ToHtmlCrossref, "#{__dir__}/markup/to_html_crossref" + autoload :ToHtmlSnippet, "#{__dir__}/markup/to_html_snippet" + autoload :ToLabel, "#{__dir__}/markup/to_label" + autoload :ToMarkdown, "#{__dir__}/markup/to_markdown" + autoload :ToRdoc, "#{__dir__}/markup/to_rdoc" + autoload :ToTableOfContents, "#{__dir__}/markup/to_table_of_contents" + autoload :ToTest, "#{__dir__}/markup/to_test" + autoload :ToTtOnly, "#{__dir__}/markup/to_tt_only" end - diff --git a/lib/rdoc/markup/attr_changer.rb b/lib/rdoc/markup/attr_changer.rb index 4c4bc6479e..e5ba470bb6 100644 --- a/lib/rdoc/markup/attr_changer.rb +++ b/lib/rdoc/markup/attr_changer.rb @@ -20,4 +20,3 @@ class RDoc::Markup::AttrChanger end end - diff --git a/lib/rdoc/markup/attr_span.rb b/lib/rdoc/markup/attr_span.rb index 20ef11cd6d..f1fabf1c3b 100644 --- a/lib/rdoc/markup/attr_span.rb +++ b/lib/rdoc/markup/attr_span.rb @@ -33,4 +33,3 @@ class RDoc::Markup::AttrSpan end end - diff --git a/lib/rdoc/markup/attribute_manager.rb b/lib/rdoc/markup/attribute_manager.rb index 50764510f3..f6eb06da95 100644 --- a/lib/rdoc/markup/attribute_manager.rb +++ b/lib/rdoc/markup/attribute_manager.rb @@ -1,8 +1,19 @@ # frozen_string_literal: true + ## # Manages changes of attributes in a block of text class RDoc::Markup::AttributeManager + unless ::MatchData.method_defined?(:match_length) + using ::Module.new { + refine(::MatchData) { + def match_length(nth) # :nodoc: + b, e = offset(nth) + e - b if b + end + } + } + end ## # The NUL character @@ -127,6 +138,7 @@ class RDoc::Markup::AttributeManager res end + # :nodoc: def exclusive?(attr) (attr & @exclusive_bitmap) != 0 end @@ -144,47 +156,42 @@ class RDoc::Markup::AttributeManager convert_attrs_word_pair_map(str, attrs, exclusive) end + # :nodoc: def convert_attrs_matching_word_pairs(str, attrs, exclusive) # first do matching ones tags = @matching_word_pairs.select { |start, bitmap| - if exclusive && exclusive?(bitmap) - true - elsif !exclusive && !exclusive?(bitmap) - true - else - false - end + exclusive == exclusive?(bitmap) }.keys return if tags.empty? - all_tags = @matching_word_pairs.keys + tags = "[#{tags.join("")}](?!#{PROTECT_ATTR})" + all_tags = "[#{@matching_word_pairs.keys.join("")}](?!#{PROTECT_ATTR})" - re = /(^|\W|[#{all_tags.join("")}])([#{tags.join("")}])(\2*[#\\]?[\w:.\/\[\]-]+?\S?)\2(?!\2)([#{all_tags.join("")}]|\W|$)/ + re = /(?:^|\W|#{all_tags})\K(#{tags})(\1*[#\\]?[\w:#{PROTECT_ATTR}.\/\[\]-]+?\S?)\1(?!\1)(?=#{all_tags}|\W|$)/ 1 while str.gsub!(re) { |orig| - attr = @matching_word_pairs[$2] - attr_updated = attrs.set_attrs($`.length + $1.length + $2.length, $3.length, attr) - if attr_updated - $1 + NULL * $2.length + $3 + NULL * $2.length + $4 + a, w = (m = $~).values_at(1, 2) + attr = @matching_word_pairs[a] + if attrs.set_attrs(m.begin(2), w.length, attr) + a = NULL * a.length else - $1 + NON_PRINTING_START + $2 + NON_PRINTING_END + $3 + NON_PRINTING_START + $2 + NON_PRINTING_END + $4 + a = NON_PRINTING_START + a + NON_PRINTING_END end + a + w + a } str.delete!(NON_PRINTING_START + NON_PRINTING_END) end + # :nodoc: def convert_attrs_word_pair_map(str, attrs, exclusive) # then non-matching unless @word_pair_map.empty? then @word_pair_map.each do |regexp, attr| - if !exclusive - next if exclusive?(attr) - else - next if !exclusive?(attr) - end + next unless exclusive == exclusive?(attr) 1 while str.gsub!(regexp) { |orig| - updated = attrs.set_attrs($`.length + $1.length, $2.length, attr) + w = (m = ($~))[2] + updated = attrs.set_attrs(m.begin(2), w.length, attr) if updated - NULL * $1.length + $2 + NULL * $3.length + NULL * m.match_length(1) + w + NULL * m.match_length(3) else orig end @@ -198,20 +205,14 @@ class RDoc::Markup::AttributeManager def convert_html(str, attrs, exclusive = false) tags = @html_tags.select { |start, bitmap| - if exclusive && exclusive?(bitmap) - true - elsif !exclusive && !exclusive?(bitmap) - true - else - false - end + exclusive == exclusive?(bitmap) }.keys.join '|' 1 while str.gsub!(/<(#{tags})>(.*?)<\/\1>/i) { |orig| attr = @html_tags[$1.downcase] - html_length = $1.length + 2 + html_length = $~.match_length(1) + 2 # "<>".length seq = NULL * html_length - attrs.set_attrs($`.length + html_length, $2.length, attr) + attrs.set_attrs($~.begin(2), $~.match_length(2), attr) seq + $2 + seq + NULL } end @@ -221,11 +222,7 @@ class RDoc::Markup::AttributeManager def convert_regexp_handlings str, attrs, exclusive = false @regexp_handlings.each do |regexp, attribute| - if exclusive - next if !exclusive?(attribute) - else - next if exclusive?(attribute) - end + next unless exclusive == exclusive?(attribute) str.scan(regexp) do capture = $~.size == 1 ? 0 : 1 @@ -406,4 +403,3 @@ class RDoc::Markup::AttributeManager end end - diff --git a/lib/rdoc/markup/attributes.rb b/lib/rdoc/markup/attributes.rb index ce014ce928..d9d18b3059 100644 --- a/lib/rdoc/markup/attributes.rb +++ b/lib/rdoc/markup/attributes.rb @@ -68,4 +68,3 @@ class RDoc::Markup::Attributes end end - diff --git a/lib/rdoc/markup/blank_line.rb b/lib/rdoc/markup/blank_line.rb index 3129ab5e7f..f63ae9479c 100644 --- a/lib/rdoc/markup/blank_line.rb +++ b/lib/rdoc/markup/blank_line.rb @@ -25,4 +25,3 @@ class RDoc::Markup::BlankLine end end - diff --git a/lib/rdoc/markup/block_quote.rb b/lib/rdoc/markup/block_quote.rb index 7a4b3e36b0..d9fcbf213c 100644 --- a/lib/rdoc/markup/block_quote.rb +++ b/lib/rdoc/markup/block_quote.rb @@ -12,4 +12,3 @@ class RDoc::Markup::BlockQuote < RDoc::Markup::Raw end end - diff --git a/lib/rdoc/markup/document.rb b/lib/rdoc/markup/document.rb index f3a5de1fc3..94cf6a3666 100644 --- a/lib/rdoc/markup/document.rb +++ b/lib/rdoc/markup/document.rb @@ -162,4 +162,3 @@ class RDoc::Markup::Document end end - diff --git a/lib/rdoc/markup/formatter.rb b/lib/rdoc/markup/formatter.rb index 2bac76e838..9daffaabb8 100644 --- a/lib/rdoc/markup/formatter.rb +++ b/lib/rdoc/markup/formatter.rb @@ -90,7 +90,7 @@ class RDoc::Markup::Formatter def add_regexp_handling_TIDYLINK @markup.add_regexp_handling(/(?: - \{.*?\} | # multi-word label + \{[^{}]*\} | # multi-word label \b[^\s{}]+? # single-word label ) @@ -263,4 +263,3 @@ class RDoc::Markup::Formatter end end - diff --git a/lib/rdoc/markup/hard_break.rb b/lib/rdoc/markup/hard_break.rb index 046068d5c2..de1819c903 100644 --- a/lib/rdoc/markup/hard_break.rb +++ b/lib/rdoc/markup/hard_break.rb @@ -29,4 +29,3 @@ class RDoc::Markup::HardBreak end end - diff --git a/lib/rdoc/markup/heading.rb b/lib/rdoc/markup/heading.rb index 93a3a52000..02476e5226 100644 --- a/lib/rdoc/markup/heading.rb +++ b/lib/rdoc/markup/heading.rb @@ -76,4 +76,3 @@ RDoc::Markup::Heading = end end - diff --git a/lib/rdoc/markup/include.rb b/lib/rdoc/markup/include.rb index ad7c4a9640..2bf63526b2 100644 --- a/lib/rdoc/markup/include.rb +++ b/lib/rdoc/markup/include.rb @@ -40,4 +40,3 @@ class RDoc::Markup::Include end end - diff --git a/lib/rdoc/markup/indented_paragraph.rb b/lib/rdoc/markup/indented_paragraph.rb index d42b2e52b8..992cd7cf81 100644 --- a/lib/rdoc/markup/indented_paragraph.rb +++ b/lib/rdoc/markup/indented_paragraph.rb @@ -45,4 +45,3 @@ class RDoc::Markup::IndentedParagraph < RDoc::Markup::Raw end end - diff --git a/lib/rdoc/markup/list.rb b/lib/rdoc/markup/list.rb index 05c3609202..112b7a1a86 100644 --- a/lib/rdoc/markup/list.rb +++ b/lib/rdoc/markup/list.rb @@ -99,4 +99,3 @@ class RDoc::Markup::List end end - diff --git a/lib/rdoc/markup/list_item.rb b/lib/rdoc/markup/list_item.rb index d22554ee73..0b8326a69f 100644 --- a/lib/rdoc/markup/list_item.rb +++ b/lib/rdoc/markup/list_item.rb @@ -97,4 +97,3 @@ class RDoc::Markup::ListItem end end - diff --git a/lib/rdoc/markup/paragraph.rb b/lib/rdoc/markup/paragraph.rb index a2e45ef009..21dfda007a 100644 --- a/lib/rdoc/markup/paragraph.rb +++ b/lib/rdoc/markup/paragraph.rb @@ -26,4 +26,3 @@ class RDoc::Markup::Paragraph < RDoc::Markup::Raw end end - diff --git a/lib/rdoc/markup/parser.rb b/lib/rdoc/markup/parser.rb index 1b54a519d1..9c77048591 100644 --- a/lib/rdoc/markup/parser.rb +++ b/lib/rdoc/markup/parser.rb @@ -218,7 +218,7 @@ class RDoc::Markup::Parser break if peek_token.first == :BREAK - data << ' ' if skip :NEWLINE + data << ' ' if skip :NEWLINE and /#{SPACE_SEPARATED_LETTER_CLASS}\z/o.match?(data) else unget break @@ -287,6 +287,12 @@ class RDoc::Markup::Parser line << ' ' * indent when :BREAK, :TEXT then line << data + when :BLOCKQUOTE then + line << '>>>' + peek_type, _, peek_column = peek_token + if peek_type != :NEWLINE and peek_column + line << ' ' * (peek_column - column - 3) + end else # *LIST_TOKENS list_marker = case type when :BULLET then data @@ -372,11 +378,8 @@ class RDoc::Markup::Parser unget parse_text parent, indent when :BLOCKQUOTE then - type, _, column = get - if type == :NEWLINE - type, _, column = get - end - unget if type + nil while (type, = get; type) and type != :NEWLINE + _, _, column, = peek_token bq = RDoc::Markup::BlockQuote.new p :blockquote_start => [data, column] if @debug parse bq, column @@ -417,6 +420,8 @@ class RDoc::Markup::Parser # A simple wrapper of StringScanner that is aware of the current column and lineno class MyStringScanner + # :stopdoc: + def initialize(input) @line = @column = 0 @s = StringScanner.new input @@ -453,6 +458,8 @@ class RDoc::Markup::Parser def [](i) @s[i] end + + #:startdoc: end ## @@ -544,7 +551,10 @@ class RDoc::Markup::Parser [:NOTE, @s[1], *pos] # >>> followed by end of line => :BLOCKQUOTE when @s.scan(/>>> *(\w+)?$/) then - [:BLOCKQUOTE, @s[1], *pos] + if word = @s[1] + @s.unscan(word) + end + [:BLOCKQUOTE, word, *pos] # anything else: :TEXT else @s.scan(/(.*?)( )?\r?$/) diff --git a/lib/rdoc/markup/pre_process.rb b/lib/rdoc/markup/pre_process.rb index 3080ae3578..88078c9cef 100644 --- a/lib/rdoc/markup/pre_process.rb +++ b/lib/rdoc/markup/pre_process.rb @@ -163,6 +163,8 @@ class RDoc::Markup::PreProcess if RDoc::Context === code_object then section = code_object.add_section param code_object.temporary_section = section + elsif RDoc::AnyMethod === code_object then + code_object.section_title = param end blankline # ignore category if we're not on an RDoc::Context diff --git a/lib/rdoc/markup/raw.rb b/lib/rdoc/markup/raw.rb index 85e2c8b825..a7c1c210a6 100644 --- a/lib/rdoc/markup/raw.rb +++ b/lib/rdoc/markup/raw.rb @@ -67,4 +67,3 @@ class RDoc::Markup::Raw end end - diff --git a/lib/rdoc/markup/regexp_handling.rb b/lib/rdoc/markup/regexp_handling.rb index 6ed868c2c1..c471fe73c7 100644 --- a/lib/rdoc/markup/regexp_handling.rb +++ b/lib/rdoc/markup/regexp_handling.rb @@ -38,4 +38,3 @@ class RDoc::Markup::RegexpHandling end end - diff --git a/lib/rdoc/markup/rule.rb b/lib/rdoc/markup/rule.rb index 38c1dc7f56..448148d6d1 100644 --- a/lib/rdoc/markup/rule.rb +++ b/lib/rdoc/markup/rule.rb @@ -18,4 +18,3 @@ class RDoc::Markup::Rule < Struct.new :weight end end - diff --git a/lib/rdoc/markup/table.rb b/lib/rdoc/markup/table.rb index 7bcb10aff3..27a20f073a 100644 --- a/lib/rdoc/markup/table.rb +++ b/lib/rdoc/markup/table.rb @@ -3,12 +3,21 @@ # A section of table class RDoc::Markup::Table - attr_accessor :header, :align, :body + # headers of each column + attr_accessor :header + # alignments of each column + attr_accessor :align + + # body texts of each column + attr_accessor :body + + # Creates new instance def initialize header, align, body @header, @align, @body = header, align, body end + # :stopdoc: def == other self.class == other.class and @header == other.header and @@ -20,7 +29,7 @@ class RDoc::Markup::Table visitor.accept_table @header, @body, @align end - def pretty_print q # :nodoc: + def pretty_print q q.group 2, '[Table: ', ']' do q.group 2, '[Head: ', ']' do q.seplist @header.zip(@align) do |text, align| diff --git a/lib/rdoc/markup/to_ansi.rb b/lib/rdoc/markup/to_ansi.rb index 6cc3b70e93..c3eacab21a 100644 --- a/lib/rdoc/markup/to_ansi.rb +++ b/lib/rdoc/markup/to_ansi.rb @@ -91,4 +91,3 @@ class RDoc::Markup::ToAnsi < RDoc::Markup::ToRdoc end end - diff --git a/lib/rdoc/markup/to_bs.rb b/lib/rdoc/markup/to_bs.rb index f9b86487db..afd9d6e981 100644 --- a/lib/rdoc/markup/to_bs.rb +++ b/lib/rdoc/markup/to_bs.rb @@ -41,6 +41,31 @@ class RDoc::Markup::ToBs < RDoc::Markup::ToRdoc end ## + # Prepares the visitor for consuming +list_item+ + + def accept_list_item_start list_item + type = @list_type.last + + case type + when :NOTE, :LABEL then + bullets = Array(list_item.label).map do |label| + attributes(label).strip + end.join "\n" + + bullets << ":\n" unless bullets.empty? + + @prefix = ' ' * @indent + @indent += 2 + @prefix << bullets + (' ' * @indent) + else + bullet = type == :BULLET ? '*' : @list_index.last.to_s + '.' + @prefix = (' ' * @indent) + bullet.ljust(bullet.length + 1) + width = bullet.length + 1 + @indent += width + end + end + + ## # Turns on or off regexp handling for +convert_string+ def annotate tag diff --git a/lib/rdoc/markup/to_html.rb b/lib/rdoc/markup/to_html.rb index d3bb8af835..91cadf9d16 100644 --- a/lib/rdoc/markup/to_html.rb +++ b/lib/rdoc/markup/to_html.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require 'cgi' +require 'cgi/util' ## # Outputs RDoc markup as HTML. @@ -61,12 +61,15 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter # # These methods are used by regexp handling markup added by RDoc::Markup#add_regexp_handling. + # :nodoc: + URL_CHARACTERS_REGEXP_STR = /[A-Za-z0-9\-._~:\/\?#\[\]@!$&'\(\)*+,;%=]/.source + ## # Adds regexp handlings. def init_regexp_handlings # external links - @markup.add_regexp_handling(/(?:link:|https?:|mailto:|ftp:|irc:|www\.)\S+\w/, + @markup.add_regexp_handling(/(?:link:|https?:|mailto:|ftp:|irc:|www\.)#{URL_CHARACTERS_REGEXP_STR}+\w/, :HYPERLINK) init_link_notation_regexp_handlings end @@ -82,7 +85,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter def handle_RDOCLINK url # :nodoc: case url when /^rdoc-ref:/ - $' + CGI.escapeHTML($') when /^rdoc-label:/ text = $' @@ -93,13 +96,11 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter else text end - gen_url url, text + gen_url CGI.escapeHTML(url), CGI.escapeHTML(text) when /^rdoc-image:/ - "<img src=\"#{$'}\">" - else - url =~ /\Ardoc-[a-z]+:/ - - $' + %[<img src=\"#{CGI.escapeHTML($')}\">] + when /\Ardoc-[a-z]+:/ + CGI.escapeHTML($') end end @@ -123,7 +124,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter # Reference to a local file relative to the output directory. def handle_regexp_HYPERLINK(target) - url = target.text + url = CGI.escapeHTML(target.text) gen_url url, url end @@ -152,9 +153,13 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter text =~ /^\{(.*)\}\[(.*?)\]$/ or text =~ /^(\S+)\[(.*?)\]$/ label = $1 - url = $2 + url = CGI.escapeHTML($2) - label = handle_RDOCLINK label if /^rdoc-image:/ =~ label + if /^rdoc-image:/ =~ label + label = handle_RDOCLINK(label) + else + label = CGI.escapeHTML(label) + end gen_url url, label end @@ -198,7 +203,9 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter def accept_paragraph paragraph @res << "\n<p>" text = paragraph.text @hard_break - text = text.gsub(/\r?\n/, ' ') + text = text.gsub(/(#{SPACE_SEPARATED_LETTER_CLASS})?\K\r?\n(?=(?(1)(#{SPACE_SEPARATED_LETTER_CLASS})?))/o) { + defined?($2) && ' ' + } @res << to_html(text) @res << "</p>\n" end @@ -322,7 +329,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter header.zip(aligns) do |text, align| @res << '<th' @res << ' align="' << align << '"' if align - @res << '>' << CGI.escapeHTML(text) << "</th>\n" + @res << '>' << to_html(text) << "</th>\n" end @res << "</tr>\n</thead>\n<tbody>\n" body.each do |row| @@ -330,7 +337,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter row.zip(aligns) do |text, align| @res << '<td' @res << ' align="' << align << '"' if align - @res << '>' << CGI.escapeHTML(text) << "</td>\n" + @res << '>' << to_html(text) << "</td>\n" end @res << "</tr>\n" end @@ -426,7 +433,9 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter def parseable? text verbose, $VERBOSE = $VERBOSE, nil - eval("BEGIN {return true}\n#{text}") + catch(:valid) do + eval("BEGIN { throw :valid, true }\n#{text}") + end rescue SyntaxError false ensure @@ -441,4 +450,3 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter end end - diff --git a/lib/rdoc/markup/to_html_crossref.rb b/lib/rdoc/markup/to_html_crossref.rb index a9fd09df41..9b5de62fd6 100644 --- a/lib/rdoc/markup/to_html_crossref.rb +++ b/lib/rdoc/markup/to_html_crossref.rb @@ -42,6 +42,7 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml @cross_reference = RDoc::CrossReference.new @context end + # :nodoc: def init_link_notation_regexp_handlings add_regexp_handling_RDOCLINK @@ -62,8 +63,8 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml name = name[1..-1] unless @show_hash if name[0, 1] == '#' - if !(name.end_with?('+@', '-@')) and name =~ /(.*[^#:])@/ - text ||= "#{CGI.unescape $'} at <code>#{$1}</code>" + if !(name.end_with?('+@', '-@')) and name =~ /(.*[^#:])?@/ + text ||= [CGI.unescape($'), (" at <code>#{$1}</code>" if $~.begin(1))].join("") code = false else text ||= name @@ -138,39 +139,37 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml # Creates an HTML link to +name+ with the given +text+. def link name, text, code = true - if !(name.end_with?('+@', '-@')) and name =~ /(.*[^#:])@/ + if !(name.end_with?('+@', '-@')) and name =~ /(.*[^#:])?@/ name = $1 label = $' end - ref = @cross_reference.resolve name, text + ref = @cross_reference.resolve name, text if name case ref when String then ref else - path = ref.as_href @from_path + path = ref ? ref.as_href(@from_path) : +"" if code and RDoc::CodeObject === ref and !(RDoc::TopLevel === ref) text = "<code>#{CGI.escapeHTML text}</code>" end - if path =~ /#/ then - path << "-label-#{label}" - elsif ref.sections and - ref.sections.any? { |section| label == section.title } then - path << "##{label}" - else - if ref.respond_to?(:aref) + if label + if path =~ /#/ + path << "-label-#{label}" + elsif ref&.sections&.any? { |section| label == section.title } + path << "##{label}" + elsif ref.respond_to?(:aref) path << "##{ref.aref}-label-#{label}" else path << "#label-#{label}" end - end if label + end "<a href=\"#{path}\">#{text}</a>" end end end - diff --git a/lib/rdoc/markup/to_html_snippet.rb b/lib/rdoc/markup/to_html_snippet.rb index 4eb36592b7..f471395a3a 100644 --- a/lib/rdoc/markup/to_html_snippet.rb +++ b/lib/rdoc/markup/to_html_snippet.rb @@ -66,6 +66,9 @@ class RDoc::Markup::ToHtmlSnippet < RDoc::Markup::ToHtml alias accept_rule ignore + ## + # Adds +paragraph+ to the output + def accept_paragraph paragraph para = @in_list_entry.last || "<p>" @@ -282,4 +285,3 @@ class RDoc::Markup::ToHtmlSnippet < RDoc::Markup::ToHtml end end - diff --git a/lib/rdoc/markup/to_joined_paragraph.rb b/lib/rdoc/markup/to_joined_paragraph.rb index 46e07c94ad..31cbe0853c 100644 --- a/lib/rdoc/markup/to_joined_paragraph.rb +++ b/lib/rdoc/markup/to_joined_paragraph.rb @@ -25,9 +25,9 @@ class RDoc::Markup::ToJoinedParagraph < RDoc::Markup::Formatter def accept_paragraph paragraph parts = paragraph.parts.chunk do |part| String === part - end.map do |string, chunk| + end.flat_map do |string, chunk| string ? chunk.join.rstrip : chunk - end.flatten + end paragraph.parts.replace parts end @@ -44,4 +44,3 @@ class RDoc::Markup::ToJoinedParagraph < RDoc::Markup::Formatter alias accept_table ignore end - diff --git a/lib/rdoc/markup/to_label.rb b/lib/rdoc/markup/to_label.rb index 3d95ccc2e2..cf808364e9 100644 --- a/lib/rdoc/markup/to_label.rb +++ b/lib/rdoc/markup/to_label.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require 'cgi' +require 'cgi/util' ## # Creates HTML-safe labels suitable for use in id attributes. Tidylinks are @@ -72,4 +72,3 @@ class RDoc::Markup::ToLabel < RDoc::Markup::Formatter alias start_accepting ignore end - diff --git a/lib/rdoc/markup/to_markdown.rb b/lib/rdoc/markup/to_markdown.rb index 3ee48becb0..b915fab60b 100644 --- a/lib/rdoc/markup/to_markdown.rb +++ b/lib/rdoc/markup/to_markdown.rb @@ -45,8 +45,6 @@ class RDoc::Markup::ToMarkdown < RDoc::Markup::ToRdoc # Finishes consumption of `list` def accept_list_end list - @res << "\n" - super end @@ -60,6 +58,8 @@ class RDoc::Markup::ToMarkdown < RDoc::Markup::ToRdoc when :NOTE, :LABEL then use_prefix + @res << "\n" + 4 else @list_index[-1] = @list_index.last.succ @@ -81,11 +81,11 @@ class RDoc::Markup::ToMarkdown < RDoc::Markup::ToRdoc attributes(label).strip end.join "\n" - bullets << "\n:" + bullets << "\n" unless bullets.empty? @prefix = ' ' * @indent @indent += 4 - @prefix << bullets + (' ' * (@indent - 1)) + @prefix << bullets << ":" << (' ' * (@indent - 1)) else bullet = type == :BULLET ? '*' : @list_index.last.to_s + '.' @prefix = (' ' * @indent) + bullet.ljust(4) @@ -189,4 +189,3 @@ class RDoc::Markup::ToMarkdown < RDoc::Markup::ToRdoc end end - diff --git a/lib/rdoc/markup/to_rdoc.rb b/lib/rdoc/markup/to_rdoc.rb index 3cdf4fd08b..88234f5096 100644 --- a/lib/rdoc/markup/to_rdoc.rb +++ b/lib/rdoc/markup/to_rdoc.rb @@ -145,11 +145,19 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter case type when :NOTE, :LABEL then - bullets = Array(list_item.label).map do |label| + stripped_labels = Array(list_item.label).map do |label| attributes(label).strip - end.join "\n" + end + + bullets = case type + when :NOTE + stripped_labels.map { |b| "#{b}::" } + when :LABEL + stripped_labels.map { |b| "[#{b}]" } + end - bullets << ":\n" unless bullets.empty? + bullets = bullets.join("\n") + bullets << "\n" unless stripped_labels.empty? @prefix = ' ' * @indent @indent += 2 @@ -330,33 +338,15 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter text_len = 20 if text_len < 20 - re = /^(.{0,#{text_len}})[ \n]/ next_prefix = ' ' * @indent prefix = @prefix || next_prefix @prefix = nil - @res << prefix - - while text.length > text_len - if text =~ re then - @res << $1 - text.slice!(0, $&.length) - else - @res << text.slice!(0, text_len) - end - - @res << "\n" << next_prefix - end - - if text.empty? then - @res.pop - @res.pop - else - @res << text - @res << "\n" + text.scan(/\G(?:([^ \n]{#{text_len}})(?=[^ \n])|(.{1,#{text_len}})(?:[ \n]|\z))/) do + @res << prefix << ($1 || $2) << "\n" + prefix = next_prefix end end end - diff --git a/lib/rdoc/markup/to_table_of_contents.rb b/lib/rdoc/markup/to_table_of_contents.rb index eb8e8faa16..e5b8225ba3 100644 --- a/lib/rdoc/markup/to_table_of_contents.rb +++ b/lib/rdoc/markup/to_table_of_contents.rb @@ -86,4 +86,3 @@ class RDoc::Markup::ToTableOfContents < RDoc::Markup::Formatter # :startdoc: end - diff --git a/lib/rdoc/markup/to_test.rb b/lib/rdoc/markup/to_test.rb index 61d3cffaf0..30113da561 100644 --- a/lib/rdoc/markup/to_test.rb +++ b/lib/rdoc/markup/to_test.rb @@ -67,4 +67,3 @@ class RDoc::Markup::ToTest < RDoc::Markup::Formatter # :startdoc: end - diff --git a/lib/rdoc/markup/to_tt_only.rb b/lib/rdoc/markup/to_tt_only.rb index 9235d33f04..9ac14ed235 100644 --- a/lib/rdoc/markup/to_tt_only.rb +++ b/lib/rdoc/markup/to_tt_only.rb @@ -118,4 +118,3 @@ class RDoc::Markup::ToTtOnly < RDoc::Markup::Formatter end end - diff --git a/lib/rdoc/markup/verbatim.rb b/lib/rdoc/markup/verbatim.rb index 7f1bc29a09..f51c2cfa14 100644 --- a/lib/rdoc/markup/verbatim.rb +++ b/lib/rdoc/markup/verbatim.rb @@ -81,4 +81,3 @@ class RDoc::Markup::Verbatim < RDoc::Markup::Raw end end - diff --git a/lib/rdoc/meta_method.rb b/lib/rdoc/meta_method.rb index 7927a9ce9c..8c95a0f78c 100644 --- a/lib/rdoc/meta_method.rb +++ b/lib/rdoc/meta_method.rb @@ -4,4 +4,3 @@ class RDoc::MetaMethod < RDoc::AnyMethod end - diff --git a/lib/rdoc/method_attr.rb b/lib/rdoc/method_attr.rb index 3cef78c4a5..61ddb32f46 100644 --- a/lib/rdoc/method_attr.rb +++ b/lib/rdoc/method_attr.rb @@ -289,7 +289,7 @@ class RDoc::MethodAttr < RDoc::CodeObject # HTML id-friendly method/attribute name def html_name - require 'cgi' + require 'cgi/util' CGI.escape(@name.gsub('-', '-2D')).gsub('%','-').sub(/^-/, '') end @@ -416,4 +416,3 @@ class RDoc::MethodAttr < RDoc::CodeObject end end - diff --git a/lib/rdoc/mixin.rb b/lib/rdoc/mixin.rb index 379d7cc526..fa8faefc15 100644 --- a/lib/rdoc/mixin.rb +++ b/lib/rdoc/mixin.rb @@ -118,4 +118,3 @@ class RDoc::Mixin < RDoc::CodeObject end end - diff --git a/lib/rdoc/normal_class.rb b/lib/rdoc/normal_class.rb index 6729b18448..aa340b5d15 100644 --- a/lib/rdoc/normal_class.rb +++ b/lib/rdoc/normal_class.rb @@ -56,7 +56,7 @@ class RDoc::NormalClass < RDoc::ClassModule def pretty_print q # :nodoc: superclass = @superclass ? " < #{@superclass}" : nil - q.group 2, "[class #{full_name}#{superclass} ", "]" do + q.group 2, "[class #{full_name}#{superclass}", "]" do q.breakable q.text "includes:" q.breakable @@ -90,4 +90,3 @@ class RDoc::NormalClass < RDoc::ClassModule end end - diff --git a/lib/rdoc/normal_module.rb b/lib/rdoc/normal_module.rb index 8f364be41c..498ec4dde2 100644 --- a/lib/rdoc/normal_module.rb +++ b/lib/rdoc/normal_module.rb @@ -30,7 +30,7 @@ class RDoc::NormalModule < RDoc::ClassModule end def pretty_print q # :nodoc: - q.group 2, "[module #{full_name}: ", "]" do + q.group 2, "[module #{full_name}:", "]" do q.breakable q.text "includes:" q.breakable @@ -71,4 +71,3 @@ class RDoc::NormalModule < RDoc::ClassModule end end - diff --git a/lib/rdoc/options.rb b/lib/rdoc/options.rb index 13b7ba5c6c..7518e6cc54 100644 --- a/lib/rdoc/options.rb +++ b/lib/rdoc/options.rb @@ -105,7 +105,9 @@ class RDoc::Options generator_name generator_options generators + locale op_dir + page_dir option_parser pipe rdoc_include @@ -338,6 +340,10 @@ class RDoc::Options attr_reader :visibility + ## + # Indicates if files of test suites should be skipped + attr_accessor :skip_tests + def initialize loaded_options = nil # :nodoc: init_ivars override loaded_options if loaded_options @@ -385,6 +391,7 @@ class RDoc::Options @write_options = false @encoding = Encoding::UTF_8 @charset = @encoding.name + @skip_tests = true end def init_with map # :nodoc: @@ -434,6 +441,7 @@ class RDoc::Options @main_page = map['main_page'] if map.has_key?('main_page') @markup = map['markup'] if map.has_key?('markup') @op_dir = map['op_dir'] if map.has_key?('op_dir') + @page_dir = map['page_dir'] if map.has_key?('page_dir') @show_hash = map['show_hash'] if map.has_key?('show_hash') @tab_width = map['tab_width'] if map.has_key?('tab_width') @template_dir = map['template_dir'] if map.has_key?('template_dir') @@ -513,19 +521,22 @@ class RDoc::Options ## # For dumping YAML - def encode_with coder # :nodoc: + def to_yaml(*options) # :nodoc: encoding = @encoding ? @encoding.name : nil - coder.add 'encoding', encoding - coder.add 'static_path', sanitize_path(@static_path) - coder.add 'rdoc_include', sanitize_path(@rdoc_include) + yaml = {} + yaml['encoding'] = encoding + yaml['static_path'] = sanitize_path(@static_path) + yaml['rdoc_include'] = sanitize_path(@rdoc_include) + yaml['page_dir'] = (sanitize_path([@page_dir]).first if @page_dir) ivars = instance_variables.map { |ivar| ivar.to_s[1..-1] } ivars -= SPECIAL ivars.sort.each do |ivar| - coder.add ivar, instance_variable_get("@#{ivar}") + yaml[ivar] = instance_variable_get("@#{ivar}") end + yaml.to_yaml end ## @@ -548,11 +559,17 @@ class RDoc::Options # #template. def finish + if @write_options then + write_options + exit + end + @op_dir ||= 'doc' - @rdoc_include << "." if @rdoc_include.empty? root = @root.to_s - @rdoc_include << root unless @rdoc_include.include?(root) + if @rdoc_include.empty? || !@rdoc_include.include?(root) + @rdoc_include << root + end @exclude = self.exclude @@ -585,14 +602,14 @@ class RDoc::Options def finish_page_dir return unless @page_dir - @files << @page_dir.to_s + @files << @page_dir - page_dir = nil + page_dir = Pathname(@page_dir) begin - page_dir = @page_dir.expand_path.relative_path_from @root + page_dir = page_dir.expand_path.relative_path_from @root rescue ArgumentError # On Windows, sometimes crosses different drive letters. - page_dir = @page_dir.expand_path + page_dir = page_dir.expand_path end @page_dir = page_dir @@ -768,6 +785,13 @@ Usage: #{opt.program_name} [options] [names...] opt.separator nil + opt.on("--no-skipping-tests", nil, + "Don't skip generating documentation for test and spec files") do |value| + @skip_tests = false + end + + opt.separator nil + opt.on("--extension=NEW=OLD", "-E", "Treat files ending with .new as if they", "ended with .old. Using '-E cgi=rb' will", @@ -847,7 +871,7 @@ Usage: #{opt.program_name} [options] [names...] "such files at your project root.", "NOTE: Do not use the same file name in", "the page dir and the root of your project") do |page_dir| - @page_dir = Pathname(page_dir) + @page_dir = page_dir end opt.separator nil @@ -971,7 +995,7 @@ Usage: #{opt.program_name} [options] [names...] opt.on("--template-stylesheets=FILES", PathArray, "Set (or add to) the list of files to", "include with the html template.") do |value| - @template_stylesheets << value + @template_stylesheets.concat value end opt.separator nil @@ -1159,13 +1183,6 @@ Usage: #{opt.program_name} [options] [names...] @files = argv.dup - finish - - if @write_options then - write_options - exit - end - self end @@ -1278,8 +1295,37 @@ Usage: #{opt.program_name} [options] [names...] File.open '.rdoc_options', 'w' do |io| io.set_encoding Encoding::UTF_8 - YAML.dump self, io + io.print to_yaml + end + end + + ## + # Loads options from .rdoc_options if the file exists, otherwise creates a + # new RDoc::Options instance. + + def self.load_options + options_file = File.expand_path '.rdoc_options' + return RDoc::Options.new unless File.exist? options_file + + RDoc.load_yaml + + begin + options = YAML.safe_load File.read('.rdoc_options'), permitted_classes: [RDoc::Options, Symbol] + rescue Psych::SyntaxError + raise RDoc::Error, "#{options_file} is not a valid rdoc options file" + end + + return RDoc::Options.new unless options # Allow empty file. + + raise RDoc::Error, "#{options_file} is not a valid rdoc options file" unless + RDoc::Options === options or Hash === options + + if Hash === options + # Override the default values with the contents of YAML file. + options = RDoc::Options.new options end + + options end end diff --git a/lib/rdoc/parser.rb b/lib/rdoc/parser.rb index 425bc48632..425105effa 100644 --- a/lib/rdoc/parser.rb +++ b/lib/rdoc/parser.rb @@ -125,9 +125,11 @@ class RDoc::Parser return parser if ext_name.empty? if parser == RDoc::Parser::Simple and ext_name !~ /txt|rdoc/ then - case check_modeline file_name + case mode = check_modeline(file_name) when nil, 'rdoc' then # continue - else return nil + else + RDoc::Parser.parsers.find { |_, p| return p if mode.casecmp?(p.name[/\w+\z/]) } + return nil end end @@ -263,9 +265,26 @@ class RDoc::Parser @preprocess.options = @options end - autoload :RubyTools, 'rdoc/parser/ruby_tools' - autoload :Text, 'rdoc/parser/text' + autoload :RubyTools, "#{__dir__}/parser/ruby_tools" + autoload :Text, "#{__dir__}/parser/text" + ## + # Normalizes tabs in +body+ + + def handle_tab_width(body) + if /\t/ =~ body + tab_width = @options.tab_width + body.split(/\n/).map do |line| + 1 while line.gsub!(/\t+/) do + b, e = $~.offset(0) + ' ' * (tab_width * (e-b) - b % tab_width) + end + line + end.join "\n" + else + body + end + end end # simple must come first in order to show up last in the parsers list diff --git a/lib/rdoc/parser/c.rb b/lib/rdoc/parser/c.rb index 9d8db6cdee..f8f238fd74 100644 --- a/lib/rdoc/parser/c.rb +++ b/lib/rdoc/parser/c.rb @@ -122,6 +122,11 @@ class RDoc::Parser::C < RDoc::Parser include RDoc::Text + # :stopdoc: + BOOL_ARG_PATTERN = /\s*+\b([01]|Q?(?:true|false)|TRUE|FALSE)\b\s*/ + TRUE_VALUES = ['1', 'TRUE', 'true', 'Qtrue'].freeze + # :startdoc: + ## # Maps C variable names to names of Ruby classes or modules @@ -173,6 +178,8 @@ class RDoc::Parser::C < RDoc::Parser @classes = load_variable_map :c_class_variables @singleton_classes = load_variable_map :c_singleton_class_variables + @markup = @options.markup + # class_variable => { function => [method, ...] } @methods = Hash.new { |h, f| h[f] = Hash.new { |i, m| i[m] = [] } } @@ -257,18 +264,18 @@ class RDoc::Parser::C < RDoc::Parser @content.scan(/rb_attr\s*\( \s*(\w+), \s*([\w"()]+), - \s*([01]), - \s*([01]), - \s*\w+\);/xm) do |var_name, attr_name, read, write| + #{BOOL_ARG_PATTERN}, + #{BOOL_ARG_PATTERN}, + \s*\w+\);/xmo) do |var_name, attr_name, read, write| handle_attr var_name, attr_name, read, write end @content.scan(%r%rb_define_attr\( \s*([\w\.]+), \s*"([^"]+)", - \s*(\d+), - \s*(\d+)\s*\); - %xm) do |var_name, attr_name, read, write| + #{BOOL_ARG_PATTERN}, + #{BOOL_ARG_PATTERN}\); + %xmo) do |var_name, attr_name, read, write| handle_attr var_name, attr_name, read, write end end @@ -293,94 +300,92 @@ class RDoc::Parser::C < RDoc::Parser @content.scan( %r( + (?<open>\s*\(\s*) {0} + (?<close>\s*\)\s*) {0} + (?<name>\s*"(?<class_name>\w+)") {0} + (?<parent>\s*(?: + (?<parent_name>[\w\*\s\(\)\.\->]+) | + rb_path2class\s*\(\s*"(?<path>[\w:]+)"\s*\) + )) {0} + (?<under>\w+) {0} + (?<var_name>[\w\.]+)\s* = \s*rb_(?: define_(?: - class(?: # rb_define_class(class_name_1, parent_name_1) - \s*\( - \s*"(?<class_name_1>\w+)", - \s*(?<parent_name_1>\w+)\s* - \) - | - _under\s*\( # rb_define_class_under(class_under, class_name2, parent_name2...) - \s* (?<class_under>\w+), - \s* "(?<class_name_2>\w+)", - \s* - (?: - (?<parent_name_2>[\w\*\s\(\)\.\->]+) | - rb_path2class\("(?<path>[\w:]+)"\) - ) + class(?: # rb_define_class(name, parent_name) + \(\s* + \g<name>, + \g<parent> \s*\) + | + _under\g<open> # rb_define_class_under(under, name, parent_name...) + \g<under>, + \g<name>, + \g<parent> + \g<close> ) | - module(?: # rb_define_module(module_name_1) - \s*\( - \s*"(?<module_name_1>\w+)"\s* - \) + (?<module>) + module(?: # rb_define_module(name) + \g<open> + \g<name> + \g<close> | - _under\s*\( # rb_define_module_under(module_under, module_name_2) - \s*(?<module_under>\w+), - \s*"(?<module_name_2>\w+)" - \s*\) + _under\g<open> # rb_define_module_under(under, name) + \g<under>, + \g<name> + \g<close> ) ) | - struct_define_without_accessor\s*\( # rb_struct_define_without_accessor(class_name_3, parent_name_3, ...) - \s*"(?<class_name_3>\w+)", - \s*(?<parent_name_3>\w+), - \s*\w+, # Allocation function - (?:\s*"\w+",)* # Attributes - \s*NULL - \) + (?<attributes>(?:\s*"\w+",)*\s*NULL\s*) {0} + struct_define(?: + \g<open> # rb_struct_define(name, ...) + \g<name>, + | + _under\g<open> # rb_struct_define_under(under, name, ...) + \g<under>, + \g<name>, + | + _without_accessor(?: + \g<open> # rb_struct_define_without_accessor(name, parent_name, ...) + | + _under\g<open> # rb_struct_define_without_accessor_under(under, name, parent_name, ...) + \g<under>, + ) + \g<name>, + \g<parent>, + \s*\w+, # Allocation function + ) + \g<attributes> + \g<close> | - singleton_class\s*\( # rb_singleton_class(target_class_name) - \s*(?<target_class_name>\w+) - \) + singleton_class\g<open> # rb_singleton_class(target_class_name) + (?<target_class_name>\w+) + \g<close> ) )mx ) do - class_name = $~[:class_name_1] - type = :class - if class_name - # rb_define_class(class_name_1, parent_name_1) - parent_name = $~[:parent_name_1] - #under = nil - else - class_name = $~[:class_name_2] - if class_name - # rb_define_class_under(class_under, class_name2, parent_name2...) - parent_name = $~[:parent_name_2] || $~[:path] - under = $~[:class_under] - else - class_name = $~[:class_name_3] - if class_name - # rb_struct_define_without_accessor(class_name_3, parent_name_3, ...) - parent_name = $~[:parent_name_3] - #under = nil - else - type = :module - class_name = $~[:module_name_1] - #parent_name = nil - if class_name - # rb_define_module(module_name_1) - #under = nil - else - class_name = $~[:module_name_2] - if class_name - # rb_define_module_under(module_under, module_name_1) - under = $~[:module_under] - else - # rb_singleton_class(target_class_name) - target_class_name = $~[:target_class_name] - handle_singleton $~[:var_name], target_class_name - next - end - end - end - end + if target_class_name = $~[:target_class_name] + # rb_singleton_class(target_class_name) + handle_singleton $~[:var_name], target_class_name + next end - handle_class_module($~[:var_name], type, class_name, parent_name, under) + var_name = $~[:var_name] + type = $~[:module] ? :module : :class + class_name = $~[:class_name] + parent_name = $~[:parent_name] || $~[:path] + under = $~[:under] + attributes = $~[:attributes] + + handle_class_module(var_name, type, class_name, parent_name, under) + if attributes and !parent_name # rb_struct_define *not* without_accessor + true_flag = 'Qtrue' + attributes.scan(/"\K\w+(?=")/) do |attr_name| + handle_attr var_name, attr_name, true_flag, true_flag + end + end end end @@ -439,7 +444,7 @@ class RDoc::Parser::C < RDoc::Parser next unless cls = @classes[c] m = @known_classes[m] || m - comment = RDoc::Comment.new '', @top_level, :c + comment = new_comment '', @top_level, :c incl = cls.add_include RDoc::Include.new(m, comment) incl.record_location @top_level end @@ -521,7 +526,7 @@ class RDoc::Parser::C < RDoc::Parser \s*"#{Regexp.escape new_name}"\s*, \s*"#{Regexp.escape old_name}"\s*\);%xm - RDoc::Comment.new($1 || '', @top_level, :c) + new_comment($1 || '', @top_level, :c) end ## @@ -560,7 +565,7 @@ class RDoc::Parser::C < RDoc::Parser '' end - RDoc::Comment.new comment, @top_level, :c + new_comment comment, @top_level, :c end ## @@ -570,19 +575,18 @@ class RDoc::Parser::C < RDoc::Parser table = {} file_content.scan(%r{ ((?>/\*.*?\*/\s*)?) - ((?:(?:\w+)\s+)? - (?:intern\s+)?VALUE\s+(\w+) - \s*(?:\([^)]*\))(?:[^\);]|$)) + ((?:\w+\s+){0,2} VALUE\s+(\w+) + \s*(?:\([^\)]*\))(?:[^\);]|$)) | ((?>/\*.*?\*/\s*))^\s*(\#\s*define\s+(\w+)\s+(\w+)) | ^\s*\#\s*define\s+(\w+)\s+(\w+) }xm) do case - when $1 - table[$3] = [:func_def, $1, $2, $~.offset(2)] if !table[$3] || table[$3][0] != :func_def - when $4 - table[$6] = [:macro_def, $4, $5, $~.offset(5), $7] if !table[$6] || table[$6][0] == :macro_alias - when $8 - table[$8] ||= [:macro_alias, $9] + when name = $3 + table[name] = [:func_def, $1, $2, $~.offset(2)] if !(t = table[name]) || t[0] != :func_def + when name = $6 + table[name] = [:macro_def, $4, $5, $~.offset(5), $7] if !(t = table[name]) || t[0] == :macro_alias + when name = $8 + table[name] ||= [:macro_alias, $9] end end table @@ -600,7 +604,7 @@ class RDoc::Parser::C < RDoc::Parser case type when :func_def - comment = RDoc::Comment.new args[0], @top_level, :c + comment = new_comment args[0], @top_level, :c body = args[1] offset, = args[2] @@ -630,7 +634,7 @@ class RDoc::Parser::C < RDoc::Parser body when :macro_def - comment = RDoc::Comment.new args[0], @top_level, :c + comment = new_comment args[0], @top_level, :c body = args[1] offset, = args[2] @@ -675,13 +679,14 @@ class RDoc::Parser::C < RDoc::Parser ## # Finds a RDoc::NormalClass or RDoc::NormalModule for +raw_name+ - def find_class(raw_name, name) + def find_class(raw_name, name, base_name = nil) unless @classes[raw_name] if raw_name =~ /^rb_m/ container = @top_level.add_module RDoc::NormalModule, name else container = @top_level.add_class RDoc::NormalClass, name end + container.name = base_name if base_name container.record_location @top_level @classes[raw_name] = container @@ -722,7 +727,7 @@ class RDoc::Parser::C < RDoc::Parser ((?>/\*.*?\*/\s+)) (static\s+)? void\s+ - Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)?\)%xmi then + Init(?:VM)?_(?i:#{class_name})\s*(?:_\(\s*)?\(\s*(?:void\s*)?\)%xm then comment = $1.sub(%r%Document-(?:class|module):\s+#{class_name}%, '') elsif @content =~ %r%Document-(?:class|module):\s+#{class_name}\s*? (?:<\s+[:,\w]+)?\n((?>.*?\*/))%xm then @@ -737,7 +742,7 @@ class RDoc::Parser::C < RDoc::Parser comment = '' end - comment = RDoc::Comment.new comment, @top_level, :c + comment = new_comment comment, @top_level, :c comment.normalize look_for_directives_in class_mod, comment @@ -751,17 +756,27 @@ class RDoc::Parser::C < RDoc::Parser def gen_const_table file_content table = {} @content.scan(%r{ - ((?>^\s*/\*.*?\*/\s+)) - rb_define_(\w+)\((?:\s*(?:\w+),)?\s* - "(\w+)"\s*, + (?<doc>(?>^\s*/\*.*?\*/\s+)) + rb_define_(?<type>\w+)\(\s*(?:\w+),\s* + "(?<name>\w+)"\s*, .*?\)\s*; + | (?<doc>(?>^\s*/\*.*?\*/\s+)) + rb_file_(?<type>const)\(\s* + "(?<name>\w+)"\s*, + .*?\)\s*; + | (?<doc>(?>^\s*/\*.*?\*/\s+)) + rb_curses_define_(?<type>const)\(\s* + (?<name>\w+) + \s*\)\s*; | Document-(?:const|global|variable):\s - ((?:\w+::)*\w+) - \s*?\n((?>.*?\*/)) + (?<name>(?:\w+::)*\w+) + \s*?\n(?<doc>(?>.*?\*/)) }mxi) do - case - when $1 then table[[$2, $3]] = $1 - when $4 then table[$4] = "/*\n" + $5 + name, doc, type = $~.values_at(:name, :doc, :type) + if type + table[[type, name]] = doc + else + table[name] = "/*\n" + doc end end table @@ -782,7 +797,7 @@ class RDoc::Parser::C < RDoc::Parser table[const_name] || '' - RDoc::Comment.new comment, @top_level, :c + new_comment comment, @top_level, :c end ## @@ -813,7 +828,7 @@ class RDoc::Parser::C < RDoc::Parser return unless comment - RDoc::Comment.new comment, @top_level, :c + new_comment comment, @top_level, :c end ## @@ -822,8 +837,8 @@ class RDoc::Parser::C < RDoc::Parser def handle_attr(var_name, attr_name, read, write) rw = '' - rw += 'R' if '1' == read - rw += 'W' if '1' == write + rw += 'R' if TRUE_VALUES.include?(read) + rw += 'W' if TRUE_VALUES.include?(write) class_name = @known_classes[var_name] @@ -919,7 +934,7 @@ class RDoc::Parser::C < RDoc::Parser return unless class_name - class_obj = find_class var_name, class_name + class_obj = find_class var_name, class_name, class_name[/::\K[^:]+\z/] unless class_obj then @options.warn 'Enclosing class or module %p is not known' % [const_name] @@ -933,21 +948,20 @@ class RDoc::Parser::C < RDoc::Parser # "/* definition: comment */" form. The literal ':' and '\' characters # can be escaped with a backslash. if type.downcase == 'const' then - no_match, new_definition, new_comment = comment.text.split(/(\A.*):/) + if /\A(.+?)?:(?!\S)/ =~ comment.text + new_definition, new_comment = $1, $' - if no_match and no_match.empty? then - if new_definition.empty? then # Default to literal C definition + if !new_definition # Default to literal C definition new_definition = definition else - new_definition = new_definition.gsub("\:", ":") - new_definition = new_definition.gsub("\\", '\\') + new_definition = new_definition.gsub(/\\([\\:])/, '\1') end new_definition.sub!(/\A(\s+)/, '') new_comment = "#{$1}#{new_comment.lstrip}" - new_comment = RDoc::Comment.new new_comment, @top_level, :c + new_comment = self.new_comment(new_comment, @top_level, :c) con = RDoc::Constant.new const_name, new_definition, new_comment else @@ -1023,12 +1037,18 @@ class RDoc::Parser::C < RDoc::Parser elsif p_count == -1 then # argc, argv rb_scan_args body else - "(#{(1..p_count).map { |i| "p#{i}" }.join ', '})" + args = (1..p_count).map { |i| "p#{i}" } + "(#{args.join ', '})" end meth_obj.record_location @top_level + + if meth_obj.section_title + class_obj.temporary_section = class_obj.add_section(meth_obj.section_title) + end class_obj.add_method meth_obj + @stats.add_method meth_obj meth_obj.visibility = :private if 'private_method' == type end @@ -1046,23 +1066,6 @@ class RDoc::Parser::C < RDoc::Parser end ## - # Normalizes tabs in +body+ - - def handle_tab_width(body) - if /\t/ =~ body - tab_width = @options.tab_width - body.split(/\n/).map do |line| - 1 while line.gsub!(/\t+/) do - ' ' * (tab_width * $&.length - $`.length % tab_width) - end && $~ - line - end.join "\n" - else - body - end - end - - ## # Loads the variable map with the given +name+ from the RDoc::Store, if # present. @@ -1222,4 +1225,12 @@ class RDoc::Parser::C < RDoc::Parser @top_level end + ## + # Creates a RDoc::Comment instance. + + def new_comment text = nil, location = nil, language = nil + RDoc::Comment.new(text, location, language).tap do |comment| + comment.format = @markup + end + end end diff --git a/lib/rdoc/parser/changelog.rb b/lib/rdoc/parser/changelog.rb index 9245d49376..a046241870 100644 --- a/lib/rdoc/parser/changelog.rb +++ b/lib/rdoc/parser/changelog.rb @@ -216,12 +216,22 @@ class RDoc::Parser::ChangeLog < RDoc::Parser @top_level end + ## + # The extension for Git commit log + module Git + ## + # Parses auxiliary info. Currentry `base-url` to expand + # references is effective. + def parse_info(info) /^\s*base-url\s*=\s*(.*\S)/ =~ info @base_url = $1 end + ## + # Parses the entries in the Git commit logs + def parse_entries entries = [] @@ -244,6 +254,11 @@ class RDoc::Parser::ChangeLog < RDoc::Parser entries end + ## + # Returns a list of ChangeLog entries as + # RDoc::Parser::ChangeLog::Git::LogEntry list for the given + # +entries+. + def create_entries entries # git log entries have no strictly itemized style like the old # style, just assume Markdown. @@ -332,4 +347,3 @@ class RDoc::Parser::ChangeLog < RDoc::Parser end end end - diff --git a/lib/rdoc/parser/markdown.rb b/lib/rdoc/parser/markdown.rb index 9ff478f872..3c316227b9 100644 --- a/lib/rdoc/parser/markdown.rb +++ b/lib/rdoc/parser/markdown.rb @@ -20,5 +20,3 @@ class RDoc::Parser::Markdown < RDoc::Parser end end - - diff --git a/lib/rdoc/parser/rd.rb b/lib/rdoc/parser/rd.rb index 25f5711731..19e47e549d 100644 --- a/lib/rdoc/parser/rd.rb +++ b/lib/rdoc/parser/rd.rb @@ -20,4 +20,3 @@ class RDoc::Parser::RD < RDoc::Parser end end - diff --git a/lib/rdoc/parser/ripper_state_lex.rb b/lib/rdoc/parser/ripper_state_lex.rb index 5492f08726..f6cefd0305 100644 --- a/lib/rdoc/parser/ripper_state_lex.rb +++ b/lib/rdoc/parser/ripper_state_lex.rb @@ -1,7 +1,12 @@ # frozen_string_literal: true require 'ripper' +## +# Wrapper for Ripper lex states + class RDoc::Parser::RipperStateLex + # :stopdoc: + # TODO: Remove this constants after Ruby 2.4 EOL RIPPER_HAS_LEX_STATE = Ripper::Filter.method_defined?(:state) @@ -368,7 +373,7 @@ class RDoc::Parser::RipperStateLex private def get_symbol_tk(tk) is_symbol = true symbol_tk = Token.new(tk.line_no, tk.char_no, :on_symbol) - if ":'" == tk[:text] or ':"' == tk[:text] + if ":'" == tk[:text] or ':"' == tk[:text] or tk[:text].start_with?('%s') tk1 = get_string_tk(tk) symbol_tk[:text] = tk1[:text] symbol_tk[:state] = tk1[:state] @@ -565,6 +570,9 @@ class RDoc::Parser::RipperStateLex tk end + # :startdoc: + + # New lexer for +code+. def initialize(code) @buf = [] @heredoc_queue = [] @@ -572,6 +580,7 @@ class RDoc::Parser::RipperStateLex @tokens = @inner_lex.parse([]) end + # Returns tokens parsed from +code+. def self.parse(code) lex = self.new(code) tokens = [] @@ -584,6 +593,7 @@ class RDoc::Parser::RipperStateLex tokens end + # Returns +true+ if lex state will be +END+ after +token+. def self.end?(token) (token[:state] & EXPR_END) end diff --git a/lib/rdoc/parser/ruby.rb b/lib/rdoc/parser/ruby.rb index e546fe2141..85f1cd0391 100644 --- a/lib/rdoc/parser/ruby.rb +++ b/lib/rdoc/parser/ruby.rb @@ -8,6 +8,9 @@ # by Keiju ISHITSUKA (Nippon Rational Inc.) # +require 'ripper' +require_relative 'ripper_state_lex' + ## # Extracts code elements from a source file returning a TopLevel object # containing the constituent file elements. @@ -138,9 +141,6 @@ # Note that by default, the :method: directive will be ignored if there is a # standard rdocable item following it. -require 'ripper' -require_relative 'ripper_state_lex' - class RDoc::Parser::Ruby < RDoc::Parser parse_files_matching(/\.rbw?$/) @@ -164,15 +164,7 @@ class RDoc::Parser::Ruby < RDoc::Parser def initialize(top_level, file_name, content, options, stats) super - if /\t/ =~ content then - tab_width = @options.tab_width - content = content.split(/\n/).map do |line| - 1 while line.gsub!(/\t+/) { - ' ' * (tab_width*$&.length - $`.length % tab_width) - } && $~ - line - end.join("\n") - end + content = handle_tab_width(content) @size = 0 @token_listeners = nil @@ -188,6 +180,9 @@ class RDoc::Parser::Ruby < RDoc::Parser reset end + ## + # Return +true+ if +tk+ is a newline. + def tk_nl?(tk) :on_nl == tk[:kind] or :on_ignored_nl == tk[:kind] end @@ -400,6 +395,29 @@ class RDoc::Parser::Ruby < RDoc::Parser end ## + # Skip opening parentheses and yield the block. + # Skip closing parentheses too when exists. + + def skip_parentheses(&block) + left_tk = peek_tk + + if :on_lparen == left_tk[:kind] + get_tk + + ret = skip_parentheses(&block) + + right_tk = peek_tk + if :on_rparen == right_tk[:kind] + get_tk + end + + ret + else + yield + end + end + + ## # Return a superclass, which can be either a constant of an expression def get_class_specification @@ -771,8 +789,10 @@ class RDoc::Parser::Ruby < RDoc::Parser al.line = line_no read_documentation_modifiers al, RDoc::ATTR_MODIFIERS - context.add_alias al - @stats.add_alias al + if al.document_self or not @track_visibility + context.add_alias al + @stats.add_alias al + end al end @@ -833,7 +853,7 @@ class RDoc::Parser::Ruby < RDoc::Parser cls = parse_class_regular container, declaration_context, single, name_t, given_name, comment elsif name_t[:kind] == :on_op && name_t[:text] == '<<' - case name = get_class_specification + case name = skip_parentheses { get_class_specification } when 'self', container.name read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS parse_statements container, SINGLE @@ -1435,6 +1455,12 @@ class RDoc::Parser::Ruby < RDoc::Parser meth = RDoc::AnyMethod.new get_tkread, name look_for_directives_in meth, comment meth.singleton = single == SINGLE ? true : singleton + if singleton + # `current_line_visibility' is useless because it works against + # the normal method named as same as the singleton method, after + # the latter was defined. Of course these are different things. + container.current_line_visibility = :public + end record_location meth meth.line = line_no @@ -1758,6 +1784,7 @@ class RDoc::Parser::Ruby < RDoc::Parser nest = 1 save_visibility = container.visibility + container.visibility = :public unless current_method non_comment_seen = true @@ -2119,7 +2146,7 @@ class RDoc::Parser::Ruby < RDoc::Parser if :on_nl == tk[:kind] or (:on_kw == tk[:kind] && 'def' == tk[:text]) then return elsif :on_comment == tk[:kind] or :on_embdoc == tk[:kind] then - return unless tk[:text] =~ /\s*:?([\w-]+):\s*(.*)/ + return unless tk[:text] =~ /:?\b([\w-]+):\s*(.*)/ directive = $1.downcase diff --git a/lib/rdoc/parser/ruby_tools.rb b/lib/rdoc/parser/ruby_tools.rb index 681d7166ce..40ea517c4d 100644 --- a/lib/rdoc/parser/ruby_tools.rb +++ b/lib/rdoc/parser/ruby_tools.rb @@ -163,5 +163,3 @@ module RDoc::Parser::RubyTools end end - - diff --git a/lib/rdoc/parser/text.rb b/lib/rdoc/parser/text.rb index 01de0cc595..5095d8cc64 100644 --- a/lib/rdoc/parser/text.rb +++ b/lib/rdoc/parser/text.rb @@ -9,4 +9,3 @@ module RDoc::Parser::Text end - diff --git a/lib/rdoc/rd.rb b/lib/rdoc/rd.rb index 0d3d3cea85..8c2366a3ca 100644 --- a/lib/rdoc/rd.rb +++ b/lib/rdoc/rd.rb @@ -92,9 +92,8 @@ class RDoc::RD document end - autoload :BlockParser, 'rdoc/rd/block_parser' - autoload :InlineParser, 'rdoc/rd/inline_parser' - autoload :Inline, 'rdoc/rd/inline' + autoload :BlockParser, "#{__dir__}/rd/block_parser" + autoload :InlineParser, "#{__dir__}/rd/inline_parser" + autoload :Inline, "#{__dir__}/rd/inline" end - diff --git a/lib/rdoc/rd/block_parser.rb b/lib/rdoc/rd/block_parser.rb index cf30043593..527147d91d 100644 --- a/lib/rdoc/rd/block_parser.rb +++ b/lib/rdoc/rd/block_parser.rb @@ -1,11 +1,659 @@ # frozen_string_literal: true # # DO NOT MODIFY!!!! -# This file is automatically generated by Racc 1.5.1 -# from Racc grammar file "". +# This file is automatically generated by Racc 1.7.3 +# from Racc grammar file "block_parser.ry". # -require 'racc/parser.rb' +###### racc/parser.rb begin +unless $".find {|p| p.end_with?('/racc/parser.rb')} +$".push "#{__dir__}/racc/parser.rb" +#-- +# Copyright (c) 1999-2006 Minero Aoki +# +# This program is free software. +# You can distribute/modify this program under the same terms of ruby. +# +# As a special exception, when this code is copied by Racc +# into a Racc output file, you may use that output file +# without restriction. +#++ + +unless $".find {|p| p.end_with?('/racc/info.rb')} +$".push "#{__dir__}/racc/info.rb" + +module Racc + VERSION = '1.7.3' + Version = VERSION + Copyright = 'Copyright (c) 1999-2006 Minero Aoki' +end + +end + + +unless defined?(NotImplementedError) + NotImplementedError = NotImplementError # :nodoc: +end + +module Racc + class ParseError < StandardError; end +end +unless defined?(::ParseError) + ParseError = Racc::ParseError # :nodoc: +end + +# Racc is a LALR(1) parser generator. +# It is written in Ruby itself, and generates Ruby programs. +# +# == Command-line Reference +# +# racc [-o<var>filename</var>] [--output-file=<var>filename</var>] +# [-e<var>rubypath</var>] [--executable=<var>rubypath</var>] +# [-v] [--verbose] +# [-O<var>filename</var>] [--log-file=<var>filename</var>] +# [-g] [--debug] +# [-E] [--embedded] +# [-l] [--no-line-convert] +# [-c] [--line-convert-all] +# [-a] [--no-omit-actions] +# [-C] [--check-only] +# [-S] [--output-status] +# [--version] [--copyright] [--help] <var>grammarfile</var> +# +# [+grammarfile+] +# Racc grammar file. Any extension is permitted. +# [-o+outfile+, --output-file=+outfile+] +# A filename for output. default is <+filename+>.tab.rb +# [-O+filename+, --log-file=+filename+] +# Place logging output in file +filename+. +# Default log file name is <+filename+>.output. +# [-e+rubypath+, --executable=+rubypath+] +# output executable file(mode 755). where +path+ is the Ruby interpreter. +# [-v, --verbose] +# verbose mode. create +filename+.output file, like yacc's y.output file. +# [-g, --debug] +# add debug code to parser class. To display debugging information, +# use this '-g' option and set @yydebug true in parser class. +# [-E, --embedded] +# Output parser which doesn't need runtime files (racc/parser.rb). +# [-F, --frozen] +# Output parser which declares frozen_string_literals: true +# [-C, --check-only] +# Check syntax of racc grammar file and quit. +# [-S, --output-status] +# Print messages time to time while compiling. +# [-l, --no-line-convert] +# turns off line number converting. +# [-c, --line-convert-all] +# Convert line number of actions, inner, header and footer. +# [-a, --no-omit-actions] +# Call all actions, even if an action is empty. +# [--version] +# print Racc version and quit. +# [--copyright] +# Print copyright and quit. +# [--help] +# Print usage and quit. +# +# == Generating Parser Using Racc +# +# To compile Racc grammar file, simply type: +# +# $ racc parse.y +# +# This creates Ruby script file "parse.tab.y". The -o option can change the output filename. +# +# == Writing A Racc Grammar File +# +# If you want your own parser, you have to write a grammar file. +# A grammar file contains the name of your parser class, grammar for the parser, +# user code, and anything else. +# When writing a grammar file, yacc's knowledge is helpful. +# If you have not used yacc before, Racc is not too difficult. +# +# Here's an example Racc grammar file. +# +# class Calcparser +# rule +# target: exp { print val[0] } +# +# exp: exp '+' exp +# | exp '*' exp +# | '(' exp ')' +# | NUMBER +# end +# +# Racc grammar files resemble yacc files. +# But (of course), this is Ruby code. +# yacc's $$ is the 'result', $0, $1... is +# an array called 'val', and $-1, $-2... is an array called '_values'. +# +# See the {Grammar File Reference}[rdoc-ref:lib/racc/rdoc/grammar.en.rdoc] for +# more information on grammar files. +# +# == Parser +# +# Then you must prepare the parse entry method. There are two types of +# parse methods in Racc, Racc::Parser#do_parse and Racc::Parser#yyparse +# +# Racc::Parser#do_parse is simple. +# +# It's yyparse() of yacc, and Racc::Parser#next_token is yylex(). +# This method must returns an array like [TOKENSYMBOL, ITS_VALUE]. +# EOF is [false, false]. +# (TOKENSYMBOL is a Ruby symbol (taken from String#intern) by default. +# If you want to change this, see the grammar reference. +# +# Racc::Parser#yyparse is little complicated, but useful. +# It does not use Racc::Parser#next_token, instead it gets tokens from any iterator. +# +# For example, <code>yyparse(obj, :scan)</code> causes +# calling +obj#scan+, and you can return tokens by yielding them from +obj#scan+. +# +# == Debugging +# +# When debugging, "-v" or/and the "-g" option is helpful. +# +# "-v" creates verbose log file (.output). +# "-g" creates a "Verbose Parser". +# Verbose Parser prints the internal status when parsing. +# But it's _not_ automatic. +# You must use -g option and set +@yydebug+ to +true+ in order to get output. +# -g option only creates the verbose parser. +# +# === Racc reported syntax error. +# +# Isn't there too many "end"? +# grammar of racc file is changed in v0.10. +# +# Racc does not use '%' mark, while yacc uses huge number of '%' marks.. +# +# === Racc reported "XXXX conflicts". +# +# Try "racc -v xxxx.y". +# It causes producing racc's internal log file, xxxx.output. +# +# === Generated parsers does not work correctly +# +# Try "racc -g xxxx.y". +# This command let racc generate "debugging parser". +# Then set @yydebug=true in your parser. +# It produces a working log of your parser. +# +# == Re-distributing Racc runtime +# +# A parser, which is created by Racc, requires the Racc runtime module; +# racc/parser.rb. +# +# Ruby 1.8.x comes with Racc runtime module, +# you need NOT distribute Racc runtime files. +# +# If you want to include the Racc runtime module with your parser. +# This can be done by using '-E' option: +# +# $ racc -E -omyparser.rb myparser.y +# +# This command creates myparser.rb which `includes' Racc runtime. +# Only you must do is to distribute your parser file (myparser.rb). +# +# Note: parser.rb is ruby license, but your parser is not. +# Your own parser is completely yours. +module Racc + + unless defined?(Racc_No_Extensions) + Racc_No_Extensions = false # :nodoc: + end + + class Parser + + Racc_Runtime_Version = ::Racc::VERSION + Racc_Runtime_Core_Version_R = ::Racc::VERSION + + begin + if Object.const_defined?(:RUBY_ENGINE) and RUBY_ENGINE == 'jruby' + require 'jruby' + require 'racc/cparse-jruby.jar' + com.headius.racc.Cparse.new.load(JRuby.runtime, false) + else + require 'racc/cparse' + end + + unless new.respond_to?(:_racc_do_parse_c, true) + raise LoadError, 'old cparse.so' + end + if Racc_No_Extensions + raise LoadError, 'selecting ruby version of racc runtime core' + end + + Racc_Main_Parsing_Routine = :_racc_do_parse_c # :nodoc: + Racc_YY_Parse_Method = :_racc_yyparse_c # :nodoc: + Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C # :nodoc: + Racc_Runtime_Type = 'c' # :nodoc: + rescue LoadError + Racc_Main_Parsing_Routine = :_racc_do_parse_rb + Racc_YY_Parse_Method = :_racc_yyparse_rb + Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R + Racc_Runtime_Type = 'ruby' + end + + def Parser.racc_runtime_type # :nodoc: + Racc_Runtime_Type + end + + def _racc_setup + @yydebug = false unless self.class::Racc_debug_parser + @yydebug = false unless defined?(@yydebug) + if @yydebug + @racc_debug_out = $stderr unless defined?(@racc_debug_out) + @racc_debug_out ||= $stderr + end + arg = self.class::Racc_arg + arg[13] = true if arg.size < 14 + arg + end + + def _racc_init_sysvars + @racc_state = [0] + @racc_tstack = [] + @racc_vstack = [] + + @racc_t = nil + @racc_val = nil + + @racc_read_next = true + + @racc_user_yyerror = false + @racc_error_status = 0 + end + + # The entry point of the parser. This method is used with #next_token. + # If Racc wants to get token (and its value), calls next_token. + # + # Example: + # def parse + # @q = [[1,1], + # [2,2], + # [3,3], + # [false, '$']] + # do_parse + # end + # + # def next_token + # @q.shift + # end + class_eval <<~RUBY, __FILE__, __LINE__ + 1 + def do_parse + #{Racc_Main_Parsing_Routine}(_racc_setup(), false) + end + RUBY + + # The method to fetch next token. + # If you use #do_parse method, you must implement #next_token. + # + # The format of return value is [TOKEN_SYMBOL, VALUE]. + # +token-symbol+ is represented by Ruby's symbol by default, e.g. :IDENT + # for 'IDENT'. ";" (String) for ';'. + # + # The final symbol (End of file) must be false. + def next_token + raise NotImplementedError, "#{self.class}\#next_token is not defined" + end + + def _racc_do_parse_rb(arg, in_debug) + action_table, action_check, action_default, action_pointer, + _, _, _, _, + _, _, token_table, * = arg + + _racc_init_sysvars + tok = act = i = nil + + catch(:racc_end_parse) { + while true + if i = action_pointer[@racc_state[-1]] + if @racc_read_next + if @racc_t != 0 # not EOF + tok, @racc_val = next_token() + unless tok # EOF + @racc_t = 0 + else + @racc_t = (token_table[tok] or 1) # error token + end + racc_read_token(@racc_t, tok, @racc_val) if @yydebug + @racc_read_next = false + end + end + i += @racc_t + unless i >= 0 and + act = action_table[i] and + action_check[i] == @racc_state[-1] + act = action_default[@racc_state[-1]] + end + else + act = action_default[@racc_state[-1]] + end + while act = _racc_evalact(act, arg) + ; + end + end + } + end + + # Another entry point for the parser. + # If you use this method, you must implement RECEIVER#METHOD_ID method. + # + # RECEIVER#METHOD_ID is a method to get next token. + # It must 'yield' the token, which format is [TOKEN-SYMBOL, VALUE]. + class_eval <<~RUBY, __FILE__, __LINE__ + 1 + def yyparse(recv, mid) + #{Racc_YY_Parse_Method}(recv, mid, _racc_setup(), false) + end + RUBY + + def _racc_yyparse_rb(recv, mid, arg, c_debug) + action_table, action_check, action_default, action_pointer, + _, _, _, _, + _, _, token_table, * = arg + + _racc_init_sysvars + + catch(:racc_end_parse) { + until i = action_pointer[@racc_state[-1]] + while act = _racc_evalact(action_default[@racc_state[-1]], arg) + ; + end + end + recv.__send__(mid) do |tok, val| + unless tok + @racc_t = 0 + else + @racc_t = (token_table[tok] or 1) # error token + end + @racc_val = val + @racc_read_next = false + + i += @racc_t + unless i >= 0 and + act = action_table[i] and + action_check[i] == @racc_state[-1] + act = action_default[@racc_state[-1]] + end + while act = _racc_evalact(act, arg) + ; + end + + while !(i = action_pointer[@racc_state[-1]]) || + ! @racc_read_next || + @racc_t == 0 # $ + unless i and i += @racc_t and + i >= 0 and + act = action_table[i] and + action_check[i] == @racc_state[-1] + act = action_default[@racc_state[-1]] + end + while act = _racc_evalact(act, arg) + ; + end + end + end + } + end + + ### + ### common + ### + + def _racc_evalact(act, arg) + action_table, action_check, _, action_pointer, + _, _, _, _, + _, _, _, shift_n, + reduce_n, * = arg + nerr = 0 # tmp + + if act > 0 and act < shift_n + # + # shift + # + if @racc_error_status > 0 + @racc_error_status -= 1 unless @racc_t <= 1 # error token or EOF + end + @racc_vstack.push @racc_val + @racc_state.push act + @racc_read_next = true + if @yydebug + @racc_tstack.push @racc_t + racc_shift @racc_t, @racc_tstack, @racc_vstack + end + + elsif act < 0 and act > -reduce_n + # + # reduce + # + code = catch(:racc_jump) { + @racc_state.push _racc_do_reduce(arg, act) + false + } + if code + case code + when 1 # yyerror + @racc_user_yyerror = true # user_yyerror + return -reduce_n + when 2 # yyaccept + return shift_n + else + raise '[Racc Bug] unknown jump code' + end + end + + elsif act == shift_n + # + # accept + # + racc_accept if @yydebug + throw :racc_end_parse, @racc_vstack[0] + + elsif act == -reduce_n + # + # error + # + case @racc_error_status + when 0 + unless arg[21] # user_yyerror + nerr += 1 + on_error @racc_t, @racc_val, @racc_vstack + end + when 3 + if @racc_t == 0 # is $ + # We're at EOF, and another error occurred immediately after + # attempting auto-recovery + throw :racc_end_parse, nil + end + @racc_read_next = true + end + @racc_user_yyerror = false + @racc_error_status = 3 + while true + if i = action_pointer[@racc_state[-1]] + i += 1 # error token + if i >= 0 and + (act = action_table[i]) and + action_check[i] == @racc_state[-1] + break + end + end + throw :racc_end_parse, nil if @racc_state.size <= 1 + @racc_state.pop + @racc_vstack.pop + if @yydebug + @racc_tstack.pop + racc_e_pop @racc_state, @racc_tstack, @racc_vstack + end + end + return act + + else + raise "[Racc Bug] unknown action #{act.inspect}" + end + + racc_next_state(@racc_state[-1], @racc_state) if @yydebug + + nil + end + + def _racc_do_reduce(arg, act) + _, _, _, _, + goto_table, goto_check, goto_default, goto_pointer, + nt_base, reduce_table, _, _, + _, use_result, * = arg + + state = @racc_state + vstack = @racc_vstack + tstack = @racc_tstack + + i = act * -3 + len = reduce_table[i] + reduce_to = reduce_table[i+1] + method_id = reduce_table[i+2] + void_array = [] + + tmp_t = tstack[-len, len] if @yydebug + tmp_v = vstack[-len, len] + tstack[-len, len] = void_array if @yydebug + vstack[-len, len] = void_array + state[-len, len] = void_array + + # tstack must be updated AFTER method call + if use_result + vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0]) + else + vstack.push __send__(method_id, tmp_v, vstack) + end + tstack.push reduce_to + + racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug + + k1 = reduce_to - nt_base + if i = goto_pointer[k1] + i += state[-1] + if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1 + return curstate + end + end + goto_default[k1] + end + + # This method is called when a parse error is found. + # + # ERROR_TOKEN_ID is an internal ID of token which caused error. + # You can get string representation of this ID by calling + # #token_to_str. + # + # ERROR_VALUE is a value of error token. + # + # value_stack is a stack of symbol values. + # DO NOT MODIFY this object. + # + # This method raises ParseError by default. + # + # If this method returns, parsers enter "error recovering mode". + def on_error(t, val, vstack) + raise ParseError, sprintf("parse error on value %s (%s)", + val.inspect, token_to_str(t) || '?') + end + + # Enter error recovering mode. + # This method does not call #on_error. + def yyerror + throw :racc_jump, 1 + end + + # Exit parser. + # Return value is +Symbol_Value_Stack[0]+. + def yyaccept + throw :racc_jump, 2 + end + + # Leave error recovering mode. + def yyerrok + @racc_error_status = 0 + end + + # For debugging output + def racc_read_token(t, tok, val) + @racc_debug_out.print 'read ' + @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') ' + @racc_debug_out.puts val.inspect + @racc_debug_out.puts + end + + def racc_shift(tok, tstack, vstack) + @racc_debug_out.puts "shift #{racc_token2str tok}" + racc_print_stacks tstack, vstack + @racc_debug_out.puts + end + + def racc_reduce(toks, sim, tstack, vstack) + out = @racc_debug_out + out.print 'reduce ' + if toks.empty? + out.print ' <none>' + else + toks.each {|t| out.print ' ', racc_token2str(t) } + end + out.puts " --> #{racc_token2str(sim)}" + racc_print_stacks tstack, vstack + @racc_debug_out.puts + end + + def racc_accept + @racc_debug_out.puts 'accept' + @racc_debug_out.puts + end + + def racc_e_pop(state, tstack, vstack) + @racc_debug_out.puts 'error recovering mode: pop token' + racc_print_states state + racc_print_stacks tstack, vstack + @racc_debug_out.puts + end + + def racc_next_state(curstate, state) + @racc_debug_out.puts "goto #{curstate}" + racc_print_states state + @racc_debug_out.puts + end + + def racc_print_stacks(t, v) + out = @racc_debug_out + out.print ' [' + t.each_index do |i| + out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')' + end + out.puts ' ]' + end + + def racc_print_states(s) + out = @racc_debug_out + out.print ' [' + s.each {|st| out.print ' ', st } + out.puts ' ]' + end + + def racc_token2str(tok) + self.class::Racc_token_to_s_table[tok] or + raise "[Racc Bug] can't convert token #{tok} to string" + end + + # Convert internal ID of token symbol to the string. + def token_to_str(t) + self.class::Racc_token_to_s_table[t] + end + + end + +end + +end +###### racc/parser.rb end class RDoc::RD @@ -18,8 +666,6 @@ class BlockParser < Racc::Parser # :stopdoc: -TMPFILE = ["rdtmp", $$, 0] - MARK_TO_LEVEL = { '=' => 1, '==' => 2, @@ -129,15 +775,19 @@ def next_token # :nodoc: # non-RD part begin when /^=begin\s+(\w+)/ part = $1 +=begin # not imported to RDoc if @in_part # if in non-RD part @part_content.push(line) else @in_part = part if @tree.filter[part] # if filter exists # p "BEGIN_PART: #{@in_part}" # DEBUG end +=end + @in_part = part # non-RD part end - when /^=end/ + when /^=end(?:$|[\s\0\C-d\C-z])/ if @in_part # if in non-RD part +=begin # not imported to RDoc # p "END_PART: #{@in_part}" # DEBUG # make Part-in object part = RDoc::RD::Part.new(@part_content.join(""), @tree, "r") @@ -148,20 +798,22 @@ def next_token # :nodoc: if @tree.filter[@in_part].mode == :rd # if output is RD formatted subtree = parse_subtree(part_out.to_a) else # if output is target formatted - basename = TMPFILE.join('.') - TMPFILE[-1] += 1 - tmpfile = open(@tree.tmp_dir + "/" + basename + ".#{@in_part}", "w") - tmpfile.print(part_out) - tmpfile.close + basename = Tempfile.create(["rdtmp", ".#{@in_part}"], @tree.tmp_dir) do |tmpfile| + tmpfile.print(part_out) + File.basename(tmpfile.path) + end subtree = parse_subtree(["=begin\n", "<<< #{basename}\n", "=end\n"]) end @in_part = nil return [:SUBTREE, subtree] +=end end else +=begin # not imported to RDoc if @in_part # if in non-RD part @part_content.push(line) end +=end end end @@ -356,7 +1008,7 @@ def get_included(file) file_name = File.join dir, file if File.exist? file_name then - included = IO.readlines file_name + included = File.readlines file_name break end end @@ -620,6 +1272,7 @@ Racc_arg = [ racc_shift_n, racc_reduce_n, racc_use_result_var ] +Ractor.make_shareable(Racc_arg) if defined?(Ractor) Racc_token_to_s_table = [ "$end", @@ -670,6 +1323,7 @@ Racc_token_to_s_table = [ "blocks_in_list", "block_in_list", "whitelines2" ] +Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor) Racc_debug_parser = false diff --git a/lib/rdoc/rd/inline.rb b/lib/rdoc/rd/inline.rb index e5cb545728..77d88b2860 100644 --- a/lib/rdoc/rd/inline.rb +++ b/lib/rdoc/rd/inline.rb @@ -69,4 +69,3 @@ class RDoc::RD::Inline alias to_s rdoc # :nodoc: end - diff --git a/lib/rdoc/rd/inline_parser.rb b/lib/rdoc/rd/inline_parser.rb index 007327bf0e..adacf64d5b 100644 --- a/lib/rdoc/rd/inline_parser.rb +++ b/lib/rdoc/rd/inline_parser.rb @@ -1,11 +1,659 @@ # frozen_string_literal: true # # DO NOT MODIFY!!!! -# This file is automatically generated by Racc 1.5.1 -# from Racc grammar file "". +# This file is automatically generated by Racc 1.7.3 +# from Racc grammar file "inline_parser.ry". # -require 'racc/parser.rb' +###### racc/parser.rb begin +unless $".find {|p| p.end_with?('/racc/parser.rb')} +$".push "#{__dir__}/racc/parser.rb" +#-- +# Copyright (c) 1999-2006 Minero Aoki +# +# This program is free software. +# You can distribute/modify this program under the same terms of ruby. +# +# As a special exception, when this code is copied by Racc +# into a Racc output file, you may use that output file +# without restriction. +#++ + +unless $".find {|p| p.end_with?('/racc/info.rb')} +$".push "#{__dir__}/racc/info.rb" + +module Racc + VERSION = '1.7.3' + Version = VERSION + Copyright = 'Copyright (c) 1999-2006 Minero Aoki' +end + +end + + +unless defined?(NotImplementedError) + NotImplementedError = NotImplementError # :nodoc: +end + +module Racc + class ParseError < StandardError; end +end +unless defined?(::ParseError) + ParseError = Racc::ParseError # :nodoc: +end + +# Racc is a LALR(1) parser generator. +# It is written in Ruby itself, and generates Ruby programs. +# +# == Command-line Reference +# +# racc [-o<var>filename</var>] [--output-file=<var>filename</var>] +# [-e<var>rubypath</var>] [--executable=<var>rubypath</var>] +# [-v] [--verbose] +# [-O<var>filename</var>] [--log-file=<var>filename</var>] +# [-g] [--debug] +# [-E] [--embedded] +# [-l] [--no-line-convert] +# [-c] [--line-convert-all] +# [-a] [--no-omit-actions] +# [-C] [--check-only] +# [-S] [--output-status] +# [--version] [--copyright] [--help] <var>grammarfile</var> +# +# [+grammarfile+] +# Racc grammar file. Any extension is permitted. +# [-o+outfile+, --output-file=+outfile+] +# A filename for output. default is <+filename+>.tab.rb +# [-O+filename+, --log-file=+filename+] +# Place logging output in file +filename+. +# Default log file name is <+filename+>.output. +# [-e+rubypath+, --executable=+rubypath+] +# output executable file(mode 755). where +path+ is the Ruby interpreter. +# [-v, --verbose] +# verbose mode. create +filename+.output file, like yacc's y.output file. +# [-g, --debug] +# add debug code to parser class. To display debugging information, +# use this '-g' option and set @yydebug true in parser class. +# [-E, --embedded] +# Output parser which doesn't need runtime files (racc/parser.rb). +# [-F, --frozen] +# Output parser which declares frozen_string_literals: true +# [-C, --check-only] +# Check syntax of racc grammar file and quit. +# [-S, --output-status] +# Print messages time to time while compiling. +# [-l, --no-line-convert] +# turns off line number converting. +# [-c, --line-convert-all] +# Convert line number of actions, inner, header and footer. +# [-a, --no-omit-actions] +# Call all actions, even if an action is empty. +# [--version] +# print Racc version and quit. +# [--copyright] +# Print copyright and quit. +# [--help] +# Print usage and quit. +# +# == Generating Parser Using Racc +# +# To compile Racc grammar file, simply type: +# +# $ racc parse.y +# +# This creates Ruby script file "parse.tab.y". The -o option can change the output filename. +# +# == Writing A Racc Grammar File +# +# If you want your own parser, you have to write a grammar file. +# A grammar file contains the name of your parser class, grammar for the parser, +# user code, and anything else. +# When writing a grammar file, yacc's knowledge is helpful. +# If you have not used yacc before, Racc is not too difficult. +# +# Here's an example Racc grammar file. +# +# class Calcparser +# rule +# target: exp { print val[0] } +# +# exp: exp '+' exp +# | exp '*' exp +# | '(' exp ')' +# | NUMBER +# end +# +# Racc grammar files resemble yacc files. +# But (of course), this is Ruby code. +# yacc's $$ is the 'result', $0, $1... is +# an array called 'val', and $-1, $-2... is an array called '_values'. +# +# See the {Grammar File Reference}[rdoc-ref:lib/racc/rdoc/grammar.en.rdoc] for +# more information on grammar files. +# +# == Parser +# +# Then you must prepare the parse entry method. There are two types of +# parse methods in Racc, Racc::Parser#do_parse and Racc::Parser#yyparse +# +# Racc::Parser#do_parse is simple. +# +# It's yyparse() of yacc, and Racc::Parser#next_token is yylex(). +# This method must returns an array like [TOKENSYMBOL, ITS_VALUE]. +# EOF is [false, false]. +# (TOKENSYMBOL is a Ruby symbol (taken from String#intern) by default. +# If you want to change this, see the grammar reference. +# +# Racc::Parser#yyparse is little complicated, but useful. +# It does not use Racc::Parser#next_token, instead it gets tokens from any iterator. +# +# For example, <code>yyparse(obj, :scan)</code> causes +# calling +obj#scan+, and you can return tokens by yielding them from +obj#scan+. +# +# == Debugging +# +# When debugging, "-v" or/and the "-g" option is helpful. +# +# "-v" creates verbose log file (.output). +# "-g" creates a "Verbose Parser". +# Verbose Parser prints the internal status when parsing. +# But it's _not_ automatic. +# You must use -g option and set +@yydebug+ to +true+ in order to get output. +# -g option only creates the verbose parser. +# +# === Racc reported syntax error. +# +# Isn't there too many "end"? +# grammar of racc file is changed in v0.10. +# +# Racc does not use '%' mark, while yacc uses huge number of '%' marks.. +# +# === Racc reported "XXXX conflicts". +# +# Try "racc -v xxxx.y". +# It causes producing racc's internal log file, xxxx.output. +# +# === Generated parsers does not work correctly +# +# Try "racc -g xxxx.y". +# This command let racc generate "debugging parser". +# Then set @yydebug=true in your parser. +# It produces a working log of your parser. +# +# == Re-distributing Racc runtime +# +# A parser, which is created by Racc, requires the Racc runtime module; +# racc/parser.rb. +# +# Ruby 1.8.x comes with Racc runtime module, +# you need NOT distribute Racc runtime files. +# +# If you want to include the Racc runtime module with your parser. +# This can be done by using '-E' option: +# +# $ racc -E -omyparser.rb myparser.y +# +# This command creates myparser.rb which `includes' Racc runtime. +# Only you must do is to distribute your parser file (myparser.rb). +# +# Note: parser.rb is ruby license, but your parser is not. +# Your own parser is completely yours. +module Racc + + unless defined?(Racc_No_Extensions) + Racc_No_Extensions = false # :nodoc: + end + + class Parser + + Racc_Runtime_Version = ::Racc::VERSION + Racc_Runtime_Core_Version_R = ::Racc::VERSION + + begin + if Object.const_defined?(:RUBY_ENGINE) and RUBY_ENGINE == 'jruby' + require 'jruby' + require 'racc/cparse-jruby.jar' + com.headius.racc.Cparse.new.load(JRuby.runtime, false) + else + require 'racc/cparse' + end + + unless new.respond_to?(:_racc_do_parse_c, true) + raise LoadError, 'old cparse.so' + end + if Racc_No_Extensions + raise LoadError, 'selecting ruby version of racc runtime core' + end + + Racc_Main_Parsing_Routine = :_racc_do_parse_c # :nodoc: + Racc_YY_Parse_Method = :_racc_yyparse_c # :nodoc: + Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C # :nodoc: + Racc_Runtime_Type = 'c' # :nodoc: + rescue LoadError + Racc_Main_Parsing_Routine = :_racc_do_parse_rb + Racc_YY_Parse_Method = :_racc_yyparse_rb + Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R + Racc_Runtime_Type = 'ruby' + end + + def Parser.racc_runtime_type # :nodoc: + Racc_Runtime_Type + end + + def _racc_setup + @yydebug = false unless self.class::Racc_debug_parser + @yydebug = false unless defined?(@yydebug) + if @yydebug + @racc_debug_out = $stderr unless defined?(@racc_debug_out) + @racc_debug_out ||= $stderr + end + arg = self.class::Racc_arg + arg[13] = true if arg.size < 14 + arg + end + + def _racc_init_sysvars + @racc_state = [0] + @racc_tstack = [] + @racc_vstack = [] + + @racc_t = nil + @racc_val = nil + + @racc_read_next = true + + @racc_user_yyerror = false + @racc_error_status = 0 + end + + # The entry point of the parser. This method is used with #next_token. + # If Racc wants to get token (and its value), calls next_token. + # + # Example: + # def parse + # @q = [[1,1], + # [2,2], + # [3,3], + # [false, '$']] + # do_parse + # end + # + # def next_token + # @q.shift + # end + class_eval <<~RUBY, __FILE__, __LINE__ + 1 + def do_parse + #{Racc_Main_Parsing_Routine}(_racc_setup(), false) + end + RUBY + + # The method to fetch next token. + # If you use #do_parse method, you must implement #next_token. + # + # The format of return value is [TOKEN_SYMBOL, VALUE]. + # +token-symbol+ is represented by Ruby's symbol by default, e.g. :IDENT + # for 'IDENT'. ";" (String) for ';'. + # + # The final symbol (End of file) must be false. + def next_token + raise NotImplementedError, "#{self.class}\#next_token is not defined" + end + + def _racc_do_parse_rb(arg, in_debug) + action_table, action_check, action_default, action_pointer, + _, _, _, _, + _, _, token_table, * = arg + + _racc_init_sysvars + tok = act = i = nil + + catch(:racc_end_parse) { + while true + if i = action_pointer[@racc_state[-1]] + if @racc_read_next + if @racc_t != 0 # not EOF + tok, @racc_val = next_token() + unless tok # EOF + @racc_t = 0 + else + @racc_t = (token_table[tok] or 1) # error token + end + racc_read_token(@racc_t, tok, @racc_val) if @yydebug + @racc_read_next = false + end + end + i += @racc_t + unless i >= 0 and + act = action_table[i] and + action_check[i] == @racc_state[-1] + act = action_default[@racc_state[-1]] + end + else + act = action_default[@racc_state[-1]] + end + while act = _racc_evalact(act, arg) + ; + end + end + } + end + + # Another entry point for the parser. + # If you use this method, you must implement RECEIVER#METHOD_ID method. + # + # RECEIVER#METHOD_ID is a method to get next token. + # It must 'yield' the token, which format is [TOKEN-SYMBOL, VALUE]. + class_eval <<~RUBY, __FILE__, __LINE__ + 1 + def yyparse(recv, mid) + #{Racc_YY_Parse_Method}(recv, mid, _racc_setup(), false) + end + RUBY + + def _racc_yyparse_rb(recv, mid, arg, c_debug) + action_table, action_check, action_default, action_pointer, + _, _, _, _, + _, _, token_table, * = arg + + _racc_init_sysvars + + catch(:racc_end_parse) { + until i = action_pointer[@racc_state[-1]] + while act = _racc_evalact(action_default[@racc_state[-1]], arg) + ; + end + end + recv.__send__(mid) do |tok, val| + unless tok + @racc_t = 0 + else + @racc_t = (token_table[tok] or 1) # error token + end + @racc_val = val + @racc_read_next = false + + i += @racc_t + unless i >= 0 and + act = action_table[i] and + action_check[i] == @racc_state[-1] + act = action_default[@racc_state[-1]] + end + while act = _racc_evalact(act, arg) + ; + end + + while !(i = action_pointer[@racc_state[-1]]) || + ! @racc_read_next || + @racc_t == 0 # $ + unless i and i += @racc_t and + i >= 0 and + act = action_table[i] and + action_check[i] == @racc_state[-1] + act = action_default[@racc_state[-1]] + end + while act = _racc_evalact(act, arg) + ; + end + end + end + } + end + + ### + ### common + ### + + def _racc_evalact(act, arg) + action_table, action_check, _, action_pointer, + _, _, _, _, + _, _, _, shift_n, + reduce_n, * = arg + nerr = 0 # tmp + + if act > 0 and act < shift_n + # + # shift + # + if @racc_error_status > 0 + @racc_error_status -= 1 unless @racc_t <= 1 # error token or EOF + end + @racc_vstack.push @racc_val + @racc_state.push act + @racc_read_next = true + if @yydebug + @racc_tstack.push @racc_t + racc_shift @racc_t, @racc_tstack, @racc_vstack + end + + elsif act < 0 and act > -reduce_n + # + # reduce + # + code = catch(:racc_jump) { + @racc_state.push _racc_do_reduce(arg, act) + false + } + if code + case code + when 1 # yyerror + @racc_user_yyerror = true # user_yyerror + return -reduce_n + when 2 # yyaccept + return shift_n + else + raise '[Racc Bug] unknown jump code' + end + end + + elsif act == shift_n + # + # accept + # + racc_accept if @yydebug + throw :racc_end_parse, @racc_vstack[0] + + elsif act == -reduce_n + # + # error + # + case @racc_error_status + when 0 + unless arg[21] # user_yyerror + nerr += 1 + on_error @racc_t, @racc_val, @racc_vstack + end + when 3 + if @racc_t == 0 # is $ + # We're at EOF, and another error occurred immediately after + # attempting auto-recovery + throw :racc_end_parse, nil + end + @racc_read_next = true + end + @racc_user_yyerror = false + @racc_error_status = 3 + while true + if i = action_pointer[@racc_state[-1]] + i += 1 # error token + if i >= 0 and + (act = action_table[i]) and + action_check[i] == @racc_state[-1] + break + end + end + throw :racc_end_parse, nil if @racc_state.size <= 1 + @racc_state.pop + @racc_vstack.pop + if @yydebug + @racc_tstack.pop + racc_e_pop @racc_state, @racc_tstack, @racc_vstack + end + end + return act + + else + raise "[Racc Bug] unknown action #{act.inspect}" + end + + racc_next_state(@racc_state[-1], @racc_state) if @yydebug + + nil + end + + def _racc_do_reduce(arg, act) + _, _, _, _, + goto_table, goto_check, goto_default, goto_pointer, + nt_base, reduce_table, _, _, + _, use_result, * = arg + + state = @racc_state + vstack = @racc_vstack + tstack = @racc_tstack + + i = act * -3 + len = reduce_table[i] + reduce_to = reduce_table[i+1] + method_id = reduce_table[i+2] + void_array = [] + + tmp_t = tstack[-len, len] if @yydebug + tmp_v = vstack[-len, len] + tstack[-len, len] = void_array if @yydebug + vstack[-len, len] = void_array + state[-len, len] = void_array + + # tstack must be updated AFTER method call + if use_result + vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0]) + else + vstack.push __send__(method_id, tmp_v, vstack) + end + tstack.push reduce_to + + racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug + + k1 = reduce_to - nt_base + if i = goto_pointer[k1] + i += state[-1] + if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1 + return curstate + end + end + goto_default[k1] + end + + # This method is called when a parse error is found. + # + # ERROR_TOKEN_ID is an internal ID of token which caused error. + # You can get string representation of this ID by calling + # #token_to_str. + # + # ERROR_VALUE is a value of error token. + # + # value_stack is a stack of symbol values. + # DO NOT MODIFY this object. + # + # This method raises ParseError by default. + # + # If this method returns, parsers enter "error recovering mode". + def on_error(t, val, vstack) + raise ParseError, sprintf("parse error on value %s (%s)", + val.inspect, token_to_str(t) || '?') + end + + # Enter error recovering mode. + # This method does not call #on_error. + def yyerror + throw :racc_jump, 1 + end + + # Exit parser. + # Return value is +Symbol_Value_Stack[0]+. + def yyaccept + throw :racc_jump, 2 + end + + # Leave error recovering mode. + def yyerrok + @racc_error_status = 0 + end + + # For debugging output + def racc_read_token(t, tok, val) + @racc_debug_out.print 'read ' + @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') ' + @racc_debug_out.puts val.inspect + @racc_debug_out.puts + end + + def racc_shift(tok, tstack, vstack) + @racc_debug_out.puts "shift #{racc_token2str tok}" + racc_print_stacks tstack, vstack + @racc_debug_out.puts + end + + def racc_reduce(toks, sim, tstack, vstack) + out = @racc_debug_out + out.print 'reduce ' + if toks.empty? + out.print ' <none>' + else + toks.each {|t| out.print ' ', racc_token2str(t) } + end + out.puts " --> #{racc_token2str(sim)}" + racc_print_stacks tstack, vstack + @racc_debug_out.puts + end + + def racc_accept + @racc_debug_out.puts 'accept' + @racc_debug_out.puts + end + + def racc_e_pop(state, tstack, vstack) + @racc_debug_out.puts 'error recovering mode: pop token' + racc_print_states state + racc_print_stacks tstack, vstack + @racc_debug_out.puts + end + + def racc_next_state(curstate, state) + @racc_debug_out.puts "goto #{curstate}" + racc_print_states state + @racc_debug_out.puts + end + + def racc_print_stacks(t, v) + out = @racc_debug_out + out.print ' [' + t.each_index do |i| + out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')' + end + out.puts ' ]' + end + + def racc_print_states(s) + out = @racc_debug_out + out.print ' [' + s.each {|st| out.print ' ', st } + out.puts ' ]' + end + + def racc_token2str(tok) + self.class::Racc_token_to_s_table[tok] or + raise "[Racc Bug] can't convert token #{tok} to string" + end + + # Convert internal ID of token symbol to the string. + def token_to_str(t) + self.class::Racc_token_to_s_table[t] + end + + end + +end + +end +###### racc/parser.rb end require 'strscan' @@ -652,6 +1300,7 @@ Racc_arg = [ racc_shift_n, racc_reduce_n, racc_use_result_var ] +Ractor.make_shareable(Racc_arg) if defined?(Ractor) Racc_token_to_s_table = [ "$end", @@ -723,6 +1372,7 @@ Racc_token_to_s_table = [ "normal_strings", "verb_string", "verb_normal_string" ] +Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor) Racc_debug_parser = false diff --git a/lib/rdoc/rdoc.gemspec b/lib/rdoc/rdoc.gemspec index 75f8534b9e..93a281c8ae 100644 --- a/lib/rdoc/rdoc.gemspec +++ b/lib/rdoc/rdoc.gemspec @@ -28,6 +28,10 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat s.homepage = "https://ruby.github.io/rdoc" s.licenses = ["Ruby"] + s.metadata["homepage_uri"] = s.homepage + s.metadata["source_code_uri"] = "https://github.com/ruby/rdoc" + s.metadata["changelog_uri"] = "#{s.metadata["source_code_uri"]}/releases" + s.bindir = "exe" s.executables = ["rdoc", "ri"] s.require_paths = ["lib"] @@ -38,16 +42,12 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat "CVE-2013-0256.rdoc", "ExampleMarkdown.md", "ExampleRDoc.rdoc", - "Gemfile", "History.rdoc", "LEGAL.rdoc", "LICENSE.rdoc", "README.rdoc", "RI.rdoc", - "Rakefile", "TODO.rdoc", - "bin/console", - "bin/setup", "exe/rdoc", "exe/ri", "lib/rdoc.rb", @@ -223,28 +223,15 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat "lib/rdoc/top_level.rb", "lib/rdoc/version.rb", "man/ri.1", - "rdoc.gemspec", ] # files from .gitignore s.files << "lib/rdoc/rd/block_parser.rb" << "lib/rdoc/rd/inline_parser.rb" << "lib/rdoc/markdown.rb" << "lib/rdoc/markdown/literals.rb" s.rdoc_options = ["--main", "README.rdoc"] - s.extra_rdoc_files += %w[ - CVE-2013-0256.rdoc - CONTRIBUTING.rdoc - ExampleMarkdown.md - ExampleRDoc.rdoc - History.rdoc - LEGAL.rdoc - LICENSE.rdoc - README.rdoc - RI.rdoc - TODO.rdoc - ] + s.extra_rdoc_files += s.files.grep(%r[\A[^\/]+\.(?:rdoc|md)\z]) - s.required_ruby_version = Gem::Requirement.new(">= 2.5.0") + s.required_ruby_version = Gem::Requirement.new(">= 2.6.0") s.required_rubygems_version = Gem::Requirement.new(">= 2.2") s.add_dependency 'psych', '>= 4.0.0' - s.add_development_dependency("gettext") end diff --git a/lib/rdoc/rdoc.rb b/lib/rdoc/rdoc.rb index 3a3defacb6..2da6d9b575 100644 --- a/lib/rdoc/rdoc.rb +++ b/lib/rdoc/rdoc.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require 'rdoc' +require_relative '../rdoc' require 'find' require 'fileutils' @@ -14,7 +14,7 @@ require 'time' # is: # # rdoc = RDoc::RDoc.new -# options = rdoc.load_options # returns an RDoc::Options instance +# options = RDoc::Options.load_options # returns an RDoc::Options instance # # set extra options # rdoc.document options # @@ -36,6 +36,17 @@ class RDoc::RDoc GENERATORS = {} ## + # List of directory names always skipped + + UNCONDITIONALLY_SKIPPED_DIRECTORIES = %w[CVS .svn .git].freeze + + ## + # List of directory names skipped if test suites should be skipped + + TEST_SUITE_DIRECTORY_NAMES = %w[spec test].freeze + + + ## # Generator instance used for creating output attr_accessor :generator @@ -108,7 +119,7 @@ class RDoc::RDoc # +files+. def gather_files files - files = ["."] if files.empty? + files = [@options.root.to_s] if files.empty? file_list = normalized_file_list files, true, @options.exclude @@ -152,35 +163,6 @@ class RDoc::RDoc end ## - # Loads options from .rdoc_options if the file exists, otherwise creates a - # new RDoc::Options instance. - - def load_options - options_file = File.expand_path '.rdoc_options' - return RDoc::Options.new unless File.exist? options_file - - RDoc.load_yaml - - begin - options = YAML.safe_load File.read('.rdoc_options'), permitted_classes: [RDoc::Options, Symbol] - rescue Psych::SyntaxError - raise RDoc::Error, "#{options_file} is not a valid rdoc options file" - end - - return RDoc::Options.new unless options # Allow empty file. - - raise RDoc::Error, "#{options_file} is not a valid rdoc options file" unless - RDoc::Options === options or Hash === options - - if Hash === options - # Override the default values with the contents of YAML file. - options = RDoc::Options.new options - end - - options - end - - ## # Create an output dir if it doesn't exist. If it does exist, but doesn't # contain the flag file <tt>created.rid</tt> then we refuse to use it, as # we may clobber some manually generated documentation @@ -309,7 +291,10 @@ option) file_list[rel_file_name] = mtime end when "directory" then - next if rel_file_name == "CVS" || rel_file_name == ".svn" + next if UNCONDITIONALLY_SKIPPED_DIRECTORIES.include?(rel_file_name) + + basename = File.basename(rel_file_name) + next if options.skip_tests && TEST_SUITE_DIRECTORY_NAMES.include?(basename) created_rid = File.join rel_file_name, "created.rid" next if File.file? created_rid @@ -444,9 +429,7 @@ The internal error was: files.reject do |file, *| file =~ /\.(?:class|eps|erb|scpt\.txt|svg|ttf|yml)$/i or (file =~ /tags$/i and - File.open(file, 'rb') { |io| - io.read(100) =~ /\A(\f\n[^,]+,\d+$|!_TAG_)/ - }) + /\A(\f\n[^,]+,\d+$|!_TAG_)/.match?(File.binread(file, 100))) end end @@ -469,11 +452,11 @@ The internal error was: if RDoc::Options === options then @options = options - @options.finish else - @options = load_options + @options = RDoc::Options.load_options @options.parse options end + @options.finish if @options.pipe then handle_pipe diff --git a/lib/rdoc/require.rb b/lib/rdoc/require.rb index 91f9c24e5d..05e26b84b0 100644 --- a/lib/rdoc/require.rb +++ b/lib/rdoc/require.rb @@ -49,4 +49,3 @@ class RDoc::Require < RDoc::CodeObject end end - diff --git a/lib/rdoc/ri.rb b/lib/rdoc/ri.rb index c798c1fc49..0af05f729f 100644 --- a/lib/rdoc/ri.rb +++ b/lib/rdoc/ri.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require 'rdoc' +require_relative '../rdoc' ## # Namespace for the ri command line tool's implementation. @@ -13,9 +13,8 @@ module RDoc::RI class Error < RDoc::Error; end - autoload :Driver, 'rdoc/ri/driver' - autoload :Paths, 'rdoc/ri/paths' - autoload :Store, 'rdoc/ri/store' + autoload :Driver, "#{__dir__}/ri/driver" + autoload :Paths, "#{__dir__}/ri/paths" + autoload :Store, "#{__dir__}/ri/store" end - diff --git a/lib/rdoc/ri/driver.rb b/lib/rdoc/ri/driver.rb index 7549a39203..64783dc163 100644 --- a/lib/rdoc/ri/driver.rb +++ b/lib/rdoc/ri/driver.rb @@ -1,23 +1,10 @@ # frozen_string_literal: true -require 'abbrev' require 'optparse' -begin - require 'readline' -rescue LoadError -end - -begin - require 'win32console' -rescue LoadError -end - -require 'rdoc' - -## -# For RubyGems backwards compatibility +require_relative '../../rdoc' -require_relative 'formatter' +require_relative 'formatter' # For RubyGems backwards compatibility +# TODO: Fix weird documentation with `require_relative` ## # The RI driver implements the command-line ri tool. @@ -47,9 +34,9 @@ class RDoc::RI::Driver class NotFoundError < Error - def initialize(klass, suggestions = nil) # :nodoc: + def initialize(klass, suggestion_proc = nil) # :nodoc: @klass = klass - @suggestions = suggestions + @suggestion_proc = suggestion_proc end ## @@ -61,8 +48,9 @@ class RDoc::RI::Driver def message # :nodoc: str = "Nothing known about #{@klass}" - if @suggestions and !@suggestions.empty? - str += "\nDid you mean? #{@suggestions.join("\n ")}" + suggestions = @suggestion_proc&.call + if suggestions and !suggestions.empty? + str += "\nDid you mean? #{suggestions.join("\n ")}" end str end @@ -433,9 +421,6 @@ or the PAGER environment variable. @use_stdout = options[:use_stdout] @show_all = options[:show_all] @width = options[:width] - - # pager process for jruby - @jruby_pager_process = nil end ## @@ -964,8 +949,8 @@ or the PAGER environment variable. ary = class_names.grep(Regexp.new("\\A#{klass.gsub(/(?=::|\z)/, '[^:]*')}\\z")) if ary.length != 1 && ary.first != klass if check_did_you_mean - suggestions = DidYouMean::SpellChecker.new(dictionary: class_names).correct(klass) - raise NotFoundError.new(klass, suggestions) + suggestion_proc = -> { DidYouMean::SpellChecker.new(dictionary: class_names).correct(klass) } + raise NotFoundError.new(klass, suggestion_proc) else raise NotFoundError, klass end @@ -1052,36 +1037,6 @@ or the PAGER environment variable. end ## - # Finds the given +pager+ for jruby. Returns an IO if +pager+ was found. - # - # Returns false if +pager+ does not exist. - # - # Returns nil if the jruby JVM doesn't support ProcessBuilder redirection - # (1.6 and older). - - def find_pager_jruby pager - require 'java' - require 'shellwords' - - return nil unless java.lang.ProcessBuilder.constants.include? :Redirect - - pager = Shellwords.split pager - - pb = java.lang.ProcessBuilder.new(*pager) - pb = pb.redirect_output java.lang.ProcessBuilder::Redirect::INHERIT - - @jruby_pager_process = pb.start - - input = @jruby_pager_process.output_stream - - io = input.to_io - io.sync = true - io - rescue java.io.IOException - false - end - - ## # Finds a store that matches +name+ which can be the name of a gem, "ruby", # "home" or "site". # @@ -1120,6 +1075,10 @@ or the PAGER environment variable. def interactive puts "\nEnter the method name you want to look up." + begin + require 'readline' + rescue LoadError + end if defined? Readline then Readline.completion_proc = method :complete puts "You can use tab to autocomplete." @@ -1129,7 +1088,7 @@ or the PAGER environment variable. loop do name = if defined? Readline then - Readline.readline ">> " + Readline.readline ">> ", true else print ">> " $stdin.gets @@ -1149,17 +1108,6 @@ or the PAGER environment variable. end ## - # Is +file+ in ENV['PATH']? - - def in_path? file - return true if file =~ %r%\A/% and File.exist? file - - ENV['PATH'].split(File::PATH_SEPARATOR).any? do |path| - File.exist? File.join(path, file) - end - end - - ## # Lists classes known to ri starting with +names+. If +names+ is empty all # known classes are shown. @@ -1290,8 +1238,8 @@ or the PAGER environment variable. methods.push(*store.instance_methods[klass]) if [:instance, :both].include? types end methods = methods.uniq - suggestions = DidYouMean::SpellChecker.new(dictionary: methods).correct(method_name) - raise NotFoundError.new(name, suggestions) + suggestion_proc = -> { DidYouMean::SpellChecker.new(dictionary: methods).correct(method_name) } + raise NotFoundError.new(name, suggestion_proc) else raise NotFoundError, name end @@ -1353,7 +1301,6 @@ or the PAGER environment variable. yield pager ensure pager.close - @jruby_pager_process.wait_for if @jruby_pager_process end else yield $stdout @@ -1521,27 +1468,14 @@ or the PAGER environment variable. def setup_pager return if @use_stdout - jruby = RUBY_ENGINE == 'jruby' - pagers = [ENV['RI_PAGER'], ENV['PAGER'], 'pager', 'less', 'more'] + require 'shellwords' pagers.compact.uniq.each do |pager| - next unless pager - - pager_cmd = pager.split(' ').first - - next unless in_path? pager_cmd - - if jruby then - case io = find_pager_jruby(pager) - when nil then break - when false then next - else io - end - else - io = IO.popen(pager, 'w') rescue next - end + pager = Shellwords.split(pager) + next if pager.empty? + io = IO.popen(pager, 'w') rescue next next if $? and $?.pid == io.pid and $?.exited? # pager didn't work @paging = true diff --git a/lib/rdoc/ri/store.rb b/lib/rdoc/ri/store.rb index 9f4b03734a..96742e7ae3 100644 --- a/lib/rdoc/ri/store.rb +++ b/lib/rdoc/ri/store.rb @@ -4,4 +4,3 @@ module RDoc::RI Store = RDoc::Store # :nodoc: end - diff --git a/lib/rdoc/rubygems_hook.rb b/lib/rdoc/rubygems_hook.rb index 3781ff9858..3160072e53 100644 --- a/lib/rdoc/rubygems_hook.rb +++ b/lib/rdoc/rubygems_hook.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'rubygems/user_interaction' require 'fileutils' -require 'rdoc' +require_relative '../rdoc' ## # Gem::RDoc provides methods to generate RDoc and ri data for installed gems diff --git a/lib/rdoc/servlet.rb b/lib/rdoc/servlet.rb index 0ab1eaf19d..d05368766a 100644 --- a/lib/rdoc/servlet.rb +++ b/lib/rdoc/servlet.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require 'rdoc' +require_relative '../rdoc' require 'erb' require 'time' require 'json' diff --git a/lib/rdoc/single_class.rb b/lib/rdoc/single_class.rb index 6a7b67deb3..dd16529648 100644 --- a/lib/rdoc/single_class.rb +++ b/lib/rdoc/single_class.rb @@ -22,5 +22,9 @@ class RDoc::SingleClass < RDoc::ClassModule "class << #{full_name}" end + def pretty_print q # :nodoc: + q.group 2, "[class << #{full_name}", "]" do + next + end + end end - diff --git a/lib/rdoc/stats.rb b/lib/rdoc/stats.rb index bd6c0ef23a..4817c9c729 100644 --- a/lib/rdoc/stats.rb +++ b/lib/rdoc/stats.rb @@ -454,9 +454,8 @@ class RDoc::Stats [params.length, undoc] end - autoload :Quiet, 'rdoc/stats/quiet' - autoload :Normal, 'rdoc/stats/normal' - autoload :Verbose, 'rdoc/stats/verbose' + autoload :Quiet, "#{__dir__}/stats/quiet" + autoload :Normal, "#{__dir__}/stats/normal" + autoload :Verbose, "#{__dir__}/stats/verbose" end - diff --git a/lib/rdoc/stats/quiet.rb b/lib/rdoc/stats/quiet.rb index bc4161b2d4..9c98ea5f86 100644 --- a/lib/rdoc/stats/quiet.rb +++ b/lib/rdoc/stats/quiet.rb @@ -57,4 +57,3 @@ class RDoc::Stats::Quiet def done_adding(*) end end - diff --git a/lib/rdoc/stats/verbose.rb b/lib/rdoc/stats/verbose.rb index 6ace8937a2..7090d561f8 100644 --- a/lib/rdoc/stats/verbose.rb +++ b/lib/rdoc/stats/verbose.rb @@ -42,5 +42,3 @@ class RDoc::Stats::Verbose < RDoc::Stats::Normal end end - - diff --git a/lib/rdoc/store.rb b/lib/rdoc/store.rb index 5ba671ca1b..cd27d47dd1 100644 --- a/lib/rdoc/store.rb +++ b/lib/rdoc/store.rb @@ -197,6 +197,9 @@ class RDoc::Store top_level end + ## + # Sets the parser of +absolute_name+, unless it from a source code file. + def update_parser_of_file(absolute_name, parser) if top_level = @files_hash[absolute_name] then @text_files_hash[absolute_name] = top_level if top_level.text? @@ -556,9 +559,7 @@ class RDoc::Store def load_cache #orig_enc = @encoding - File.open cache_path, 'rb' do |io| - @cache = Marshal.load io.read - end + @cache = marshal_load(cache_path) load_enc = @cache[:encoding] @@ -615,9 +616,7 @@ class RDoc::Store def load_class_data klass_name file = class_file klass_name - File.open file, 'rb' do |io| - Marshal.load io.read - end + marshal_load(file) rescue Errno::ENOENT => e error = MissingFileError.new(self, file, klass_name) error.set_backtrace e.backtrace @@ -630,14 +629,10 @@ class RDoc::Store def load_method klass_name, method_name file = method_file klass_name, method_name - File.open file, 'rb' do |io| - obj = Marshal.load io.read - obj.store = self - obj.parent = - find_class_or_module(klass_name) || load_class(klass_name) unless - obj.parent - obj - end + obj = marshal_load(file) + obj.store = self + obj.parent ||= find_class_or_module(klass_name) || load_class(klass_name) + obj rescue Errno::ENOENT => e error = MissingFileError.new(self, file, klass_name + method_name) error.set_backtrace e.backtrace @@ -650,11 +645,9 @@ class RDoc::Store def load_page page_name file = page_file page_name - File.open file, 'rb' do |io| - obj = Marshal.load io.read - obj.store = self - obj - end + obj = marshal_load(file) + obj.store = self + obj rescue Errno::ENOENT => e error = MissingFileError.new(self, file, page_name) error.set_backtrace e.backtrace @@ -976,4 +969,21 @@ class RDoc::Store @unique_modules end + private + def marshal_load(file) + File.open(file, 'rb') {|io| Marshal.load(io, MarshalFilter)} + end + + MarshalFilter = proc do |obj| + case obj + when true, false, nil, Array, Class, Encoding, Hash, Integer, String, Symbol, RDoc::Text + else + unless obj.class.name.start_with?("RDoc::") + raise TypeError, "not permitted class: #{obj.class.name}" + end + end + obj + end + private_constant :MarshalFilter + end diff --git a/lib/rdoc/task.rb b/lib/rdoc/task.rb index 0bedaa50b0..eb584c9d2a 100644 --- a/lib/rdoc/task.rb +++ b/lib/rdoc/task.rb @@ -32,7 +32,7 @@ begin rescue Gem::LoadError end unless defined?(Rake) -require 'rdoc' +require_relative '../rdoc' require 'rake' require 'rake/tasklib' @@ -50,6 +50,9 @@ require 'rake/tasklib' # [rerdoc] # Rebuild the rdoc files from scratch, even if they are not out of date. # +# [rdoc:coverage] +# Print RDoc coverage report for all rdoc files. +# # Simple Example: # # require 'rdoc/task' @@ -71,7 +74,7 @@ require 'rake/tasklib' # require 'rdoc/task' # # RDoc::Task.new :rdoc_dev do |rdoc| -# rdoc.main = "README.doc" +# rdoc.main = "README.rdoc" # rdoc.rdoc_files.include("README.rdoc", "lib/**/*.rb") # rdoc.options << "--all" # end @@ -90,8 +93,8 @@ require 'rake/tasklib' # RDoc::Task.new(:rdoc => "rdoc", :clobber_rdoc => "rdoc:clean", # :rerdoc => "rdoc:force") # -# This will create the tasks <tt>:rdoc</tt>, <tt>:rdoc:clean</tt> and -# <tt>:rdoc:force</tt>. +# This will create the tasks <tt>:rdoc</tt>, <tt>:rdoc:clean</tt>, +# <tt>:rdoc:force</tt>, and <tt>:rdoc:coverage</tt>. class RDoc::Task < Rake::TaskLib @@ -248,6 +251,18 @@ class RDoc::Task < Rake::TaskLib RDoc::RDoc.new.document args end + namespace rdoc_task_name do + desc coverage_task_description + task coverage_task_name do + @before_running_rdoc.call if @before_running_rdoc + opts = option_list << "-C" + args = opts + @rdoc_files + + $stderr.puts "rdoc #{args.join ' '}" if Rake.application.options.trace + RDoc::RDoc.new.document args + end + end + self end @@ -288,6 +303,13 @@ class RDoc::Task < Rake::TaskLib "Rebuild RDoc HTML files" end + ## + # Task description for the coverage task or its renamed description + + def coverage_task_description + "Print RDoc coverage report" + end + private def rdoc_target @@ -315,6 +337,10 @@ class RDoc::Task < Rake::TaskLib end end + def coverage_task_name + "coverage" + end + end # :stopdoc: @@ -323,7 +349,7 @@ module Rake ## # For backwards compatibility - RDocTask = RDoc::Task + RDocTask = RDoc::Task # :nodoc: end # :startdoc: diff --git a/lib/rdoc/text.rb b/lib/rdoc/text.rb index c3218fdb2f..9804f81abe 100644 --- a/lib/rdoc/text.rb +++ b/lib/rdoc/text.rb @@ -10,6 +10,10 @@ require 'strscan' module RDoc::Text + ## + # The language for this text. This affects stripping comments + # markers. + attr_accessor :language ## @@ -218,10 +222,10 @@ module RDoc::Text when s.scan(/\.\.\.(\.?)/) then html << s[1] << encoded[:ellipsis] after_word = nil - when s.scan(/\(c\)/) then + when s.scan(/\(c\)/i) then html << encoded[:copyright] after_word = nil - when s.scan(/\(r\)/) then + when s.scan(/\(r\)/i) then html << encoded[:trademark] after_word = nil when s.scan(/---/) then @@ -237,10 +241,18 @@ module RDoc::Text when s.scan(/``/) then # backtick double quote html << encoded[:open_dquote] after_word = nil - when s.scan(/''/) then # tick double quote + when s.scan(/(?:'|'){2}/) then # tick double quote html << encoded[:close_dquote] after_word = nil - when s.scan(/'/) then # single quote + when s.scan(/`/) then # backtick + if insquotes or after_word + html << '`' + after_word = false + else + html << encoded[:open_squote] + insquotes = true + end + when s.scan(/'|'/) then # single quote if insquotes html << encoded[:close_squote] insquotes = false @@ -301,4 +313,10 @@ module RDoc::Text res.join.strip end + ## + # Character class to be separated by a space when concatenating + # lines. + + SPACE_SEPARATED_LETTER_CLASS = /[\p{Nd}\p{Lc}\p{Pc}]|[!-~&&\W]/ + end diff --git a/lib/rdoc/token_stream.rb b/lib/rdoc/token_stream.rb index f428e2400c..19ca7ed248 100644 --- a/lib/rdoc/token_stream.rb +++ b/lib/rdoc/token_stream.rb @@ -112,8 +112,7 @@ module RDoc::TokenStream # Returns a string representation of the token stream def tokens_to_s - token_stream.compact.map { |token| token[:text] }.join '' + (token_stream or return '').compact.map { |token| token[:text] }.join '' end end - diff --git a/lib/rdoc/top_level.rb b/lib/rdoc/top_level.rb index b8b6110bb2..3864f66431 100644 --- a/lib/rdoc/top_level.rb +++ b/lib/rdoc/top_level.rb @@ -52,6 +52,9 @@ class RDoc::TopLevel < RDoc::Context @classes_or_modules = [] end + ## + # Sets the parser for this toplevel context, also the store. + def parser=(val) @parser = val @store.update_parser_of_file(absolute_name, val) if @store @@ -286,4 +289,3 @@ class RDoc::TopLevel < RDoc::Context end end - diff --git a/lib/rdoc/version.rb b/lib/rdoc/version.rb index a3ef62d6be..87842d9847 100644 --- a/lib/rdoc/version.rb +++ b/lib/rdoc/version.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + module RDoc ## # RDoc version you are using - VERSION = '6.3.2' + VERSION = '6.6.3.1' end |