diff-lcs 1.6.1 → 2.0.0.beta.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 +4 -4
- data/CHANGELOG.md +48 -0
- data/CONTRIBUTING.md +85 -34
- data/CONTRIBUTORS.md +1 -0
- data/LICENCE.md +39 -11
- data/Manifest.txt +3 -13
- data/README.md +1 -1
- data/Rakefile +29 -55
- data/SECURITY.md +27 -23
- data/lib/diff/lcs/block.rb +29 -24
- data/lib/diff/lcs/callbacks.rb +240 -242
- data/lib/diff/lcs/change.rb +84 -91
- data/lib/diff/lcs/hunk.rb +92 -155
- data/lib/diff/lcs/internals.rb +92 -96
- data/lib/diff/lcs/ldiff.rb +21 -34
- data/lib/diff/lcs/version.rb +1 -1
- data/lib/diff/lcs.rb +439 -466
- data/licenses/dco.txt +34 -0
- data/spec/hunk_spec.rb +0 -11
- data/spec/lcs_spec.rb +6 -6
- data/spec/ldiff_spec.rb +1 -1
- data/spec/spec_helper.rb +14 -16
- metadata +91 -36
- data/.rspec +0 -1
- data/bin/htmldiff +0 -35
- data/lib/diff/lcs/backports.rb +0 -9
- data/lib/diff/lcs/htmldiff.rb +0 -160
- data/mise.toml +0 -5
- data/spec/fixtures/ldiff/output.diff-e +0 -3
- data/spec/fixtures/ldiff/output.diff-f +0 -3
- data/spec/fixtures/ldiff/output.diff.chef-e +0 -3
- data/spec/fixtures/ldiff/output.diff.chef-f +0 -3
- data/spec/fixtures/ldiff/output.diff.chef2-e +0 -7
- data/spec/fixtures/ldiff/output.diff.chef2-f +0 -7
- /data/{docs → licenses}/COPYING.txt +0 -0
- /data/{docs → licenses}/artistic.txt +0 -0
data/lib/diff/lcs/change.rb
CHANGED
|
@@ -1,53 +1,49 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
# enumerable.
|
|
6
|
-
class Diff::LCS::Change
|
|
7
|
-
IntClass = 1.class # Fixnum is deprecated in Ruby 2.4 # standard:disable Naming/ConstantName
|
|
3
|
+
Diff::LCS::Change = Data.define(:action, :position, :element) # :nodoc:
|
|
4
|
+
Diff::LCS::ContextChange = Data.define(:action, :old_position, :old_element, :new_position, :new_element) # :nodoc:
|
|
8
5
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
#
|
|
6
|
+
# Represents a simplistic (non-contextual) change. Represents the removal or addition of
|
|
7
|
+
# an element from either the old or the new sequenced enumerable.
|
|
8
|
+
class Diff::LCS::Change
|
|
9
|
+
# The only actions valid for changes are '+' (add), '-' (delete), '=' (no change), '!'
|
|
10
|
+
# (changed), '<' (tail changes from first sequence), or '>' (tail changes from second
|
|
11
|
+
# sequence). The last two ('<>') are only found with Diff::LCS::diff and
|
|
12
|
+
# Diff::LCS::sdiff.
|
|
13
13
|
VALID_ACTIONS = %w[+ - = ! > <].freeze
|
|
14
14
|
|
|
15
|
-
def self.valid_action?(action)
|
|
16
|
-
VALID_ACTIONS.include? action
|
|
17
|
-
end
|
|
15
|
+
def self.valid_action?(action) = VALID_ACTIONS.include?(action)
|
|
18
16
|
|
|
17
|
+
##
|
|
19
18
|
# Returns the action this Change represents.
|
|
20
|
-
attr_reader
|
|
19
|
+
# :attr_reader: action
|
|
21
20
|
|
|
21
|
+
##
|
|
22
22
|
# Returns the position of the Change.
|
|
23
|
-
attr_reader
|
|
24
|
-
# Returns the sequence element of the Change.
|
|
25
|
-
attr_reader :element
|
|
23
|
+
# :attr_reader: position
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
##
|
|
26
|
+
# Returns the sequence element of the Change.
|
|
27
|
+
# :attr_reader: element
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
fail "Invalid
|
|
32
|
-
|
|
29
|
+
def initialize(action:, position:, element:)
|
|
30
|
+
fail "Invalid Change Action '#{action}'" unless Diff::LCS::Change.valid_action?(action)
|
|
31
|
+
fail "Invalid Position Type" unless position.is_a?(Integer)
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
"#<#{self.class}: #{to_a.inspect}>"
|
|
33
|
+
super
|
|
36
34
|
end
|
|
37
35
|
|
|
38
|
-
def to_a
|
|
39
|
-
[@action, @position, @element]
|
|
40
|
-
end
|
|
36
|
+
def inspect(*_args) = "#<#{self.class}: #{to_a.inspect}>"
|
|
41
37
|
|
|
38
|
+
def to_a = [action, position, element]
|
|
42
39
|
alias_method :to_ary, :to_a
|
|
43
40
|
|
|
44
41
|
def self.from_a(arr)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
Diff::LCS::Change.new(*(arr[0...3]))
|
|
42
|
+
case arr
|
|
43
|
+
in [action, [old_position, old_element], [new_position, new_element]]
|
|
44
|
+
Diff::LCS::ContextChange[action, old_position, old_element, new_position, new_element]
|
|
45
|
+
in [action, position, element]
|
|
46
|
+
new(action, position, element)
|
|
51
47
|
else
|
|
52
48
|
fail "Invalid change array format provided."
|
|
53
49
|
end
|
|
@@ -69,72 +65,57 @@ class Diff::LCS::Change
|
|
|
69
65
|
r
|
|
70
66
|
end
|
|
71
67
|
|
|
72
|
-
def adding?
|
|
73
|
-
@action == "+"
|
|
74
|
-
end
|
|
68
|
+
def adding? = action == "+"
|
|
75
69
|
|
|
76
|
-
def deleting?
|
|
77
|
-
@action == "-"
|
|
78
|
-
end
|
|
70
|
+
def deleting? = action == "-"
|
|
79
71
|
|
|
80
|
-
def unchanged?
|
|
81
|
-
@action == "="
|
|
82
|
-
end
|
|
72
|
+
def unchanged? = action == "="
|
|
83
73
|
|
|
84
|
-
def changed?
|
|
85
|
-
@action == "!"
|
|
86
|
-
end
|
|
74
|
+
def changed? = action == "!"
|
|
87
75
|
|
|
88
|
-
def finished_a?
|
|
89
|
-
@action == ">"
|
|
90
|
-
end
|
|
76
|
+
def finished_a? = action == ">"
|
|
91
77
|
|
|
92
|
-
def finished_b?
|
|
93
|
-
@action == "<"
|
|
94
|
-
end
|
|
78
|
+
def finished_b? = action == "<"
|
|
95
79
|
end
|
|
96
80
|
|
|
97
|
-
# Represents a contextual change. Contains the position and values of the
|
|
98
|
-
#
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
#
|
|
102
|
-
|
|
103
|
-
undef :element
|
|
81
|
+
# Represents a contextual change. Contains the position and values of the elements in the
|
|
82
|
+
# old and the new sequenced enumerable values as well as the action taken.
|
|
83
|
+
class Diff::LCS::ContextChange
|
|
84
|
+
##
|
|
85
|
+
# Returns the action this Change represents.
|
|
86
|
+
# :attr_reader: action
|
|
104
87
|
|
|
88
|
+
##
|
|
105
89
|
# Returns the old position being changed.
|
|
106
|
-
attr_reader
|
|
90
|
+
# :attr_reader: old_position
|
|
91
|
+
|
|
92
|
+
##
|
|
107
93
|
# Returns the new position being changed.
|
|
108
|
-
attr_reader
|
|
94
|
+
# :attr_reader: new_position
|
|
95
|
+
|
|
96
|
+
##
|
|
109
97
|
# Returns the old element being changed.
|
|
110
|
-
attr_reader
|
|
111
|
-
# Returns the new element being changed.
|
|
112
|
-
attr_reader :new_element
|
|
98
|
+
# :attr_reader: old_element
|
|
113
99
|
|
|
114
|
-
|
|
115
|
-
|
|
100
|
+
##
|
|
101
|
+
# Returns the new element being changed.
|
|
102
|
+
# :attr_reader: new_element
|
|
116
103
|
|
|
117
|
-
|
|
118
|
-
fail "Invalid
|
|
119
|
-
fail "Invalid (
|
|
120
|
-
|
|
104
|
+
def initialize(action:, old_position:, old_element:, new_position:, new_element:)
|
|
105
|
+
fail "Invalid Change Action '#{action}'" unless Diff::LCS::Change.valid_action?(action)
|
|
106
|
+
fail "Invalid (Old) Position Type" unless old_position.nil? || old_position.is_a?(Integer)
|
|
107
|
+
fail "Invalid (New) Position Type" unless new_position.nil? || new_position.is_a?(Integer)
|
|
121
108
|
|
|
122
|
-
|
|
123
|
-
[
|
|
124
|
-
@action,
|
|
125
|
-
[@old_position, @old_element],
|
|
126
|
-
[@new_position, @new_element]
|
|
127
|
-
]
|
|
109
|
+
super
|
|
128
110
|
end
|
|
129
111
|
|
|
112
|
+
def to_a = [action, [old_position, old_element], [new_position, new_element]]
|
|
130
113
|
alias_method :to_ary, :to_a
|
|
131
114
|
|
|
132
|
-
def self.from_a(arr)
|
|
133
|
-
Diff::LCS::Change.from_a(arr)
|
|
134
|
-
end
|
|
115
|
+
def self.from_a(arr) = Diff::LCS::Change.from_a(arr)
|
|
135
116
|
|
|
136
|
-
# Simplifies a context change for use in some diff callbacks. '<' actions
|
|
137
|
-
#
|
|
117
|
+
# Simplifies a context change for use in some diff callbacks. '<' actions are converted
|
|
118
|
+
# to '-' and '>' actions are converted to '+'.
|
|
138
119
|
def self.simplify(event)
|
|
139
120
|
ea = event.to_a
|
|
140
121
|
|
|
@@ -151,24 +132,36 @@ class Diff::LCS::ContextChange < Diff::LCS::Change
|
|
|
151
132
|
ea[1][1] = nil
|
|
152
133
|
end
|
|
153
134
|
|
|
154
|
-
|
|
135
|
+
from_a(ea)
|
|
155
136
|
end
|
|
156
137
|
|
|
157
138
|
def ==(other)
|
|
158
|
-
(self.class == other.class)
|
|
159
|
-
(
|
|
160
|
-
(
|
|
161
|
-
(
|
|
162
|
-
(
|
|
163
|
-
(
|
|
139
|
+
(self.class == other.class) &&
|
|
140
|
+
(action == other.action) &&
|
|
141
|
+
(old_position == other.old_position) &&
|
|
142
|
+
(new_position == other.new_position) &&
|
|
143
|
+
(old_element == other.old_element) &&
|
|
144
|
+
(new_element == other.new_element)
|
|
164
145
|
end
|
|
165
146
|
|
|
166
147
|
def <=>(other)
|
|
167
|
-
r =
|
|
168
|
-
r =
|
|
169
|
-
r =
|
|
170
|
-
r =
|
|
171
|
-
r =
|
|
148
|
+
r = action <=> other.action
|
|
149
|
+
r = old_position <=> other.old_position if r.zero?
|
|
150
|
+
r = new_position <=> other.new_position if r.zero?
|
|
151
|
+
r = old_element <=> other.old_element if r.zero?
|
|
152
|
+
r = new_element <=> other.new_element if r.zero?
|
|
172
153
|
r
|
|
173
154
|
end
|
|
155
|
+
|
|
156
|
+
def adding? = action == "+"
|
|
157
|
+
|
|
158
|
+
def deleting? = action == "-"
|
|
159
|
+
|
|
160
|
+
def unchanged? = action == "="
|
|
161
|
+
|
|
162
|
+
def changed? = action == "!"
|
|
163
|
+
|
|
164
|
+
def finished_a? = action == ">"
|
|
165
|
+
|
|
166
|
+
def finished_b? = action == "<"
|
|
174
167
|
end
|
data/lib/diff/lcs/hunk.rb
CHANGED
|
@@ -2,28 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
require "diff/lcs/block"
|
|
4
4
|
|
|
5
|
-
# A Hunk is a group of Blocks which overlap because of the context surrounding
|
|
6
|
-
#
|
|
7
|
-
#
|
|
5
|
+
# A Hunk is a group of Blocks which overlap because of the context surrounding each block.
|
|
6
|
+
# (So if we're not using context, every hunk will contain one block.) Used in the diff
|
|
7
|
+
# program (bin/ldiff).
|
|
8
8
|
class Diff::LCS::Hunk
|
|
9
9
|
OLD_DIFF_OP_ACTION = {"+" => "a", "-" => "d", "!" => "c"}.freeze # :nodoc:
|
|
10
|
-
|
|
10
|
+
private_constant :OLD_DIFF_OP_ACTION
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
# Create a hunk using references to both the old and new data, as well as the
|
|
15
|
-
# piece of data.
|
|
12
|
+
# Create a hunk using references to both the old and new data, as well as the piece of
|
|
13
|
+
# data.
|
|
16
14
|
def initialize(data_old, data_new, piece, flag_context, file_length_difference)
|
|
17
15
|
# At first, a hunk will have just one Block in it
|
|
18
|
-
@blocks = [Diff::LCS::Block.
|
|
16
|
+
@blocks = [Diff::LCS::Block.from_chunk(piece)]
|
|
19
17
|
|
|
20
18
|
if @blocks[0].remove.empty? && @blocks[0].insert.empty?
|
|
21
19
|
fail "Cannot build a hunk from #{piece.inspect}; has no add or remove actions"
|
|
22
20
|
end
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
@preferred_data_encoding = data_old.fetch(0) { data_new.fetch(0) { "" } }.encoding
|
|
23
|
+
@newline = "\n".encode(@preferred_data_encoding)
|
|
24
|
+
@missing_newline = "\".encode(@preferred_data_encoding)
|
|
27
25
|
|
|
28
26
|
@data_old = data_old
|
|
29
27
|
@data_new = data_new
|
|
@@ -35,10 +33,9 @@ class Diff::LCS::Hunk
|
|
|
35
33
|
@file_length_difference = after # The caller must get this manually
|
|
36
34
|
@max_diff_size = @blocks.map { |e| e.diff_size.abs }.max
|
|
37
35
|
|
|
38
|
-
# Save the start
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
# file lengths.
|
|
36
|
+
# Save the start and end of each array. If the array doesn't exist (e.g., we're only
|
|
37
|
+
# adding items in this block), then figure out the line number based on the line
|
|
38
|
+
# number of the other file and the current difference in file lengths.
|
|
42
39
|
if @blocks[0].remove.empty?
|
|
43
40
|
a1 = a2 = nil
|
|
44
41
|
else
|
|
@@ -66,11 +63,13 @@ class Diff::LCS::Hunk
|
|
|
66
63
|
attr_reader :end_old, :end_new
|
|
67
64
|
attr_reader :file_length_difference
|
|
68
65
|
|
|
69
|
-
|
|
70
|
-
# to this hunk.
|
|
71
|
-
attr_accessor :flag_context
|
|
72
|
-
|
|
73
|
-
|
|
66
|
+
##
|
|
67
|
+
# Change the "start" and "end" fields to note that context should be added to this hunk.
|
|
68
|
+
# :attr_accessor: :flag_context
|
|
69
|
+
attr_reader :flag_context
|
|
70
|
+
|
|
71
|
+
##
|
|
72
|
+
def flag_context=(context) # :nodoc:
|
|
74
73
|
return if context.nil? || context.zero?
|
|
75
74
|
|
|
76
75
|
add_start = (context > @start_old) ? @start_old : context
|
|
@@ -91,9 +90,8 @@ class Diff::LCS::Hunk
|
|
|
91
90
|
@end_new += add_end
|
|
92
91
|
end
|
|
93
92
|
|
|
94
|
-
# Merges this hunk and the provided hunk together if they overlap. Returns
|
|
95
|
-
#
|
|
96
|
-
# was skipped.
|
|
93
|
+
# Merges this hunk and the provided hunk together if they overlap. Returns a truthy
|
|
94
|
+
# value so that if there is no overlap, you can know the merge was skipped.
|
|
97
95
|
def merge(hunk)
|
|
98
96
|
return unless overlaps?(hunk)
|
|
99
97
|
|
|
@@ -103,12 +101,11 @@ class Diff::LCS::Hunk
|
|
|
103
101
|
end
|
|
104
102
|
alias_method :unshift, :merge
|
|
105
103
|
|
|
106
|
-
# Determines whether there is an overlap between this hunk and the
|
|
107
|
-
#
|
|
108
|
-
#
|
|
104
|
+
# Determines whether there is an overlap between this hunk and the provided hunk. This
|
|
105
|
+
# will be true if the difference between the two hunks start or end positions is within
|
|
106
|
+
# one position of each other.
|
|
109
107
|
def overlaps?(hunk)
|
|
110
|
-
hunk
|
|
111
|
-
((@start_new - hunk.end_new) <= 1))
|
|
108
|
+
hunk && (((@start_old - hunk.end_old) <= 1) || ((@start_new - hunk.end_new) <= 1))
|
|
112
109
|
end
|
|
113
110
|
|
|
114
111
|
# Returns a diff string based on a format.
|
|
@@ -120,20 +117,21 @@ class Diff::LCS::Hunk
|
|
|
120
117
|
unified_diff(last)
|
|
121
118
|
when :context
|
|
122
119
|
context_diff(last)
|
|
123
|
-
when :ed
|
|
124
|
-
self
|
|
125
|
-
when :reverse_ed, :ed_finish
|
|
126
|
-
ed_diff(format, last)
|
|
127
120
|
else
|
|
128
121
|
fail "Unknown diff format #{format}."
|
|
129
122
|
end
|
|
130
123
|
end
|
|
131
124
|
|
|
132
|
-
|
|
133
|
-
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
# Note that an old diff can't have any context. Therefore, we know that there's only one
|
|
128
|
+
# block in the hunk.
|
|
134
129
|
def old_diff(last = false)
|
|
135
130
|
warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1
|
|
136
131
|
|
|
132
|
+
del, ins, sep, _ = ["< ", "> ", "---\n", "\\n"]
|
|
133
|
+
.map { _1.encode(@preferred_data_encoding) }
|
|
134
|
+
|
|
137
135
|
block = @blocks[0]
|
|
138
136
|
|
|
139
137
|
if last
|
|
@@ -141,47 +139,45 @@ class Diff::LCS::Hunk
|
|
|
141
139
|
new_missing_newline = !@new_empty && missing_last_newline?(@data_new)
|
|
142
140
|
end
|
|
143
141
|
|
|
144
|
-
# Calculate item number range. Old diff range is just like a context
|
|
145
|
-
#
|
|
146
|
-
#
|
|
147
|
-
|
|
148
|
-
# If removing anything, just print out all the remove lines in the hunk
|
|
149
|
-
#
|
|
142
|
+
# Calculate item number range. Old diff range is just like a context diff range,
|
|
143
|
+
# except the ranges are on one line with the action between them.
|
|
144
|
+
s = "#{context_range(:old, ",")}#{OLD_DIFF_OP_ACTION[block.op]}#{context_range(:new, ",")}\n"
|
|
145
|
+
.encode(@preferred_data_encoding)
|
|
146
|
+
# If removing anything, just print out all the remove lines in the hunk which is just
|
|
147
|
+
# all the remove lines in the block.
|
|
150
148
|
unless block.remove.empty?
|
|
151
|
-
@data_old[@start_old..@end_old].each { |e| s <<
|
|
149
|
+
@data_old[@start_old..@end_old].each { |e| s << del + e.chomp + @newline }
|
|
152
150
|
end
|
|
153
151
|
|
|
154
|
-
s <<
|
|
155
|
-
s <<
|
|
152
|
+
s << @missing_newline << @newline if old_missing_newline && !new_missing_newline
|
|
153
|
+
s << sep if block.op == "!"
|
|
156
154
|
|
|
157
155
|
unless block.insert.empty?
|
|
158
|
-
@data_new[@start_new..@end_new].each { |e| s <<
|
|
156
|
+
@data_new[@start_new..@end_new].each { |e| s << ins + e.chomp + @newline }
|
|
159
157
|
end
|
|
160
158
|
|
|
161
|
-
s <<
|
|
159
|
+
s << @missing_newline << @newline if new_missing_newline && !old_missing_newline
|
|
162
160
|
|
|
163
161
|
s
|
|
164
162
|
end
|
|
165
|
-
private :old_diff
|
|
166
163
|
|
|
167
164
|
def unified_diff(last = false)
|
|
168
165
|
# Calculate item number range.
|
|
169
|
-
s =
|
|
166
|
+
s = "@@ -#{unified_range(:old)} +#{unified_range(:new)} @@\n"
|
|
167
|
+
.encode(@preferred_data_encoding)
|
|
170
168
|
|
|
171
|
-
#
|
|
172
|
-
#
|
|
173
|
-
#
|
|
174
|
-
#
|
|
175
|
-
# changed the length of outlist.
|
|
169
|
+
# `outlist` starts containing the hunk of the old file. Removing an item just means
|
|
170
|
+
# putting a '-' in front of it. Inserting an item requires getting it from the new
|
|
171
|
+
# file and splicing it in. We splice in `num_added` items. Remove blocks use
|
|
172
|
+
# `num_added` because splicing changed the length of outlist.
|
|
176
173
|
#
|
|
177
|
-
# We remove
|
|
178
|
-
#
|
|
179
|
-
#
|
|
174
|
+
# We remove `num_removed` items. Insert blocks use `num_removed` because their item
|
|
175
|
+
# numbers -- corresponding to positions in the NEW file -- don't take removed items
|
|
176
|
+
# into account.
|
|
180
177
|
lo, hi, num_added, num_removed = @start_old, @end_old, 0, 0
|
|
181
178
|
|
|
182
|
-
|
|
183
|
-
outlist = @data_old[lo..hi].map { |e|
|
|
184
|
-
# standard:enable Performance/UnfreezeString
|
|
179
|
+
space = " ".encode(@preferred_data_encoding)
|
|
180
|
+
outlist = @data_old[lo..hi].map { |e| "#{space}#{e.chomp}" }
|
|
185
181
|
|
|
186
182
|
last_block = blocks[-1]
|
|
187
183
|
|
|
@@ -192,127 +188,92 @@ class Diff::LCS::Hunk
|
|
|
192
188
|
|
|
193
189
|
@blocks.each do |block|
|
|
194
190
|
block.remove.each do |item|
|
|
195
|
-
op = item.action.to_s # -
|
|
196
191
|
offset = item.position - lo + num_added
|
|
197
|
-
outlist[offset][0, 1] = encode(
|
|
192
|
+
outlist[offset][0, 1] = item.action.to_s.encode(@preferred_data_encoding) # -
|
|
198
193
|
num_removed += 1
|
|
199
194
|
end
|
|
200
195
|
|
|
201
196
|
if last && block == last_block && old_missing_newline && !new_missing_newline
|
|
202
|
-
outlist <<
|
|
197
|
+
outlist << @missing_newline
|
|
203
198
|
num_removed += 1
|
|
204
199
|
end
|
|
205
200
|
|
|
206
201
|
block.insert.each do |item|
|
|
207
|
-
op = item.action.to_s # +
|
|
202
|
+
op = item.action.to_s.encode(@preferred_data_encoding) # +
|
|
208
203
|
offset = item.position - @start_new + num_removed
|
|
209
|
-
outlist[offset, 0] =
|
|
204
|
+
outlist[offset, 0] = op + @data_new[item.position].chomp
|
|
210
205
|
num_added += 1
|
|
211
206
|
end
|
|
212
207
|
end
|
|
213
208
|
|
|
214
|
-
outlist <<
|
|
209
|
+
outlist << @missing_newline if last && new_missing_newline
|
|
215
210
|
|
|
216
|
-
s << outlist.join(
|
|
211
|
+
s << outlist.join("\n".encode(@preferred_data_encoding))
|
|
217
212
|
|
|
218
213
|
s
|
|
219
214
|
end
|
|
220
|
-
private :unified_diff
|
|
221
215
|
|
|
222
216
|
def context_diff(last = false)
|
|
223
|
-
s =
|
|
224
|
-
s <<
|
|
217
|
+
s = "***************\n".encode(@preferred_data_encoding)
|
|
218
|
+
s << "*** #{context_range(:old, ",")} ****\n".encode(@preferred_data_encoding)
|
|
225
219
|
r = context_range(:new, ",")
|
|
226
220
|
|
|
221
|
+
spaces = " ".encode(@preferred_data_encoding)
|
|
222
|
+
|
|
227
223
|
if last
|
|
228
224
|
old_missing_newline = missing_last_newline?(@data_old)
|
|
229
225
|
new_missing_newline = missing_last_newline?(@data_new)
|
|
230
226
|
end
|
|
231
227
|
|
|
232
|
-
# Print out file 1 part for each block in context diff format if there
|
|
233
|
-
#
|
|
228
|
+
# Print out file 1 part for each block in context diff format if there are any blocks
|
|
229
|
+
# that remove items
|
|
234
230
|
lo, hi = @start_old, @end_old
|
|
235
231
|
removes = @blocks.reject { |e| e.remove.empty? }
|
|
236
232
|
|
|
237
233
|
unless removes.empty?
|
|
238
|
-
#
|
|
239
|
-
outlist = @data_old[lo..hi].map { |e| String.new("#{encode(" ")}#{e.chomp}") }
|
|
240
|
-
# standard:enable Performance/UnfreezeString
|
|
234
|
+
outlist = @data_old[lo..hi].map { |e| "#{spaces}#{e.chomp}" }
|
|
241
235
|
|
|
242
236
|
last_block = removes[-1]
|
|
243
237
|
|
|
244
238
|
removes.each do |block|
|
|
245
239
|
block.remove.each do |item|
|
|
246
|
-
outlist[item.position - lo][0, 1] =
|
|
240
|
+
outlist[item.position - lo][0, 1] = block.op.encode(@preferred_data_encoding) # - or !
|
|
247
241
|
end
|
|
248
242
|
|
|
249
243
|
if last && block == last_block && old_missing_newline
|
|
250
|
-
outlist <<
|
|
244
|
+
outlist << @missing_newline
|
|
251
245
|
end
|
|
252
246
|
end
|
|
253
247
|
|
|
254
|
-
s << outlist.join(
|
|
248
|
+
s << outlist.join(@newline) << @newline
|
|
255
249
|
end
|
|
256
250
|
|
|
257
|
-
s <<
|
|
251
|
+
s << "--- #{r} ----\n".encode(@preferred_data_encoding)
|
|
258
252
|
lo, hi = @start_new, @end_new
|
|
259
253
|
inserts = @blocks.reject { |e| e.insert.empty? }
|
|
260
254
|
|
|
261
255
|
unless inserts.empty?
|
|
262
|
-
#
|
|
263
|
-
outlist = @data_new[lo..hi].map { |e| String.new("#{encode(" ")}#{e.chomp}") }
|
|
264
|
-
# standard:enable Performance/UnfreezeString
|
|
256
|
+
outlist = @data_new[lo..hi].map { |e| "#{spaces}#{e.chomp}" }
|
|
265
257
|
|
|
266
258
|
last_block = inserts[-1]
|
|
267
259
|
|
|
268
260
|
inserts.each do |block|
|
|
269
261
|
block.insert.each do |item|
|
|
270
|
-
outlist[item.position - lo][0, 1] =
|
|
262
|
+
outlist[item.position - lo][0, 1] = block.op.encode(@preferred_data_encoding) # + or !
|
|
271
263
|
end
|
|
272
264
|
|
|
273
265
|
if last && block == last_block && new_missing_newline
|
|
274
|
-
outlist <<
|
|
266
|
+
outlist << @missing_newline
|
|
275
267
|
end
|
|
276
268
|
end
|
|
277
|
-
s << outlist.join(
|
|
269
|
+
s << outlist.join(@newline)
|
|
278
270
|
end
|
|
279
271
|
|
|
280
272
|
s
|
|
281
273
|
end
|
|
282
|
-
private :context_diff
|
|
283
274
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
if last
|
|
287
|
-
# ed script doesn't support well incomplete lines
|
|
288
|
-
warn "<old_file>: No newline at end of file\n" if !@old_empty && missing_last_newline?(@data_old)
|
|
289
|
-
warn "<new_file>: No newline at end of file\n" if !@new_empty && missing_last_newline?(@data_new)
|
|
290
|
-
|
|
291
|
-
if @blocks[0].op == "!"
|
|
292
|
-
return +"" if @blocks[0].changes[0].element == @blocks[0].changes[1].element + "\n"
|
|
293
|
-
return +"" if @blocks[0].changes[0].element + "\n" == @blocks[0].changes[1].element
|
|
294
|
-
end
|
|
295
|
-
end
|
|
296
|
-
|
|
297
|
-
s =
|
|
298
|
-
if format == :reverse_ed
|
|
299
|
-
encode("#{ED_DIFF_OP_ACTION[@blocks[0].op]}#{context_range(:old, " ")}\n")
|
|
300
|
-
else
|
|
301
|
-
encode("#{context_range(:old, ",")}#{ED_DIFF_OP_ACTION[@blocks[0].op]}\n")
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
unless @blocks[0].insert.empty?
|
|
305
|
-
@data_new[@start_new..@end_new].each do |e|
|
|
306
|
-
s << e.chomp + encode("\n")
|
|
307
|
-
end
|
|
308
|
-
s << encode(".\n")
|
|
309
|
-
end
|
|
310
|
-
s
|
|
311
|
-
end
|
|
312
|
-
private :ed_diff
|
|
313
|
-
|
|
314
|
-
# Generate a range of item numbers to print. Only print 1 number if the
|
|
315
|
-
# range has only one item in it. Otherwise, it's 'start,end'
|
|
275
|
+
# Generate a range of item numbers to print. Only print 1 number if the range has only
|
|
276
|
+
# one item in it. Otherwise, it's 'start,end'
|
|
316
277
|
def context_range(mode, op)
|
|
317
278
|
case mode
|
|
318
279
|
when :old
|
|
@@ -323,57 +284,33 @@ class Diff::LCS::Hunk
|
|
|
323
284
|
|
|
324
285
|
(s < e) ? "#{s}#{op}#{e}" : e.to_s
|
|
325
286
|
end
|
|
326
|
-
private :context_range
|
|
327
287
|
|
|
328
|
-
# Generate a range of item numbers to print for unified diff. Print number
|
|
329
|
-
#
|
|
330
|
-
#
|
|
288
|
+
# Generate a range of item numbers to print for unified diff. Print number where block
|
|
289
|
+
# starts, followed by number of lines in the block (don't print number of lines if it's
|
|
290
|
+
# 1)
|
|
331
291
|
def unified_range(mode)
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
292
|
+
s, e =
|
|
293
|
+
case mode
|
|
294
|
+
when :old
|
|
295
|
+
return "0,0" if @old_empty
|
|
296
|
+
[(@start_old + 1), (@end_old + 1)]
|
|
297
|
+
when :new
|
|
298
|
+
return "0,0" if @new_empty
|
|
299
|
+
[(@start_new + 1), (@end_new + 1)]
|
|
300
|
+
end
|
|
340
301
|
|
|
341
302
|
length = e - s + 1
|
|
342
303
|
|
|
343
304
|
(length <= 1) ? e.to_s : "#{s},#{length}"
|
|
344
305
|
end
|
|
345
|
-
private :unified_range
|
|
346
306
|
|
|
347
307
|
def missing_last_newline?(data)
|
|
348
|
-
newline = encode("\n")
|
|
349
|
-
|
|
350
308
|
if data[-2]
|
|
351
|
-
data[-2].end_with?(newline) && !data[-1].end_with?(newline)
|
|
309
|
+
data[-2].end_with?(@newline) && !data[-1].end_with?(@newline)
|
|
352
310
|
elsif data[-1]
|
|
353
|
-
!data[-1].end_with?(newline)
|
|
311
|
+
!data[-1].end_with?(@newline)
|
|
354
312
|
else
|
|
355
313
|
true
|
|
356
314
|
end
|
|
357
315
|
end
|
|
358
|
-
|
|
359
|
-
if String.method_defined?(:encoding)
|
|
360
|
-
def encode(literal, target_encoding = @preferred_data_encoding)
|
|
361
|
-
literal.encode target_encoding
|
|
362
|
-
end
|
|
363
|
-
|
|
364
|
-
def encode_as(string, *args)
|
|
365
|
-
args.map { |arg| arg.encode(string.encoding) }
|
|
366
|
-
end
|
|
367
|
-
else
|
|
368
|
-
def encode(literal, _target_encoding = nil)
|
|
369
|
-
literal
|
|
370
|
-
end
|
|
371
|
-
|
|
372
|
-
def encode_as(_string, *args)
|
|
373
|
-
args
|
|
374
|
-
end
|
|
375
|
-
end
|
|
376
|
-
|
|
377
|
-
private :encode
|
|
378
|
-
private :encode_as
|
|
379
316
|
end
|