1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
// Package edit provides edit scripts.
// Edit scripts are a core notion for diffs.
// They represent a way to go from A to B by a sequence
// of insertions, deletions, and equal elements.
package edit
import (
"fmt"
"strings"
)
// A Script is an edit script to alter A into B.
type Script struct {
Ranges []Range
}
// NewScript returns a Script containing the ranges r.
// It is only a convenience wrapper used to reduce line noise.
func NewScript(r ...Range) Script {
return Script{Ranges: r}
}
// IsIdentity reports whether s is the identity edit script,
// that is, whether A and B are identical.
func (s *Script) IsIdentity() bool {
for _, r := range s.Ranges {
if !r.IsEqual() {
return false
}
}
return true
}
// Stat reports the total number of insertions and deletions in s.
func (s *Script) Stat() (ins, del int) {
for _, r := range s.Ranges {
switch {
case r.IsDelete():
del += r.HighA - r.LowA
case r.IsInsert():
ins += r.HighB - r.LowB
}
}
return ins, del
}
// dump formats s for debugging.
func (s *Script) dump() string {
buf := new(strings.Builder)
for _, r := range s.Ranges {
fmt.Fprintln(buf, r)
}
return buf.String()
}
// A Range is a pair of clopen index ranges.
// It represents the elements A[LowA:HighA] and B[LowB:HighB].
type Range struct {
LowA, HighA int
LowB, HighB int
}
// IsInsert reports whether r represents an insertion in a Script.
// If so, the inserted elements are B[LowB:HighB].
func (r *Range) IsInsert() bool {
return r.LowA == r.HighA
}
// IsDelete reports whether r represents a deletion in a Script.
// If so, the deleted elements are A[LowA:HighA].
func (r *Range) IsDelete() bool {
return r.LowB == r.HighB
}
// IsEqual reports whether r represents a series of equal elements in a Script.
// If so, the elements A[LowA:HighA] are equal to the elements B[LowB:HighB].
func (r *Range) IsEqual() bool {
return r.HighB-r.LowB == r.HighA-r.LowA
}
// An Op is a edit operation in a Script.
type Op int8
//go:generate stringer -type Op
const (
Del Op = -1 // delete
Eq Op = 0 // equal
Ins Op = 1 // insert
)
// Op reports what kind of operation r represents.
// This can also be determined by calling r.IsInsert,
// r.IsDelete, and r.IsEqual,
// but this form is sometimes more convenient to use.
func (r *Range) Op() Op {
if r.IsInsert() {
return Ins
}
if r.IsDelete() {
return Del
}
if r.IsEqual() {
return Eq
}
panic("malformed Range")
}
// Len reports the number of elements in r.
// In a deletion, it is the number of deleted elements.
// In an insertion, it is the number of inserted elements.
// For equal elements, it is the number of equal elements.
func (r *Range) Len() int {
if r.LowA == r.HighA {
return r.HighB - r.LowB
}
return r.HighA - r.LowA
}
|