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