Skip to content

Multiline Inline Diff #99

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 10, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 51 additions & 29 deletions lib/coderay/scanners/diff.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def scan_tokens encoder, options

line_kind = nil
state = :initial
deleted_lines = 0
deleted_lines_count = 0
scanners = Hash.new do |h, lang|
h[lang] = Scanners[lang].new '', :keep_tokens => true, :keep_state => true
end
Expand All @@ -30,7 +30,7 @@ def scan_tokens encoder, options
until eos?

if match = scan(/\n/)
deleted_lines = 0 unless line_kind == :delete
deleted_lines_count = 0 unless line_kind == :delete
if line_kind
encoder.end_line line_kind
line_kind = nil
Expand Down Expand Up @@ -99,37 +99,59 @@ def scan_tokens encoder, options
end
next
elsif match = scan(/-/)
deleted_lines += 1
encoder.begin_line line_kind = :delete
encoder.text_token match, :delete
if options[:inline_diff] && deleted_lines == 1 && check(/(?>.*)\n\+(?>.*)$(?!\n\+)/)
content_scanner_entry_state = content_scanner.state
skip(/(.*)\n\+(.*)$/)
head, deletion, insertion, tail = diff self[1], self[2]
pre, deleted, post = content_scanner.tokenize [head, deletion, tail], :tokens => Tokens.new
encoder.tokens pre
unless deleted.empty?
encoder.begin_group :eyecatcher
encoder.tokens deleted
encoder.end_group :eyecatcher
deleted_lines_count += 1
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\+)/)
deleted_lines = Array.new(changed_lines_count) { |i| skip(/\n\-/) if i > 0; scan(/.*/) }
inserted_lines = Array.new(changed_lines_count) { |i| skip(/\n\+/) ; scan(/.*/) }

deleted_lines_tokenized = []
inserted_lines_tokenized = []
for deleted_line, inserted_line in deleted_lines.zip(inserted_lines)
pre, deleted_part, inserted_part, post = diff deleted_line, inserted_line
content_scanner_entry_state = content_scanner.state
deleted_lines_tokenized << content_scanner.tokenize([pre, deleted_part, post], :tokens => Tokens.new)
content_scanner.state = content_scanner_entry_state || :initial
inserted_lines_tokenized << content_scanner.tokenize([pre, inserted_part, post], :tokens => Tokens.new)
end
encoder.tokens post
encoder.end_line line_kind
encoder.text_token "\n", :space
encoder.begin_line line_kind = :insert
encoder.text_token '+', :insert
content_scanner.state = content_scanner_entry_state || :initial
pre, inserted, post = content_scanner.tokenize [head, insertion, tail], :tokens => Tokens.new
encoder.tokens pre
unless inserted.empty?
encoder.begin_group :eyecatcher
encoder.tokens inserted
encoder.end_group :eyecatcher

for pre, deleted_part, post in deleted_lines_tokenized
encoder.begin_line :delete
encoder.text_token '-', :delete
encoder.tokens pre
unless deleted_part.empty?
encoder.begin_group :eyecatcher
encoder.tokens deleted_part
encoder.end_group :eyecatcher
end
encoder.tokens post
encoder.end_line :delete
encoder.text_token "\n", :space
end

for pre, inserted_part, post in inserted_lines_tokenized
encoder.begin_line :insert
encoder.text_token '+', :insert
encoder.tokens pre
unless inserted_part.empty?
encoder.begin_group :eyecatcher
encoder.tokens inserted_part
encoder.end_group :eyecatcher
end
encoder.tokens post
changed_lines_count -= 1
if changed_lines_count > 0
encoder.end_line :insert
encoder.text_token "\n", :space
end
end
encoder.tokens post

line_kind = :insert

elsif match = scan(/.*/)
encoder.begin_line line_kind = :delete
encoder.text_token '-', :delete
if options[:highlight_code]
if deleted_lines == 1
if deleted_lines_count == 1
content_scanner_entry_state = content_scanner.state
end
content_scanner.tokenize match, :tokens => encoder unless match.empty?
Expand Down
2 changes: 1 addition & 1 deletion lib/coderay/scanners/erb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def reset_instance
end

def scan_tokens encoder, options

# FIXME: keep_state
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's this about?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of scanners don't keep their state around yet. Most don't even use the state protocol. It's a TODO, related but not essential for this feature.

until eos?

if (match = scan_until(/(?=#{START_OF_ERB})/o) || scan_rest) and not match.empty?
Expand Down