_diff_lines(from_start, from_end, to_start, to_end)
click to toggle source
def _diff_lines(from_start, from_end, to_start, to_end)
if from_start < from_end
if to_start < to_end
diff_lines(from_start, from_end, to_start, to_end)
else
tag_deleted(@from[from_start...from_end])
end
else
tag_inserted(@to[to_start...to_end])
end
end
compute_width(line, start, _end)
click to toggle source
def compute_width(line, start, _end)
if line.respond_to?(:encoding) and
Encoding.compatible?(Encoding::UTF_8, line.encoding)
utf8_line = line[start..._end].encode(Encoding::UTF_8)
width = 0
utf8_line.each_codepoint do |unicode_codepoint|
if UTF8Line.wide_character?(unicode_codepoint)
width += 2
else
width += 1
end
end
width
elsif line.is_a?(UTF8Line)
line.compute_width(start, _end)
else
_end - start
end
end
cut_off_ratio()
click to toggle source
def cut_off_ratio
0.75
end
default_ratio()
click to toggle source
def default_ratio
0.74
end
diff_line(from_line, to_line)
click to toggle source
def diff_line(from_line, to_line)
from_tags = ""
to_tags = ""
from_line, to_line, _operations = line_operations(from_line, to_line)
_operations.each do |tag, from_start, from_end, to_start, to_end|
from_width = compute_width(from_line, from_start, from_end)
to_width = compute_width(to_line, to_start, to_end)
case tag
when :replace
from_tags << "^" * from_width
to_tags << "^" * to_width
when :delete
from_tags << "-" * from_width
when :insert
to_tags << "+" * to_width
when :equal
from_tags << " " * from_width
to_tags << " " * to_width
else
raise "unknown tag: #{tag}"
end
end
format_diff_point(from_line, to_line, from_tags, to_tags)
end
diff_lines(from_start, from_end, to_start, to_end)
click to toggle source
def diff_lines(from_start, from_end, to_start, to_end)
info = find_diff_line_info(from_start, from_end, to_start, to_end)
best_ratio, from_equal_index, to_equal_index, *info = info
from_best_index, to_best_index = info
from_best_index ||= from_start
to_best_index ||= to_start
if best_ratio < cut_off_ratio
if from_equal_index.nil?
if to_end - to_start < from_end - from_start
tag_inserted(@to[to_start...to_end])
tag_deleted(@from[from_start...from_end])
else
tag_deleted(@from[from_start...from_end])
tag_inserted(@to[to_start...to_end])
end
return
end
from_best_index = from_equal_index
to_best_index = to_equal_index
best_ratio = 1.0
end
_diff_lines(from_start, from_best_index, to_start, to_best_index)
diff_line(@from[from_best_index], @to[to_best_index])
_diff_lines(from_best_index + 1, from_end, to_best_index + 1, to_end)
end
find_diff_line_info(from_start, from_end, to_start, to_end)
click to toggle source
def find_diff_line_info(from_start, from_end, to_start, to_end)
best_ratio = default_ratio
from_equal_index = to_equal_index = nil
from_best_index = to_best_index = nil
to_start.upto(to_end - 1) do |to_index|
from_start.upto(from_end - 1) do |from_index|
if @from[from_index] == @to[to_index]
from_equal_index ||= from_index
to_equal_index ||= to_index
next
end
matcher = SequenceMatcher.new(@from[from_index], @to[to_index],
&method(:space_character?))
if matcher.ratio > best_ratio
best_ratio = matcher.ratio
from_best_index = from_index
to_best_index = to_index
end
end
end
[best_ratio,
from_equal_index, to_equal_index,
from_best_index, to_best_index]
end
line_operations(from_line, to_line)
click to toggle source
def line_operations(from_line, to_line)
if !from_line.respond_to?(:force_encoding) and $KCODE == "UTF8"
from_line = UTF8Line.new(from_line)
to_line = UTF8Line.new(to_line)
end
matcher = SequenceMatcher.new(from_line, to_line,
&method(:space_character?))
[from_line, to_line, matcher.operations]
end
n_leading_characters(string, character)
click to toggle source
def n_leading_characters(string, character)
n = 0
while string[n] == character
n += 1
end
n
end
operations()
click to toggle source
def operations
@operations ||= nil
if @operations.nil?
matcher = SequenceMatcher.new(@from, @to)
@operations = matcher.operations
end
@operations
end
space_character?(character)
click to toggle source
def space_character?(character)
[" "[0], "\t"[0]].include?(character)
end
tag(mark, contents)
click to toggle source
def tag(mark, contents)
contents.each do |content|
@result << "#{mark}#{content}"
end
end
tag_deleted(contents)
click to toggle source
def tag_deleted(contents)
tag("- ", contents)
end
tag_difference(contents)
click to toggle source
def tag_difference(contents)
tag("? ", contents)
end
tag_equal(contents)
click to toggle source
def tag_equal(contents)
tag(" ", contents)
end
tag_inserted(contents)
click to toggle source
def tag_inserted(contents)
tag("+ ", contents)
end