mukan-ignite/ignite/internal/tools/gen-mig-diffs/pkg/diff/subtract.go
Mukan Erkin Törük 26b204bd04
Some checks are pending
Docs Deploy / build_and_deploy (push) Waiting to run
Generate Docs / cli (push) Waiting to run
Generate Config Doc / cli (push) Waiting to run
Go formatting / go-formatting (push) Waiting to run
Check links / markdown-link-check (push) Waiting to run
Integration / pre-test (push) Waiting to run
Integration / test on (push) Blocked by required conditions
Integration / status (push) Blocked by required conditions
Lint / Lint Go code (push) Waiting to run
Test / test (ubuntu-latest) (push) Waiting to run
feat: fork Ignite CLI v29 as Mukan Ignite — remove cosmos-sdk restrictions
2026-05-11 03:31:37 +03:00

165 lines
3.5 KiB
Go

package diff
import (
"sort"
"github.com/hexops/gotextdiff"
)
// subtract two unified diffs from each other.
func subtract(a, b gotextdiff.Unified) gotextdiff.Unified {
return gotextdiff.Unified{
From: a.From,
To: a.To,
Hunks: subtractHunks(a.Hunks, b.Hunks),
}
}
func subtractHunks(src, base []*gotextdiff.Hunk) []*gotextdiff.Hunk {
sortHunks(src)
sortHunks(base)
res := make([]*gotextdiff.Hunk, 0, len(src))
offset := 0
for i, j := 0, 0; i < len(src) || j < len(base); {
if i >= len(src) {
break
}
if j >= len(base) {
res = append(res, src[i])
i++
continue
}
s := src[i]
b := base[j]
switch {
case beforeHunk(s, b, offset):
res = append(res, s)
offset += calculateHunkOffsetChange(s.Lines)
i++
case beforeHunk(b, s, -offset):
j++
case hunksOverlap(s, b, offset):
if s.FromLine < b.FromLine {
res = append(res, s)
offset += calculateHunkOffsetChange(s.Lines) - calculateHunkOffsetChange(b.Lines)
i++
} else {
offset += calculateHunkOffsetChange(s.Lines) - calculateHunkOffsetChange(b.Lines)
j++
}
default:
h := subtractHunk(s, b)
if !isHunkEmpty(h) {
res = append(res, subtractHunk(s, b))
}
offset += calculateHunkOffsetChange(s.Lines) - calculateHunkOffsetChange(b.Lines)
i++
j++
}
}
return res
}
func sortHunks(hunks []*gotextdiff.Hunk) {
sort.Slice(hunks, func(i, j int) bool {
return hunks[i].FromLine < hunks[j].FromLine
})
}
// beforeHunk returns true if a comes before b.
func beforeHunk(a, b *gotextdiff.Hunk, offset int) bool {
return a.ToLine-calculateEndEqualLines(a) < b.FromLine+calculateStartEqualLines(b)+offset
}
func calculateStartEqualLines(h *gotextdiff.Hunk) int {
lines := 0
for _, l := range h.Lines {
if l.Kind == gotextdiff.Equal {
lines++
} else {
break
}
}
return lines
}
func calculateEndEqualLines(h *gotextdiff.Hunk) int {
lines := 0
for i := len(h.Lines) - 1; i >= 0; i-- {
if h.Lines[i].Kind == gotextdiff.Equal {
lines++
} else {
break
}
}
return lines
}
func calculateHunkOffsetChange(lines []gotextdiff.Line) int {
offset := 0
for _, l := range lines {
if l.Kind == gotextdiff.Insert {
offset++
} else if l.Kind == gotextdiff.Delete {
offset--
}
}
return offset
}
func hunksOverlap(a, b *gotextdiff.Hunk, offset int) bool {
if !isLineInHunk(a.FromLine, b, offset) && isLineInHunk(a.ToLine, b, offset) {
return true
}
if isLineInHunk(a.FromLine, b, offset) && !isLineInHunk(a.ToLine, b, offset) {
return true
}
return false
}
func isLineInHunk(line int, h *gotextdiff.Hunk, offset int) bool {
return line-calculateStartEqualLines(h) > h.FromLine+offset && line+calculateEndEqualLines(h) < h.ToLine+offset
}
func subtractHunk(a, b *gotextdiff.Hunk) *gotextdiff.Hunk {
lines := subtractLines(a.Lines, b.Lines)
return &gotextdiff.Hunk{
FromLine: a.FromLine,
ToLine: a.ToLine + calculateHunkOffsetChange(a.Lines) - calculateHunkOffsetChange(lines),
Lines: lines,
}
}
func subtractLines(a, b []gotextdiff.Line) []gotextdiff.Line {
res := make([]gotextdiff.Line, 0, len(a))
for _, la := range a {
rep := false
for _, lb := range b {
if la.Kind != gotextdiff.Equal && la.Kind == lb.Kind && la.Content == lb.Content {
rep = true
break
}
}
if !rep {
res = append(res, la)
}
}
return res
}
func isHunkEmpty(h *gotextdiff.Hunk) bool {
effectiveLines := 0
for _, l := range h.Lines {
if l.Kind != gotextdiff.Equal {
effectiveLines++
}
}
return effectiveLines == 0
}