nub/internal/tool/builtin/diff.go
Tom a97013d876 initial commit
- v 0.1.0 siehe CHANGELOG.md
2026-07-25 11:08:01 +02:00

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")
}