- Fix ChunkedBuffer.Insert to always update file length. - Fix UpdateLineIndexAfterEdit to not shift the first line offset. - Remove redundant ReadFileTask dispatch in HandleBrowserTap. - Add end-to-end test for typing at start of buffer.
105 lines
2.8 KiB
Go
105 lines
2.8 KiB
Go
package browser
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"pad/internal/ui"
|
|
)
|
|
|
|
// HandleScroll updates the browser scroll index by the given delta (in entries).
|
|
// Clamps to valid bounds and triggers prefetch/eviction as needed.
|
|
func HandleScroll(s *BrowserState, delta int) {
|
|
deltaPx := int(float64(delta) * s.EntryHeight)
|
|
HandlePixelScroll(s, deltaPx)
|
|
}
|
|
|
|
// HandlePixelScroll updates the browser scroll offset by the given delta (in pixels).
|
|
// Clamps to valid bounds and triggers eviction as needed.
|
|
func HandlePixelScroll(s *BrowserState, delta int) {
|
|
s.ScrollOffset += float64(delta)
|
|
|
|
// Clamp to valid bounds
|
|
clampScrollOffset(s)
|
|
|
|
// Trigger eviction of distant pages
|
|
s.EvictPages()
|
|
}
|
|
|
|
// clampScrollOffset ensures the scroll offset stays within valid bounds.
|
|
func clampScrollOffset(s *BrowserState) {
|
|
if s.ScrollOffset < 0 {
|
|
s.ScrollOffset = 0
|
|
}
|
|
|
|
// Use search results count if active, otherwise use TotalEntries
|
|
entryCount := s.TotalEntries
|
|
if s.Query != "" {
|
|
entryCount = len(s.SearchResults)
|
|
}
|
|
|
|
// Calculate maximum scroll offset
|
|
maxScroll := 0.0
|
|
if entryCount > s.VisibleCount {
|
|
maxScroll = float64(entryCount-s.VisibleCount) * s.EntryHeight
|
|
}
|
|
|
|
if s.ScrollOffset > maxScroll {
|
|
s.ScrollOffset = maxScroll
|
|
}
|
|
}
|
|
|
|
// resolveTapIndex maps a ListView row index to the actual sorted entry index.
|
|
// When search is active, the row index is into SearchResults, so we must
|
|
// look through SearchResults to find the real entry index.
|
|
func resolveTapIndex(s *BrowserState, index int) int {
|
|
if s.Query != "" && len(s.SearchResults) > 0 {
|
|
if index < 0 || index >= len(s.SearchResults) {
|
|
return -1
|
|
}
|
|
return s.SearchResults[index]
|
|
}
|
|
return index
|
|
}
|
|
|
|
// HandleBrowserTap processes a tap on the ListView at the given index.
|
|
func HandleBrowserTap(bm *BrowserManager, s *BrowserState, index int) {
|
|
// Resolve the ListView row index to the actual sorted entry index.
|
|
// When search is active, the row is an index into SearchResults.
|
|
entryIndex := resolveTapIndex(s, index)
|
|
if entryIndex < 0 || entryIndex >= s.TotalEntries {
|
|
return
|
|
}
|
|
|
|
entry, ok := getEntryByIndex(s, entryIndex)
|
|
if !ok {
|
|
return // Page not loaded
|
|
}
|
|
|
|
if entry.IsDir {
|
|
// Navigate into directory or up
|
|
var newPath string
|
|
if entry.Name == ".." {
|
|
newPath = filepath.Dir(s.CurrentPath)
|
|
} else {
|
|
newPath = filepath.Join(s.CurrentPath, entry.Name)
|
|
if !strings.HasPrefix(newPath, "/") {
|
|
newPath = "/" + newPath
|
|
}
|
|
}
|
|
bm.NavigateTo(newPath)
|
|
} else {
|
|
// Open file
|
|
s.SelectedIndex = entryIndex
|
|
fmt.Printf("HandleBrowserTap: Opening file %s\n", entry.Path)
|
|
if ui.OpenFile != nil {
|
|
ui.OpenFile(entry.Path)
|
|
}
|
|
// Dispatch ReadFileTask to the worker pool
|
|
// task := pool.NewReadFileTask(entry.Path, bm.fs)
|
|
// fmt.Printf("HandleBrowserTap: Dispatching ReadFileTask for %s\n", entry.Path)
|
|
// bm.workerPool.Dispatch(task)
|
|
}
|
|
}
|