Skip to content

Commit 0a511de

Browse files
committed
remove adapters, create wrappers
package diff now has a simple, single-call API. for more control, people can use the subpackages. Part of #18.
1 parent a78b239 commit 0a511de

File tree

7 files changed

+211
-199
lines changed

7 files changed

+211
-199
lines changed

adapter.go

Lines changed: 0 additions & 103 deletions
This file was deleted.

cmd/pkg-diff-example/main.go

Lines changed: 4 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,16 @@
33
package main
44

55
import (
6-
"bufio"
7-
"context"
86
"flag"
97
"fmt"
108
"log"
119
"os"
1210

1311
"github.com/pkg/diff"
14-
"github.com/pkg/diff/ctxt"
15-
"github.com/pkg/diff/myers"
1612
"github.com/pkg/diff/write"
1713
)
1814

19-
var (
20-
color = flag.Bool("color", false, "colorize the output")
21-
timeout = flag.Duration("timeout", 0, "timeout")
22-
unified = flag.Int("unified", 3, "lines of unified context")
23-
)
15+
var color = flag.Bool("color", false, "colorize the output")
2416

2517
// check logs a fatal error and exits if err is not nil.
2618
func check(err error) {
@@ -29,22 +21,6 @@ func check(err error) {
2921
}
3022
}
3123

32-
// fileLines returns the lines of the file called name.
33-
func fileLines(name string) ([]string, error) {
34-
f, err := os.Open(name)
35-
if err != nil {
36-
return nil, err
37-
}
38-
defer f.Close()
39-
40-
var lines []string
41-
s := bufio.NewScanner(f)
42-
for s.Scan() {
43-
lines = append(lines, s.Text())
44-
}
45-
return lines, s.Err()
46-
}
47-
4824
func usage() {
4925
fmt.Fprintf(os.Stderr, "pkg-diff-example [flags] file1 file2\n")
5026
flag.PrintDefaults()
@@ -62,28 +38,13 @@ func main() {
6238
}
6339

6440
aName := flag.Arg(0)
65-
aLines, err := fileLines(aName)
66-
check(err)
67-
6841
bName := flag.Arg(1)
69-
bLines, err := fileLines(bName)
70-
check(err)
7142

72-
ab := diff.Strings(aLines, bLines)
73-
ctx := context.Background()
74-
if *timeout != 0 {
75-
var cancel context.CancelFunc
76-
ctx, cancel = context.WithTimeout(ctx, *timeout)
77-
defer cancel()
78-
}
79-
e := myers.Diff(ctx, ab)
80-
e = ctxt.Size(e, *unified) // limit amount of output context
81-
opts := []write.Option{
82-
write.Names(aName, bName),
83-
}
43+
var opts []write.Option
8444
if *color {
8545
opts = append(opts, write.TerminalColor())
8646
}
87-
_, err = write.Unified(e, os.Stdout, ab, opts...)
47+
48+
err := diff.Text(aName, bName, nil, nil, os.Stdout, opts...)
8849
check(err)
8950
}

