Files
kjol/tools/tsgo/vendor/github.com/peter-evans/patience/unified.go
2026-07-09 16:50:43 -04:00

152 lines
3.8 KiB
Go

package patience
// Hunk represents a subsection of a diff.
type Hunk struct {
Diffs []DiffLine
SrcStart int
SrcLines int
DstStart int
DstLines int
}
// makeHunks returns the hunks of a diff.
func makeHunks(diffs []DiffLine, precontext, postcontext int) []Hunk {
if len(diffs) == 0 {
return nil
}
hunks := []Hunk{}
// Update hunks with a diff block.
updateHunks := func(block Hunk, lastBlock bool) {
curHunk := len(hunks) - 1
if block.Diffs[0].Type == Equal {
// Unmodified block.
if len(hunks) == 0 {
// Start a new hunk with the tail of the block.
ctxLen := min(precontext, len(block.Diffs))
hunks = append(
hunks,
Hunk{
Diffs: block.Diffs[len(block.Diffs)-ctxLen:],
SrcStart: len(block.Diffs) - ctxLen + block.SrcStart,
SrcLines: ctxLen,
DstStart: len(block.Diffs) - ctxLen + block.DstStart,
DstLines: ctxLen,
},
)
} else {
// Update the current hunk.
maxNonContext := precontext + postcontext
if lastBlock {
maxNonContext = postcontext
}
if len(block.Diffs) <= maxNonContext {
// Block is small enough to be appended to the current hunk.
hunks[curHunk].Diffs = append(hunks[curHunk].Diffs, block.Diffs...)
hunks[curHunk].SrcLines += len(block.Diffs)
hunks[curHunk].DstLines += len(block.Diffs)
} else {
// Append the head of the block to the current hunk.
hunks[curHunk].Diffs = append(hunks[curHunk].Diffs, block.Diffs[:postcontext]...)
hunks[curHunk].SrcLines += postcontext
hunks[curHunk].DstLines += postcontext
if !lastBlock {
// Start a new hunk with the tail of the block.
hunks = append(
hunks,
Hunk{
Diffs: block.Diffs[len(block.Diffs)-precontext:],
SrcStart: len(block.Diffs) - precontext + block.SrcStart,
SrcLines: precontext,
DstStart: len(block.Diffs) - precontext + block.DstStart,
DstLines: precontext,
},
)
}
}
// Update starting line numbers if the current hunk had no source or destination diff.
if hunks[curHunk].SrcStart == 0 {
hunks[curHunk].SrcStart = block.SrcStart
}
if hunks[curHunk].DstStart == 0 {
hunks[curHunk].DstStart = block.DstStart
}
}
} else {
// Modified block.
if len(hunks) > 0 {
hunks[curHunk].Diffs = append(hunks[curHunk].Diffs, block.Diffs...)
hunks[curHunk].SrcLines += block.SrcLines
hunks[curHunk].DstLines += block.DstLines
} else {
hunks = append(
hunks,
Hunk{
Diffs: block.Diffs,
SrcStart: block.SrcStart,
SrcLines: block.SrcLines,
DstStart: block.DstStart,
DstLines: block.DstLines,
},
)
}
}
}
// Aggregate blocks of modified and unmodified diff lines, creating
// or updating hunks after each block.
var block Hunk
modifiedLines := 0 //nolint:ifshort
srcLineNum, dstLineNum := 0, 0
for _, l := range diffs {
if len(block.Diffs) == 0 ||
block.Diffs[0].Type == l.Type ||
(block.Diffs[0].Type != l.Type && block.Diffs[0].Type != Equal && l.Type != Equal) {
block.Diffs = append(block.Diffs, l)
} else {
updateHunks(block, false)
block = Hunk{Diffs: []DiffLine{l}}
}
switch l.Type {
case Delete:
srcLineNum++
block.SrcLines++
modifiedLines++
case Insert:
dstLineNum++
block.DstLines++
modifiedLines++
case Equal:
srcLineNum++
dstLineNum++
block.SrcLines++
block.DstLines++
}
if block.SrcStart == 0 && (l.Type == Equal || l.Type == Delete) {
block.SrcStart = srcLineNum
}
if block.DstStart == 0 && (l.Type == Equal || l.Type == Insert) {
block.DstStart = dstLineNum
}
}
updateHunks(block, true)
// Return no hunks if the diffs contain only equal lines.
if modifiedLines == 0 {
return nil
}
return hunks
}
// min returns the minimum of two integers.
func min(a, b int) int {
if a < b {
return a
}
return b
}