Detailed changes
@@ -16,6 +16,7 @@ require (
github.com/charmbracelet/glamour v0.9.1
github.com/charmbracelet/lipgloss v1.1.0
github.com/charmbracelet/x/ansi v0.8.0
+ github.com/charmbracelet/x/exp/golden v0.0.0-20250602192518-9e722df69bbb
github.com/fsnotify/fsnotify v1.8.0
github.com/go-logfmt/logfmt v0.6.0
github.com/google/uuid v1.6.0
@@ -82,8 +82,8 @@ github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2ll
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
-github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
-github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
+github.com/charmbracelet/x/exp/golden v0.0.0-20250602192518-9e722df69bbb h1:GT/STWThMsrOfYQnhnIPb165e/g1waAp0gNMFvEO6WI=
+github.com/charmbracelet/x/exp/golden v0.0.0-20250602192518-9e722df69bbb/go.mod h1:929X+xY3LeoOZrDWIBVZcx/zyS0CYtyLiUIvE4VbKC0=
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
@@ -0,0 +1 @@
+package diff
@@ -0,0 +1,11 @@
+--- main.go
++++ main.go
+@@ -5,5 +5,6 @@
+ )
+
+ func main() {
+- fmt.Println("Hello, World!")
++ content := "Hello, World!"
++ fmt.Println(content)
+ }
+\ No newline at end of file
@@ -0,0 +1,40 @@
+{
+ "From": "main.go",
+ "To": "main.go",
+ "Hunks": [
+ {
+ "FromLine": 5,
+ "ToLine": 5,
+ "Lines": [
+ {
+ "Kind": 2,
+ "Content": "\t)\n"
+ },
+ {
+ "Kind": 2,
+ "Content": "\n"
+ },
+ {
+ "Kind": 2,
+ "Content": "\tfunc main() {\n"
+ },
+ {
+ "Kind": 0,
+ "Content": "\t\tfmt.Println(\"Hello, World!\")\n"
+ },
+ {
+ "Kind": 1,
+ "Content": "\t\tcontent := \"Hello, World!\"\n"
+ },
+ {
+ "Kind": 1,
+ "Content": "\t\tfmt.Println(content)\n"
+ },
+ {
+ "Kind": 2,
+ "Content": "\t}"
+ }
+ ]
+ }
+ ]
+}
@@ -0,0 +1,12 @@
+--- main.go
++++ main.go
+@@ -4,6 +4,7 @@
+ "fmt"
+ )
+
+ func main() {
+- fmt.Println("Hello, World!")
++ content := "Hello, World!"
++ fmt.Println(content)
+ }
+\ No newline at end of file
@@ -0,0 +1,44 @@
+{
+ "From": "main.go",
+ "To": "main.go",
+ "Hunks": [
+ {
+ "FromLine": 4,
+ "ToLine": 4,
+ "Lines": [
+ {
+ "Kind": 2,
+ "Content": "\t\t\"fmt\"\n"
+ },
+ {
+ "Kind": 2,
+ "Content": "\t)\n"
+ },
+ {
+ "Kind": 2,
+ "Content": "\n"
+ },
+ {
+ "Kind": 2,
+ "Content": "\tfunc main() {\n"
+ },
+ {
+ "Kind": 0,
+ "Content": "\t\tfmt.Println(\"Hello, World!\")\n"
+ },
+ {
+ "Kind": 1,
+ "Content": "\t\tcontent := \"Hello, World!\"\n"
+ },
+ {
+ "Kind": 1,
+ "Content": "\t\tfmt.Println(content)\n"
+ },
+ {
+ "Kind": 2,
+ "Content": "\t}"
+ }
+ ]
+ }
+ ]
+}
@@ -0,0 +1,13 @@
+--- main.go
++++ main.go
+@@ -3,7 +3,8 @@
+ import (
+ "fmt"
+ )
+
+ func main() {
+- fmt.Println("Hello, World!")
++ content := "Hello, World!"
++ fmt.Println(content)
+ }
+\ No newline at end of file
@@ -0,0 +1,48 @@
+{
+ "From": "main.go",
+ "To": "main.go",
+ "Hunks": [
+ {
+ "FromLine": 3,
+ "ToLine": 3,
+ "Lines": [
+ {
+ "Kind": 2,
+ "Content": "\timport (\n"
+ },
+ {
+ "Kind": 2,
+ "Content": "\t\t\"fmt\"\n"
+ },
+ {
+ "Kind": 2,
+ "Content": "\t)\n"
+ },
+ {
+ "Kind": 2,
+ "Content": "\n"
+ },
+ {
+ "Kind": 2,
+ "Content": "\tfunc main() {\n"
+ },
+ {
+ "Kind": 0,
+ "Content": "\t\tfmt.Println(\"Hello, World!\")\n"
+ },
+ {
+ "Kind": 1,
+ "Content": "\t\tcontent := \"Hello, World!\"\n"
+ },
+ {
+ "Kind": 1,
+ "Content": "\t\tfmt.Println(content)\n"
+ },
+ {
+ "Kind": 2,
+ "Content": "\t}"
+ }
+ ]
+ }
+ ]
+}
@@ -0,0 +1,11 @@
+--- main.go
++++ main.go
+@@ -5,5 +5,6 @@
+ )
+
+ func main() {
+- fmt.Println("Hello, World!")
++ content := "Hello, World!"
++ fmt.Println(content)
+ }
+\ No newline at end of file
@@ -0,0 +1,92 @@
+package diff_test
+
+import (
+ "bytes"
+ "encoding/json"
+ "testing"
+
+ "github.com/aymanbagabas/go-udiff"
+ "github.com/aymanbagabas/go-udiff/myers"
+ "github.com/charmbracelet/x/exp/golden"
+)
+
+func TestUdiff(t *testing.T) {
+ before := `package main
+
+ import (
+ "fmt"
+ )
+
+ func main() {
+ fmt.Println("Hello, World!")
+ }`
+
+ after := `package main
+
+ import (
+ "fmt"
+ )
+
+ func main() {
+ content := "Hello, World!"
+ fmt.Println(content)
+ }`
+
+ t.Run("Unified", func(t *testing.T) {
+ content := udiff.Unified("main.go", "main.go", before, after)
+ golden.RequireEqual(t, []byte(content))
+ })
+
+ t.Run("ToUnifiedDiff", func(t *testing.T) {
+ toUnifiedDiff := func(t *testing.T, before, after string, contextLines int) udiff.UnifiedDiff {
+ edits := myers.ComputeEdits(before, after)
+ unifiedDiff, err := udiff.ToUnifiedDiff("main.go", "main.go", before, edits, contextLines)
+ if err != nil {
+ t.Fatalf("ToUnifiedDiff failed: %v", err)
+ }
+ return unifiedDiff
+ }
+ toJSON := func(t *testing.T, unifiedDiff udiff.UnifiedDiff) []byte {
+ var buff bytes.Buffer
+ encoder := json.NewEncoder(&buff)
+ encoder.SetIndent("", " ")
+ if err := encoder.Encode(unifiedDiff); err != nil {
+ t.Fatalf("Failed to encode unified diff: %v", err)
+ }
+ return buff.Bytes()
+ }
+
+ t.Run("DefaultContextLines", func(t *testing.T) {
+ unifiedDiff := toUnifiedDiff(t, before, after, udiff.DefaultContextLines)
+
+ t.Run("Content", func(t *testing.T) {
+ golden.RequireEqual(t, []byte(unifiedDiff.String()))
+ })
+ t.Run("JSON", func(t *testing.T) {
+ golden.RequireEqual(t, toJSON(t, unifiedDiff))
+ })
+ })
+
+ t.Run("DefaultContextLinesPlusOne", func(t *testing.T) {
+ unifiedDiff := toUnifiedDiff(t, before, after, udiff.DefaultContextLines+1)
+
+ t.Run("Content", func(t *testing.T) {
+ golden.RequireEqual(t, []byte(unifiedDiff.String()))
+ })
+ t.Run("JSON", func(t *testing.T) {
+ golden.RequireEqual(t, toJSON(t, unifiedDiff))
+ })
+ })
+
+ t.Run("DefaultContextLinesPlusTwo", func(t *testing.T) {
+ unifiedDiff := toUnifiedDiff(t, before, after, udiff.DefaultContextLines+2)
+
+ t.Run("Content", func(t *testing.T) {
+ golden.RequireEqual(t, []byte(unifiedDiff.String()))
+ })
+ t.Run("JSON", func(t *testing.T) {
+ golden.RequireEqual(t, toJSON(t, unifiedDiff))
+ })
+ })
+ })
+}