1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2024-12-04 10:34:55 +02:00
lazygit/pkg/commands/patch/hunk.go
2022-03-24 20:14:41 +11:00

144 lines
3.8 KiB
Go

package patch
import (
"fmt"
"strings"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
)
type PatchHunk struct {
FirstLineIdx int
oldStart int
newStart int
heading string
bodyLines []string
}
func (hunk *PatchHunk) LastLineIdx() int {
return hunk.FirstLineIdx + len(hunk.bodyLines)
}
func newHunk(lines []string, firstLineIdx int) *PatchHunk {
header := lines[0]
bodyLines := lines[1:]
oldStart, newStart, heading := headerInfo(header)
return &PatchHunk{
oldStart: oldStart,
newStart: newStart,
heading: heading,
FirstLineIdx: firstLineIdx,
bodyLines: bodyLines,
}
}
func headerInfo(header string) (int, int, string) {
match := hunkHeaderRegexp.FindStringSubmatch(header)
oldStart := utils.MustConvertToInt(match[1])
newStart := utils.MustConvertToInt(match[2])
heading := match[3]
return oldStart, newStart, heading
}
func (hunk *PatchHunk) updatedLines(lineIndices []int, reverse bool) []string {
skippedNewlineMessageIndex := -1
newLines := []string{}
lineIdx := hunk.FirstLineIdx
for _, line := range hunk.bodyLines {
lineIdx++ // incrementing at the start to skip the header line
if line == "" {
break
}
isLineSelected := lo.Contains(lineIndices, lineIdx)
firstChar, content := line[:1], line[1:]
transformedFirstChar := transformedFirstChar(firstChar, reverse, isLineSelected)
if isLineSelected || (transformedFirstChar == "\\" && skippedNewlineMessageIndex != lineIdx) || transformedFirstChar == " " {
newLines = append(newLines, transformedFirstChar+content)
continue
}
if transformedFirstChar == "+" {
// we don't want to include the 'newline at end of file' line if it involves an addition we're not including
skippedNewlineMessageIndex = lineIdx + 1
}
}
return newLines
}
func transformedFirstChar(firstChar string, reverse bool, isLineSelected bool) string {
if reverse {
if !isLineSelected && firstChar == "+" {
return " "
} else if firstChar == "-" {
return "+"
} else if firstChar == "+" {
return "-"
} else {
return firstChar
}
}
if !isLineSelected && firstChar == "-" {
return " "
}
return firstChar
}
func (hunk *PatchHunk) formatHeader(oldStart int, oldLength int, newStart int, newLength int, heading string) string {
return fmt.Sprintf("@@ -%d,%d +%d,%d @@%s\n", oldStart, oldLength, newStart, newLength, heading)
}
func (hunk *PatchHunk) formatWithChanges(lineIndices []int, reverse bool, startOffset int) (int, string) {
bodyLines := hunk.updatedLines(lineIndices, reverse)
startOffset, header, ok := hunk.updatedHeader(bodyLines, startOffset, reverse)
if !ok {
return startOffset, ""
}
return startOffset, header + strings.Join(bodyLines, "")
}
func (hunk *PatchHunk) updatedHeader(newBodyLines []string, startOffset int, reverse bool) (int, string, bool) {
changeCount := nLinesWithPrefix(newBodyLines, []string{"+", "-"})
oldLength := nLinesWithPrefix(newBodyLines, []string{" ", "-"})
newLength := nLinesWithPrefix(newBodyLines, []string{"+", " "})
if changeCount == 0 {
// if nothing has changed we just return nothing
return startOffset, "", false
}
var oldStart int
if reverse {
oldStart = hunk.newStart
} else {
oldStart = hunk.oldStart
}
var newStartOffset int
// if the hunk went from zero to positive length, we need to increment the starting point by one
// if the hunk went from positive to zero length, we need to decrement the starting point by one
if oldLength == 0 {
newStartOffset = 1
} else if newLength == 0 {
newStartOffset = -1
} else {
newStartOffset = 0
}
newStart := oldStart + startOffset + newStartOffset
newStartOffset = startOffset + newLength - oldLength
formattedHeader := hunk.formatHeader(oldStart, oldLength, newStart, newLength, hunk.heading)
return newStartOffset, formattedHeader, true
}