class RDoc::Generator::Darkfish

def assemble_template(body_file)

def assemble_template(body_file)
  body = body_file.read
  return body if body =~ /<html/
  head_file = @template_dir + '_head.rhtml'
  <<-TEMPLATE
DOCTYPE html>
tml lang="#{@options.locale&.name || 'en'}">
ead>
head_file.read}
body}
  TEMPLATE
end

def copy_static

def copy_static
  return if @options.static_path.empty?
  fu_options = { :verbose => $DEBUG_RDOC, :noop => @dry_run }
  @options.static_path.each do |path|
    unless File.directory? path then
      FileUtils.install path, @outputdir, **fu_options.merge(:mode => 0644)
      next
    end
    Dir.chdir path do
      Dir[File.join('**', '*')].each do |entry|
        dest_file = @outputdir + entry
        if File.directory? entry then
          FileUtils.mkdir_p entry, **fu_options
        else
          FileUtils.install entry, dest_file, **fu_options.merge(:mode => 0644)
        end
      end
    end
  end
end

def debug_msg *msg

def debug_msg *msg
  return unless $DEBUG_RDOC
  $stderr.puts(*msg)
end

def excerpt(comment)

Returns an excerpt of the comment for usage in meta description tags
def excerpt(comment)
  text = case comment
  when RDoc::Comment
    comment.text
  else
    comment
  end
  # Match from a capital letter to the first period, discarding any links, so
  # that we don't end up matching badges in the README
  pattern = ParagraphExcerptRegexpUnicode
  begin
    first_paragraph_match = text.match(pattern)
  rescue Encoding::CompatibilityError
    # The doc is non-ASCII text and encoded in other than Unicode base encodings.
    raise if pattern == ParagraphExcerptRegexpOther
    pattern = ParagraphExcerptRegexpOther
    retry
  end
  return text[0...150].tr_s("\n", " ").squeeze(" ") unless first_paragraph_match
  extracted_text = first_paragraph_match[0]
  second_paragraph = text.match(pattern, first_paragraph_match.end(0))
  extracted_text << " " << second_paragraph[0] if second_paragraph
  extracted_text[0...150].tr_s("\n", " ").squeeze(" ")
end

def gen_sub_directories

def gen_sub_directories
  @outputdir.mkpath
end

def generate

def generate
  setup
  write_style_sheet
  generate_index
  generate_class_files
  generate_file_files
  generate_table_of_contents
  @json_index.generate
  @json_index.generate_gzipped
  copy_static
rescue => e
  debug_msg "%s: %s\n  %s" % [
    e.class.name, e.message, e.backtrace.join("\n  ")
  ]
  raise
end

def generate_ancestor_list(ancestors, klass)

def generate_ancestor_list(ancestors, klass)
  return '' if ancestors.empty?
  ancestor = ancestors.shift
  content = +'<ul><li>'
  if ancestor.is_a?(RDoc::NormalClass)
    content << "<a href=\"#{klass.aref_to ancestor.path}\">#{ancestor.full_name}</a>"
  else
    content << ancestor.to_s
  end
  # Recursively call the method for the remaining ancestors
  content << generate_ancestor_list(ancestors, klass)
  content << '</li></ul>'
end

def generate_class(klass, template_file = nil)

def generate_class(klass, template_file = nil)
  current = klass
  template_file ||= @template_dir + 'class.rhtml'
  debug_msg "  working on %s (%s)" % [klass.full_name, klass.path]
  out_file   = @outputdir + klass.path
  rel_prefix = @outputdir.relative_path_from out_file.dirname
  search_index_rel_prefix = rel_prefix
  search_index_rel_prefix += @asset_rel_path if @file_output
  asset_rel_prefix = rel_prefix + @asset_rel_path
  breadcrumb = # used in templates
  breadcrumb = generate_nesting_namespaces_breadcrumb(current, rel_prefix)
  @title = "#{klass.type} #{klass.full_name} - #{@options.title}"
  debug_msg "  rendering #{out_file}"
  render_template template_file, out_file do |io|
    here = binding
    # suppress 1.9.3 warning
    here.local_variable_set(:asset_rel_prefix, asset_rel_prefix)
    here
  end
end

def generate_class_files

