Documentation
¶
Index ¶
- Constants
- func FprintUniHunks[T any](w io.Writer, uniHunks []UniHunk[T])
- func SprintUniHunks[T any](uniHunks []UniHunk[T]) string
- type Diff
- func (diff *Diff[T]) Compose()
- func (d *Diff[T]) EditDistance() int
- func (diff *Diff[T]) FprintSes(w io.Writer)
- func (diff *Diff[T]) Lcs() []T
- func (d *Diff[T]) OnlyEd() *Diff[T]
- func (diff *Diff[T]) Patch(seq []T) []T
- func (diff *Diff[T]) PrintSes()
- func (diff *Diff[T]) PrintUniHunks(uniHunks []UniHunk[T])
- func (diff *Diff[T]) Ses() []SesElem[T]
- func (d *Diff[T]) SetContextSize(n int) *Diff[T]
- func (d *Diff[T]) SetRouteSize(n int) *Diff[T]
- func (diff *Diff[T]) SprintSes() string
- func (diff *Diff[T]) UniPatch(seq []T, uniHunks []UniHunk[T]) ([]T, error)
- func (diff *Diff[T]) UnifiedHunks() []UniHunk[T]
- type Elem
- type Point
- type PointWithRoute
- type SesElem
- type SesType
- type UniHunk
Examples ¶
Constants ¶
const ( PhaseFrontDiff = iota PhaseInDiff PhaseBehindDiff )
const (
DefaultContextSize = 3
)
const (
// limit of cordinate size
DefaultRouteSize = 2000000
)
Variables ¶
This section is empty.
Functions ¶
func FprintUniHunks ¶
FprintUniHunks emit about unified format difference between a and b to w
func SprintUniHunks ¶
SprintUniHunks returns string about unified format difference between a and b
Types ¶
type Diff ¶
type Diff[T Elem] struct { // contains filtered or unexported fields }
Diff is context for calculating difference between a and b
func (*Diff[T]) EditDistance ¶
EditDistance returns edit distance between a and b
func (*Diff[T]) Lcs ¶
func (diff *Diff[T]) Lcs() []T
Lcs returns LCS (Longest Common Subsequence) between a and b
func (*Diff[T]) Patch ¶
func (diff *Diff[T]) Patch(seq []T) []T
Patch applies SES between a and b to seq
Example (FilePatch) ¶
package main
import (
"bufio"
"fmt"
"log"
"os"
"github.com/quenbyako/gonp"
)
func main() {
if len(os.Args) < 3 {
log.Fatal("./filepatch filename1 filename2")
}
f1 := os.Args[1]
f2 := os.Args[2]
var (
a []string
b []string
err error
)
a, err = getLines(f1)
if err != nil {
log.Fatalf("%s: %s", f1, err)
}
b, err = getLines(f2)
if err != nil {
log.Fatalf("%s: %s", f2, err)
}
diff := gonp.New(a, b)
diff.Compose()
patchedSeq := diff.Patch(a)
fmt.Printf("success:%v, applying SES between '%s' and '%s'\n", equalsStringSlice(b, patchedSeq), f1, f2)
uniPatchedSeq, err := diff.UniPatch(a, diff.UnifiedHunks())
if err != nil {
log.Fatal(err)
}
fmt.Printf("success:%v, applying unified format difference between '%s' and '%s'\n", equalsStringSlice(b, uniPatchedSeq), f1, f2)
}
func equalsStringSlice(a, b []string) bool {
m, n := len(a), len(b)
if m != n {
return false
}
for i := 0; i < m; i++ {
if a[i] != b[i] {
return false
}
}
return true
}
// getLines returns a file contents as string array
func getLines(f string) ([]string, error) {
fp, err := os.Open(f)
if err != nil {
return []string{}, err
}
defer fp.Close()
scanner := bufio.NewScanner(fp)
lines := make([]string, 0)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines, nil
}
Example (UniIntDiff) ¶
package main
import (
"cmp"
"fmt"
"github.com/quenbyako/gonp"
)
func main() {
a := []Row{{1, "Pupa"}, {2, "Lupa"}, {3, "Popa"}}
b := []Row{{1, "Pupa"}, {2, "Lupa"}, {3, "Zhopa"}}
diff := gonp.NewCmp(a, b, cmpRow)
diff.Compose()
fmt.Printf("diff %v %v\n", a, b)
fmt.Printf("EditDistance: %d\n", diff.EditDistance())
fmt.Printf("LCS: %v\n", diff.Lcs())
fmt.Println("Unified format difference:")
diff.PrintUniHunks(diff.UnifiedHunks())
}
type Row struct {
ID int
Name string
}
func (r *Row) String() string {
return fmt.Sprintf("%v, %v", r.ID, r.Name)
}
func cmpRow(a, b Row) int {
for _, v := range []int{
cmp.Compare(a.ID, b.ID),
cmp.Compare(a.Name, b.Name),
} {
if v != 0 {
return v
}
}
return 0
}
func (*Diff[T]) PrintSes ¶
func (diff *Diff[T]) PrintSes()
PrintSes prints shortest edit script between a and b
Example (IntDiff) ¶
package main
import (
"fmt"
"github.com/quenbyako/gonp"
)
func main() {
a := []int{1, 2, 3, 4, 5}
b := []int{1, 2, 9, 4, 5}
diff := gonp.New(a, b)
diff.Compose()
fmt.Printf("diff %v %v\n", a, b)
fmt.Printf("EditDistance: %d\n", diff.EditDistance())
fmt.Printf("LCS: %v\n", diff.Lcs())
fmt.Println("SES:")
diff.PrintSes()
}
Example (StrDiff) ¶
package main
import (
"bytes"
"fmt"
"log"
"os"
"unicode/utf8"
"github.com/quenbyako/gonp"
)
func main() {
if len(os.Args) < 3 {
log.Fatal("./strdiff arg1 arg2")
}
if !utf8.ValidString(os.Args[1]) {
log.Fatalf("arg1 contains invalid rune")
}
if !utf8.ValidString(os.Args[2]) {
log.Fatalf("arg2 contains invalid rune")
}
a := []rune(os.Args[1])
b := []rune(os.Args[2])
diff := gonp.New(a, b)
diff.Compose()
fmt.Printf("EditDistance: %d\n", diff.EditDistance())
fmt.Printf("LCS: %s\n", string(diff.Lcs()))
fmt.Println("SES:")
var buf bytes.Buffer
ses := diff.Ses()
for _, e := range ses {
ee := e.GetElem()
switch e.GetType() {
case gonp.SesDelete:
fmt.Fprintf(&buf, "-%c\n", ee)
case gonp.SesAdd:
fmt.Fprintf(&buf, "+%c\n", ee)
case gonp.SesCommon:
fmt.Fprintf(&buf, " %c\n", ee)
}
}
fmt.Print(buf.String())
}
func (*Diff[T]) PrintUniHunks ¶
PrintUniHunks prints unified format difference between and b
Example (UniFileDiff) ¶
package main
import (
"bufio"
"bytes"
"fmt"
"log"
"os"
"time"
"github.com/quenbyako/gonp"
)
func main() {
if len(os.Args) < 3 {
log.Fatal("./unifilediff filename1 filename2")
}
f1 := os.Args[1]
f2 := os.Args[2]
var (
a []string
b []string
err error
)
a, err = getLines(f1)
if err != nil {
log.Fatalf("%s: %s", f1, err)
}
b, err = getLines(f2)
if err != nil {
log.Fatalf("%s: %s", f2, err)
}
th, err := buildTargetHeader(f1, f2)
if err != nil {
log.Fatal(err)
}
diff := gonp.New(a, b)
diff.Compose()
fmt.Printf(th.String())
diff.PrintUniHunks(diff.UnifiedHunks())
}
// Target consists of a path and mtime of file.
type Target struct {
fname string
mtime time.Time
}
// TargetHeader has 2 targets based on pathes and mtimes based on 2 files
type TargetHeader struct {
targets []Target
}
// getLines returns a file contents as string array
func getLines(f string) ([]string, error) {
fp, err := os.Open(f)
if err != nil {
return []string{}, err
}
defer fp.Close()
scanner := bufio.NewScanner(fp)
lines := make([]string, 0)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines, nil
}
// builderTargetHeader returns TargetHeader constructed based on 2 files given as arguments
func buildTargetHeader(f1, f2 string) (TargetHeader, error) {
fi1, err := os.Stat(f1)
if err != nil {
return TargetHeader{}, err
}
fi2, err := os.Stat(f2)
if err != nil {
return TargetHeader{}, err
}
return TargetHeader{
targets: []Target{
{fname: f1, mtime: fi1.ModTime()},
{fname: f2, mtime: fi2.ModTime()},
},
}, nil
}
// String returns a content of TargetHeader as a string
func (th *TargetHeader) String() string {
if len(th.targets) != 2 {
return ""
}
var b bytes.Buffer
fmt.Fprintf(&b, "--- %s\t%s\n", th.targets[0].fname, th.targets[0].mtime.Format(time.RFC3339Nano))
fmt.Fprintf(&b, "+++ %s\t%s\n", th.targets[1].fname, th.targets[1].mtime.Format(time.RFC3339Nano))
return b.String()
}
func (*Diff[T]) SetContextSize ¶
SetContextSize sets the context size of unified format difference
func (*Diff[T]) SetRouteSize ¶
SetRouteSize sets the context size of unified format difference
func (*Diff[T]) UniPatch ¶
UniPatch applies unified format difference between a and b to seq
Example (StrPatch) ¶
package main
import (
"fmt"
"log"
"os"
"unicode/utf8"
"github.com/quenbyako/gonp"
)
func main() {
if len(os.Args) < 3 {
log.Fatal("./strpatch arg1 arg2")
}
if !utf8.ValidString(os.Args[1]) {
log.Fatal("arg1 contains invalid rune")
}
if !utf8.ValidString(os.Args[2]) {
log.Fatal("arg2 contains invalid rune")
}
a := []rune(os.Args[1])
b := []rune(os.Args[2])
diff := gonp.New(a, b)
diff.Compose()
patchedSeq := diff.Patch(a)
fmt.Printf("success:%v, applying SES between '%s' and '%s' to '%s' is '%s'\n",
string(b) == string(patchedSeq),
string(a), string(b),
string(a), string(patchedSeq))
uniPatchedSeq, err := diff.UniPatch(a, diff.UnifiedHunks())
if err != nil {
log.Fatal(err)
}
fmt.Printf("success:%v, applying unified format difference between '%s' and '%s' to '%s' is '%s'\n",
string(b) == string(uniPatchedSeq),
string(a), string(b),
string(a), string(uniPatchedSeq))
}
Example (UniStrDiff) ¶
package main
import (
"bytes"
"fmt"
"log"
"os"
"unicode/utf8"
"github.com/quenbyako/gonp"
)
func main() {
if len(os.Args) < 3 {
log.Fatal("./unistrdiff arg1 arg2")
}
if !utf8.ValidString(os.Args[1]) {
log.Fatalf("arg1 contains invalid rune")
}
if !utf8.ValidString(os.Args[2]) {
log.Fatalf("arg2 contains invalid rune")
}
a := []rune(os.Args[1])
b := []rune(os.Args[2])
diff := gonp.New(a, b)
diff.Compose()
fmt.Printf("EditDistance:%d\n", diff.EditDistance())
fmt.Printf("LCS:%s\n", string(diff.Lcs()))
//diff.PrintUniHunks(diff.UnifiedHunks())
fmt.Println("Unified format difference:")
uniHunks := diff.UnifiedHunks()
var w bytes.Buffer
for _, uniHunk := range uniHunks {
fmt.Fprintf(&w, uniHunk.SprintDiffRange())
for _, e := range uniHunk.GetChanges() {
switch e.GetType() {
case gonp.SesDelete:
fmt.Fprintf(&w, "-%c\n", e.GetElem())
case gonp.SesAdd:
fmt.Fprintf(&w, "+%c\n", e.GetElem())
case gonp.SesCommon:
fmt.Fprintf(&w, " %c\n", e.GetElem())
}
}
}
fmt.Print(w.String())
}
func (*Diff[T]) UnifiedHunks ¶
UnifiedHunks composes unified format difference between a and b
type Point ¶
type Point struct {
// contains filtered or unexported fields
}
Point is coordinate in edit graph
type PointWithRoute ¶
type PointWithRoute struct {
// contains filtered or unexported fields
}
PointWithRoute is coordinate in edit graph attached route
type SesElem ¶
type SesElem[T any] struct { // contains filtered or unexported fields }
SesElem is element of SES
type UniHunk ¶
type UniHunk[T Elem] struct { // contains filtered or unexported fields }
UniHunk is an element of unified format difference
func (*UniHunk[T]) GetChanges ¶
GetChanges is getter of changes in UniHunk
func (*UniHunk[T]) SprintDiffRange ¶
SprintDiffRange returns formatted string represents difference range