module Diffy class HtmlFormatter def initialize(diff, options = {}) @diff = diff @options = options end def to_s if @options[:highlight_words] wrap_lines(highlighted_words) else wrap_lines(@diff.map{|line| wrap_line(ERB::Util.h(line))}) end end private def wrap_line(line) cleaned = line.gsub(/^./, '').chomp case line when /^\+/ '
  • ' + cleaned + '
  • ' when /^-/ '
  • ' + cleaned + '
  • ' when /^ / '
  • ' + cleaned + '
  • ' end end def wrap_lines(lines) %'
    \n \n
    \n' end def highlighted_words chunks = @diff.each_chunk.to_a processed = [] lines = chunks.each_with_index.map do |chunk1, index| next if processed.include? index processed << index chunk1 = chunk1 chunk2 = chunks[index + 1] if not chunk2 next chunk1 end chunk1 = ERB::Util.h(chunk1) chunk2 = ERB::Util.h(chunk2) dir1 = chunk1.each_char.first dir2 = chunk2.each_char.first case [dir1, dir2] when ['-', '+'] line_diff = Diffy::Diff.new( split_characters(chunk1), split_characters(chunk2) ) hi1 = reconstruct_characters(line_diff, '-') hi2 = reconstruct_characters(line_diff, '+') processed << (index + 1) [hi1, hi2] else chunk1 end end.flatten lines.map{|line| line.each_line.map(&:chomp).to_a if line }.flatten.compact. map{|line|wrap_line(line) }.compact end def split_characters(chunk) chunk.gsub(/^./, '').each_line.map do |line| line.chomp.split('') + ['\n'] end.flatten.join("\n") end def reconstruct_characters(line_diff, type) line_diff.each_chunk.map do |l| re = /(^|\\n)#{Regexp.escape(type)}/ case l when re "" + l.gsub(re, '').gsub("\n", ''). gsub('\n', "\n") + "" when /^ / l.gsub(/^./, '').gsub("\n", ''). gsub('\r', "\r").gsub('\n', "\n") end end.join('').split("\n").map do |l| type + l end end end end