Skip to content

Commit c597e53

Browse files
committed
[[ Diff ]] Keep content lines separate from edit operations, and include terminating newlines at end of content lines
[[ Diff ]] Implement unified diff marker to indicate no newline on last line of input / output files.
1 parent 9ea5343 commit c597e53

File tree

1 file changed

+92
-53
lines changed

1 file changed

+92
-53
lines changed

extensions/script-libraries/diff/diff.livecodescript

Lines changed: 92 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,13 @@ function DiffCompare pFrom, pTo, pContext
7070
put 3 into pContext
7171
end if
7272

73+
put _split(pFrom, return) into pFrom
74+
put _split(pTo, return) into pTo
75+
7376
local tEdits
74-
put diff_strings(pFrom, pTo) into tEdits
75-
split pFrom by cr
76-
return convert_to_unified(tEdits, pFrom, the number of elements in pFrom, pContext)
77+
put diff_arrays(pFrom, pTo) into tEdits
78+
79+
return convert_to_unified(tEdits, pFrom, pTo, pContext)
7780
end DiffCompare
7881

7982
/**
@@ -96,9 +99,9 @@ An updated version of pSource with the changes from pDiff applied.
9699
*/
97100

98101
function DiffPatch pSource, pDiff
99-
local tEdits
100-
put parse_unified(pDiff) into tEdits
101-
return patch_string(pSource, tEdits)
102+
local tEdits, tContent
103+
parse_unified pDiff, tEdits, tContent
104+
return patch_string(pSource, tEdits, tContent)
102105
end DiffPatch
103106