diff.go

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,136 @@
1+
// Package diff and its subpackages create, modify, and print diffs.
2+
//
3+
// Package diff contains high level routines that generate a textual diff.
4+
// It is implemented in terms of the diff/* subpackages.
5+
// If you want fine-grained control,
6+
// want to inspect an diff programmatically,
7+
// want to provide a context for cancellation,
8+
// need to diff gigantic files that don't fit in memory,
9+
// or want to diff unusual things,
10+
// use the subpackages.
111
package diff
12+
13+
import (
14+
"bufio"
15+
"bytes"
16+
"context"
17+
"fmt"
18+
"io"
19+
"os"
20+
"reflect"
21+
"strings"
22+
23+
"github.com/pkg/diff/ctxt"
24+
"github.com/pkg/diff/myers"
25+
"github.com/pkg/diff/write"
26+
)
27+
28+
// lines returns the lines contained in text/filename.
29+
// text and filename are interpreted as described in the docs for Text.
30+
func lines(filename string, text interface{}) ([]string, error) {
31+
var r io.Reader
32+
switch text := text.(type) {
33+
case nil:
34+
f, err := os.Open(filename)
35+
if err != nil {
36+
return nil, err
37+
}
38+
defer f.Close()
39+
r = f
40+
case string:
41+
r = strings.NewReader(text)
42+
case []byte:
43+
r = bytes.NewReader(text)
44+
case io.Reader:
45+
r = text
46+
default:
47+
return nil, fmt.Errorf("unexpected type %T, want string, []byte, io.Reader, or nil", text)
48+
}
49+
var x []string
50+
scan := bufio.NewScanner(r)
51+
for scan.Scan() {
52+
// TODO: intern? See intern comment in todo.go.
53+
x = append(x, scan.Text())
54+
}
55+
return x, scan.Err()
56+
}
57+
58+
// addNames adds a Names write.Option using aName and bName,
59+
// taking care to put it at the end,
60+
// so as not to overwrite any competing option.
61+
func addNames(aName, bName string, options []write.Option) []write.Option {
62+
opts := make([]write.Option, len(options)+1)
63+
opts[0] = write.Names(aName, bName)
64+
copy(opts[1:], options)
65+
return opts
66+
}
67+
68+
// Text diffs a and b and writes the result to w.
69+
// It treats a and b as text, and splits them into lines using bufio.ScanLines.
70+
// aFile and bFile are filenames to use in the output.
71+
// a and b each may be nil or may have type string, []byte, or io.Reader.
72+
// If nil, the text is read from the filename.
73+
func Text(aFile, bFile string, a, b interface{}, w io.Writer, options ...write.Option) error {
74+
aLines, err := lines(aFile, a)
75+
if err != nil {
76+
return err
77+
}
78+
bLines, err := lines(bFile, b)
79+
if err != nil {
80+
return err
81+
}
82+
ab := &diffStrings{a: aLines, b: bLines}
83+
s := myers.Diff(context.Background(), ab)
84+
s = ctxt.Size(s, 3)
85+
opts := addNames(aFile, bFile, options)
86+
_, err = write.Unified(s, w, ab, opts...)
87+
return err
88+
}
89+
90+
type diffStrings struct {
91+
a, b []string
92+
}
93+
94+
func (ab *diffStrings) LenA() int { return len(ab.a) }
95+
func (ab *diffStrings) LenB() int { return len(ab.b) }
96+
func (ab *diffStrings) Equal(ai, bi int) bool { return ab.a[ai] == ab.b[bi] }
97+
func (ab *diffStrings) WriteATo(w io.Writer, i int) (int, error) { return io.WriteString(w, ab.a[i]) }
98+
func (ab *diffStrings) WriteBTo(w io.Writer, i int) (int, error) { return io.WriteString(w, ab.b[i]) }
99+
100+
// Slices diffs slices a and b and writes the result to w.
101+
// It uses fmt.Print to print the elements of a and b.
102+
// It uses reflect.DeepEqual to compare elements of a and b.
103+
// It uses aName and bName as the names of a and b in the output.
104+
func Slices(aName, bName string, a, b interface{}, w io.Writer, options ...write.Option) error {
105+
ab := &diffSlices{a: reflect.ValueOf(a), b: reflect.ValueOf(b)}
106+
if err := ab.validateTypes(); err != nil {
107+
return err
108+
}
109+
s := myers.Diff(context.Background(), ab)
110+
s = ctxt.Size(s, 3)
111+
opts := addNames(aName, bName, options)
112+
_, err := write.Unified(s, w, ab, opts...)
113+
return err
114+
}
115+
116+
type diffSlices struct {
117+
a, b reflect.Value
118+
}
119+
120+
func (ab *diffSlices) LenA() int { return ab.a.Len() }
121+
func (ab *diffSlices) LenB() int { return ab.b.Len() }
122+
func (ab *diffSlices) atA(i int) interface{} { return ab.a.Index(i).Interface() }
123+
func (ab *diffSlices) atB(i int) interface{} { return ab.b.Index(i).Interface() }
124+
func (ab *diffSlices) Equal(ai, bi int) bool { return reflect.DeepEqual(ab.atA(ai), ab.atB(bi)) }
125+
func (ab *diffSlices) WriteATo(w io.Writer, i int) (int, error) { return fmt.Fprint(w, ab.atA(i)) }
126+
func (ab *diffSlices) WriteBTo(w io.Writer, i int) (int, error) { return fmt.Fprint(w, ab.atB(i)) }
127+
128+
func (ab *diffSlices) validateTypes() error {
129+
if t := ab.a.Type(); t.Kind() != reflect.Slice {
130+
return fmt.Errorf("a has type %v, must be a slice", t)
131+
}
132+
if t := ab.b.Type(); t.Kind() != reflect.Slice {
133+
return fmt.Errorf("b has type %v, must be a slice", t)
134+
}
135+
return nil
136+
}

doc.go

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)