Skip to content

Commit

Permalink
new diff lib: diferenco (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
fcharlie committed Dec 6, 2024
1 parent fc2d2be commit 415fc6f
Show file tree
Hide file tree
Showing 26 changed files with 3,262 additions and 0 deletions.
92 changes: 92 additions & 0 deletions modules/diferenco/diferenco.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package diferenco

import "slices"

// https://github.com/Wilfred/difftastic/wiki/Line-Based-Diffs
// https://neil.fraser.name/writing/diff/
// https://prettydiff.com/2/guide/unrelated_diff.xhtml

// Operation defines the operation of a diff item.
type Operation int8

const (
// Delete item represents a delete hunk.
Delete Operation = -1
// Insert item represents an insert hunk.
Insert Operation = 1
// Equal item represents an equal hunk.
Equal Operation = 0
)

// commonPrefixLength returns the length of the common prefix of two T slices.
func commonPrefixLength[E comparable](a, b []E) int {
n := min(len(a), len(b))
i := 0
for i < n && a[i] == b[i] {
i++
}
return i
}

// commonSuffixLength returns the length of the common suffix of two rune slices.
func commonSuffixLength[E comparable](a, b []E) int {
i1, i2 := len(a), len(b)
n := min(i1, i2)
i := 0
for i < n && a[i1-1-i] == b[i2-1-i] {
i++
}
return i
}

func slicesHasSuffix[E comparable](a, suffix []E) bool {
return len(a) >= len(suffix) && slices.Equal(a[len(a)-len(suffix):], suffix)
}

func slicesHasPrefix[E comparable](a, prefix []E) bool {
return len(a) >= len(prefix) && slices.Equal(a[:len(prefix)], prefix)
}

// slicesIndex is the equivalent of strings.Index for rune slices.
func slicesIndex[E comparable](s1, s2 []E) int {
last := len(s1) - len(s2)
for i := 0; i <= last; i++ {
if slices.Equal(s1[i:i+len(s2)], s2) {
return i
}
}
return -1
}

// slicesIndexOf returns the index of pattern in target, starting at target[i].
func slicesIndexOf[E comparable](target, pattern []E, i int) int {
if i > len(target)-1 {
return -1
}
if i <= 0 {
return slicesIndex(target, pattern)
}
ind := slicesIndex(target[i:], pattern)
if ind == -1 {
return -1
}
return ind + i
}

type Change struct {
P1 int // before: position in before
P2 int // after: position in after
Del int // number of elements that deleted from a
Ins int // number of elements that inserted into b
}

type Dfio[E comparable] struct {
T Operation
E []E
}

// StringDiff represents one diff operation
type StringDiff struct {
Type Operation
Text string
}
67 changes: 67 additions & 0 deletions modules/diferenco/diferenco_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package diferenco

import (
"fmt"
"os"
"path/filepath"
"runtime"
"testing"
)

func TestDiff(t *testing.T) {
_, filename, _, _ := runtime.Caller(0)
dir := filepath.Dir(filename)
bytesA, err := os.ReadFile(filepath.Join(dir, "testdata/a.txt"))
if err != nil {
fmt.Fprintf(os.Stderr, "read a error: %v\n", err)
return
}
textA := string(bytesA)
bytesB, err := os.ReadFile(filepath.Join(dir, "testdata/b.txt"))
if err != nil {
fmt.Fprintf(os.Stderr, "read b error: %v\n", err)
return
}
textB := string(bytesB)
sink := &Sink{
Index: make(map[string]int),
}
a := sink.ParseLines(textA)
b := sink.ParseLines(textB)
changes := OnpDiff(a, b)
i := 0
for _, c := range changes {
for ; i < c.P1; i++ {
fmt.Fprintf(os.Stderr, " %s", sink.Lines[a[i]])
}
for j := c.P1; j < c.P1+c.Del; j++ {
fmt.Fprintf(os.Stderr, "\x1b[31m- %s\x1b[0m", sink.Lines[a[j]])
}
for j := c.P2; j < c.P2+c.Ins; j++ {
fmt.Fprintf(os.Stderr, "\x1b[32m+ %s\x1b[0m", sink.Lines[b[j]])
}
i += c.Del
}
for ; i < len(a); i++ {
fmt.Fprintf(os.Stderr, " %s", sink.Lines[a[i]])
}
fmt.Fprintf(os.Stderr, "\n\npatience\n\n")

diffs := PatienceDiff(a, b)
for _, d := range diffs {
switch d.T {
case Delete:
for _, i := range d.E {
fmt.Fprintf(os.Stderr, "\x1b[31m-%s\x1b[0m", sink.Lines[i])
}
case Insert:
for _, i := range d.E {
fmt.Fprintf(os.Stderr, "\x1b[32m+%s\x1b[0m", sink.Lines[i])
}
default:
for _, i := range d.E {
fmt.Fprintf(os.Stderr, " %s", sink.Lines[i])
}
}
}
}
Loading

0 comments on commit 415fc6f

Please sign in to comment.