summaryrefslogtreecommitdiffstats
path: root/pkg/commands/patch/hunk.go
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2020-08-15 11:18:40 +1000
committerJesse Duffield <jessedduffield@gmail.com>2020-08-15 11:41:37 +1000
commit826d1660c97b7c5c55420ffed21eaa5f16118118 (patch)
tree8f2f65a3d2617aa242034273c4a41b6ec5aea659 /pkg/commands/patch/hunk.go
parent291a8e4de0f5d5557cf6fbd7b5b6b9d42bcaa16e (diff)
move patch stuff into its own package
Diffstat (limited to 'pkg/commands/patch/hunk.go')
-rw-r--r--pkg/commands/patch/hunk.go142
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
+}