class RDoc::Parser::ChangeLog

def continue_entry_body entry_body, continuation

def continue_entry_body entry_body, continuation
  return unless last = entry_body.last
  if last =~ /\)\s*\z/ and continuation =~ /\A\(/ then
    last.sub!(/\)\s*\z/, ',')
    continuation = continuation.sub(/\A\(/, '')
  end
  if last =~ /\s\z/ then
    last << continuation
  else
    last << ' ' + continuation
  end
end

def create_document groups

def create_document groups
  doc = RDoc::Markup::Document.new
  doc.omit_headings_below = 2
  doc.file = @top_level
  doc << RDoc::Markup::Heading.new(1, File.basename(@file_name))
  doc << RDoc::Markup::BlankLine.new
  groups.sort_by do |day,| day end.reverse_each do |day, entries|
    doc << RDoc::Markup::Heading.new(2, day.dup)
    doc << RDoc::Markup::BlankLine.new
    doc.concat create_entries entries
  end
  doc
end

def create_entries entries

def create_entries entries
  out = []
  entries.each do |entry, items|
    out << RDoc::Markup::Heading.new(3, entry)
    out << RDoc::Markup::BlankLine.new
    out << create_items(items)
  end
  out
end

def create_items items

def create_items items
  list = RDoc::Markup::List.new :NOTE
  items.each do |item|
    item =~ /\A(.*?(?:\([^)]+\))?):\s*/
    title = $1
    body = $'
    paragraph = RDoc::Markup::Paragraph.new body
    list_item = RDoc::Markup::ListItem.new title, paragraph
    list << list_item
  end
  list
end

def group_entries entries

def group_entries entries
  @time_cache ||= {}
  entries.group_by do |title, _|
    begin
      time = @time_cache[title]
      (time || parse_date(title)).strftime '%Y-%m-%d'
    rescue NoMethodError, ArgumentError
      time, = title.split '  ', 2
      parse_date(time).strftime '%Y-%m-%d'
    end
  end
end

def parse_date(date)

def parse_date(date)
  case date
  when /\A\s*(\d+)-(\d+)-(\d+)(?:[ T](\d+):(\d+):(\d+) *([-+]\d\d):?(\d\d))?\b/
    Time.new($1, $2, $3, $4, $5, $6, ("#{$7}:#{$8}" if $7))
  when /\A\s*\w{3}, +(\d+) (\w{3}) (\d+) (\d+):(\d+):(\d+) *(?:([-+]\d\d):?(\d\d))\b/
    Time.new($3, $2, $1, $4, $5, $6, ("#{$7}:#{$8}" if $7))
  when /\A\s*\w{3} (\w{3}) +(\d+) (\d+) (\d+):(\d+):(\d+) *(?:([-+]\d\d):?(\d\d))\b/
    Time.new($3, $1, $2, $4, $5, $6, ("#{$7}:#{$8}" if $7))
  when /\A\s*\w{3} (\w{3}) +(\d+) (\d+):(\d+):(\d+) (\d+)\b/
    Time.new($6, $1, $2, $3, $4, $5)
  else
    raise ArgumentError, "bad date: #{date}"
  end
end

def parse_entries

def parse_entries
  @time_cache ||= {}
  if /\A((?:.*\n){,3})commit\s/ =~ @content
    class << self; prepend Git; end
    parse_info($1)
    return parse_entries
  end
  entries = []
  entry_name = nil
  entry_body = []
  @content.each_line do |line|
    case line
    when /^\s*$/ then
      next
    when /^\w.*/ then
      entries << [entry_name, entry_body] if entry_name
      entry_name = $&
      begin
        time = parse_date entry_name
        @time_cache[entry_name] = time
      rescue ArgumentError
        entry_name = nil
      end
      entry_body = []
    when /^(\t| {8})?\*\s*(.*)/ then # "\t* file.c (func): ..."
      entry_body << $2.dup
    when /^(\t| {8})?\s*(\(.*)/ then # "\t(func): ..."
      entry = $2
      if entry_body.last =~ /:/ then
        entry_body << entry.dup
      else
        continue_entry_body entry_body, entry
      end
    when /^(\t| {8})?\s*(.*)/ then
      continue_entry_body entry_body, $2
    end
  end
  entries << [entry_name, entry_body] if entry_name
  entries.reject! do |(entry, _)|
    entry == nil
  end
  entries
end

def scan

def scan
  @time_cache = {}
  entries = parse_entries
  grouped_entries = group_entries entries
  doc = create_document grouped_entries
  @top_level.comment = doc
  @top_level
end