annotate vendor/gems/coderay-1.0.0/lib/coderay/scanners/diff.rb @ 1472:f0b798dad2d6 feature_526

Close obsolete branch feature_526
author Chris Cannam
date Tue, 20 Nov 2012 19:45:51 +0000
parents cbb26bc654de
children
rev   line source
Chris@909 1 module CodeRay
Chris@909 2 module Scanners
Chris@909 3
Chris@909 4 # Scanner for output of the diff command.
Chris@909 5 #
Chris@909 6 # Alias: +patch+
Chris@909 7 class Diff < Scanner
Chris@909 8
Chris@909 9 register_for :diff
Chris@909 10 title 'diff output'
Chris@909 11
Chris@909 12 DEFAULT_OPTIONS = {
Chris@909 13 :highlight_code => true,
Chris@909 14 :inline_diff => true,
Chris@909 15 }
Chris@909 16
Chris@909 17 protected
Chris@909 18
Chris@909 19 require 'coderay/helpers/file_type'
Chris@909 20
Chris@909 21 def scan_tokens encoder, options
Chris@909 22
Chris@909 23 line_kind = nil
Chris@909 24 state = :initial
Chris@909 25 deleted_lines = 0
Chris@909 26 scanners = Hash.new do |h, lang|
Chris@909 27 h[lang] = Scanners[lang].new '', :keep_tokens => true, :keep_state => true
Chris@909 28 end
Chris@909 29 content_scanner = scanners[:plain]
Chris@909 30 content_scanner_entry_state = nil
Chris@909 31
Chris@909 32 until eos?
Chris@909 33
Chris@909 34 if match = scan(/\n/)
Chris@909 35 deleted_lines = 0 unless line_kind == :delete
Chris@909 36 if line_kind
Chris@909 37 encoder.end_line line_kind
Chris@909 38 line_kind = nil
Chris@909 39 end
Chris@909 40 encoder.text_token match, :space
Chris@909 41 next
Chris@909 42 end
Chris@909 43
Chris@909 44 case state
Chris@909 45
Chris@909 46 when :initial
Chris@909 47 if match = scan(/--- |\+\+\+ |=+|_+/)
Chris@909 48 encoder.begin_line line_kind = :head
Chris@909 49 encoder.text_token match, :head
Chris@909 50 if match = scan(/.*?(?=$|[\t\n\x00]| \(revision)/)
Chris@909 51 encoder.text_token match, :filename
Chris@909 52 if options[:highlight_code]
Chris@909 53 file_type = FileType.fetch(match, :text)
Chris@909 54 file_type = :text if file_type == :diff
Chris@909 55 content_scanner = scanners[file_type]
Chris@909 56 content_scanner_entry_state = nil
Chris@909 57 end
Chris@909 58 end
Chris@909 59 next unless match = scan(/.+/)
Chris@909 60 encoder.text_token match, :plain
Chris@909 61 elsif match = scan(/Index: |Property changes on: /)
Chris@909 62 encoder.begin_line line_kind = :head
Chris@909 63 encoder.text_token match, :head
Chris@909 64 next unless match = scan(/.+/)
Chris@909 65 encoder.text_token match, :plain
Chris@909 66 elsif match = scan(/Added: /)
Chris@909 67 encoder.begin_line line_kind = :head
Chris@909 68 encoder.text_token match, :head
Chris@909 69 next unless match = scan(/.+/)
Chris@909 70 encoder.text_token match, :plain
Chris@909 71 state = :added
Chris@909 72 elsif match = scan(/\\ .*/)
Chris@909 73 encoder.text_token match, :comment
Chris@909 74 elsif match = scan(/@@(?>[^@\n]*)@@/)
Chris@909 75 content_scanner.state = :initial unless match?(/\n\+/)
Chris@909 76 content_scanner_entry_state = nil
Chris@909 77 if check(/\n|$/)
Chris@909 78 encoder.begin_line line_kind = :change
Chris@909 79 else
Chris@909 80 encoder.begin_group :change
Chris@909 81 end
Chris@909 82 encoder.text_token match[0,2], :change
Chris@909 83 encoder.text_token match[2...-2], :plain
Chris@909 84 encoder.text_token match[-2,2], :change
Chris@909 85 encoder.end_group :change unless line_kind
Chris@909 86 next unless match = scan(/.+/)
Chris@909 87 if options[:highlight_code]
Chris@909 88 content_scanner.tokenize match, :tokens => encoder
Chris@909 89 else
Chris@909 90 encoder.text_token match, :plain
Chris@909 91 end
Chris@909 92 next
Chris@909 93 elsif match = scan(/\+/)
Chris@909 94 encoder.begin_line line_kind = :insert
Chris@909 95 encoder.text_token match, :insert
Chris@909 96 next unless match = scan(/.+/)
Chris@909 97 if options[:highlight_code]
Chris@909 98 content_scanner.tokenize match, :tokens => encoder
Chris@909 99 else
Chris@909 100 encoder.text_token match, :plain
Chris@909 101 end
Chris@909 102 next
Chris@909 103 elsif match = scan(/-/)
Chris@909 104 deleted_lines += 1
Chris@909 105 encoder.begin_line line_kind = :delete
Chris@909 106 encoder.text_token match, :delete
Chris@909 107 if options[:inline_diff] && deleted_lines == 1 && check(/(?>.*)\n\+(?>.*)$(?!\n\+)/)
Chris@909 108 content_scanner_entry_state = content_scanner.state
Chris@909 109 skip(/(.*)\n\+(.*)$/)
Chris@909 110 head, deletion, insertion, tail = diff self[1], self[2]
Chris@909 111 pre, deleted, post = content_scanner.tokenize [head, deletion, tail], :tokens => Tokens.new
Chris@909 112 encoder.tokens pre
Chris@909 113 unless deleted.empty?
Chris@909 114 encoder.begin_group :eyecatcher
Chris@909 115 encoder.tokens deleted
Chris@909 116 encoder.end_group :eyecatcher
Chris@909 117 end
Chris@909 118 encoder.tokens post
Chris@909 119 encoder.end_line line_kind
Chris@909 120 encoder.text_token "\n", :space
Chris@909 121 encoder.begin_line line_kind = :insert
Chris@909 122 encoder.text_token '+', :insert
Chris@909 123 content_scanner.state = content_scanner_entry_state || :initial
Chris@909 124 pre, inserted, post = content_scanner.tokenize [head, insertion, tail], :tokens => Tokens.new
Chris@909 125 encoder.tokens pre
Chris@909 126 unless inserted.empty?
Chris@909 127 encoder.begin_group :eyecatcher
Chris@909 128 encoder.tokens inserted
Chris@909 129 encoder.end_group :eyecatcher
Chris@909 130 end
Chris@909 131 encoder.tokens post
Chris@909 132 elsif match = scan(/.*/)
Chris@909 133 if options[:highlight_code]
Chris@909 134 if deleted_lines == 1
Chris@909 135 content_scanner_entry_state = content_scanner.state
Chris@909 136 end
Chris@909 137 content_scanner.tokenize match, :tokens => encoder unless match.empty?
Chris@909 138 if !match?(/\n-/)
Chris@909 139 if match?(/\n\+/)
Chris@909 140 content_scanner.state = content_scanner_entry_state || :initial
Chris@909 141 end
Chris@909 142 content_scanner_entry_state = nil
Chris@909 143 end
Chris@909 144 else
Chris@909 145 encoder.text_token match, :plain
Chris@909 146 end
Chris@909 147 end
Chris@909 148 next
Chris@909 149 elsif match = scan(/ .*/)
Chris@909 150 if options[:highlight_code]
Chris@909 151 content_scanner.tokenize match, :tokens => encoder
Chris@909 152 else
Chris@909 153 encoder.text_token match, :plain
Chris@909 154 end
Chris@909 155 next
Chris@909 156 elsif match = scan(/.+/)
Chris@909 157 encoder.begin_line line_kind = :comment
Chris@909 158 encoder.text_token match, :plain
Chris@909 159 else
Chris@909 160 raise_inspect 'else case rached'
Chris@909 161 end
Chris@909 162
Chris@909 163 when :added
Chris@909 164 if match = scan(/ \+/)
Chris@909 165 encoder.begin_line line_kind = :insert
Chris@909 166 encoder.text_token match, :insert
Chris@909 167 next unless match = scan(/.+/)
Chris@909 168 encoder.text_token match, :plain
Chris@909 169 else
Chris@909 170 state = :initial
Chris@909 171 next
Chris@909 172 end
Chris@909 173 end
Chris@909 174
Chris@909 175 end
Chris@909 176
Chris@909 177 encoder.end_line line_kind if line_kind
Chris@909 178
Chris@909 179 encoder
Chris@909 180 end
Chris@909 181
Chris@909 182 private
Chris@909 183
Chris@909 184 def diff a, b
Chris@909 185 # i will be the index of the leftmost difference from the left.
Chris@909 186 i_max = [a.size, b.size].min
Chris@909 187 i = 0
Chris@909 188 i += 1 while i < i_max && a[i] == b[i]
Chris@909 189 # j_min will be the index of the leftmost difference from the right.
Chris@909 190 j_min = i - i_max
Chris@909 191 # j will be the index of the rightmost difference from the right which
Chris@909 192 # does not precede the leftmost one from the left.
Chris@909 193 j = -1
Chris@909 194 j -= 1 while j >= j_min && a[j] == b[j]
Chris@909 195 return a[0...i], a[i..j], b[i..j], (j < -1) ? a[j+1..-1] : ''
Chris@909 196 end
Chris@909 197
Chris@909 198 end
Chris@909 199
Chris@909 200 end
Chris@909 201 end