gofmt: format all remaining files with the go1.27 toolchain
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.
This commit is contained in:
parent
180fa966c8
commit
06b1444207
|
|
@ -66,7 +66,7 @@ func computeVisiblePageRange(s *BrowserState) (minPage, maxPage int) {
|
|||
if minPage < 0 {
|
||||
minPage = 0
|
||||
}
|
||||
maxPage = (s.GetScrollIndex() + s.VisibleCount)/PageSize + PrefetchDist
|
||||
maxPage = (s.GetScrollIndex()+s.VisibleCount)/PageSize + PrefetchDist
|
||||
return minPage, maxPage
|
||||
}
|
||||
|
||||
|
|
@ -164,4 +164,3 @@ func filterEntriesByQuery(entries []Entry, query string) []int {
|
|||
|
||||
return results
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ func TestLoadPage_FromIndexAtOffset(t *testing.T) {
|
|||
|
||||
// Build position maps for sort modes
|
||||
s.SortIndex = &DirectoryIndex{
|
||||
Entries: allEntries,
|
||||
Entries: allEntries,
|
||||
SortOrders: map[string][]int{
|
||||
"name_asc": buildPositionMap(allEntries, SortModeNameAsc),
|
||||
"date_desc": buildPositionMap(allEntries, SortModeDateDesc),
|
||||
|
|
@ -76,7 +76,7 @@ func TestLoadPage_LastPagePartialFromIndex(t *testing.T) {
|
|||
|
||||
// Build position maps for sort modes
|
||||
s.SortIndex = &DirectoryIndex{
|
||||
Entries: allEntries,
|
||||
Entries: allEntries,
|
||||
SortOrders: map[string][]int{
|
||||
"name_asc": buildPositionMap(allEntries, SortModeNameAsc),
|
||||
"date_desc": buildPositionMap(allEntries, SortModeDateDesc),
|
||||
|
|
@ -116,7 +116,7 @@ func TestLoadPage_OutOfBoundsFromIndex(t *testing.T) {
|
|||
|
||||
// Build position maps for sort modes
|
||||
s.SortIndex = &DirectoryIndex{
|
||||
Entries: allEntries,
|
||||
Entries: allEntries,
|
||||
SortOrders: map[string][]int{
|
||||
"name_asc": buildPositionMap(allEntries, SortModeNameAsc),
|
||||
"date_desc": buildPositionMap(allEntries, SortModeDateDesc),
|
||||
|
|
@ -195,7 +195,7 @@ func TestGetEntryByIndex(t *testing.T) {
|
|||
|
||||
// Build position maps for sort modes
|
||||
s.SortIndex = &DirectoryIndex{
|
||||
Entries: allEntries,
|
||||
Entries: allEntries,
|
||||
SortOrders: map[string][]int{
|
||||
"name_asc": buildPositionMap(allEntries, SortModeNameAsc),
|
||||
"date_desc": buildPositionMap(allEntries, SortModeDateDesc),
|
||||
|
|
@ -236,7 +236,7 @@ func TestGetEntryByIndex_UnloadedPage(t *testing.T) {
|
|||
|
||||
// Build position maps for sort modes
|
||||
s.SortIndex = &DirectoryIndex{
|
||||
Entries: allEntries,
|
||||
Entries: allEntries,
|
||||
SortOrders: map[string][]int{
|
||||
"name_asc": buildPositionMap(allEntries, SortModeNameAsc),
|
||||
"date_desc": buildPositionMap(allEntries, SortModeDateDesc),
|
||||
|
|
|
|||
|
|
@ -13,11 +13,11 @@ import (
|
|||
// DirectoryIndex holds a cached index of a directory's contents.
|
||||
// Per design: index stores raw metadata; sorting is pre-computed via position maps.
|
||||
type DirectoryIndex struct {
|
||||
Path string `json:"path"`
|
||||
Mtime time.Time `json:"mtime"`
|
||||
EntryCount int `json:"entry_count"`
|
||||
Entries []Entry `json:"entries"`
|
||||
SortOrders map[string][]int `json:"sort_orders,omitempty"` // key: "name_asc", "name_desc", etc.
|
||||
Path string `json:"path"`
|
||||
Mtime time.Time `json:"mtime"`
|
||||
EntryCount int `json:"entry_count"`
|
||||
Entries []Entry `json:"entries"`
|
||||
SortOrders map[string][]int `json:"sort_orders,omitempty"` // key: "name_asc", "name_desc", etc.
|
||||
}
|
||||
|
||||
// getCachePath returns the path to the cached index file for a directory.
|
||||
|
|
|
|||
|
|
@ -224,5 +224,3 @@ func TestBuildIndex_LargeDirectory(t *testing.T) {
|
|||
t.Errorf("buildIndex took %v, expected < 5s", elapsed)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -160,8 +160,6 @@ func recomputeSearchResults(s *BrowserState) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ComputeVisibleEntriesForTest is exported for testing purposes.
|
||||
// It builds the list of ui.ListItem entries that should be rendered.
|
||||
func ComputeVisibleEntriesForTest(state *BrowserState) []ui.ListItem {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ func makeTestState(t *testing.T, entryCount int, scrollIndex int, visibleCount i
|
|||
|
||||
// Build position maps for sort modes
|
||||
s.SortIndex = &DirectoryIndex{
|
||||
Entries: entries,
|
||||
Entries: entries,
|
||||
SortOrders: map[string][]int{
|
||||
"name_asc": buildPositionMap(entries, SortModeNameAsc),
|
||||
"date_desc": buildPositionMap(entries, SortModeDateDesc),
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ func TestPixelScroll_EvictionTriggered(t *testing.T) {
|
|||
entries[i] = NewEntry("/test/file.txt", "file.txt", 100, s.TapTimestamp, false)
|
||||
}
|
||||
s.SortIndex = &DirectoryIndex{
|
||||
Entries: entries,
|
||||
Entries: entries,
|
||||
SortOrders: map[string][]int{
|
||||
"name_asc": buildPositionMap(entries, SortModeNameAsc),
|
||||
"date_desc": buildPositionMap(entries, SortModeDateDesc),
|
||||
|
|
@ -184,7 +184,7 @@ func TestPixelScroll_PrefetchTriggered(t *testing.T) {
|
|||
entries[i] = NewEntry("/test/file.txt", "file.txt", 100, s.TapTimestamp, false)
|
||||
}
|
||||
s.SortIndex = &DirectoryIndex{
|
||||
Entries: entries,
|
||||
Entries: entries,
|
||||
SortOrders: map[string][]int{
|
||||
"name_asc": buildPositionMap(entries, SortModeNameAsc),
|
||||
"date_desc": buildPositionMap(entries, SortModeDateDesc),
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ func TestScroll_PrefetchTriggered(t *testing.T) {
|
|||
}
|
||||
// Build position maps for sort modes
|
||||
s.SortIndex = &DirectoryIndex{
|
||||
Entries: entries,
|
||||
Entries: entries,
|
||||
SortOrders: map[string][]int{
|
||||
"name_asc": buildPositionMap(entries, SortModeNameAsc),
|
||||
"date_desc": buildPositionMap(entries, SortModeDateDesc),
|
||||
|
|
@ -131,7 +131,7 @@ func TestScroll_EvictionTriggered(t *testing.T) {
|
|||
}
|
||||
// Build position maps for sort modes
|
||||
s.SortIndex = &DirectoryIndex{
|
||||
Entries: entries,
|
||||
Entries: entries,
|
||||
SortOrders: map[string][]int{
|
||||
"name_asc": buildPositionMap(entries, SortModeNameAsc),
|
||||
"date_desc": buildPositionMap(entries, SortModeDateDesc),
|
||||
|
|
@ -246,7 +246,7 @@ func TestScroll_PrefetchTriggeredOnPageBoundary(t *testing.T) {
|
|||
}
|
||||
// Build position maps for sort modes
|
||||
s.SortIndex = &DirectoryIndex{
|
||||
Entries: entries,
|
||||
Entries: entries,
|
||||
SortOrders: map[string][]int{
|
||||
"name_asc": buildPositionMap(entries, SortModeNameAsc),
|
||||
"date_desc": buildPositionMap(entries, SortModeDateDesc),
|
||||
|
|
|
|||
|
|
@ -69,4 +69,3 @@ func comparator(mode SortMode) func(a, b Entry) int {
|
|||
return func(a, b Entry) int { return 0 }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,20 +19,20 @@ type Entry struct {
|
|||
|
||||
// Page represents a chunk of directory entries loaded from disk.
|
||||
type Page struct {
|
||||
Index int // Page number (0-based)
|
||||
Entries []Entry // Entries in this page
|
||||
Loaded bool // True if page data is in memory
|
||||
Dirty bool // True if page needs refresh (external change detected)
|
||||
Index int // Page number (0-based)
|
||||
Entries []Entry // Entries in this page
|
||||
Loaded bool // True if page data is in memory
|
||||
Dirty bool // True if page needs refresh (external change detected)
|
||||
}
|
||||
|
||||
// BrowserState holds all mutable browser state owned by the logic goroutine.
|
||||
type BrowserState struct {
|
||||
// Navigation
|
||||
CurrentPath string // Currently browsed directory (relative to root)
|
||||
History []string // Path history for navigation
|
||||
ScrollOffset float64 // Vertical scroll offset in pixels (per-pixel scrolling)
|
||||
EntryHeight float64 // Height of a single entry in pixels
|
||||
VisibleCount int // Number of entries currently visible
|
||||
CurrentPath string // Currently browsed directory (relative to root)
|
||||
History []string // Path history for navigation
|
||||
ScrollOffset float64 // Vertical scroll offset in pixels (per-pixel scrolling)
|
||||
EntryHeight float64 // Height of a single entry in pixels
|
||||
VisibleCount int // Number of entries currently visible
|
||||
|
||||
// Lazy loading
|
||||
Pages map[int]*Page // Loaded pages by page index
|
||||
|
|
@ -44,8 +44,8 @@ type BrowserState struct {
|
|||
SortMode SortMode // Current sort mode
|
||||
|
||||
// Search
|
||||
Query string // Current search query (forwarded from the main-owned search widget)
|
||||
SearchResults []int // Indices of matching entries (empty = no filter)
|
||||
Query string // Current search query (forwarded from the main-owned search widget)
|
||||
SearchResults []int // Indices of matching entries (empty = no filter)
|
||||
// NOTE: the search bar's widget.Editor is intentionally NOT part of this
|
||||
// state: Gio mutates widget state on the main goroutine during draw, and
|
||||
// this state is owned by the logic goroutine (architecture.md §1). The
|
||||
|
|
@ -62,8 +62,8 @@ type BrowserState struct {
|
|||
}
|
||||
|
||||
const (
|
||||
PageSize = 100 // Entries per page (tunable; ~5KB per page in memory)
|
||||
PrefetchDist = 2 // Pages to prefetch beyond visible region
|
||||
PageSize = 100 // Entries per page (tunable; ~5KB per page in memory)
|
||||
PrefetchDist = 2 // Pages to prefetch beyond visible region
|
||||
)
|
||||
|
||||
// NewEntry creates a new Entry from the given parameters.
|
||||
|
|
@ -127,10 +127,10 @@ func formatSize(bytes int64) string {
|
|||
// EvictPages removes pages that are far from the current scroll position.
|
||||
func (s *BrowserState) EvictPages() {
|
||||
minPage := s.GetScrollIndex()/PageSize - PrefetchDist
|
||||
maxPage := (s.GetScrollIndex() + s.VisibleCount)/PageSize + PrefetchDist
|
||||
maxPage := (s.GetScrollIndex()+s.VisibleCount)/PageSize + PrefetchDist
|
||||
for idx, page := range s.Pages {
|
||||
if idx < minPage || idx > maxPage {
|
||||
page.Entries = nil // Release memory
|
||||
page.Entries = nil // Release memory
|
||||
page.Loaded = false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ func TestFormatSize(t *testing.T) {
|
|||
{0, "0 B"},
|
||||
{500, "500 B"},
|
||||
{1024, "1.0 KB"},
|
||||
{1024*1024, "1.0 MB"},
|
||||
{1024 * 1024, "1.0 MB"},
|
||||
{1024 * 1024 * 1024, "1.0 GB"},
|
||||
}
|
||||
|
||||
|
|
@ -118,7 +118,7 @@ func TestFormatSize(t *testing.T) {
|
|||
func TestBrowserStateEvictPages(t *testing.T) {
|
||||
s := NewBrowserState()
|
||||
s.EntryHeight = 48.0
|
||||
s.ScrollOffset = 500 * 48 // Page 5
|
||||
s.ScrollOffset = 500 * 48 // Page 5
|
||||
s.VisibleCount = 10
|
||||
|
||||
// With ScrollIndex=500, PageSize=100:
|
||||
|
|
@ -127,10 +127,10 @@ func TestBrowserStateEvictPages(t *testing.T) {
|
|||
// Pages 3-7 should be kept, others evicted
|
||||
|
||||
// Add pages at various positions
|
||||
s.Pages[0] = NewPage(0, nil) // Should be evicted (far)
|
||||
s.Pages[3] = NewPage(3, nil) // Should be kept (at min boundary)
|
||||
s.Pages[5] = NewPage(5, nil) // Should be kept (visible)
|
||||
s.Pages[7] = NewPage(7, nil) // Should be kept (at max boundary)
|
||||
s.Pages[0] = NewPage(0, nil) // Should be evicted (far)
|
||||
s.Pages[3] = NewPage(3, nil) // Should be kept (at min boundary)
|
||||
s.Pages[5] = NewPage(5, nil) // Should be kept (visible)
|
||||
s.Pages[7] = NewPage(7, nil) // Should be kept (at max boundary)
|
||||
s.Pages[10] = NewPage(10, nil) // Should be evicted (far)
|
||||
|
||||
s.EvictPages()
|
||||
|
|
|
|||
|
|
@ -189,9 +189,9 @@ func TestLargeFileChunkBoundary(t *testing.T) {
|
|||
// (The old fixed-slot model treated each chunk as an independent buffer and
|
||||
// did NOT shift later chunks; that was the bug this design replaces.)
|
||||
expectedStr := string(initialContent)
|
||||
expectedStr = expectedStr[:65000] + "CHUNK1" + expectedStr[65000:] // insert 1 @65000
|
||||
expectedStr = expectedStr[:65535] + "BOUNDARY" + expectedStr[65535:] // insert 2 @65535
|
||||
expectedStr = expectedStr[:262000] + "CHUNK3" + expectedStr[262000:] // insert 3 @262000
|
||||
expectedStr = expectedStr[:65000] + "CHUNK1" + expectedStr[65000:] // insert 1 @65000
|
||||
expectedStr = expectedStr[:65535] + "BOUNDARY" + expectedStr[65535:] // insert 2 @65535
|
||||
expectedStr = expectedStr[:262000] + "CHUNK3" + expectedStr[262000:] // insert 3 @262000
|
||||
expected := []byte(expectedStr)
|
||||
|
||||
if len(savedContent) != len(expected) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package editor
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"pad/internal/ui"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEditorLayout_Filename(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ func newChunkedState(t *testing.T, content string, chunkSize int) *State {
|
|||
|
||||
func TestRuneIndexToByteStr(t *testing.T) {
|
||||
cases := []struct {
|
||||
s string
|
||||
n int
|
||||
s string
|
||||
n int
|
||||
want int
|
||||
}{
|
||||
{"", 0, 0},
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ func TestWordWrapFragmentStartY(t *testing.T) {
|
|||
// Test case: Word wrap enabled, scroll to visual line 5
|
||||
// With word wrap, visual lines don't correspond 1:1 with logical lines
|
||||
wordWrap := true
|
||||
_ = wordWrap // Mark as used for this test
|
||||
_ = wordWrap // Mark as used for this test
|
||||
scrollOffset := ui.Dp(5 * float64(lineHeight)) // Scroll to visual line 5
|
||||
visualLine := int(scrollOffset / lineHeight)
|
||||
|
||||
|
|
@ -152,24 +152,24 @@ func TestByteOffsetAndYFromScroll(t *testing.T) {
|
|||
}
|
||||
|
||||
layout := ui.GlyphLayout{
|
||||
ByteOffsets: []int{0, 7, 14, 21},
|
||||
X: []ui.Dp{0, 0, 0, 0},
|
||||
Y: []ui.Dp{0, 16.8, 33.6, 50.4},
|
||||
Advance: []ui.Dp{10, 10, 10, 10},
|
||||
LineHeight: lineHeight,
|
||||
ByteOffsets: []int{0, 7, 14, 21},
|
||||
X: []ui.Dp{0, 0, 0, 0},
|
||||
Y: []ui.Dp{0, 16.8, 33.6, 50.4},
|
||||
Advance: []ui.Dp{10, 10, 10, 10},
|
||||
LineHeight: lineHeight,
|
||||
VisualLineIndex: visualLineIndex,
|
||||
}
|
||||
|
||||
// Test scrolling to different positions
|
||||
testCases := []struct {
|
||||
scrollOffset ui.Dp
|
||||
expectedByte int
|
||||
expectedY ui.Dp
|
||||
scrollOffset ui.Dp
|
||||
expectedByte int
|
||||
expectedY ui.Dp
|
||||
}{
|
||||
{ui.Dp(0), 0, ui.Dp(0)}, // Top of document
|
||||
{ui.Dp(16.8), 7, ui.Dp(16.8)}, // Start of line 1
|
||||
{ui.Dp(33.6), 14, ui.Dp(33.6)}, // Start of line 2
|
||||
{ui.Dp(50.4), 21, ui.Dp(50.4)}, // Start of line 3
|
||||
{ui.Dp(0), 0, ui.Dp(0)}, // Top of document
|
||||
{ui.Dp(16.8), 7, ui.Dp(16.8)}, // Start of line 1
|
||||
{ui.Dp(33.6), 14, ui.Dp(33.6)}, // Start of line 2
|
||||
{ui.Dp(50.4), 21, ui.Dp(50.4)}, // Start of line 3
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
|
|
|||
|
|
@ -202,4 +202,3 @@ func byteOffsetOfLine(content string, i int) int {
|
|||
}
|
||||
return o
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,13 +53,13 @@ func (t *cancelTask) Execute() Result {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *cancelTask) Priority() Priority { return t.priority }
|
||||
func (t *cancelTask) TaskID() string { return t.id }
|
||||
func (t *cancelTask) TaskType() TaskType { return t.taskType }
|
||||
func (t *cancelTask) DirPath() string { return "/test" }
|
||||
func (t *cancelTask) Priority() Priority { return t.priority }
|
||||
func (t *cancelTask) TaskID() string { return t.id }
|
||||
func (t *cancelTask) TaskType() TaskType { return t.taskType }
|
||||
func (t *cancelTask) DirPath() string { return "/test" }
|
||||
func (t *cancelTask) Context() context.Context { return t.ctx }
|
||||
func (t *cancelTask) Cancel() { t.cancel() }
|
||||
func (t *cancelTask) Timeout() time.Duration { return 0 }
|
||||
func (t *cancelTask) Cancel() { t.cancel() }
|
||||
func (t *cancelTask) Timeout() time.Duration { return 0 }
|
||||
|
||||
// timeoutTask is a task that respects timeout.
|
||||
type timeoutTask struct {
|
||||
|
|
@ -79,13 +79,13 @@ func (t *timeoutTask) Execute() Result {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *timeoutTask) Priority() Priority { return t.priority }
|
||||
func (t *timeoutTask) TaskID() string { return t.id }
|
||||
func (t *timeoutTask) TaskType() TaskType { return t.taskType }
|
||||
func (t *timeoutTask) DirPath() string { return "/test" }
|
||||
func (t *timeoutTask) Priority() Priority { return t.priority }
|
||||
func (t *timeoutTask) TaskID() string { return t.id }
|
||||
func (t *timeoutTask) TaskType() TaskType { return t.taskType }
|
||||
func (t *timeoutTask) DirPath() string { return "/test" }
|
||||
func (t *timeoutTask) Context() context.Context { return context.Background() }
|
||||
func (t *timeoutTask) Cancel() {}
|
||||
func (t *timeoutTask) Timeout() time.Duration { return 50 * time.Millisecond }
|
||||
func (t *timeoutTask) Cancel() {}
|
||||
func (t *timeoutTask) Timeout() time.Duration { return 50 * time.Millisecond }
|
||||
|
||||
func TestTaskContextCancellation(t *testing.T) {
|
||||
task := newCancelTask("test-cancel", 1*time.Second)
|
||||
|
|
|
|||
|
|
@ -68,10 +68,10 @@ type notifyEvent struct {
|
|||
// FileSystem is a thread-safe in-memory filesystem for testing.
|
||||
type FileSystem struct {
|
||||
mu sync.RWMutex
|
||||
files map[string]*File // path -> file
|
||||
delay time.Duration // uniform delay applied to all operations
|
||||
changes chan FileChangeEvent // async change notifications (nil = no notifications)
|
||||
writeError bool // Added to simulate write errors
|
||||
files map[string]*File // path -> file
|
||||
delay time.Duration // uniform delay applied to all operations
|
||||
changes chan FileChangeEvent // async change notifications (nil = no notifications)
|
||||
writeError bool // Added to simulate write errors
|
||||
}
|
||||
|
||||
// NewFileSystem creates an empty mock filesystem.
|
||||
|
|
|
|||
|
|
@ -115,8 +115,6 @@ func (t TaskType) String() string {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// --- Specific Task Implementations ---
|
||||
|
||||
// ReadChunkTask reads a specific chunk of a file.
|
||||
|
|
@ -163,13 +161,17 @@ func (t *ReadChunkTask) Execute() Result {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *ReadChunkTask) Priority() Priority { return HighPriority }
|
||||
func (t *ReadChunkTask) TaskType() TaskType { return TypeReadChunk }
|
||||
func (t *ReadChunkTask) TaskID() string { return t.taskID }
|
||||
func (t *ReadChunkTask) DirPath() string { return filepath.Dir(t.Path) }
|
||||
func (t *ReadChunkTask) Priority() Priority { return HighPriority }
|
||||
func (t *ReadChunkTask) TaskType() TaskType { return TypeReadChunk }
|
||||
func (t *ReadChunkTask) TaskID() string { return t.taskID }
|
||||
func (t *ReadChunkTask) DirPath() string { return filepath.Dir(t.Path) }
|
||||
func (t *ReadChunkTask) Context() context.Context { return t.ctx }
|
||||
func (t *ReadChunkTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *ReadChunkTask) Cancel() { if t.cancel != nil { t.cancel() } }
|
||||
func (t *ReadChunkTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *ReadChunkTask) Cancel() {
|
||||
if t.cancel != nil {
|
||||
t.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
// StatFileTask retrieves file metadata (like size and modification time).
|
||||
// The plan indicates this replaces the full-file ReadFileTask for opening.
|
||||
|
|
@ -210,13 +212,17 @@ func (t *StatFileTask) Execute() Result {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *StatFileTask) Priority() Priority { return MediumPriority }
|
||||
func (t *StatFileTask) TaskType() TaskType { return TypeStatFile }
|
||||
func (t *StatFileTask) TaskID() string { return t.taskID }
|
||||
func (t *StatFileTask) DirPath() string { return filepath.Dir(t.Path) }
|
||||
func (t *StatFileTask) Priority() Priority { return MediumPriority }
|
||||
func (t *StatFileTask) TaskType() TaskType { return TypeStatFile }
|
||||
func (t *StatFileTask) TaskID() string { return t.taskID }
|
||||
func (t *StatFileTask) DirPath() string { return filepath.Dir(t.Path) }
|
||||
func (t *StatFileTask) Context() context.Context { return t.ctx }
|
||||
func (t *StatFileTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *StatFileTask) Cancel() { if t.cancel != nil { t.cancel() } }
|
||||
func (t *StatFileTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *StatFileTask) Cancel() {
|
||||
if t.cancel != nil {
|
||||
t.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
// FileStat holds file metadata.
|
||||
type FileStat struct {
|
||||
|
|
@ -267,13 +273,17 @@ func (t *BuildLineIndexTask) Execute() Result {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *BuildLineIndexTask) Priority() Priority { return LowPriority }
|
||||
func (t *BuildLineIndexTask) TaskType() TaskType { return TypeBuildLineIndex }
|
||||
func (t *BuildLineIndexTask) TaskID() string { return t.taskID }
|
||||
func (t *BuildLineIndexTask) DirPath() string { return filepath.Dir(t.Path) }
|
||||
func (t *BuildLineIndexTask) Priority() Priority { return LowPriority }
|
||||
func (t *BuildLineIndexTask) TaskType() TaskType { return TypeBuildLineIndex }
|
||||
func (t *BuildLineIndexTask) TaskID() string { return t.taskID }
|
||||
func (t *BuildLineIndexTask) DirPath() string { return filepath.Dir(t.Path) }
|
||||
func (t *BuildLineIndexTask) Context() context.Context { return t.ctx }
|
||||
func (t *BuildLineIndexTask) Timeout() time.Duration { return 30 * time.Second }
|
||||
func (t *BuildLineIndexTask) Cancel() { if t.cancel != nil { t.cancel() } }
|
||||
func (t *BuildLineIndexTask) Timeout() time.Duration { return 30 * time.Second }
|
||||
func (t *BuildLineIndexTask) Cancel() {
|
||||
if t.cancel != nil {
|
||||
t.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
// BuildIndexTask builds the directory index for the browser.
|
||||
type BuildIndexTask struct {
|
||||
|
|
@ -304,13 +314,17 @@ func (t *BuildIndexTask) Execute() Result {
|
|||
return Result{TaskID: t.taskID, TaskType: TypeBuildIndex, Success: true, Data: entries}
|
||||
}
|
||||
|
||||
func (t *BuildIndexTask) Priority() Priority { return HighPriority }
|
||||
func (t *BuildIndexTask) TaskType() TaskType { return TypeBuildIndex }
|
||||
func (t *BuildIndexTask) TaskID() string { return t.taskID }
|
||||
func (t *BuildIndexTask) DirPath() string { return t.Dir }
|
||||
func (t *BuildIndexTask) Priority() Priority { return HighPriority }
|
||||
func (t *BuildIndexTask) TaskType() TaskType { return TypeBuildIndex }
|
||||
func (t *BuildIndexTask) TaskID() string { return t.taskID }
|
||||
func (t *BuildIndexTask) DirPath() string { return t.Dir }
|
||||
func (t *BuildIndexTask) Context() context.Context { return t.ctx }
|
||||
func (t *BuildIndexTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *BuildIndexTask) Cancel() { if t.cancel != nil { t.cancel() } }
|
||||
func (t *BuildIndexTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *BuildIndexTask) Cancel() {
|
||||
if t.cancel != nil {
|
||||
t.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
// LoadPagesTask loads specific pages from a directory index.
|
||||
type LoadPagesTask struct {
|
||||
|
|
@ -343,13 +357,17 @@ func (t *LoadPagesTask) Execute() Result {
|
|||
return Result{TaskID: t.taskID, TaskType: TypeLoadPages, Success: true, Data: t.PageIdxs}
|
||||
}
|
||||
|
||||
func (t *LoadPagesTask) Priority() Priority { return HighPriority }
|
||||
func (t *LoadPagesTask) TaskType() TaskType { return TypeLoadPages }
|
||||
func (t *LoadPagesTask) TaskID() string { return t.taskID }
|
||||
func (t *LoadPagesTask) DirPath() string { return t.Dir }
|
||||
func (t *LoadPagesTask) Priority() Priority { return HighPriority }
|
||||
func (t *LoadPagesTask) TaskType() TaskType { return TypeLoadPages }
|
||||
func (t *LoadPagesTask) TaskID() string { return t.taskID }
|
||||
func (t *LoadPagesTask) DirPath() string { return t.Dir }
|
||||
func (t *LoadPagesTask) Context() context.Context { return t.ctx }
|
||||
func (t *LoadPagesTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *LoadPagesTask) Cancel() { if t.cancel != nil { t.cancel() } }
|
||||
func (t *LoadPagesTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *LoadPagesTask) Cancel() {
|
||||
if t.cancel != nil {
|
||||
t.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
// ReadDirTask reads directory entries.
|
||||
type ReadDirTask struct {
|
||||
|
|
@ -381,13 +399,17 @@ func (t *ReadDirTask) Execute() Result {
|
|||
return Result{TaskID: t.taskID, TaskType: TypeReadDir, Success: true, Data: entries}
|
||||
}
|
||||
|
||||
func (t *ReadDirTask) Priority() Priority { return HighPriority }
|
||||
func (t *ReadDirTask) TaskType() TaskType { return TypeReadDir }
|
||||
func (t *ReadDirTask) TaskID() string { return t.taskID }
|
||||
func (t *ReadDirTask) DirPath() string { return t.Dir }
|
||||
func (t *ReadDirTask) Priority() Priority { return HighPriority }
|
||||
func (t *ReadDirTask) TaskType() TaskType { return TypeReadDir }
|
||||
func (t *ReadDirTask) TaskID() string { return t.taskID }
|
||||
func (t *ReadDirTask) DirPath() string { return t.Dir }
|
||||
func (t *ReadDirTask) Context() context.Context { return t.ctx }
|
||||
func (t *ReadDirTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *ReadDirTask) Cancel() { if t.cancel != nil { t.cancel() } }
|
||||
func (t *ReadDirTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *ReadDirTask) Cancel() {
|
||||
if t.cancel != nil {
|
||||
t.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
// SaveStateTask persists application state.
|
||||
type SaveStateTask struct {
|
||||
|
|
@ -421,13 +443,17 @@ func (t *SaveStateTask) Execute() Result {
|
|||
return Result{TaskID: t.taskID, TaskType: TypeSaveState, Success: true}
|
||||
}
|
||||
|
||||
func (t *SaveStateTask) Priority() Priority { return LowPriority }
|
||||
func (t *SaveStateTask) TaskType() TaskType { return TypeSaveState }
|
||||
func (t *SaveStateTask) TaskID() string { return t.taskID }
|
||||
func (t *SaveStateTask) DirPath() string { return filepath.Dir(t.Path) }
|
||||
func (t *SaveStateTask) Priority() Priority { return LowPriority }
|
||||
func (t *SaveStateTask) TaskType() TaskType { return TypeSaveState }
|
||||
func (t *SaveStateTask) TaskID() string { return t.taskID }
|
||||
func (t *SaveStateTask) DirPath() string { return filepath.Dir(t.Path) }
|
||||
func (t *SaveStateTask) Context() context.Context { return t.ctx }
|
||||
func (t *SaveStateTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *SaveStateTask) Cancel() { if t.cancel != nil { t.cancel() } }
|
||||
func (t *SaveStateTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *SaveStateTask) Cancel() {
|
||||
if t.cancel != nil {
|
||||
t.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
// SaveUndoTask persists undo stack.
|
||||
type SaveUndoTask struct {
|
||||
|
|
@ -461,13 +487,17 @@ func (t *SaveUndoTask) Execute() Result {
|
|||
return Result{TaskID: t.taskID, TaskType: TypeSaveUndo, Success: true}
|
||||
}
|
||||
|
||||
func (t *SaveUndoTask) Priority() Priority { return LowPriority }
|
||||
func (t *SaveUndoTask) TaskType() TaskType { return TypeSaveUndo }
|
||||
func (t *SaveUndoTask) TaskID() string { return t.taskID }
|
||||
func (t *SaveUndoTask) DirPath() string { return filepath.Dir(t.Path) }
|
||||
func (t *SaveUndoTask) Priority() Priority { return LowPriority }
|
||||
func (t *SaveUndoTask) TaskType() TaskType { return TypeSaveUndo }
|
||||
func (t *SaveUndoTask) TaskID() string { return t.taskID }
|
||||
func (t *SaveUndoTask) DirPath() string { return filepath.Dir(t.Path) }
|
||||
func (t *SaveUndoTask) Context() context.Context { return t.ctx }
|
||||
func (t *SaveUndoTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *SaveUndoTask) Cancel() { if t.cancel != nil { t.cancel() } }
|
||||
func (t *SaveUndoTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *SaveUndoTask) Cancel() {
|
||||
if t.cancel != nil {
|
||||
t.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
// ReadFileTask reads the full content of a file.
|
||||
// Used as a fallback for small files or initial load before chunking is set up.
|
||||
|
|
@ -499,13 +529,17 @@ func (t *ReadFileTask) Execute() Result {
|
|||
return Result{TaskID: t.taskID, TaskType: TypeReadFile, FilePath: t.Path, Success: true, Data: content}
|
||||
}
|
||||
|
||||
func (t *ReadFileTask) Priority() Priority { return HighPriority }
|
||||
func (t *ReadFileTask) TaskType() TaskType { return TypeReadFile }
|
||||
func (t *ReadFileTask) TaskID() string { return t.taskID }
|
||||
func (t *ReadFileTask) DirPath() string { return filepath.Dir(t.Path) }
|
||||
func (t *ReadFileTask) Priority() Priority { return HighPriority }
|
||||
func (t *ReadFileTask) TaskType() TaskType { return TypeReadFile }
|
||||
func (t *ReadFileTask) TaskID() string { return t.taskID }
|
||||
func (t *ReadFileTask) DirPath() string { return filepath.Dir(t.Path) }
|
||||
func (t *ReadFileTask) Context() context.Context { return t.ctx }
|
||||
func (t *ReadFileTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *ReadFileTask) Cancel() { if t.cancel != nil { t.cancel() } }
|
||||
func (t *ReadFileTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *ReadFileTask) Cancel() {
|
||||
if t.cancel != nil {
|
||||
t.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
// SearchData is the payload of a completed SearchTask: the byte ranges
|
||||
// [start, end) of every match of Query in the scanned Text, ascending and
|
||||
|
|
@ -587,13 +621,17 @@ func toLowerFold(s string) string {
|
|||
// unit; it is the standard library's two-way search.
|
||||
func indexOf(s, sub string) int { return strings.Index(s, sub) }
|
||||
|
||||
func (t *SearchTask) Priority() Priority { return MediumPriority }
|
||||
func (t *SearchTask) TaskType() TaskType { return TypeSearch }
|
||||
func (t *SearchTask) TaskID() string { return t.taskID }
|
||||
func (t *SearchTask) DirPath() string { return "" }
|
||||
func (t *SearchTask) Context() context.Context { return t.ctx }
|
||||
func (t *SearchTask) Timeout() time.Duration { return 10 * time.Second }
|
||||
func (t *SearchTask) Cancel() { if t.cancel != nil { t.cancel() } }
|
||||
func (t *SearchTask) Priority() Priority { return MediumPriority }
|
||||
func (t *SearchTask) TaskType() TaskType { return TypeSearch }
|
||||
func (t *SearchTask) TaskID() string { return t.taskID }
|
||||
func (t *SearchTask) DirPath() string { return "" }
|
||||
func (t *SearchTask) Context() context.Context { return t.ctx }
|
||||
func (t *SearchTask) Timeout() time.Duration { return 10 * time.Second }
|
||||
func (t *SearchTask) Cancel() {
|
||||
if t.cancel != nil {
|
||||
t.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
// WriteFileTask writes content to a file.
|
||||
type WriteFileTask struct {
|
||||
|
|
@ -626,13 +664,17 @@ func (t *WriteFileTask) Execute() Result {
|
|||
return Result{TaskID: t.taskID, TaskType: TypeWriteFile, FilePath: t.Path, Success: true}
|
||||
}
|
||||
|
||||
func (t *WriteFileTask) Priority() Priority { return LowPriority }
|
||||
func (t *WriteFileTask) TaskType() TaskType { return TypeWriteFile }
|
||||
func (t *WriteFileTask) TaskID() string { return t.taskID }
|
||||
func (t *WriteFileTask) DirPath() string { return filepath.Dir(t.Path) }
|
||||
func (t *WriteFileTask) Priority() Priority { return LowPriority }
|
||||
func (t *WriteFileTask) TaskType() TaskType { return TypeWriteFile }
|
||||
func (t *WriteFileTask) TaskID() string { return t.taskID }
|
||||
func (t *WriteFileTask) DirPath() string { return filepath.Dir(t.Path) }
|
||||
func (t *WriteFileTask) Context() context.Context { return t.ctx }
|
||||
func (t *WriteFileTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *WriteFileTask) Cancel() { if t.cancel != nil { t.cancel() } }
|
||||
func (t *WriteFileTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *WriteFileTask) Cancel() {
|
||||
if t.cancel != nil {
|
||||
t.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
// --- Mock File System (for testing/development) ---
|
||||
// MockFS implements the pool.FileSystem interface for testing.
|
||||
|
|
@ -709,12 +751,12 @@ type mockFileInfo struct {
|
|||
modTime time.Time
|
||||
}
|
||||
|
||||
func (f *mockFileInfo) Name() string { return f.name }
|
||||
func (f *mockFileInfo) Size() int64 { return f.size }
|
||||
func (f *mockFileInfo) Mode() os.FileMode { return os.FileMode(f.mode) }
|
||||
func (f *mockFileInfo) ModTime() time.Time { return f.modTime }
|
||||
func (f *mockFileInfo) IsDir() bool { return false }
|
||||
func (f *mockFileInfo) Sys() any { return nil }
|
||||
func (f *mockFileInfo) Name() string { return f.name }
|
||||
func (f *mockFileInfo) Size() int64 { return f.size }
|
||||
func (f *mockFileInfo) Mode() os.FileMode { return os.FileMode(f.mode) }
|
||||
func (f *mockFileInfo) ModTime() time.Time { return f.modTime }
|
||||
func (f *mockFileInfo) IsDir() bool { return false }
|
||||
func (f *mockFileInfo) Sys() any { return nil }
|
||||
|
||||
// mockDirEntry implements types.DirEntry for MockFS ReadDir.
|
||||
type mockDirEntry struct {
|
||||
|
|
@ -722,8 +764,8 @@ type mockDirEntry struct {
|
|||
isDir bool
|
||||
}
|
||||
|
||||
func (e *mockDirEntry) Name() string { return e.name }
|
||||
func (e *mockDirEntry) IsDir() bool { return e.isDir }
|
||||
func (e *mockDirEntry) Name() string { return e.name }
|
||||
func (e *mockDirEntry) IsDir() bool { return e.isDir }
|
||||
func (e *mockDirEntry) Info() (os.FileInfo, error) {
|
||||
return &mockFileInfo{name: e.name, size: 0}, nil
|
||||
}
|
||||
|
|
@ -739,6 +781,3 @@ func (m *MockFS) ReadDir(path string) ([]types.DirEntry, error) {
|
|||
}
|
||||
|
||||
var _ FileSystem = (*MockFS)(nil) // Compile-time interface check
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -73,18 +73,18 @@ func (li *LineIndex) FindLogicalLineForByteOffset(byteOffset int) int {
|
|||
low, high := 0, len(li.Offsets)-1
|
||||
for low <= high {
|
||||
mid := (low + high) / 2
|
||||
midOffset := int(li.Offsets[mid])
|
||||
midOffset := int(li.Offsets[mid])
|
||||
|
||||
if byteOffset >= midOffset {
|
||||
// This line starts at or before our byte offset
|
||||
// Check if the next line starts after our byte offset
|
||||
if mid == len(li.Offsets)-1 || int(li.Offsets[mid+1]) > byteOffset {
|
||||
return mid // Found the line
|
||||
}
|
||||
low = mid + 1
|
||||
} else {
|
||||
high = mid - 1
|
||||
if byteOffset >= midOffset {
|
||||
// This line starts at or before our byte offset
|
||||
// Check if the next line starts after our byte offset
|
||||
if mid == len(li.Offsets)-1 || int(li.Offsets[mid+1]) > byteOffset {
|
||||
return mid // Found the line
|
||||
}
|
||||
low = mid + 1
|
||||
} else {
|
||||
high = mid - 1
|
||||
}
|
||||
}
|
||||
|
||||
return -1 // Not found
|
||||
|
|
|
|||
|
|
@ -13,15 +13,15 @@ import (
|
|||
// - Workers execute tasks and post results on resultChan
|
||||
// - Workers never access state directly
|
||||
type WorkerPool struct {
|
||||
highWorkChan chan Task
|
||||
lowWorkChan chan Task
|
||||
resultChan chan Result
|
||||
workerCount int
|
||||
stopOnce sync.Once
|
||||
stopChan chan struct{}
|
||||
wg sync.WaitGroup
|
||||
taskCounter atomic.Int64
|
||||
running atomic.Bool
|
||||
highWorkChan chan Task
|
||||
lowWorkChan chan Task
|
||||
resultChan chan Result
|
||||
workerCount int
|
||||
stopOnce sync.Once
|
||||
stopChan chan struct{}
|
||||
wg sync.WaitGroup
|
||||
taskCounter atomic.Int64
|
||||
running atomic.Bool
|
||||
|
||||
// pendingTasks tracks in-flight tasks for cancellation by directory.
|
||||
pendingTasks map[string][]Task
|
||||
|
|
|
|||
|
|
@ -42,13 +42,13 @@ func (t *stubTask) Execute() Result {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *stubTask) Priority() Priority { return t.priority }
|
||||
func (t *stubTask) TaskID() string { return t.id }
|
||||
func (t *stubTask) TaskType() TaskType { return t.taskType }
|
||||
func (t *stubTask) DirPath() string { return "" }
|
||||
func (t *stubTask) Priority() Priority { return t.priority }
|
||||
func (t *stubTask) TaskID() string { return t.id }
|
||||
func (t *stubTask) TaskType() TaskType { return t.taskType }
|
||||
func (t *stubTask) DirPath() string { return "" }
|
||||
func (t *stubTask) Context() context.Context { return context.Background() }
|
||||
func (t *stubTask) Cancel() {}
|
||||
func (t *stubTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
func (t *stubTask) Cancel() {}
|
||||
func (t *stubTask) Timeout() time.Duration { return 5 * time.Second }
|
||||
|
||||
func TestWorkerPool_StartStop(t *testing.T) {
|
||||
pool := NewWorkerPool(4)
|
||||
|
|
@ -672,9 +672,9 @@ func TestWorkerPool_ResultIsSuccess(t *testing.T) {
|
|||
}
|
||||
|
||||
result2 := Result{
|
||||
TaskID: "test",
|
||||
TaskID: "test",
|
||||
Success: false,
|
||||
Error: fmt.Errorf("error"),
|
||||
Error: fmt.Errorf("error"),
|
||||
}
|
||||
if result2.IsSuccess() {
|
||||
t.Error("Result should not be successful")
|
||||
|
|
@ -683,7 +683,7 @@ func TestWorkerPool_ResultIsSuccess(t *testing.T) {
|
|||
|
||||
func TestWorkerPool_ResultIsError(t *testing.T) {
|
||||
result := Result{
|
||||
TaskID: "test",
|
||||
TaskID: "test",
|
||||
Success: false,
|
||||
Error: fmt.Errorf("error"),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ type TestScenario struct {
|
|||
Setup func(*Harness)
|
||||
Actions []HarnessAction
|
||||
Assertions []FrameAssertion
|
||||
FrameIndex int // which frame to assert on (-1 for last)
|
||||
FrameIndex int // which frame to assert on (-1 for last)
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -646,7 +646,7 @@ func TestRestore_LinePinHoldsAcrossLateWrapFeedback(t *testing.T) {
|
|||
File: "/wrap.txt",
|
||||
Cursor: 0,
|
||||
Scroll: float64(ui.Dp(500 * lh)), // the saving session's visual-space offset
|
||||
ScrollLine: 200, // the logical line at the viewport top
|
||||
ScrollLine: 200, // the logical line at the viewport top
|
||||
ScrollSub: 0,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@ package ui
|
|||
|
||||
const (
|
||||
// Standard dimensions in Dp
|
||||
StatusBarLineHeight = Dp(24)
|
||||
StatusBarLineHeight = Dp(24)
|
||||
StatusBarFilenameLine = Dp(24)
|
||||
StatusBarIconsLine = Dp(24)
|
||||
BottomBarHeight = Dp(24)
|
||||
IconSize = Dp(24)
|
||||
IconGap = Dp(36)
|
||||
Padding = Dp(8)
|
||||
ButtonPadding = Dp(8)
|
||||
StatusBarIconsLine = Dp(24)
|
||||
BottomBarHeight = Dp(24)
|
||||
IconSize = Dp(24)
|
||||
IconGap = Dp(36)
|
||||
Padding = Dp(8)
|
||||
ButtonPadding = Dp(8)
|
||||
)
|
||||
|
||||
// LineHeightScale is the baseline-to-baseline spacing multiplier for editor text.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user