152 lines
3.8 KiB
Go
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
|
|
}
|