diff-lcs 1.3 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/Contributing.md +86 -48
- data/History.md +370 -159
- data/License.md +6 -4
- data/Manifest.txt +23 -1
- data/README.rdoc +10 -10
- data/Rakefile +109 -36
- data/bin/htmldiff +9 -6
- data/bin/ldiff +4 -1
- data/lib/diff/lcs/array.rb +2 -2
- data/lib/diff/lcs/backports.rb +9 -0
- data/lib/diff/lcs/block.rb +5 -5
- data/lib/diff/lcs/callbacks.rb +22 -17
- data/lib/diff/lcs/change.rb +42 -49
- data/lib/diff/lcs/htmldiff.rb +21 -12
- data/lib/diff/lcs/hunk.rb +160 -73
- data/lib/diff/lcs/internals.rb +57 -56
- data/lib/diff/lcs/ldiff.rb +63 -57
- data/lib/diff/lcs/string.rb +1 -1
- data/lib/diff/lcs.rb +226 -210
- data/lib/diff-lcs.rb +2 -2
- data/spec/change_spec.rb +58 -34
- data/spec/diff_spec.rb +13 -9
- data/spec/fixtures/aX +1 -0
- data/spec/fixtures/bXaX +1 -0
- data/spec/fixtures/ldiff/output.diff +4 -0
- data/spec/fixtures/ldiff/output.diff-c +7 -0
- data/spec/fixtures/ldiff/output.diff-e +3 -0
- data/spec/fixtures/ldiff/output.diff-f +3 -0
- data/spec/fixtures/ldiff/output.diff-u +5 -0
- data/spec/fixtures/ldiff/output.diff.chef +4 -0
- data/spec/fixtures/ldiff/output.diff.chef-c +15 -0
- data/spec/fixtures/ldiff/output.diff.chef-e +3 -0
- data/spec/fixtures/ldiff/output.diff.chef-f +3 -0
- data/spec/fixtures/ldiff/output.diff.chef-u +9 -0
- data/spec/fixtures/ldiff/output.diff.chef2 +7 -0
- data/spec/fixtures/ldiff/output.diff.chef2-c +20 -0
- data/spec/fixtures/ldiff/output.diff.chef2-d +7 -0
- data/spec/fixtures/ldiff/output.diff.chef2-e +7 -0
- data/spec/fixtures/ldiff/output.diff.chef2-f +7 -0
- data/spec/fixtures/ldiff/output.diff.chef2-u +16 -0
- data/spec/fixtures/new-chef +4 -0
- data/spec/fixtures/new-chef2 +17 -0
- data/spec/fixtures/old-chef +4 -0
- data/spec/fixtures/old-chef2 +14 -0
- data/spec/hunk_spec.rb +48 -37
- data/spec/issues_spec.rb +132 -21
- data/spec/lcs_spec.rb +3 -3
- data/spec/ldiff_spec.rb +74 -32
- data/spec/patch_spec.rb +14 -20
- data/spec/sdiff_spec.rb +83 -81
- data/spec/spec_helper.rb +146 -91
- data/spec/traverse_balanced_spec.rb +138 -136
- data/spec/traverse_sequences_spec.rb +7 -9
- metadata +76 -48
- data/autotest/discover.rb +0 -1
data/lib/diff/lcs/htmldiff.rb
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "cgi"
|
|
4
4
|
|
|
5
|
+
# Produce a simple HTML diff view.
|
|
5
6
|
class Diff::LCS::HTMLDiff
|
|
6
7
|
class << self
|
|
7
|
-
attr_accessor :can_expand_tabs
|
|
8
|
+
attr_accessor :can_expand_tabs # :nodoc:
|
|
8
9
|
end
|
|
9
10
|
self.can_expand_tabs = true
|
|
10
11
|
|
|
11
|
-
class Callbacks
|
|
12
|
+
class Callbacks # :nodoc:
|
|
12
13
|
attr_accessor :output
|
|
13
14
|
attr_accessor :match_class
|
|
14
15
|
attr_accessor :only_a_class
|
|
@@ -25,7 +26,7 @@ class Diff::LCS::HTMLDiff
|
|
|
25
26
|
|
|
26
27
|
def htmlize(element, css_class)
|
|
27
28
|
element = " " if element.empty?
|
|
28
|
-
%
|
|
29
|
+
%(<pre class="#{__send__(css_class)}">#{element}</pre>\n)
|
|
29
30
|
end
|
|
30
31
|
private :htmlize
|
|
31
32
|
|
|
@@ -45,13 +46,16 @@ class Diff::LCS::HTMLDiff
|
|
|
45
46
|
end
|
|
46
47
|
end
|
|
47
48
|
|
|
49
|
+
# standard:disable Style/HashSyntax
|
|
48
50
|
DEFAULT_OPTIONS = {
|
|
49
51
|
:expand_tabs => nil,
|
|
50
52
|
:output => nil,
|
|
51
53
|
:css => nil,
|
|
52
|
-
:title => nil
|
|
53
|
-
}
|
|
54
|
+
:title => nil
|
|
55
|
+
}.freeze
|
|
56
|
+
# standard:enable Style/HashSyntax
|
|
54
57
|
|
|
58
|
+
# standard:disable Layout/HeredocIndentation
|
|
55
59
|
DEFAULT_CSS = <<-CSS
|
|
56
60
|
body { margin: 0; }
|
|
57
61
|
.diff
|
|
@@ -85,18 +89,19 @@ pre
|
|
|
85
89
|
}
|
|
86
90
|
h1 { margin-left: 2em; }
|
|
87
91
|
CSS
|
|
92
|
+
# standard:enable Layout/HeredocIndentation
|
|
88
93
|
|
|
89
94
|
def initialize(left, right, options = nil)
|
|
90
|
-
@left
|
|
91
|
-
@right
|
|
92
|
-
@options
|
|
95
|
+
@left = left
|
|
96
|
+
@right = right
|
|
97
|
+
@options = options
|
|
93
98
|
|
|
94
99
|
@options = DEFAULT_OPTIONS.dup if @options.nil?
|
|
95
100
|
end
|
|
96
101
|
|
|
97
102
|
def verify_options
|
|
98
103
|
@options[:expand_tabs] ||= 4
|
|
99
|
-
@options[:expand_tabs] = 4 if @options[:expand_tabs]
|
|
104
|
+
@options[:expand_tabs] = 4 if @options[:expand_tabs].negative?
|
|
100
105
|
|
|
101
106
|
@options[:output] ||= $stdout
|
|
102
107
|
|
|
@@ -111,7 +116,7 @@ h1 { margin-left: 2em; }
|
|
|
111
116
|
def run
|
|
112
117
|
verify_options
|
|
113
118
|
|
|
114
|
-
if @options[:expand_tabs]
|
|
119
|
+
if @options[:expand_tabs].positive? && self.class.can_expand_tabs
|
|
115
120
|
formatter = Text::Format.new
|
|
116
121
|
formatter.tabstop = @options[:expand_tabs]
|
|
117
122
|
|
|
@@ -122,6 +127,7 @@ h1 { margin-left: 2em; }
|
|
|
122
127
|
@left.map! { |line| CGI.escapeHTML(line.chomp) }
|
|
123
128
|
@right.map! { |line| CGI.escapeHTML(line.chomp) }
|
|
124
129
|
|
|
130
|
+
# standard:disable Layout/HeredocIndentation
|
|
125
131
|
@options[:output] << <<-OUTPUT
|
|
126
132
|
<html>
|
|
127
133
|
<head>
|
|
@@ -136,14 +142,17 @@ h1 { margin-left: 2em; }
|
|
|
136
142
|
<span class="only_b">Only in New</span></p>
|
|
137
143
|
<div class="diff">
|
|
138
144
|
OUTPUT
|
|
145
|
+
# standard:enable Layout/HeredocIndentation
|
|
139
146
|
|
|
140
147
|
callbacks = Callbacks.new(@options[:output])
|
|
141
148
|
Diff::LCS.traverse_sequences(@left, @right, callbacks)
|
|
142
149
|
|
|
150
|
+
# standard:disable Layout/HeredocIndentation
|
|
143
151
|
@options[:output] << <<-OUTPUT
|
|
144
152
|
</div>
|
|
145
153
|
</body>
|
|
146
154
|
</html>
|
|
147
155
|
OUTPUT
|
|
156
|
+
# standard:enable Layout/HeredocIndentation
|
|
148
157
|
end
|
|
149
158
|
end
|
data/lib/diff/lcs/hunk.rb
CHANGED
|
@@ -1,30 +1,42 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "diff/lcs/block"
|
|
4
4
|
|
|
5
|
-
# A Hunk is a group of Blocks which overlap because of the context
|
|
6
|
-
#
|
|
7
|
-
#
|
|
5
|
+
# A Hunk is a group of Blocks which overlap because of the context surrounding
|
|
6
|
+
# each block. (So if we're not using context, every hunk will contain one
|
|
7
|
+
# block.) Used in the diff program (bin/ldiff).
|
|
8
8
|
class Diff::LCS::Hunk
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
OLD_DIFF_OP_ACTION = {"+" => "a", "-" => "d", "!" => "c"}.freeze # :nodoc:
|
|
10
|
+
ED_DIFF_OP_ACTION = {"+" => "a", "-" => "d", "!" => "c"}.freeze # :nodoc:
|
|
11
|
+
|
|
12
|
+
private_constant :OLD_DIFF_OP_ACTION, :ED_DIFF_OP_ACTION if respond_to?(:private_constant)
|
|
13
|
+
|
|
14
|
+
# Create a hunk using references to both the old and new data, as well as the
|
|
15
|
+
# piece of data.
|
|
11
16
|
def initialize(data_old, data_new, piece, flag_context, file_length_difference)
|
|
12
17
|
# At first, a hunk will have just one Block in it
|
|
13
|
-
@blocks = [
|
|
18
|
+
@blocks = [Diff::LCS::Block.new(piece)]
|
|
19
|
+
|
|
20
|
+
if @blocks[0].remove.empty? && @blocks[0].insert.empty?
|
|
21
|
+
fail "Cannot build a hunk from #{piece.inspect}; has no add or remove actions"
|
|
22
|
+
end
|
|
23
|
+
|
|
14
24
|
if String.method_defined?(:encoding)
|
|
15
|
-
@preferred_data_encoding = data_old.fetch(0
|
|
25
|
+
@preferred_data_encoding = data_old.fetch(0) { data_new.fetch(0, "") }.encoding
|
|
16
26
|
end
|
|
27
|
+
|
|
17
28
|
@data_old = data_old
|
|
18
29
|
@data_new = data_new
|
|
19
30
|
|
|
20
31
|
before = after = file_length_difference
|
|
21
32
|
after += @blocks[0].diff_size
|
|
22
33
|
@file_length_difference = after # The caller must get this manually
|
|
34
|
+
@max_diff_size = @blocks.map { |e| e.diff_size.abs }.max
|
|
23
35
|
|
|
24
36
|
# Save the start & end of each array. If the array doesn't exist (e.g.,
|
|
25
|
-
# we're only adding items in this block), then figure out the line
|
|
26
|
-
#
|
|
27
|
-
#
|
|
37
|
+
# we're only adding items in this block), then figure out the line number
|
|
38
|
+
# based on the line number of the other file and the current difference in
|
|
39
|
+
# file lengths.
|
|
28
40
|
if @blocks[0].remove.empty?
|
|
29
41
|
a1 = a2 = nil
|
|
30
42
|
else
|
|
@@ -41,8 +53,8 @@ class Diff::LCS::Hunk
|
|
|
41
53
|
|
|
42
54
|
@start_old = a1 || (b1 - before)
|
|
43
55
|
@start_new = b1 || (a1 + before)
|
|
44
|
-
@end_old
|
|
45
|
-
@end_new
|
|
56
|
+
@end_old = a2 || (b2 - after)
|
|
57
|
+
@end_new = b2 || (a2 + after)
|
|
46
58
|
|
|
47
59
|
self.flag_context = flag_context
|
|
48
60
|
end
|
|
@@ -55,19 +67,26 @@ class Diff::LCS::Hunk
|
|
|
55
67
|
# Change the "start" and "end" fields to note that context should be added
|
|
56
68
|
# to this hunk.
|
|
57
69
|
attr_accessor :flag_context
|
|
58
|
-
undef :flag_context
|
|
59
|
-
def flag_context=(context)
|
|
60
|
-
return if context.nil?
|
|
70
|
+
undef :flag_context=
|
|
71
|
+
def flag_context=(context) # :nodoc: # standard:disable Lint/DuplicateMethods
|
|
72
|
+
return if context.nil? || context.zero?
|
|
61
73
|
|
|
62
74
|
add_start = (context > @start_old) ? @start_old : context
|
|
75
|
+
|
|
63
76
|
@start_old -= add_start
|
|
64
77
|
@start_new -= add_start
|
|
65
78
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
79
|
+
old_size = @data_old.size
|
|
80
|
+
|
|
81
|
+
add_end =
|
|
82
|
+
if (@end_old + context) > old_size
|
|
83
|
+
old_size - @end_old
|
|
84
|
+
else
|
|
85
|
+
context
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
add_end = @max_diff_size if add_end >= old_size
|
|
89
|
+
|
|
71
90
|
@end_old += add_end
|
|
72
91
|
@end_new += add_end
|
|
73
92
|
end
|
|
@@ -76,13 +95,11 @@ class Diff::LCS::Hunk
|
|
|
76
95
|
# a truthy value so that if there is no overlap, you can know the merge
|
|
77
96
|
# was skipped.
|
|
78
97
|
def merge(hunk)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
nil
|
|
85
|
-
end
|
|
98
|
+
return unless overlaps?(hunk)
|
|
99
|
+
|
|
100
|
+
@start_old = hunk.start_old
|
|
101
|
+
@start_new = hunk.start_new
|
|
102
|
+
blocks.unshift(*hunk.blocks)
|
|
86
103
|
end
|
|
87
104
|
alias_method :unshift, :merge
|
|
88
105
|
|
|
@@ -95,47 +112,53 @@ class Diff::LCS::Hunk
|
|
|
95
112
|
end
|
|
96
113
|
|
|
97
114
|
# Returns a diff string based on a format.
|
|
98
|
-
def diff(format)
|
|
115
|
+
def diff(format, last = false)
|
|
99
116
|
case format
|
|
100
117
|
when :old
|
|
101
|
-
old_diff
|
|
118
|
+
old_diff(last)
|
|
102
119
|
when :unified
|
|
103
|
-
unified_diff
|
|
120
|
+
unified_diff(last)
|
|
104
121
|
when :context
|
|
105
|
-
context_diff
|
|
122
|
+
context_diff(last)
|
|
106
123
|
when :ed
|
|
107
124
|
self
|
|
108
125
|
when :reverse_ed, :ed_finish
|
|
109
|
-
ed_diff(format)
|
|
126
|
+
ed_diff(format, last)
|
|
110
127
|
else
|
|
111
|
-
|
|
128
|
+
fail "Unknown diff format #{format}."
|
|
112
129
|
end
|
|
113
130
|
end
|
|
114
131
|
|
|
115
132
|
# Note that an old diff can't have any context. Therefore, we know that
|
|
116
133
|
# there's only one block in the hunk.
|
|
117
|
-
def old_diff
|
|
134
|
+
def old_diff(_last = false)
|
|
118
135
|
warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1
|
|
119
|
-
op_act = { "+" => 'a', "-" => 'd', "!" => "c" }
|
|
120
136
|
|
|
121
137
|
block = @blocks[0]
|
|
122
138
|
|
|
123
139
|
# Calculate item number range. Old diff range is just like a context
|
|
124
140
|
# diff range, except the ranges are on one line with the action between
|
|
125
141
|
# them.
|
|
126
|
-
s = encode("#{context_range(:old)}#{
|
|
142
|
+
s = encode("#{context_range(:old, ",")}#{OLD_DIFF_OP_ACTION[block.op]}#{context_range(:new, ",")}\n")
|
|
127
143
|
# If removing anything, just print out all the remove lines in the hunk
|
|
128
144
|
# which is just all the remove lines in the block.
|
|
129
|
-
|
|
145
|
+
unless block.remove.empty?
|
|
146
|
+
@data_old[@start_old..@end_old].each { |e| s << encode("< ") + e.chomp + encode("\n") }
|
|
147
|
+
end
|
|
148
|
+
|
|
130
149
|
s << encode("---\n") if block.op == "!"
|
|
131
|
-
|
|
150
|
+
|
|
151
|
+
unless block.insert.empty?
|
|
152
|
+
@data_new[@start_new..@end_new].each { |e| s << encode("> ") + e.chomp + encode("\n") }
|
|
153
|
+
end
|
|
154
|
+
|
|
132
155
|
s
|
|
133
156
|
end
|
|
134
157
|
private :old_diff
|
|
135
158
|
|
|
136
|
-
def unified_diff
|
|
159
|
+
def unified_diff(last = false)
|
|
137
160
|
# Calculate item number range.
|
|
138
|
-
s = encode("@@ -#{unified_range(:old)} +#{unified_range(:new)} @@\n")
|
|
161
|
+
s = encode("@@ -#{unified_range(:old, last)} +#{unified_range(:new, last)} @@\n")
|
|
139
162
|
|
|
140
163
|
# Outlist starts containing the hunk of the old file. Removing an item
|
|
141
164
|
# just means putting a '-' in front of it. Inserting an item requires
|
|
@@ -148,75 +171,122 @@ class Diff::LCS::Hunk
|
|
|
148
171
|
# file -- don't take removed items into account.
|
|
149
172
|
lo, hi, num_added, num_removed = @start_old, @end_old, 0, 0
|
|
150
173
|
|
|
151
|
-
|
|
174
|
+
# standard:disable Performance/UnfreezeString
|
|
175
|
+
outlist = @data_old[lo..hi].map { |e| String.new("#{encode(" ")}#{e.chomp}") }
|
|
176
|
+
# standard:enable Performance/UnfreezeString
|
|
177
|
+
|
|
178
|
+
last_block = blocks[-1]
|
|
179
|
+
|
|
180
|
+
if last
|
|
181
|
+
old_missing_newline = missing_last_newline?(@data_old)
|
|
182
|
+
new_missing_newline = missing_last_newline?(@data_new)
|
|
183
|
+
end
|
|
152
184
|
|
|
153
185
|
@blocks.each do |block|
|
|
154
186
|
block.remove.each do |item|
|
|
155
|
-
op
|
|
187
|
+
op = item.action.to_s # -
|
|
156
188
|
offset = item.position - lo + num_added
|
|
157
189
|
outlist[offset][0, 1] = encode(op)
|
|
158
190
|
num_removed += 1
|
|
159
191
|
end
|
|
192
|
+
|
|
193
|
+
if last && block == last_block && old_missing_newline && !new_missing_newline
|
|
194
|
+
outlist << encode('\')
|
|
195
|
+
num_removed += 1
|
|
196
|
+
end
|
|
197
|
+
|
|
160
198
|
block.insert.each do |item|
|
|
161
|
-
op
|
|
199
|
+
op = item.action.to_s # +
|
|
162
200
|
offset = item.position - @start_new + num_removed
|
|
163
|
-
outlist[offset, 0] = encode(op) + @data_new[item.position]
|
|
201
|
+
outlist[offset, 0] = encode(op) + @data_new[item.position].chomp
|
|
164
202
|
num_added += 1
|
|
165
203
|
end
|
|
166
204
|
end
|
|
167
205
|
|
|
206
|
+
outlist << encode('\') if last && new_missing_newline
|
|
207
|
+
|
|
168
208
|
s << outlist.join(encode("\n"))
|
|
209
|
+
|
|
210
|
+
s
|
|
169
211
|
end
|
|
170
212
|
private :unified_diff
|
|
171
213
|
|
|
172
|
-
def context_diff
|
|
214
|
+
def context_diff(last = false)
|
|
173
215
|
s = encode("***************\n")
|
|
174
|
-
s << encode("*** #{context_range(:old)} ****\n")
|
|
175
|
-
r = context_range(:new)
|
|
216
|
+
s << encode("*** #{context_range(:old, ",", last)} ****\n")
|
|
217
|
+
r = context_range(:new, ",", last)
|
|
218
|
+
|
|
219
|
+
if last
|
|
220
|
+
old_missing_newline = missing_last_newline?(@data_old)
|
|
221
|
+
new_missing_newline = missing_last_newline?(@data_new)
|
|
222
|
+
end
|
|
176
223
|
|
|
177
224
|
# Print out file 1 part for each block in context diff format if there
|
|
178
225
|
# are any blocks that remove items
|
|
179
226
|
lo, hi = @start_old, @end_old
|
|
180
|
-
removes = @blocks.
|
|
181
|
-
|
|
182
|
-
|
|
227
|
+
removes = @blocks.reject { |e| e.remove.empty? }
|
|
228
|
+
|
|
229
|
+
unless removes.empty?
|
|
230
|
+
# standard:disable Performance/UnfreezeString
|
|
231
|
+
outlist = @data_old[lo..hi].map { |e| String.new("#{encode(" ")}#{e.chomp}") }
|
|
232
|
+
# standard:enable Performance/UnfreezeString
|
|
233
|
+
|
|
234
|
+
last_block = removes[-1]
|
|
183
235
|
|
|
184
236
|
removes.each do |block|
|
|
185
237
|
block.remove.each do |item|
|
|
186
238
|
outlist[item.position - lo][0, 1] = encode(block.op) # - or !
|
|
187
239
|
end
|
|
240
|
+
|
|
241
|
+
if last && block == last_block && old_missing_newline
|
|
242
|
+
outlist << encode('\')
|
|
243
|
+
end
|
|
188
244
|
end
|
|
189
|
-
|
|
245
|
+
|
|
246
|
+
s << outlist.join(encode("\n")) << encode("\n")
|
|
190
247
|
end
|
|
191
248
|
|
|
192
|
-
s << encode("
|
|
249
|
+
s << encode("--- #{r} ----\n")
|
|
193
250
|
lo, hi = @start_new, @end_new
|
|
194
|
-
inserts = @blocks.
|
|
195
|
-
|
|
196
|
-
|
|
251
|
+
inserts = @blocks.reject { |e| e.insert.empty? }
|
|
252
|
+
|
|
253
|
+
unless inserts.empty?
|
|
254
|
+
# standard:disable Performance/UnfreezeString
|
|
255
|
+
outlist = @data_new[lo..hi].map { |e| String.new("#{encode(" ")}#{e.chomp}") }
|
|
256
|
+
# standard:enable Performance/UnfreezeString
|
|
257
|
+
|
|
258
|
+
last_block = inserts[-1]
|
|
259
|
+
|
|
197
260
|
inserts.each do |block|
|
|
198
261
|
block.insert.each do |item|
|
|
199
262
|
outlist[item.position - lo][0, 1] = encode(block.op) # + or !
|
|
200
263
|
end
|
|
264
|
+
|
|
265
|
+
if last && block == last_block && new_missing_newline
|
|
266
|
+
outlist << encode('\')
|
|
267
|
+
end
|
|
201
268
|
end
|
|
202
|
-
s << outlist.join("\n")
|
|
269
|
+
s << outlist.join(encode("\n"))
|
|
203
270
|
end
|
|
271
|
+
|
|
204
272
|
s
|
|
205
273
|
end
|
|
206
274
|
private :context_diff
|
|
207
275
|
|
|
208
|
-
def ed_diff(format)
|
|
209
|
-
op_act = { "+" => 'a', "-" => 'd', "!" => "c" }
|
|
276
|
+
def ed_diff(format, _last = false)
|
|
210
277
|
warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1
|
|
211
278
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
279
|
+
s =
|
|
280
|
+
if format == :reverse_ed
|
|
281
|
+
encode("#{ED_DIFF_OP_ACTION[@blocks[0].op]}#{context_range(:old, ",")}\n")
|
|
282
|
+
else
|
|
283
|
+
encode("#{context_range(:old, " ")}#{ED_DIFF_OP_ACTION[@blocks[0].op]}\n")
|
|
284
|
+
end
|
|
217
285
|
|
|
218
286
|
unless @blocks[0].insert.empty?
|
|
219
|
-
@data_new[@start_new
|
|
287
|
+
@data_new[@start_new..@end_new].each do |e|
|
|
288
|
+
s << e.chomp + encode("\n")
|
|
289
|
+
end
|
|
220
290
|
s << encode(".\n")
|
|
221
291
|
end
|
|
222
292
|
s
|
|
@@ -225,7 +295,7 @@ class Diff::LCS::Hunk
|
|
|
225
295
|
|
|
226
296
|
# Generate a range of item numbers to print. Only print 1 number if the
|
|
227
297
|
# range has only one item in it. Otherwise, it's 'start,end'
|
|
228
|
-
def context_range(mode, op =
|
|
298
|
+
def context_range(mode, op, last = false)
|
|
229
299
|
case mode
|
|
230
300
|
when :old
|
|
231
301
|
s, e = (@start_old + 1), (@end_old + 1)
|
|
@@ -233,14 +303,17 @@ class Diff::LCS::Hunk
|
|
|
233
303
|
s, e = (@start_new + 1), (@end_new + 1)
|
|
234
304
|
end
|
|
235
305
|
|
|
236
|
-
|
|
306
|
+
e -= 1 if last
|
|
307
|
+
e = 1 if e.zero?
|
|
308
|
+
|
|
309
|
+
(s < e) ? "#{s}#{op}#{e}" : e.to_s
|
|
237
310
|
end
|
|
238
311
|
private :context_range
|
|
239
312
|
|
|
240
313
|
# Generate a range of item numbers to print for unified diff. Print number
|
|
241
314
|
# where block starts, followed by number of lines in the block
|
|
242
315
|
# (don't print number of lines if it's 1)
|
|
243
|
-
def unified_range(mode)
|
|
316
|
+
def unified_range(mode, last)
|
|
244
317
|
case mode
|
|
245
318
|
when :old
|
|
246
319
|
s, e = (@start_old + 1), (@end_old + 1)
|
|
@@ -248,12 +321,25 @@ class Diff::LCS::Hunk
|
|
|
248
321
|
s, e = (@start_new + 1), (@end_new + 1)
|
|
249
322
|
end
|
|
250
323
|
|
|
251
|
-
length = e - s + 1
|
|
324
|
+
length = e - s + (last ? 0 : 1)
|
|
325
|
+
|
|
252
326
|
first = (length < 2) ? e : s # "strange, but correct"
|
|
253
|
-
(length
|
|
327
|
+
(length <= 1) ? first.to_s : "#{first},#{length}"
|
|
254
328
|
end
|
|
255
329
|
private :unified_range
|
|
256
330
|
|
|
331
|
+
def missing_last_newline?(data)
|
|
332
|
+
newline = encode("\n")
|
|
333
|
+
|
|
334
|
+
if data[-2]
|
|
335
|
+
data[-2].end_with?(newline) && !data[-1].end_with?(newline)
|
|
336
|
+
elsif data[-1]
|
|
337
|
+
!data[-1].end_with?(newline)
|
|
338
|
+
else
|
|
339
|
+
true
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
|
|
257
343
|
if String.method_defined?(:encoding)
|
|
258
344
|
def encode(literal, target_encoding = @preferred_data_encoding)
|
|
259
345
|
literal.encode target_encoding
|
|
@@ -263,10 +349,11 @@ class Diff::LCS::Hunk
|
|
|
263
349
|
args.map { |arg| arg.encode(string.encoding) }
|
|
264
350
|
end
|
|
265
351
|
else
|
|
266
|
-
def encode(literal,
|
|
352
|
+
def encode(literal, _target_encoding = nil)
|
|
267
353
|
literal
|
|
268
354
|
end
|
|
269
|
-
|
|
355
|
+
|
|
356
|
+
def encode_as(_string, *args)
|
|
270
357
|
args
|
|
271
358
|
end
|
|
272
359
|
end
|