104107
/**
@@ -220,14 +223,17 @@ constant kLastSourceIndex = "lastSourceIndex"
220223
constant kDelta = "delta"
221224

222225
-- produce unified diff from edit list, containing pContextLength lines of context
223-
private function convert_to_unified pEdits, pSource, pSourceLength, pContextLength
226+
private function convert_to_unified pEdits, pA, pB, pContextLength
227+
local tALength, tBLength
228+
put the number of elements in pA into tALength
229+
put the number of elements in pB into tBLength
224230
local tDiff
225231
local tHunk
226232
local tDelta = 0
227233

228234
repeat for each line tEdit in pEdits
229-
local tA, tB, tOperation, tContent
230-
parse_edit tEdit, tA, tB, tOperation, tContent
235+
local tA, tB, tOperation
236+
parse_edit tEdit, tA, tB, tOperation
231237

232238
if tHunk is an array and not continue_hunk(tHunk, tA, tOperation) then
233239
end_hunk tHunk
@@ -237,13 +243,13 @@ private function convert_to_unified pEdits, pSource, pSourceLength, pContextLeng
237243
end if
238244

239245
if tHunk is not an array then
240-
begin_hunk tHunk, pSource, pSourceLength, pContextLength
246+
begin_hunk tHunk, pA, tALength, pContextLength
241247
end if
242248

243249
if tOperation is kDiffOperationAdd then
244-
add_addition tHunk, tA, tContent
250+
add_addition tHunk, tA, pB[tB]
245251
else if tOperation is kDiffOperationDelete then
246-
add_deletion tHunk, tA, tContent
252+
add_deletion tHunk, tA, pA[tA]
247253
end if
248254
end repeat
249255

@@ -279,22 +285,30 @@ end continue_hunk
279285

280286
private command add_deletion @pHunk, pIndex, pContent
281287
add_context_before pHunk, pIndex
282-
put "-" & pContent & cr after pHunk[kContent]
288+
put "-" & pContent after pHunk[kContent]
283289
if pHunk[kFirstSourceIndex] is empty then
284290
put pIndex into pHunk[kFirstSourceIndex]
285291
end if
286292
put pIndex into pHunk[kLastSourceIndex]
287293
subtract 1 from pHunk[kDelta]
294+
295+
if not (pContent ends with return) then
296+
put return & "\ No newline at end of file" & return after pHunk[kContent]
297+
end if
288298
end add_deletion
289299

290300
private command add_addition @pHunk, pIndex, pContent
291301
add_context_before pHunk, pIndex + 1
292-
put "+" & pContent & cr after pHunk[kContent]
293302
if pHunk[kFirstSourceIndex] is empty then
294303
put pIndex into pHunk[kFirstSourceIndex]
295304
end if
296305
put pIndex into pHunk[kLastSourceIndex]
306+
put "+" & pContent after pHunk[kContent]
297307
add 1 to pHunk[kDelta]
308+
309+
if not (pContent ends with return) then
310+
put return & "\ No newline at end of file" & return after pHunk[kContent]
311+
end if
298312
end add_addition
299313

300314
private command add_context_before @pHunk, pIndex
@@ -318,9 +332,13 @@ private command add_context_before @pHunk, pIndex
318332
end if
319333

320334
repeat with i = tStart to tEnd
321-
put space & pHunk[kSource][i] & cr after pHunk[kContent]
335+
put space & pHunk[kSource][i] after pHunk[kContent]
322336
end repeat
323337

338+
if not (pHunk[kContent] ends with return) then
339+
put return & "\ No newline at end of file" & return after pHunk[kContent]
340+
end if
341+
324342
if pHunk[kFirstSourceIndex] is empty then
325343
put tStart into pHunk[kFirstSourceIndex]
326344
end if
@@ -358,8 +376,10 @@ end add_hunk
358376
----------
359377

360378
-- convert unified diff to edit list
361-
private function parse_unified pUniDiff
379+
private command parse_unified pUniDiff, @rEdits, @rContent
362380
local tEdits
381+
local tContent
382+
local tLastEdit
363383
repeat for each line tLine in pUniDiff
364384
// skip file headers if present
365385
if tLine begins with "+++" or tLine begins with "---" then
@@ -388,20 +408,35 @@ private function parse_unified pUniDiff
388408
end if
389409
else if tLine begins with space then
390410
// skip context line
411+
put empty into tLastEdit
412+
391413
add 1 to tAStart
392414
add 1 to tBStart
393415
subtract 1 from tALength
394416
subtract 1 from tBLength
395417
else if tLine begins with "+" then
396418
// addition
397-
put format_edit(tAStart - 1, tBStart, kDiffOperationAdd, char 2 to -1 of tLine) & return after tEdits
419+
put tAStart - 1,kDiffOperationAdd,tBStart into tLastEdit
420+
put tLastEdit & return after tEdits
421+
put char 2 to -1 of tLine & return into tContent[tBStart]
422+
398423
add 1 to tBStart
399424
subtract 1 from tBLength
400425
else if tLine begins with "-" then
401426
// deletion
402-
put format_edit(tAStart, tBStart - 1, kDiffOperationDelete, char 2 to -1 of tLine) & return after tEdits
427+
put tAStart, kDiffOperationDelete, tBStart - 1 into tLastEdit
428+
put tLastEdit & return after tEdits
429+
403430
add 1 to tAStart
404431
subtract 1 from tALength
432+
else if tLine begins with "\" then
433+
// no newline
434+
local tA, tB, tLastOp
435+
parse_edit tLastEdit, tA, tB, tLastOp
436+
// remove newline from content of last operation (if addition)
437+
if tLastOp is kDiffOperationAdd then
438+
delete the last char of tContent[tB]
439+
end if
405440
end if
406441
end repeat
407442

@@ -438,13 +473,36 @@ private function _combine @pArray, pDelimiter
438473
return tCombined
439474
end _combine
440475

476+
-- split function which retains delimiter chars
477+
private function _split pString, pDelim
478+
local tArray
479+
local tIndex = 0
480+
set the linedelimiter to pDelim
481+
repeat for each line tLine in pString
482+
add 1 to tIndex
483+
put tLine & pDelim into tArray[tIndex]
484+
end repeat
485+
486+
// remove delim from last line if missing from string
487+
if not (pString ends with pDelim) then
488+
delete last char of tArray[tIndex]
489+
end if
490+
491+
return tArray
492+
end _split
493+
441494
--------------------------------------------------------------------------------
442495

443496
-- generate list of edits between two strings
444497
private function diff_strings pA, pB
445-
split pA by cr
446-
split pB by cr
498+
put _split(pA, return) into pA
499+
put _split(pB, return) into pB
447500

501+
return diff_arrays(pA, pB)
502+
end diff_strings
503+
504+
-- generate list of edits between two arrays
505+
private function diff_arrays pA, pB
448506
local tALength, tBLength
449507
put the number of elements in pA into tALength
450508
put the number of elements in pB into tBLength
@@ -465,15 +523,15 @@ private function diff_strings pA, pB
465523
end if
466524

467525
return tEdits
468-
end diff_strings
526+
end diff_arrays
469527

470528
-- apply edit list to string
471-
private function patch_string pString, pEdits
472-
split pString by cr
529+
private function patch_string pString, pEdits, pContent
530+
put _split(pString, return) into pString
473531
local tOutput
474-
put patch_arrays(pString, the number of elements in pString, pEdits) into tOutput
532+
put patch_arrays(pString, pEdits, pContent) into tOutput
475533

476-
return _combine(tOutput, cr)
534+
return _combine(tOutput, empty)
477535

478536
return tOutput
479537
end patch_string
@@ -512,27 +570,9 @@ private function compare_arrays pA, pALength, pB, pBLength
512570

513571
end repeat
514572

515-
return add_content_to_edits(tPath[tDelta], pA, pB)
573+
return tPath[tDelta]
516574
end compare_arrays
517575

518-
private function add_content_to_edits pEdits, pA, pB
519-
local tEdits
520-
repeat for each line tEdit in pEdits
521-
local tA, tB, tOperation
522-
put item 2 of tEdit into tOperation
523-
local tContent
524-
if tOperation is kDiffOperationAdd then
525-
put item 3 of tEdit into tB
526-
put pB[tB] into tContent
527-
else
528-
put item 1 of tEdit into tA
529-
put pA[tA] into tContent
530-
end if
531-
put tEdit,tContent & return after tEdits
532-
end repeat
533-
return tEdits
534-
end add_content_to_edits
535-
536576
private command compare_diagonal @pFP, @pPath, @pA, pALength, @pB, pBLength, k
537577
local tLeft, tRight, tNext, tPrevPath, tOperation, tContent
538578
put pFP[k - 1] + 1 into tLeft
@@ -578,18 +618,18 @@ private function snake @pA, pALength, @pB, pBLength, k, y
578618
end snake
579619

580620
-- apply edits to source array, producing output array
581-
private function patch_arrays @pA, pALength, pEdits
621+
private function patch_arrays pA, pEdits, pContent
582622
local tOutput
583623
local tIndex, tAIndex
584624
put 1 into tIndex
585625
put 1 into tAIndex
586626
repeat for each line tEdit in pEdits
587-
local tA, tB, tOperation, tContent
588-
parse_edit tEdit, tA, tB, tOperation, tContent
627+
local tA, tB, tOperation
628+
parse_edit tEdit, tA, tB, tOperation
589629

590630
if tOperation is kDiffOperationAdd then
591631
skip_edits tOutput, tIndex, pA, tAIndex, tA
592-
put tContent into tOutput[tIndex]
632+
put pContent[tB] into tOutput[tIndex]
593633
add 1 to tIndex
594634
put tA + 1 into tAIndex
595635
else if tOperation is kDiffOperationDelete then
@@ -599,7 +639,7 @@ private function patch_arrays @pA, pALength, pEdits
599639

600640
end repeat
601641

602-
skip_edits tOutput, tIndex, pA, tAIndex, pALength
642+
skip_edits tOutput, tIndex, pA, tAIndex, the number of elements in pA
603643

604644
return tOutput
605645
end patch_arrays
@@ -617,12 +657,12 @@ private function reverse_edits pEdits
617657
local tA, tB, tOperation, tContent
618658

619659
repeat for each line tEdit in pEdits
620-
parse_edit tEdit, tA, tB, tOperation, tContent
660+
parse_edit tEdit, tA, tB, tOperation
621661

622662
if tOperation is kDiffOperationAdd then put kDiffOperationDelete into tOperation
623663
else if tOperation is kDiffOperationDelete then put kDiffOperationAdd into tOperation
624664

625-
put format_edit(tB, tA, tOperation, tContent) & return after tEdits
665+
put tB, tOperation, tA & return after tEdits
626666
end repeat
627667

628668
return tEdits
@@ -632,11 +672,10 @@ private function format_edit pAIndex, pBIndex, pOperation, pContent
632672
return pAIndex,pOperation,pBIndex,pContent
633673
end format_edit
634674

635-
private command parse_edit pEdit @rAIndex, @rBIndex, @rOperation, @rContent
675+
private command parse_edit pEdit @rAIndex, @rBIndex, @rOperation
636676
put item 1 of pEdit into rAIndex
637677
put item 2 of pEdit into rOperation
638678
put item 3 of pEdit into rBIndex
639-
put item 4 to -1 of pEdit into rContent
640679
end parse_edit
641680

642681
--------------------------------------------------------------------------------

0 commit comments

Comments
 (0)