mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-10-06 05:57:38 -04:00
Parse is lenient: it takes any text and reads a diff out of it, which is what we want when we hand it a diff, but it has no way to say "this isn't one". We're about to parse the *rendered* contents of a diff view, which a diff renderer is free to restructure — putting the line numbers in a gutter, say, shifts the +/- marker off the start of each body line, so every line reads as context and the parse silently lies about which lines are changes. Comparing each hunk's body against the lengths its header declares catches exactly that, without teaching us anything about any particular renderer's layout: a faithful unified diff agrees with its headers, a restructured one doesn't. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
74 lines
2.5 KiB
Go
74 lines
2.5 KiB
Go
package patch
|
|
|
|
import "fmt"
|
|
|
|
// Example hunk:
|
|
// @@ -16,2 +14,3 @@ func (f *CommitFile) Description() string {
|
|
// return f.Name
|
|
// -}
|
|
// +
|
|
// +// test
|
|
|
|
type Hunk struct {
|
|
// the line number of the first line in the old file ('16' in the above example)
|
|
oldStart int
|
|
// the line number of the first line in the new file ('14' in the above example)
|
|
newStart int
|
|
// the context at the end of the header line (' func (f *CommitFile) Description() string {' in the above example)
|
|
headerContext string
|
|
// the lengths declared in the header line ('2' and '3' in the above example),
|
|
// kept so that we can check the parsed body against them (see
|
|
// Patch.IsWellFormed). Only set by Parse.
|
|
declaredOldLength int
|
|
declaredNewLength int
|
|
// the body of the hunk, excluding the header line
|
|
bodyLines []*PatchLine
|
|
}
|
|
|
|
// Returns the number of lines in the hunk in the original file ('2' in the above example)
|
|
func (self *Hunk) oldLength() int {
|
|
return nLinesWithKind(self.bodyLines, []PatchLineKind{CONTEXT, DELETION})
|
|
}
|
|
|
|
// Returns the number of lines in the hunk in the new file ('3' in the above example)
|
|
func (self *Hunk) newLength() int {
|
|
return nLinesWithKind(self.bodyLines, []PatchLineKind{CONTEXT, ADDITION})
|
|
}
|
|
|
|
// Returns true if the hunk contains any changes (i.e. if it's not just a context hunk).
|
|
// We'll end up with a context hunk if we're transforming a patch and one of the hunks
|
|
// has no selected lines.
|
|
func (self *Hunk) containsChanges() bool {
|
|
return nLinesWithKind(self.bodyLines, []PatchLineKind{ADDITION, DELETION}) > 0
|
|
}
|
|
|
|
// Returns the number of lines in the hunk, including the header line
|
|
func (self *Hunk) lineCount() int {
|
|
return len(self.bodyLines) + 1
|
|
}
|
|
|
|
// Returns all lines in the hunk, including the header line
|
|
func (self *Hunk) allLines() []*PatchLine {
|
|
lines := make([]*PatchLine, 1, 1+len(self.bodyLines))
|
|
lines[0] = &PatchLine{Content: self.formatHeaderLine(), Kind: HUNK_HEADER}
|
|
lines = append(lines, self.bodyLines...)
|
|
return lines
|
|
}
|
|
|
|
// Returns the header line, including the unified diff header and the context
|
|
func (self *Hunk) formatHeaderLine() string {
|
|
return fmt.Sprintf("%s%s", self.formatHeaderStart(), self.headerContext)
|
|
}
|
|
|
|
// Returns the first part of the header line i.e. the unified diff part (excluding any context)
|
|
func (self *Hunk) formatHeaderStart() string {
|
|
newLengthDisplay := ""
|
|
newLength := self.newLength()
|
|
// if the new length is 1, it's omitted
|
|
if newLength != 1 {
|
|
newLengthDisplay = fmt.Sprintf(",%d", newLength)
|
|
}
|
|
|
|
return fmt.Sprintf("@@ -%d,%d +%d%s @@", self.oldStart, self.oldLength(), self.newStart, newLengthDisplay)
|
|
}
|