summaryrefslogtreecommitdiff
path: root/lib/coderay/scanners/diff.rb
blob: 4f3ff2e3c4b854873190fe13c0907dbf619e08cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
module CodeRay
module Scanners
  
  # Scanner for output of the diff command.
  # 
  # Alias: +patch+
  class Diff < Scanner
    
    register_for :diff
    title 'diff output'
    
  protected
    
    require 'coderay/helpers/file_type'
    
    def scan_tokens tokens, options
      
      line_kind = nil
      state = :initial
      # TODO: Cache scanners
      content_lang = nil
      
      until eos?
        kind = match = nil
        
        if match = scan(/\n/)
          if line_kind
            tokens << [:end_line, line_kind]
            line_kind = nil
          end
          tokens << [match, :space]
          next
        end
        
        case state
        
        when :initial
          if match = scan(/--- |\+\+\+ |=+|_+/)
            tokens << [:begin_line, line_kind = :head]
            tokens << [match, :head]
            if filename = scan(/.*?(?=$|[\t\n\x00]|  \(revision)/)
              tokens << [filename, :filename]
              content_lang = FileType.fetch filename, :plaintext
            end
            next unless match = scan(/.+/)
            kind = :plain
          elsif match = scan(/Index: |Property changes on: /)
            tokens << [:begin_line, line_kind = :head]
            tokens << [match, :head]
            next unless match = scan(/.+/)
            kind = :plain
          elsif match = scan(/Added: /)
            tokens << [:begin_line, line_kind = :head]
            tokens << [match, :head]
            next unless match = scan(/.+/)
            kind = :plain
            state = :added
          elsif match = scan(/\\ /)
            tokens << [:begin_line, line_kind = :change]
            tokens << [match, :change]
            next unless match = scan(/.+/)
            kind = :plain
          elsif match = scan(/@@(?>[^@\n]*)@@/)
            if check(/\n|$/)
              tokens << [:begin_line, line_kind = :change]
            else
              tokens << [:open, :change]
            end
            tokens << [match[0,2], :change]
            tokens << [match[2...-2], :plain] if match.size > 4
            tokens << [match[-2,2], :change]
            tokens << [:close, :change] unless line_kind
            next unless code = scan(/.+/)
            CodeRay.scan code, content_lang, :tokens => tokens
            next
          elsif match = scan(/\+/)
            tokens << [:begin_line, line_kind = :insert]
            tokens << [match, :insert]
            next unless match = scan(/.+/)
            CodeRay.scan match, content_lang, :tokens => tokens
            next
          elsif match = scan(/-/)
            tokens << [:begin_line, line_kind = :delete]
            tokens << [match, :delete]
            next unless code = scan(/.+/)
            CodeRay.scan code, content_lang, :tokens => tokens
            next
          elsif code = scan(/ .*/)
            CodeRay.scan code, content_lang, :tokens => tokens
            next
          elsif scan(/.+/)
            tokens << [:begin_line, line_kind = :comment]
            kind = :plain
          else
            raise_inspect 'else case rached'
          end
        
        when :added
          if match = scan(/   \+/)
            tokens << [:begin_line, line_kind = :insert]
            tokens << [match, :insert]
            next unless match = scan(/.+/)
            kind = :plain
          else
            state = :initial
            next
          end
        end
        
        match ||= matched
        if $CODERAY_DEBUG and not kind
          raise_inspect 'Error token %p in line %d' %
            [[match, kind], line], tokens
        end
        raise_inspect 'Empty token', tokens unless match
        
        tokens << [match, kind]
      end
      
      tokens << [:end_line, line_kind] if line_kind
      tokens
    end
    
  end
  
end
end