From d787c4a55ebffa09117e894909aab16eeb2033ae Mon Sep 17 00:00:00 2001 From: Andy Dixon Date: Thu, 27 Aug 2026 09:37:54 +0100 Subject: [PATCH] Use Unicode case folding for author search --- go.mod | 2 +- tui.go | 8 +++++--- tui_test.go | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index dbfec21..7ef8a8c 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/charmbracelet/bubbles v0.20.0 github.com/charmbracelet/bubbletea v1.2.4 github.com/charmbracelet/lipgloss v1.0.0 + golang.org/x/text v0.22.0 ) require ( @@ -24,5 +25,4 @@ require ( github.com/rivo/uniseg v0.4.7 // indirect golang.org/x/sync v0.11.0 // indirect golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect ) diff --git a/tui.go b/tui.go index d7da631..aa85479 100644 --- a/tui.go +++ b/tui.go @@ -11,6 +11,7 @@ import ( "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + "golang.org/x/text/cases" ) const ( @@ -1246,6 +1247,8 @@ func stageAuthorReplacement(commits []CommitRecord, draftByHash map[string]Commi if replacementEmail == "" { return 0, errors.New("replacement author email is required") } + fold := cases.Fold() + foldedQuery := fold.String(query) matched := 0 for _, commit := range commits { draft, ok := draftByHash[commit.Hash] @@ -1255,9 +1258,8 @@ func stageAuthorReplacement(commits []CommitRecord, draftByHash map[string]Commi nameMatches := strings.EqualFold(draft.AuthorName, query) emailMatches := strings.EqualFold(draft.AuthorEmail, query) if !exact { - lowerQuery := strings.ToLower(query) - nameMatches = strings.Contains(strings.ToLower(draft.AuthorName), lowerQuery) - emailMatches = strings.Contains(strings.ToLower(draft.AuthorEmail), lowerQuery) + nameMatches = strings.Contains(fold.String(draft.AuthorName), foldedQuery) + emailMatches = strings.Contains(fold.String(draft.AuthorEmail), foldedQuery) } if !nameMatches && !emailMatches { continue diff --git a/tui_test.go b/tui_test.go index 5c9f3c7..eb190ea 100644 --- a/tui_test.go +++ b/tui_test.go @@ -90,6 +90,24 @@ func TestStageAuthorReplacementExactModeRequiresWholeFieldMatch(t *testing.T) { } } +func TestStageAuthorReplacementPartialModeUsesUnicodeCaseFolding(t *testing.T) { + commits := []CommitRecord{ + {Hash: "greek", AuthorName: "Σωκράτης", AuthorEmail: "socrates@example.com"}, + } + drafts := cloneMapByHash(commits) + + matched, err := stageAuthorReplacement(commits, drafts, "ΣΩΚΡΆΤΗΣ", "Socrates", "new@example.com", false) + if err != nil { + t.Fatal(err) + } + if matched != 1 { + t.Fatalf("expected Unicode case variants to match, got %d matches", matched) + } + if got := drafts["greek"]; got.AuthorName != "Socrates" || got.AuthorEmail != "new@example.com" { + t.Fatalf("expected Unicode author identity to be replaced, got %#v", got) + } +} + func TestStageAuthorReplacementRejectsBlankInputsWithoutChangingDrafts(t *testing.T) { commits := []CommitRecord{{Hash: "one", AuthorName: "Foo Bar", AuthorEmail: "foo@bar.baz"}} tests := []struct {