Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions internal/ui/editor_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,13 @@ type editorTab struct {
Diff *DiffEditorWidget
}

// findSession keeps the editor query after its bar closes and tracks which buffer matches describe.
// findSession keeps the editor query after its bar closes and tracks which buffer version the matches describe.
type findSession struct {
query string
options SearchOptions
matchesBuffer *buffer.Buffer
activeMatch int // Match index in matchesBuffer; -1 when no match is selected.
query string
options SearchOptions
matchesBuffer *buffer.Buffer
matchesVersion uint64
activeMatch int // Match index in matchesBuffer; -1 when no match is selected.
}

type EditorGroupWidget struct {
Expand Down Expand Up @@ -1862,6 +1863,7 @@ func (g *EditorGroupWidget) SetFindSearch(query string, matches []FindMatch, opt
return
}
g.find.matchesBuffer = g.Editor.Buf
g.find.matchesVersion = g.Editor.Buf.Version()
g.applySearch(query, matches)
}

Expand Down Expand Up @@ -1989,7 +1991,8 @@ func (g *EditorGroupWidget) clearSearchState() {

func (g *EditorGroupWidget) refreshFindSearch() bool {
if !g.IsEditorActive() || g.find.query == "" ||
(g.find.matchesBuffer == g.Editor.Buf && g.Editor.SearchQuery == g.find.query) {
(g.find.matchesBuffer == g.Editor.Buf && g.Editor.SearchQuery == g.find.query &&
g.find.matchesVersion == g.Editor.Buf.Version()) {
return false
}
matches, err := FindInLines(g.Editor.Buf.Lines, g.find.query, g.find.options)
Expand All @@ -2002,6 +2005,7 @@ func (g *EditorGroupWidget) refreshFindSearch() bool {
active = -1
}
g.find.matchesBuffer = g.Editor.Buf
g.find.matchesVersion = g.Editor.Buf.Version()
g.applySearch(g.find.query, matches)
if len(matches) == 0 {
g.find.activeMatch = -1
Expand Down
67 changes: 67 additions & 0 deletions internal/ui/editor_group_find_refresh_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package ui

import (
"os"
"path/filepath"
"strings"
"testing"

"github.com/eugenioenko/ttt/internal/core/undo"
)

func openFooLines(t *testing.T) *EditorGroupWidget {
t.Helper()
path := filepath.Join(t.TempDir(), "foo.txt")
if err := os.WriteFile(path, []byte("one\ntwo\nfoo\nfour\nfive\nfoo\n"), 0o644); err != nil {
t.Fatal(err)
}
g := NewEditorGroupWidget(nil, 4, false, "extended")
g.OpenFile(path)
matches, err := FindInLines(g.Editor.Buf.Lines, "foo", SearchOptions{})
if err != nil {
t.Fatal(err)
}
g.SetFindSearch("foo", matches, SearchOptions{})
g.SetSearchActive(0)
g.ClearFindHighlights()
return g
}

func insertTwoLinesAtStart(g *EditorGroupWidget) {
g.Editor.Cursor.Line = 0
g.Editor.Cursor.Col = 0
g.Editor.exec(&undo.InsertLineCommand{Idx: 0, Text: "inserted"})
g.Editor.exec(&undo.InsertLineCommand{Idx: 0, Text: "inserted"})
}

func TestFindNextAfterEditWithFindClosedUsesCurrentMatch(t *testing.T) {
g := openFooLines(t)
insertTwoLinesAtStart(g)
g.FindNext()
line := g.Editor.Buf.Lines[g.Editor.Cursor.Line]
if !strings.Contains(line, "foo") {
t.Fatalf("cursor line %d %q, matches %+v", g.Editor.Cursor.Line, line, g.Editor.SearchMatches)
}
}

func TestFindNextAfterRestoreThenEditUsesCurrentMatch(t *testing.T) {
g := openFooLines(t)
g.FindNext()
insertTwoLinesAtStart(g)
g.FindNext()
line := g.Editor.Buf.Lines[g.Editor.Cursor.Line]
if !strings.Contains(line, "foo") {
t.Fatalf("cursor line %d %q, matches %+v", g.Editor.Cursor.Line, line, g.Editor.SearchMatches)
}
}

func TestFindPrevAfterRestoreThenEditUsesCurrentMatch(t *testing.T) {
g := openFooLines(t)
g.FindNext()
insertTwoLinesAtStart(g)
g.FindPrev()
line := g.Editor.Buf.Lines[g.Editor.Cursor.Line]
if !strings.Contains(line, "foo") {
t.Fatalf("cursor line %d %q, matches %+v", g.Editor.Cursor.Line, line, g.Editor.SearchMatches)
}
}
28 changes: 28 additions & 0 deletions tests/functional/audit-findreplace-bugs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,34 @@ describe("BUG-010: search matches go stale after buffer edits", () => {
// line index, now "beta" — the marker produces "Zbeta".
expect(readFile(file)).toMatch(/^Z.*alpha/m);
});

it("find-next after an edit with the find bar closed lands on a matching line", () => {
dir = createTempDir();
const file = createTempFile(dir, "closed-stale.txt", "one\ntwo\nfoo\nfour\nfive\nfoo\n");

tui.start(file);
tui.waitFor("foo");

tui.press("ctrl+f");
tui.type("foo");
tui.press("escape");
// Closing the bar clears highlights, so this F3 recomputes and caches the
// matches. The following edit must not leave that cache in place.
tui.press("f3");
tui.press("ctrl+home");
tui.press("enter");
tui.press("enter");
tui.press("f3");
tui.press("home");
tui.type("Z");

tui.press("ctrl+s");
tui.run();

// Buggy behavior: the cached matches still point at the old lines, so
// f3 lands on "one" and the marker produces "Zone".
expect(readFile(file)).toMatch(/^Zfoo/m);
});
});

describe("BUG-011: Replace All ignores case-sensitive toggle", () => {
Expand Down
Loading