-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
issues/60: Add ability to diff items (#67)
- Fixes: #60 Thanks to; - https://github.com/rsc/diff
- Loading branch information
Showing
9 changed files
with
327 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// Copyright 2019 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
// Package diff provides basic text comparison (like Unix's diff(1)). | ||
package kama | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
) | ||
|
||
// Most of the code here is insipired by(or taken from): | ||
// (a) https://github.com/rsc/diff whose license(BSD 3-Clause "New" or "Revised" License) can be found here: https://github.com/rsc/diff/blob/master/LICENSE | ||
|
||
// diff returns a formatted diff of the two texts, | ||
// showing the entire text and the minimum line-level | ||
// additions and removals to turn text1 into text2. | ||
// (That is, lines only in text1 appear with a leading -, | ||
// and lines only in text2 appear with a leading +.) | ||
func diff(text1, text2 string) string { | ||
if text1 != "" && !strings.HasSuffix(text1, "\n") { | ||
text1 += "(missing final newline)" | ||
} | ||
lines1 := strings.Split(text1, "\n") | ||
lines1 = lines1[:len(lines1)-1] // remove empty string after final line | ||
if text2 != "" && !strings.HasSuffix(text2, "\n") { | ||
text2 += "(missing final newline)" | ||
} | ||
lines2 := strings.Split(text2, "\n") | ||
lines2 = lines2[:len(lines2)-1] // remove empty string after final line | ||
|
||
// Naive dynamic programming algorithm for edit distance. | ||
// https://en.wikipedia.org/wiki/Wagner–Fischer_algorithm | ||
// dist[i][j] = edit distance between lines1[:len(lines1)-i] and lines2[:len(lines2)-j] | ||
// (The reversed indices make following the minimum cost path | ||
// visit lines in the same order as in the text.) | ||
dist := make([][]int, len(lines1)+1) | ||
for i := range dist { | ||
dist[i] = make([]int, len(lines2)+1) | ||
if i == 0 { | ||
for j := range dist[0] { | ||
dist[0][j] = j | ||
} | ||
continue | ||
} | ||
for j := range dist[i] { | ||
if j == 0 { | ||
dist[i][0] = i | ||
continue | ||
} | ||
cost := dist[i][j-1] + 1 | ||
if cost > dist[i-1][j]+1 { | ||
cost = dist[i-1][j] + 1 | ||
} | ||
if lines1[len(lines1)-i] == lines2[len(lines2)-j] { | ||
if cost > dist[i-1][j-1] { | ||
cost = dist[i-1][j-1] | ||
} | ||
} | ||
dist[i][j] = cost | ||
} | ||
} | ||
|
||
var buf strings.Builder | ||
i, j := len(lines1), len(lines2) | ||
for i > 0 || j > 0 { | ||
cost := dist[i][j] | ||
if i > 0 && j > 0 && cost == dist[i-1][j-1] && lines1[len(lines1)-i] == lines2[len(lines2)-j] { | ||
fmt.Fprintf(&buf, " %s\n", lines1[len(lines1)-i]) | ||
i-- | ||
j-- | ||
} else if i > 0 && cost == dist[i-1][j]+1 { | ||
fmt.Fprintf(&buf, "-%s\n", lines1[len(lines1)-i]) | ||
i-- | ||
} else { | ||
fmt.Fprintf(&buf, "+%s\n", lines2[len(lines2)-j]) | ||
j-- | ||
} | ||
} | ||
return buf.String() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// Copyright 2019 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package kama | ||
|
||
import ( | ||
"strings" | ||
"testing" | ||
) | ||
|
||
func TestSmallDiff(t *testing.T) { | ||
t.Parallel() | ||
|
||
tests := []struct { | ||
text1 string | ||
text2 string | ||
diff string | ||
}{ | ||
{"a b c", "a b d e f", "a b -c +d +e +f"}, | ||
{"", "a b c", "+a +b +c"}, | ||
{"a b c", "", "-a -b -c"}, | ||
{"a b c", "d e f", "-a -b -c +d +e +f"}, | ||
{"a b c d e f", "a b d e f", "a b -c d e f"}, | ||
{"a b c e f", "a b c d e f", "a b c +d e f"}, | ||
} | ||
|
||
for _, tt := range tests { | ||
// Turn spaces into \n. | ||
text1 := strings.ReplaceAll(tt.text1, " ", "\n") | ||
if text1 != "" { | ||
text1 += "\n" | ||
} | ||
text2 := strings.ReplaceAll(tt.text2, " ", "\n") | ||
if text2 != "" { | ||
text2 += "\n" | ||
} | ||
out := diff(text1, text2) | ||
// Cut final \n, cut spaces, turn remaining \n into spaces. | ||
out = strings.ReplaceAll(strings.ReplaceAll(strings.TrimSuffix(out, "\n"), " ", ""), "\n", " ") | ||
if out != tt.diff { | ||
t.Errorf("diff(%q, %q) = %q, want %q", text1, text2, out, tt.diff) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
|
||
[ | ||
-NAME: errors | ||
+NAME: github.com/pkg/errors | ||
CONSTANTS: [] | ||
VARIABLES: [] | ||
FUNCTIONS: [ | ||
- As(err error, target any) bool | ||
+ As(err error, target interface{}) bool | ||
+ Cause(err error) error | ||
+ Errorf(format string, args ...interface{}) error | ||
Is(err error, target error) bool | ||
- Join(errs ...error) error | ||
- New(text string) error | ||
+ New(message string) error | ||
Unwrap(err error) error | ||
+ WithMessage(err error, message string) error | ||
+ WithMessagef(err error, format string, args ...interface{}) error | ||
+ WithStack(err error) error | ||
+ Wrap(err error, message string) error | ||
+ Wrapf(err error, format string, args ...interface{}) error | ||
] | ||
-TYPES: [] | ||
+TYPES: [ | ||
+ Frame uintptr | ||
+ (Frame) Format(s fmt.State, verb rune) | ||
+ (Frame) MarshalText() ([]byte, error) | ||
+ StackTrace []Frame | ||
+ (StackTrace) Format(s fmt.State, verb rune)] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
|
||
[ | ||
NAME: net/http.Request | ||
KIND: struct | ||
SIGNATURE: [http.Request *http.Request] | ||
FIELDS: [ | ||
Method string | ||
URL *url.URL | ||
Proto string | ||
ProtoMajor int | ||
ProtoMinor int | ||
Header http.Header | ||
Body io.ReadCloser | ||
GetBody func() (io.ReadCloser, error) | ||
ContentLength int64 | ||
TransferEncoding []string | ||
Close bool | ||
Host string | ||
Form url.Values | ||
PostForm url.Values | ||
MultipartForm *multipart.Form | ||
Trailer http.Header | ||
RemoteAddr string | ||
RequestURI string | ||
TLS *tls.ConnectionState | ||
Cancel <-chan struct {} | ||
Response *http.Response | ||
] | ||
METHODS: [ | ||
AddCookie func(*http.Request, *http.Cookie) | ||
BasicAuth func(*http.Request) (string, string, bool) | ||
Clone func(*http.Request, context.Context) *http.Request | ||
Context func(*http.Request) context.Context | ||
Cookie func(*http.Request, string) (*http.Cookie, error) | ||
Cookies func(*http.Request) []*http.Cookie | ||
FormFile func(*http.Request, string) (multipart.File, *multipart.FileHeader, error) | ||
FormValue func(*http.Request, string) string | ||
MultipartReader func(*http.Request) (*multipart.Reader, error) | ||
ParseForm func(*http.Request) error | ||
ParseMultipartForm func(*http.Request, int64) error | ||
PathValue func(*http.Request, string) string | ||
PostFormValue func(*http.Request, string) string | ||
ProtoAtLeast func(*http.Request, int, int) bool | ||
Referer func(*http.Request) string | ||
SetBasicAuth func(*http.Request, string, string) | ||
SetPathValue func(*http.Request, string, string) | ||
UserAgent func(*http.Request) string | ||
WithContext func(*http.Request, context.Context) *http.Request | ||
Write func(*http.Request, io.Writer) error | ||
WriteProxy func(*http.Request, io.Writer) error | ||
] | ||
SNIPPET: Request{ | ||
- Method: "GET", | ||
+ Method: "POST", | ||
URL: *url.URL(nil), | ||
Proto: "", | ||
ProtoMajor: int(0), | ||
ProtoMinor: int(0), | ||
Header: http.Header{(nil)}, | ||
Body: io.ReadCloser nil, | ||
GetBody: func() (io.ReadCloser, error), | ||
ContentLength: int64(0), | ||
TransferEncoding: []string{(nil)}, | ||
Close: false, | ||
Host: "", | ||
Form: url.Values{(nil)}, | ||
PostForm: url.Values{(nil)}, | ||
MultipartForm: *multipart.Form(nil), | ||
Trailer: http.Header{(nil)}, | ||
RemoteAddr: "", | ||
RequestURI: "", | ||
TLS: *tls.ConnectionState(nil), | ||
Cancel: <-chan struct {} (len=0, cap=0), | ||
Response: *http.Response(nil), | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
|
||
[ | ||
NAME: compress/flate | ||
CONSTANTS: [ | ||
BestCompression untyped int | ||
BestSpeed untyped int | ||
DefaultCompression untyped int | ||
HuffmanOnly untyped int | ||
NoCompression untyped int | ||
] | ||
VARIABLES: [] | ||
FUNCTIONS: [ | ||
NewReader(r io.Reader) io.ReadCloser | ||
NewReaderDict(r io.Reader, dict []byte) io.ReadCloser | ||
NewWriter(w io.Writer, level int) (*Writer, error) | ||
NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, error) | ||
] | ||
TYPES: [ | ||
CorruptInputError int64 | ||
(CorruptInputError) Error() string | ||
InternalError string | ||
(InternalError) Error() string | ||
ReadError struct | ||
(*ReadError) Error() string | ||
Reader interface | ||
(Reader) Read(p []byte) (n int, err error) | ||
(Reader) ReadByte() (byte, error) | ||
Resetter interface | ||
(Resetter) Reset(r io.Reader, dict []byte) error | ||
WriteError struct | ||
(*WriteError) Error() string | ||
Writer struct | ||
(*Writer) Close() error | ||
(*Writer) Flush() error | ||
(*Writer) Reset(dst io.Writer) | ||
(*Writer) Write(data []byte) (n int, err error)] |