def generate_class_files
  template_file = @template_dir + 'class.rhtml'
  template_file = @template_dir + 'classpage.rhtml' unless
    template_file.exist?
  return unless template_file.exist?
  debug_msg "Generating class documentation in #{@outputdir}"
  current = nil
  @classes.each do |klass|
    current = klass
    generate_class klass, template_file
  end
rescue => e
  error = RDoc::Error.new \
    "error generating #{current.path}: #{e.message} (#{e.class})"
  error.set_backtrace e.backtrace
  raise error
end

def generate_class_index_content(classes, rel_prefix)

def generate_class_index_content(classes, rel_prefix)
  grouped_classes = group_classes_by_namespace_for_sidebar(classes)
  return '' unless top = grouped_classes[nil]
  solo = top.one? { |klass| klass.display? }
  traverse_classes(top, grouped_classes, rel_prefix, solo)
end

def generate_class_link(klass, rel_prefix)

def generate_class_link(klass, rel_prefix)
  if klass.display?
    %(<code><a href="#{rel_prefix}/#{klass.path}">#{klass.name}</a></code>)
  else
    %(<code>#{klass.name}</code>)
  end
end

def generate_file_files

def generate_file_files
  page_file     = @template_dir + 'page.rhtml'
  fileinfo_file = @template_dir + 'fileinfo.rhtml'
  # for legacy templates
  filepage_file = @template_dir + 'filepage.rhtml' unless
    page_file.exist? or fileinfo_file.exist?
  return unless
    page_file.exist? or fileinfo_file.exist? or filepage_file.exist?
  debug_msg "Generating file documentation in #{@outputdir}"
  out_file = nil
  current = nil
  @files.each do |file|
    current = file
    if file.text? and page_file.exist? then
      generate_page file
      next
    end
    template_file = nil
    out_file = @outputdir + file.path
    debug_msg "  working on %s (%s)" % [file.full_name, out_file]
    rel_prefix = @outputdir.relative_path_from out_file.dirname
    search_index_rel_prefix = rel_prefix
    search_index_rel_prefix += @asset_rel_path if @file_output
    asset_rel_prefix = rel_prefix + @asset_rel_path
    unless filepage_file then
      if file.text? then
        next unless page_file.exist?
        template_file = page_file
        @title = file.page_name
      else
        next unless fileinfo_file.exist?
        template_file = fileinfo_file
        @title = "File: #{file.base_name}"
      end
    end
    @title += " - #{@options.title}"
    template_file ||= filepage_file
    render_template template_file, out_file do |io|
      here = binding
      # suppress 1.9.3 warning
      here.local_variable_set(:asset_rel_prefix, asset_rel_prefix)
      here.local_variable_set(:current, current)
      here
    end
  end
rescue => e
  error =
    RDoc::Error.new "error generating #{out_file}: #{e.message} (#{e.class})"
  error.set_backtrace e.backtrace
  raise error
end

def generate_index

def generate_index
  template_file = @template_dir + 'index.rhtml'
  return unless template_file.exist?
  debug_msg "Rendering the index page..."
  out_file = @base_dir + @options.op_dir + 'index.html'
  rel_prefix = @outputdir.relative_path_from out_file.dirname
  search_index_rel_prefix = rel_prefix
  search_index_rel_prefix += @asset_rel_path if @file_output
  asset_rel_prefix = rel_prefix + @asset_rel_path
  @title = @options.title
  @main_page = @files.find { |f| f.full_name == @options.main_page }
  render_template template_file, out_file do |io|
    here = binding
    # suppress 1.9.3 warning
    here.local_variable_set(:asset_rel_prefix, asset_rel_prefix)
    # some partials rely on the presence of current variable to render
    here.local_variable_set(:current, @main_page) if @main_page
    here
  end
rescue => e
  error = RDoc::Error.new \
    "error generating index.html: #{e.message} (#{e.class})"
  error.set_backtrace e.backtrace
  raise error
end

def generate_nesting_namespaces_breadcrumb(klass, rel_prefix)

def generate_nesting_namespaces_breadcrumb(klass, rel_prefix)
  nesting_namespaces_to_class_modules(klass).map do |namespace, class_module|
    path = class_module ? (rel_prefix + class_module.path).to_s : ""
    { name: namespace, path: path, self: klass.full_name == class_module&.full_name }
  end
end

def generate_page(file)

def generate_page(file)
  template_file = @template_dir + 'page.rhtml'
  out_file = @outputdir + file.path
  debug_msg "  working on %s (%s)" % [file.full_name, out_file]
  rel_prefix = @outputdir.relative_path_from out_file.dirname
  search_index_rel_prefix = rel_prefix
  search_index_rel_prefix += @asset_rel_path if @file_output
  current          = file
  asset_rel_prefix = rel_prefix + @asset_rel_path
  @title = "#{file.page_name} - #{@options.title}"
  debug_msg "  rendering #{out_file}"
  render_template template_file, out_file do |io|
    here = binding
    # suppress 1.9.3 warning
    here.local_variable_set(:current, current)
    here.local_variable_set(:asset_rel_prefix, asset_rel_prefix)
    here
  end
end

def generate_servlet_not_found(message)

def generate_servlet_not_found(message)
  template_file = @template_dir + 'servlet_not_found.rhtml'
  return unless template_file.exist?
  debug_msg "Rendering the servlet 404 Not Found page..."
  rel_prefix = rel_prefix = ''
  search_index_rel_prefix = rel_prefix
  search_index_rel_prefix += @asset_rel_path if @file_output
  asset_rel_prefix = ''
  @title = 'Not Found'
  render_template template_file do |io|
    here = binding
    # suppress 1.9.3 warning
    here.local_variable_set(:asset_rel_prefix, asset_rel_prefix)
    here
  end
rescue => e
  error = RDoc::Error.new \
    "error generating servlet_not_found: #{e.message} (#{e.class})"
  error.set_backtrace e.backtrace
  raise error
end

def generate_servlet_root(installed)

def generate_servlet_root(installed)
  template_file = @template_dir + 'servlet_root.rhtml'
  return unless template_file.exist?
  debug_msg 'Rendering the servlet root page...'
  rel_prefix = '.'
  asset_rel_prefix = rel_prefix
  search_index_rel_prefix = asset_rel_prefix
  search_index_rel_prefix += @asset_rel_path if @file_output
  @title = 'Local RDoc Documentation'
  render_template template_file do |io| binding end
rescue => e
  error = RDoc::Error.new \
    "error generating servlet_root: #{e.message} (#{e.class})"
  error.set_backtrace e.backtrace
  raise error
end

def generate_table_of_contents

def generate_table_of_contents
  template_file = @template_dir + 'table_of_contents.rhtml'
  return unless template_file.exist?
  debug_msg "Rendering the Table of Contents..."
  out_file = @outputdir + 'table_of_contents.html'
  rel_prefix = @outputdir.relative_path_from out_file.dirname
  search_index_rel_prefix = rel_prefix
  search_index_rel_prefix += @asset_rel_path if @file_output
  asset_rel_prefix = rel_prefix + @asset_rel_path
  @title = "Table of Contents - #{@options.title}"
  render_template template_file, out_file do |io|
    here = binding
    # suppress 1.9.3 warning
    here.local_variable_set(:asset_rel_prefix, asset_rel_prefix)
    here
  end
rescue => e
  error = RDoc::Error.new \
    "error generating table_of_contents.html: #{e.message} (#{e.class})"
  error.set_backtrace e.backtrace
  raise error
end

def get_sorted_module_list(classes)

def get_sorted_module_list(classes)
  classes.select do |klass|
    klass.display?
  end.sort
end

def group_classes_by_namespace_for_sidebar(classes)

def group_classes_by_namespace_for_sidebar(classes)
  grouped_classes = classes.group_by do |klass|
    klass.full_name[/\A[^:]++(?:::[^:]++(?=::))*+(?=::[^:]*+\z)/]
  end.select do |_, klasses|
    klasses.any?(&:display?)
  end
  grouped_classes.values.each(&:uniq!)
  grouped_classes
end

def initialize(store, options)

def initialize(store, options)
  @store   = store
  @options = options
  @asset_rel_path = ''
  @base_dir       = Pathname.pwd.expand_path
  @dry_run        = @options.dry_run
  @file_output    = true
  @template_dir   = Pathname.new options.template_dir
  @template_cache = {}
  @classes = nil
  @context = nil
  @files   = nil
  @methods = nil
  @modsort = nil
  @json_index = RDoc::Generator::JsonIndex.new self, options
end

def install_rdoc_static_file(source, destination, options) # :nodoc:

:nodoc:
def install_rdoc_static_file(source, destination, options) # :nodoc:
  return unless source.exist?
  begin
    FileUtils.mkdir_p File.dirname(destination), **options
    begin
      FileUtils.ln source, destination, **options
    rescue Errno::EEXIST
      FileUtils.rm destination
      retry
    end
  rescue
    FileUtils.cp source, destination, **options
  end
end

def nesting_namespaces_to_class_modules(klass)

def nesting_namespaces_to_class_modules(klass)
  tree = {}
  klass.nesting_namespaces.zip(klass.fully_qualified_nesting_namespaces) do |ns, fqns|
    tree[ns] = @store.classes_hash[fqns] || @store.modules_hash[fqns]
  end
  tree
end

def render(file_name)

def render(file_name)
  template_file = @template_dir + file_name
  template = template_for template_file, false, RDoc::ERBPartial
  template.filename = template_file.to_s
  template.result @context
end

def render_template(template_file, out_file = nil) # :yield: io

:yield: io
def render_template(template_file, out_file = nil) # :yield: io
  io_output = out_file && !@dry_run && @file_output
  erb_klass = io_output ? RDoc::ERBIO : ERB
  template = template_for template_file, true, erb_klass
  if io_output then
    debug_msg "Outputting to %s" % [out_file.expand_path]
    out_file.dirname.mkpath
    out_file.open 'w', 0644 do |io|
      io.set_encoding @options.encoding
      @context = yield io
      template_result template, @context, template_file
    end
  else
    @context = yield nil
    output = template_result template, @context, template_file
    debug_msg "  would have written %d characters to %s" % [
      output.length, out_file.expand_path
    ] if @dry_run
    output
  end
end

def setup

def setup
  return if instance_variable_defined? :@outputdir
  @outputdir = Pathname.new(@options.op_dir).expand_path @base_dir
  return unless @store
  @classes = @store.all_classes_and_modules.sort
  @files   = @store.all_files.sort
  @methods = @classes.flat_map { |m| m.method_list }.sort
  @modsort = get_sorted_module_list @classes
end

def template_for(file, page = true, klass = ERB)

def template_for(file, page = true, klass = ERB)
  template = @template_cache[file]
  return template if template
  if page then
    template = assemble_template file
    erbout = 'io'
  else
    template = file.read
    template = template.encode @options.encoding
    file_var = File.basename(file).sub(/\..*/, '')
    erbout = "_erbout_#{file_var}"
  end
  template = klass.new template, trim_mode: '-', eoutvar: erbout
  @template_cache[file] = template
  template
end

def template_result(template, context, template_file)

def template_result(template, context, template_file)
  template.filename = template_file.to_s
  template.result context
rescue NoMethodError => e
  raise RDoc::Error, "Error while evaluating %s: %s" % [
    template_file.expand_path,
    e.message,
  ], e.backtrace
end

def traverse_classes(klasses, grouped_classes, rel_prefix, solo = false)

def traverse_classes(klasses, grouped_classes, rel_prefix, solo = false)
  content = +'<ul class="link-list">'
  klasses.each do |index_klass|
    if children = grouped_classes[index_klass.full_name]
      content << %(<li><details#{solo ? ' open' : ''}><summary>#{generate_class_link(index_klass, rel_prefix)}</summary>)
      content << traverse_classes(children, grouped_classes, rel_prefix)
      content << '</details></li>'
      solo = false
    elsif index_klass.display?
      content << %(<li>#{generate_class_link(index_klass, rel_prefix)}</li>)
    end
  end
  "#{content}</ul>"
end

def write_style_sheet

def write_style_sheet
  debug_msg "Copying static files"
  options = { :verbose => $DEBUG_RDOC, :noop => @dry_run }
  BUILTIN_STYLE_ITEMS.each do |item|
    install_rdoc_static_file @template_dir + item, "./#{item}", options
  end
  unless @options.template_stylesheets.empty?
    FileUtils.cp @options.template_stylesheets, '.', **options
  end
  Dir[(@template_dir + "{js,images}/**/*").to_s].each do |path|
    next if File.directory? path
    next if File.basename(path) =~ /^\./
    dst = Pathname.new(path).relative_path_from @template_dir
    install_rdoc_static_file @template_dir + path, dst, options
  end
end