The tree was formatted with an older gofmt; go1.27's gofmt additionally wants: EOF exactly one newline (no trailing blank lines), imports sorted alphabetically within a block, mixed-precedence binary expressions re-spaced for grouping ((a+b)/c), single-field composite literals un-aligned, adjacent one-line method signatures aligned, and one-line bodies containing a compound statement expanded. Applied repo-wide (31 files under internal/); pure formatting, no semantic changes — build and the full test suite pass.
167 lines
4.3 KiB
Go
167 lines
4.3 KiB
Go
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
|
|
}
|