@@ -257,13 +257,68 @@ def self.loc_string(loc, compilation_dir, logger)
257
257
# @param depth [Fixnum] Depth, for correct indentation
258
258
# @return Array<String> Displayable result
259
259
def self . diff_two_strings_with_diffy ( string1 , string2 , depth )
260
- # prevent 'No newline at end of file' for single line strings
261
- string1 += "\n " unless string1 =~ /\n /
262
- string2 += "\n " unless string2 =~ /\n /
260
+ # Single line strings?
261
+ if single_lines? ( string1 , string2 )
262
+ string1 , string2 = add_trailing_newlines ( string1 , string2 )
263
+ diff = Diffy ::Diff . new ( string1 , string2 , context : 2 , include_diff_info : true ) . to_s . split ( "\n " )
264
+ 3 . times { diff . shift }
265
+ return diff . map { |x | left_pad ( 2 * depth + 2 , make_trailing_whitespace_visible ( adjust_position_of_plus_minus ( x ) ) ) }
266
+ end
267
+
268
+ # Multiple line strings
269
+ string1 , string2 = add_trailing_newlines ( string1 , string2 )
263
270
diff = Diffy ::Diff . new ( string1 , string2 , context : 2 , include_diff_info : true ) . to_s . split ( "\n " )
264
271
diff . shift # Remove first line of diff info (filename that makes no sense)
265
272
diff . shift # Remove second line of diff info (filename that makes no sense)
266
- diff . map { |x | left_pad ( 2 * depth + 2 , x ) }
273
+ diff . map { |x | left_pad ( 2 * depth + 2 , make_trailing_whitespace_visible ( x ) ) }
274
+ end
275
+
276
+ # Determine if two incoming strings are single lines. Returns true if both
277
+ # incoming strings are single lines, false otherwise.
278
+ # @param string_1 [String] First string
279
+ # @param string_2 [String] Second string
280
+ # @return [Boolean] Whether both incoming strings are single lines
281
+ def self . single_lines? ( string_1 , string_2 )
282
+ string_1 . strip !~ /\n / && string_2 . strip !~ /\n /
283
+ end
284
+
285
+ # Add "\n" to the end of both strings, only if both strings are lacking it.
286
+ # This prevents "\\ No newline at end of file" for single string comparison.
287
+ # @param string_1 [String] First string
288
+ # @param string_2 [String] Second string
289
+ # @return [Array<String>] Adjusted string_1, string_2
290
+ def self . add_trailing_newlines ( string_1 , string_2 )
291
+ return [ string_1 , string_2 ] unless string_1 !~ /\n \Z / && string_2 !~ /\n \Z /
292
+ [ string_1 + "\n " , string_2 + "\n " ]
293
+ end
294
+
295
+ # Adjust the space after of the `-` / `+` in the diff for single line diffs.
296
+ # Diffy prints diffs with no space between the `-` / `+` in the text, but for
297
+ # single lines it's easier to read with that space added.
298
+ # @param string_in [String] Input string, which is a line of a diff from diffy
299
+ # @return [String] Modified string
300
+ def self . adjust_position_of_plus_minus ( string_in )
301
+ string_in . sub ( /\A (\e \[ \d +m)?([\- \+ ])/ , '\1\2 ' )
302
+ end
303
+
304
+ # Convert trailing whitespace to underscore for display purposes. Also convert special
305
+ # whitespace (\r, \n, \t, ...) to character representation.
306
+ # @param string_in [String] Input string, which might contain trailing whitespace
307
+ # @return [String] Modified string
308
+ def self . make_trailing_whitespace_visible ( string_in )
309
+ return string_in unless string_in =~ /\A ((?:.|\n )*?)(\s +)(\e \[ 0m)?\Z /
310
+ beginning = Regexp . last_match ( 1 )
311
+ trailing_space = Regexp . last_match ( 2 )
312
+ end_escape = Regexp . last_match ( 3 )
313
+
314
+ # Trailing space adjustment for line endings
315
+ trailing_space . gsub! "\n " , '\n'
316
+ trailing_space . gsub! "\r " , '\r'
317
+ trailing_space . gsub! "\t " , '\t'
318
+ trailing_space . gsub! "\f " , '\f'
319
+ trailing_space . tr! ' ' , '_'
320
+
321
+ [ beginning , trailing_space , end_escape ] . join ( '' )
267
322
end
268
323
269
324
# Get the diff of two hashes. Call the 'diffy' gem for this.
0 commit comments