Skip to content

Commit c38a5e2

Browse files
committed
inline diff highlighting for multi-line changes (rubychan#227)
1 parent b0e85b2 commit c38a5e2

File tree

3 files changed

+53
-31
lines changed

3 files changed

+53
-31
lines changed

coderay.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
1010
else
1111
# thanks to @Argorak for this solution
1212
revision = 134 + (`git log --oneline | wc -l`.to_i)
13-
s.version = "#{CodeRay::VERSION}.#{revision}rc3"
13+
s.version = "#{CodeRay::VERSION}.#{revision}rc1"
1414
end
1515

1616
s.authors = ['Kornelius Kalnbach']

lib/coderay/scanners/diff.rb

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def scan_tokens encoder, options
2222

2323
line_kind = nil
2424
state = :initial
25-
deleted_lines = 0
25+
deleted_lines_count = 0
2626
scanners = Hash.new do |h, lang|
2727
h[lang] = Scanners[lang].new '', :keep_tokens => true, :keep_state => true
2828
end
@@ -32,7 +32,7 @@ def scan_tokens encoder, options
3232
until eos?
3333

3434
if match = scan(/\n/)
35-
deleted_lines = 0 unless line_kind == :delete
35+
deleted_lines_count = 0 unless line_kind == :delete
3636
if line_kind
3737
encoder.end_line line_kind
3838
line_kind = nil
@@ -101,37 +101,59 @@ def scan_tokens encoder, options
101101
end
102102
next
103103
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
104+
deleted_lines_count += 1
105+
if options[:inline_diff] && deleted_lines_count == 1 && (changed_lines_count = 1 + check(/(?>.*(?:\n\-.*)*)/).count("\n")) && match?(/(?>.*(?:\n\-.*){#{changed_lines_count - 1}}(?:\n\+.*){#{changed_lines_count}})$(?!\n\+)/)
106+
deleted_lines = Array.new(changed_lines_count) { |i| skip(/\n\-/) if i > 0; scan(/.*/) }
107+
inserted_lines = Array.new(changed_lines_count) { |i| skip(/\n\+/) ; scan(/.*/) }
108+
109+
deleted_lines_tokenized = []
110+
inserted_lines_tokenized = []
111+
for deleted_line, inserted_line in deleted_lines.zip(inserted_lines)
112+
pre, deleted_part, inserted_part, post = diff deleted_line, inserted_line
113+
content_scanner_entry_state = content_scanner.state
114+
deleted_lines_tokenized << content_scanner.tokenize([pre, deleted_part, post], :tokens => Tokens.new)
115+
content_scanner.state = content_scanner_entry_state || :initial
116+
inserted_lines_tokenized << content_scanner.tokenize([pre, inserted_part, post], :tokens => Tokens.new)
117117
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
118+
119+
for pre, deleted_part, post in deleted_lines_tokenized
120+
encoder.begin_line :delete
121+
encoder.text_token '-', :delete
122+
encoder.tokens pre
123+
unless deleted_part.empty?
124+
encoder.begin_group :eyecatcher
125+
encoder.tokens deleted_part
126+
encoder.end_group :eyecatcher
127+
end
128+
encoder.tokens post
129+
encoder.end_line :delete
130+
encoder.text_token "\n", :space
131+
end
132+
133+
for pre, inserted_part, post in inserted_lines_tokenized
134+
encoder.begin_line :insert
135+
encoder.text_token '+', :insert
136+
encoder.tokens pre
137+
unless inserted_part.empty?
138+
encoder.begin_group :eyecatcher
139+
encoder.tokens inserted_part
140+
encoder.end_group :eyecatcher
141+
end
142+
encoder.tokens post
143+
changed_lines_count -= 1
144+
if changed_lines_count > 0
145+
encoder.end_line :insert
146+
encoder.text_token "\n", :space
147+
end
130148
end
131-
encoder.tokens post
149+
150+
line_kind = :insert
151+
132152
elsif match = scan(/.*/)
153+
encoder.begin_line line_kind = :delete
154+
encoder.text_token '-', :delete
133155
if options[:highlight_code]
134-
if deleted_lines == 1
156+
if deleted_lines_count == 1
135157
content_scanner_entry_state = content_scanner.state
136158
end
137159
content_scanner.tokenize match, :tokens => encoder unless match.empty?

lib/coderay/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module CodeRay
2-
VERSION = '1.0.4'
2+
VERSION = '1.0.5'
33
end

0 commit comments

Comments
 (0)