Skip to content

Commit

Permalink
feat: add udiff cmd package
Browse files Browse the repository at this point in the history
Run uDiff as a standalone binary
  • Loading branch information
aymanbagabas committed Dec 15, 2023
1 parent 58ea632 commit 9ee1cb2
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 0 deletions.
11 changes: 11 additions & 0 deletions cmd/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module github.com/aymanbagabas/go-udiff/cmd

go 1.18

require (
github.com/aymanbagabas/go-udiff v0.2.0
github.com/mattn/go-isatty v0.0.20
github.com/spf13/pflag v1.0.5
)

require golang.org/x/sys v0.6.0 // indirect
8 changes: 8 additions & 0 deletions cmd/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
155 changes: 155 additions & 0 deletions cmd/udiff/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package main

import (
"fmt"
"io"
"os"
"strings"

"github.com/aymanbagabas/go-udiff"
"github.com/mattn/go-isatty"
"github.com/spf13/pflag"
)

const (
redSeq = "\033[31m"
greenSeq = "\033[32m"
resetSeq = "\033[0m"
)

var (
contextLines int
color string
)

func init() {
pflag.Usage = usage
pflag.IntVarP(&contextLines, "context", "C", udiff.DefaultContextLines, "number of context lines")
pflag.StringVarP(&color, "color", "", "auto", "colorize the output; can be 'always', 'never', or 'auto'")
}

func usage() {
fmt.Fprintf(os.Stderr, "Usage: %s [options] file1 file2\n", os.Args[0])
pflag.PrintDefaults()
}

func main() {
pflag.Parse()
args := pflag.Args()
if len(args) != 2 {
pflag.Usage()
os.Exit(1)
}

var colorize bool
switch strings.ToLower(color) {
case "always":
colorize = true
case "auto":
colorize = isatty.IsTerminal(os.Stdout.Fd())
}

f1, err := os.Open(args[0])
if err != nil {
fmt.Fprintf(os.Stderr, "couldn't open file: %s\n", err)
os.Exit(1)
}

defer f1.Close()
f2, err := os.Open(args[1])
if err != nil {
fmt.Fprintf(os.Stderr, "couldn't open file: %s\n", err)
os.Exit(1)
}

defer f2.Close()
s1, err := io.ReadAll(f1)
if err != nil {
fmt.Fprintf(os.Stderr, "couldn't read file: %s\n", err)
os.Exit(1)
}

s2, err := io.ReadAll(f2)
if err != nil {
fmt.Fprintf(os.Stderr, "couldn't read file: %s\n", err)
os.Exit(1)
}

edits := udiff.Strings(string(s1), string(s2))
u, err := udiff.ToUnifiedDiff(f1.Name(), f2.Name(), string(s1), edits, contextLines)
if err != nil {
fmt.Fprintf(os.Stderr, "couldn't generate diff: %s\n", err)
os.Exit(1)
}

fmt.Println(toString(u, colorize))
}

// String converts a unified diff to the standard textual form for that diff.
// The output of this function can be passed to tools like patch.
func toString(u udiff.UnifiedDiff, colorize bool) string {
if len(u.Hunks) == 0 {
return ""
}
b := new(strings.Builder)
fmt.Fprintf(b, "--- %s\n", u.From)
fmt.Fprintf(b, "+++ %s\n", u.To)
for _, hunk := range u.Hunks {
fromCount, toCount := 0, 0
for _, l := range hunk.Lines {
switch l.Kind {
case udiff.Delete:
fromCount++
case udiff.Insert:
toCount++
default:
fromCount++
toCount++
}
}
fmt.Fprint(b, "@@")
if fromCount > 1 {
fmt.Fprintf(b, " -%d,%d", hunk.FromLine, fromCount)
} else if hunk.FromLine == 1 && fromCount == 0 {
// Match odd GNU diff -u behavior adding to empty file.
fmt.Fprintf(b, " -0,0")
} else {
fmt.Fprintf(b, " -%d", hunk.FromLine)
}
if toCount > 1 {
fmt.Fprintf(b, " +%d,%d", hunk.ToLine, toCount)
} else if hunk.ToLine == 1 && toCount == 0 {
// Match odd GNU diff -u behavior adding to empty file.
fmt.Fprintf(b, " +0,0")
} else {
fmt.Fprintf(b, " +%d", hunk.ToLine)
}
fmt.Fprint(b, " @@\n")
for _, l := range hunk.Lines {
switch l.Kind {
case udiff.Delete:
if colorize {
fmt.Fprint(b, redSeq)
}
fmt.Fprintf(b, "-%s", l.Content)
if colorize {
fmt.Fprint(b, resetSeq)
}
case udiff.Insert:
if colorize {
fmt.Fprint(b, greenSeq)
}
fmt.Fprintf(b, "+%s", l.Content)
if colorize {
fmt.Fprint(b, resetSeq)
}
default:
fmt.Fprintf(b, " %s", l.Content)
}
if !strings.HasSuffix(l.Content, "\n") {
fmt.Fprintf(b, "\n\\ No newline at end of file\n")
}
}
}
return b.String()
}

0 comments on commit 9ee1cb2

Please sign in to comment.