package browser import ( "strings" ) // LoadInitialPages loads the pages required for the current viewport from the // SortIndex into the Pages map. This should be called after the SortIndex is built // or updated. func LoadInitialPages(s *BrowserState) { if s.SortIndex == nil || s.TotalEntries == 0 { return } // Calculate the range of pages to load (visible + prefetch) minPage, maxPage := computeVisiblePageRange(s) for i := minPage; i <= maxPage; i++ { if _, ok := s.Pages[i]; !ok { page := loadPageFromIndex(s, i) if page != nil { s.Pages[i] = page } } } } // loadPageFromIndex creates a Page from the sorted index at the given page index. // Uses position maps to convert sorted indices to raw indices for entry lookup. // Returns nil if the page index is out of bounds. func loadPageFromIndex(s *BrowserState, pageIndex int) *Page { if pageIndex < 0 || pageIndex*PageSize >= s.TotalEntries { return nil } if s.SortIndex == nil || len(s.SortIndex.Entries) == 0 { return nil } start := pageIndex * PageSize end := start + PageSize if end > s.TotalEntries { end = s.TotalEntries } // Get the position map for the current sort mode positionMap := s.getSortedIndices() if positionMap == nil { return nil } // Build page entries using sorted order entries := make([]Entry, 0, end-start) for i := start; i < end; i++ { rawIdx := positionMap[i] entries = append(entries, s.SortIndex.Entries[rawIdx]) } return NewPage(pageIndex, entries) } // computeVisiblePageRange returns the min and max page indices that should // be loaded based on the current scroll position and visible count. func computeVisiblePageRange(s *BrowserState) (minPage, maxPage int) { minPage = s.GetScrollIndex()/PageSize - PrefetchDist if minPage < 0 { minPage = 0 } maxPage = (s.GetScrollIndex() + s.VisibleCount)/PageSize + PrefetchDist return minPage, maxPage } // getEntryByIndex returns the entry at the given sorted index, or nil if the page // containing that entry is not loaded. Uses position maps to convert sorted // indices to raw indices for correct sort order. func getEntryByIndex(s *BrowserState, sortedIndex int) (*Entry, bool) { if sortedIndex < 0 || sortedIndex >= s.TotalEntries { return nil, false } pageIndex := sortedIndex / PageSize page, ok := s.Pages[pageIndex] if !ok || !page.Loaded { return nil, false } offset := sortedIndex % PageSize if offset >= len(page.Entries) { return nil, false } return &page.Entries[offset], true } // GetSortedIndices is exported for testing purposes. func (s *BrowserState) GetSortedIndices() []int { return s.getSortedIndices() } // getSortedIndices returns the position map for the current sort mode. // Returns nil if no sort index is available. func (s *BrowserState) getSortedIndices() []int { if s.SortIndex == nil || s.SortIndex.SortOrders == nil { return nil } key := sortModeKey(s.SortMode) return s.SortIndex.SortOrders[key] } // needsPrefetch determines if a page should be prefetched based on the // current scroll position and visible count. // Returns (true, pagesNeeded) if prefetch is needed. func needsPrefetch(s *BrowserState, pageIndex int) (bool, int) { minPage, maxPage := computeVisiblePageRange(s) if pageIndex >= minPage && pageIndex <= maxPage { if page, ok := s.Pages[pageIndex]; !ok || !page.Loaded { return true, 1 } } return false, 0 } // navigateToDirectory resets browser state and sets the new current path. func navigateToDirectory(s *BrowserState, path string) { s.CurrentPath = path s.ScrollOffset = 0 s.SelectedIndex = -1 s.Pages = make(map[int]*Page) s.SearchResults = nil s.Query = "" s.TotalEntries = 0 } // computeTotalPages returns the total number of pages for the current entry count. func computeTotalPages(s *BrowserState) int { if s.TotalEntries == 0 { return 0 } pages := s.TotalEntries / PageSize if s.TotalEntries%PageSize != 0 { pages++ } return pages } // filterEntriesByQuery returns indices of entries matching the query (case-insensitive). // Returns nil for empty query. func filterEntriesByQuery(entries []Entry, query string) []int { if query == "" { return nil } queryLower := strings.ToLower(query) var results []int for i, e := range entries { if strings.Contains(strings.ToLower(e.Name), queryLower) { results = append(results, i) } } return results }