59 lines
1.6 KiB
Go
59 lines
1.6 KiB
Go
package file
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/pmezard/go-difflib/difflib"
|
|
)
|
|
|
|
// UnifiedDiff returns a proper unified diff between old and new content using LCS (Myers via difflib).
|
|
// It handles insertions, deletions, replacements, moved blocks, empty and new files.
|
|
func UnifiedDiff(filename, oldContent, newContent string) string {
|
|
if oldContent == newContent {
|
|
return ""
|
|
}
|
|
oldLines := splitLines(oldContent)
|
|
newLines := splitLines(newContent)
|
|
|
|
diff := difflib.UnifiedDiff{
|
|
A: difflib.SplitLines(oldContent),
|
|
B: difflib.SplitLines(newContent),
|
|
FromFile: "a/" + filename,
|
|
ToFile: "b/" + filename,
|
|
Context: 3,
|
|
}
|
|
// difflib.SplitLines handles trailing newlines correctly, but we also keep oldLines/newLines for
|
|
// fallback when one side is empty to ensure diff is still produced.
|
|
if len(oldLines) == 0 && len(newLines) == 0 {
|
|
return ""
|
|
}
|
|
text, _ := difflib.GetUnifiedDiffString(diff)
|
|
// difflib returns empty string when no diff; ensure header is present for new/deleted files
|
|
if text == "" {
|
|
// Fallback minimal diff for edge cases difflib might consider empty
|
|
var b strings.Builder
|
|
b.WriteString("--- a/" + filename + "\n+++ b/" + filename + "\n")
|
|
if len(oldLines) == 0 {
|
|
for _, l := range newLines {
|
|
b.WriteString("+" + l + "\n")
|
|
}
|
|
return b.String()
|
|
}
|
|
if len(newLines) == 0 {
|
|
for _, l := range oldLines {
|
|
b.WriteString("-" + l + "\n")
|
|
}
|
|
return b.String()
|
|
}
|
|
return ""
|
|
}
|
|
return text
|
|
}
|
|
|
|
func splitLines(s string) []string {
|
|
if s == "" {
|
|
return []string{}
|
|
}
|
|
s = strings.ReplaceAll(s, "\r\n", "\n")
|
|
return strings.Split(s, "\n")
|
|
}
|