diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2020-08-15 11:18:40 +1000 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2020-08-15 11:41:37 +1000 |
commit | 826d1660c97b7c5c55420ffed21eaa5f16118118 (patch) | |
tree | 8f2f65a3d2617aa242034273c4a41b6ec5aea659 /pkg/commands/patch/hunk.go | |
parent | 291a8e4de0f5d5557cf6fbd7b5b6b9d42bcaa16e (diff) |
move patch stuff into its own package
Diffstat (limited to 'pkg/commands/patch/hunk.go')
-rw-r--r-- | pkg/commands/patch/hunk.go | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/pkg/commands/patch/hunk.go b/pkg/commands/patch/hunk.go new file mode 100644 index 000000000..bbb2d54ff --- /dev/null +++ b/pkg/commands/patch/hunk.go @@ -0,0 +1,142 @@ +package patch + +import ( + "fmt" + "strings" + + "github.com/jesseduffield/lazygit/pkg/utils" +) + +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 := utils.IncludesInt(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 +} |