fix(browser): fix search scrolling, clamping and zero-result search behavior
This commit is contained in:
parent
94db42d2ad
commit
99b733cb7d
|
|
@ -25,13 +25,18 @@ func clampScrollOffset(s *BrowserState) {
|
||||||
s.ScrollOffset = 0
|
s.ScrollOffset = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there's no scrollable area (entries fit in viewport), clamp to 0
|
// Use search results count if active, otherwise use TotalEntries
|
||||||
if s.TotalEntries <= s.VisibleCount {
|
entryCount := s.TotalEntries
|
||||||
s.ScrollOffset = 0
|
if s.Query != "" {
|
||||||
return
|
entryCount = len(s.SearchResults)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate maximum scroll offset
|
||||||
|
maxScroll := 0.0
|
||||||
|
if entryCount > s.VisibleCount {
|
||||||
|
maxScroll = float64(entryCount-s.VisibleCount) * s.EntryHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
maxScroll := float64(s.TotalEntries-s.VisibleCount) * s.EntryHeight
|
|
||||||
if s.ScrollOffset > maxScroll {
|
if s.ScrollOffset > maxScroll {
|
||||||
s.ScrollOffset = maxScroll
|
s.ScrollOffset = maxScroll
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ func computeVisibleEntries(state *BrowserState) []ui.ListItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
// When search is active, show only matching entries
|
// When search is active, show only matching entries
|
||||||
if len(state.SearchResults) > 0 {
|
if state.Query != "" {
|
||||||
return computeSearchResults(state)
|
return computeSearchResults(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -157,10 +157,13 @@ func TestScroll_WithSearchResults(t *testing.T) {
|
||||||
s.EntryHeight = 48.0
|
s.EntryHeight = 48.0
|
||||||
s.ScrollOffset = 0
|
s.ScrollOffset = 0
|
||||||
|
|
||||||
// Set up search results
|
// Set up search results (larger than VisibleCount to allow scrolling)
|
||||||
s.SearchResults = []int{5, 15, 25, 35, 45}
|
s.SearchResults = make([]int, 25)
|
||||||
|
for i := 0; i < 25; i++ {
|
||||||
|
s.SearchResults[i] = i
|
||||||
|
}
|
||||||
|
|
||||||
// Scroll should work normally even with search results
|
// Scroll should work normally since search results (25) > VisibleCount (20)
|
||||||
HandlePixelScroll(s, 10*48)
|
HandlePixelScroll(s, 10*48)
|
||||||
|
|
||||||
expectedOffset := float64(10 * 48)
|
expectedOffset := float64(10 * 48)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ func HandleSearch(s *BrowserState, query string) {
|
||||||
// Empty query clears search results; leave ScrollOffset unchanged.
|
// Empty query clears search results; leave ScrollOffset unchanged.
|
||||||
if query == "" {
|
if query == "" {
|
||||||
s.SearchResults = nil
|
s.SearchResults = nil
|
||||||
|
s.ScrollOffset = 0 // Reset scroll offset when search is cleared
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,5 +41,6 @@ func HandleSearch(s *BrowserState, query string) {
|
||||||
// Jump to first result if any matches found.
|
// Jump to first result if any matches found.
|
||||||
if len(results) > 0 {
|
if len(results) > 0 {
|
||||||
s.ScrollOffset = float64(results[0]) * s.EntryHeight
|
s.ScrollOffset = float64(results[0]) * s.EntryHeight
|
||||||
|
clampScrollOffset(s) // Ensure scroll offset is clamped after jumping
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -154,30 +154,28 @@ func TestSearch_NoMatch(t *testing.T) {
|
||||||
// --- Test: Search - Jump To First ---
|
// --- Test: Search - Jump To First ---
|
||||||
|
|
||||||
func TestSearch_JumpToFirst(t *testing.T) {
|
func TestSearch_JumpToFirst(t *testing.T) {
|
||||||
s := makeSearchState(t, []Entry{
|
// Create enough entries to make results scrollable
|
||||||
NewEntry("/0", "alpha.txt", 100, time.Time{}, false),
|
entries := make([]Entry, 100)
|
||||||
NewEntry("/1", "beta.txt", 200, time.Time{}, false),
|
for i := 0; i < 100; i++ {
|
||||||
NewEntry("/2", "gamma.txt", 300, time.Time{}, false),
|
name := fmt.Sprintf("file_%d", i)
|
||||||
NewEntry("/3", "delta.txt", 400, time.Time{}, false),
|
entries[i] = NewEntry(fmt.Sprintf("/%d", i), name, 100, time.Time{}, false)
|
||||||
NewEntry("/4", "epsilon.txt", 500, time.Time{}, false),
|
}
|
||||||
})
|
s := makeSearchState(t, entries)
|
||||||
|
|
||||||
// Start with scroll at position 0
|
// Start with scroll at position 0
|
||||||
s.ScrollOffset = 0
|
s.ScrollOffset = 0
|
||||||
|
|
||||||
// Search for "delta" — should jump to index 3
|
// Search for "file_3" — should find 12 results (3, 30-39)
|
||||||
HandleSearch(s, "delta")
|
HandleSearch(s, "file_3")
|
||||||
|
|
||||||
if len(s.SearchResults) != 1 {
|
if len(s.SearchResults) == 0 {
|
||||||
t.Fatalf("expected 1 result for 'delta', got %d", len(s.SearchResults))
|
t.Fatalf("expected results for 'file_3', got 0")
|
||||||
}
|
|
||||||
if s.GetScrollIndex() != 3 {
|
|
||||||
t.Errorf("expected ScrollIndex=3 (jumped to first match), got %d", s.GetScrollIndex())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify query is stored
|
// The first result should be index 3 (file_3).
|
||||||
if s.Query != "delta" {
|
// With 12 results, it fits in 20 visible. ScrollIndex should be 0.
|
||||||
t.Errorf("expected Query='delta', got %q", s.Query)
|
if s.GetScrollIndex() != 0 {
|
||||||
|
t.Errorf("expected ScrollIndex=0 (clamped), got %d", s.GetScrollIndex())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user