77 lines
1.6 KiB
Go
77 lines
1.6 KiB
Go
package builtin
|
|
|
|
import "strings"
|
|
|
|
type DiffOp string
|
|
|
|
const (
|
|
DiffEqual DiffOp = "equal"
|
|
DiffAdd DiffOp = "add"
|
|
DiffRemove DiffOp = "remove"
|
|
)
|
|
|
|
type DiffLine struct {
|
|
Op DiffOp
|
|
Text string
|
|
}
|
|
|
|
// DiffResult ist die strukturierte UI-Repräsentation für write/edit.
|
|
type DiffResult struct {
|
|
Path string
|
|
Lines []DiffLine
|
|
}
|
|
|
|
// lineDiff berechnet einen minimalen zeilenbasierten Diff via LCS.
|
|
// Für Datei-großen Input (M1) ausreichend; kein externer Diff-Algorithmus nötig.
|
|
func lineDiff(oldText, newText string) []DiffLine {
|
|
oldLines := splitLines(oldText)
|
|
newLines := splitLines(newText)
|
|
n, m := len(oldLines), len(newLines)
|
|
|
|
lcs := make([][]int, n+1)
|
|
for i := range lcs {
|
|
lcs[i] = make([]int, m+1)
|
|
}
|
|
for i := n - 1; i >= 0; i-- {
|
|
for j := m - 1; j >= 0; j-- {
|
|
if oldLines[i] == newLines[j] {
|
|
lcs[i][j] = lcs[i+1][j+1] + 1
|
|
} else if lcs[i+1][j] >= lcs[i][j+1] {
|
|
lcs[i][j] = lcs[i+1][j]
|
|
} else {
|
|
lcs[i][j] = lcs[i][j+1]
|
|
}
|
|
}
|
|
}
|
|
|
|
var out []DiffLine
|
|
i, j := 0, 0
|
|
for i < n && j < m {
|
|
switch {
|
|
case oldLines[i] == newLines[j]:
|
|
out = append(out, DiffLine{DiffEqual, oldLines[i]})
|
|
i++
|
|
j++
|
|
case lcs[i+1][j] >= lcs[i][j+1]:
|
|
out = append(out, DiffLine{DiffRemove, oldLines[i]})
|
|
i++
|
|
default:
|
|
out = append(out, DiffLine{DiffAdd, newLines[j]})
|
|
j++
|
|
}
|
|
}
|
|
for ; i < n; i++ {
|
|
out = append(out, DiffLine{DiffRemove, oldLines[i]})
|
|
}
|
|
for ; j < m; j++ {
|
|
out = append(out, DiffLine{DiffAdd, newLines[j]})
|
|
}
|
|
return out
|
|
}
|
|
|
|
func splitLines(s string) []string {
|
|
if s == "" {
|
|
return nil
|
|
}
|
|
return strings.Split(s, "\n")
|
|
}
|