diff --git a/cmd/promptctl/main.go b/cmd/promptctl/main.go index f321f8d..f80f5c2 100644 --- a/cmd/promptctl/main.go +++ b/cmd/promptctl/main.go @@ -23,6 +23,7 @@ import ( "os" "path/filepath" "regexp" + "slices" "sort" "strings" "time" @@ -136,9 +137,8 @@ func runDiff(r *git.Repository, ref string, w io.Writer) []fileVerdict { var out []fileVerdict for _, p := range promptUnion(tree) { - old := blobContent(tree, p) - neu := diskContent(p) - if old == neu { + a, b, differs := changedLines(blobContent(tree, p), diskContent(p)) + if !differs { continue } if _, err := tree.File(p); err != nil { // added since ref: nothing to diff against @@ -146,7 +146,7 @@ func runDiff(r *git.Repository, ref string, w io.Writer) []fileVerdict { out = append(out, fileVerdict{p, "new"}) continue } - res, err := semdiff.Analyze(emb, splitLines(old), splitLines(neu)) + res, err := semdiff.Analyze(emb, a, b) if err != nil { log.Fatal(err) } @@ -549,3 +549,11 @@ func firstLine(s string) string { func splitLines(s string) []string { return strings.Split(strings.ReplaceAll(s, "\r\n", "\n"), "\n") } + +// changedLines splits both versions into lines and reports whether they differ. +// The comparison runs after splitLines normalises line endings, so a CRLF-only +// difference (core.autocrlf on Windows) is not a change. +func changedLines(old, neu string) (a, b []string, changed bool) { + a, b = splitLines(old), splitLines(neu) + return a, b, !slices.Equal(a, b) +} diff --git a/cmd/promptctl/main_test.go b/cmd/promptctl/main_test.go index f8fda00..6bc6c39 100644 --- a/cmd/promptctl/main_test.go +++ b/cmd/promptctl/main_test.go @@ -12,6 +12,29 @@ func TestPathToURI(t *testing.T) { } } +func TestChangedLines(t *testing.T) { + cases := []struct { + name, old, neu string + want bool + }{ + {"identical", "a\nb\n", "a\nb\n", false}, + {"crlf vs lf", "a\r\nb\r\n", "a\nb\n", false}, + {"lf vs crlf", "a\nb\n", "a\r\nb\r\n", false}, + {"mixed endings", "a\r\nb\n", "a\nb\r\n", false}, + {"text change", "a\r\nb\r\n", "a\nc\n", true}, + {"trailing newline added", "a\nb", "a\r\nb\r\n", true}, + } + for _, c := range cases { + a, b, changed := changedLines(c.old, c.neu) + if changed != c.want { + t.Errorf("%s: changed = %v, want %v", c.name, changed, c.want) + } + if !reflect.DeepEqual(a, splitLines(c.old)) || !reflect.DeepEqual(b, splitLines(c.neu)) { + t.Errorf("%s: lines = %q, %q, want normalised split of inputs", c.name, a, b) + } + } +} + func TestDeriveSlots(t *testing.T) { got := deriveSlots("Hi {name}, welcome to {org}. Bye {name}.") if want := []string{"name", "org"}; !reflect.DeepEqual(got, want) { // deduped, in order