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:
Greg Pomerantz 2026-08-23 10:03:27 -04:00
parent 180fa966c8
commit 06b1444207
31 changed files with 279 additions and 247 deletions

View File

@ -66,7 +66,7 @@ func computeVisiblePageRange(s *BrowserState) (minPage, maxPage int) {
if minPage < 0 { if minPage < 0 {
minPage = 0 minPage = 0
} }
maxPage = (s.GetScrollIndex() + s.VisibleCount)/PageSize + PrefetchDist maxPage = (s.GetScrollIndex()+s.VisibleCount)/PageSize + PrefetchDist
return minPage, maxPage return minPage, maxPage
} }
@ -164,4 +164,3 @@ func filterEntriesByQuery(entries []Entry, query string) []int {
return results return results
} }

View File

@ -28,7 +28,7 @@ func TestLoadPage_FromIndexAtOffset(t *testing.T) {
// Build position maps for sort modes // Build position maps for sort modes
s.SortIndex = &DirectoryIndex{ s.SortIndex = &DirectoryIndex{
Entries: allEntries, Entries: allEntries,
SortOrders: map[string][]int{ SortOrders: map[string][]int{
"name_asc": buildPositionMap(allEntries, SortModeNameAsc), "name_asc": buildPositionMap(allEntries, SortModeNameAsc),
"date_desc": buildPositionMap(allEntries, SortModeDateDesc), "date_desc": buildPositionMap(allEntries, SortModeDateDesc),
@ -76,7 +76,7 @@ func TestLoadPage_LastPagePartialFromIndex(t *testing.T) {
// Build position maps for sort modes // Build position maps for sort modes
s.SortIndex = &DirectoryIndex{ s.SortIndex = &DirectoryIndex{
Entries: allEntries, Entries: allEntries,
SortOrders: map[string][]int{ SortOrders: map[string][]int{
"name_asc": buildPositionMap(allEntries, SortModeNameAsc), "name_asc": buildPositionMap(allEntries, SortModeNameAsc),
"date_desc": buildPositionMap(allEntries, SortModeDateDesc), "date_desc": buildPositionMap(allEntries, SortModeDateDesc),
@ -116,7 +116,7 @@ func TestLoadPage_OutOfBoundsFromIndex(t *testing.T) {
// Build position maps for sort modes // Build position maps for sort modes
s.SortIndex = &DirectoryIndex{ s.SortIndex = &DirectoryIndex{
Entries: allEntries, Entries: allEntries,
SortOrders: map[string][]int{ SortOrders: map[string][]int{
"name_asc": buildPositionMap(allEntries, SortModeNameAsc), "name_asc": buildPositionMap(allEntries, SortModeNameAsc),
"date_desc": buildPositionMap(allEntries, SortModeDateDesc), "date_desc": buildPositionMap(allEntries, SortModeDateDesc),
@ -195,7 +195,7 @@ func TestGetEntryByIndex(t *testing.T) {
// Build position maps for sort modes // Build position maps for sort modes
s.SortIndex = &DirectoryIndex{ s.SortIndex = &DirectoryIndex{
Entries: allEntries, Entries: allEntries,
SortOrders: map[string][]int{ SortOrders: map[string][]int{
"name_asc": buildPositionMap(allEntries, SortModeNameAsc), "name_asc": buildPositionMap(allEntries, SortModeNameAsc),
"date_desc": buildPositionMap(allEntries, SortModeDateDesc), "date_desc": buildPositionMap(allEntries, SortModeDateDesc),
@ -236,7 +236,7 @@ func TestGetEntryByIndex_UnloadedPage(t *testing.T) {
// Build position maps for sort modes // Build position maps for sort modes
s.SortIndex = &DirectoryIndex{ s.SortIndex = &DirectoryIndex{
Entries: allEntries, Entries: allEntries,
SortOrders: map[string][]int{ SortOrders: map[string][]int{
"name_asc": buildPositionMap(allEntries, SortModeNameAsc), "name_asc": buildPositionMap(allEntries, SortModeNameAsc),
"date_desc": buildPositionMap(allEntries, SortModeDateDesc), "date_desc": buildPositionMap(allEntries, SortModeDateDesc),

View File

@ -13,11 +13,11 @@ import (
// DirectoryIndex holds a cached index of a directory's contents. // DirectoryIndex holds a cached index of a directory's contents.
// Per design: index stores raw metadata; sorting is pre-computed via position maps. // Per design: index stores raw metadata; sorting is pre-computed via position maps.
type DirectoryIndex struct { type DirectoryIndex struct {
Path string `json:"path"` Path string `json:"path"`
Mtime time.Time `json:"mtime"` Mtime time.Time `json:"mtime"`
EntryCount int `json:"entry_count"` EntryCount int `json:"entry_count"`
Entries []Entry `json:"entries"` Entries []Entry `json:"entries"`
SortOrders map[string][]int `json:"sort_orders,omitempty"` // key: "name_asc", "name_desc", etc. 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. // getCachePath returns the path to the cached index file for a directory.

View File

@ -224,5 +224,3 @@ func TestBuildIndex_LargeDirectory(t *testing.T) {
t.Errorf("buildIndex took %v, expected < 5s", elapsed) t.Errorf("buildIndex took %v, expected < 5s", elapsed)
} }
} }

View File

@ -160,8 +160,6 @@ func recomputeSearchResults(s *BrowserState) {
} }
} }
// ComputeVisibleEntriesForTest is exported for testing purposes. // ComputeVisibleEntriesForTest is exported for testing purposes.
// It builds the list of ui.ListItem entries that should be rendered. // It builds the list of ui.ListItem entries that should be rendered.
func ComputeVisibleEntriesForTest(state *BrowserState) []ui.ListItem { func ComputeVisibleEntriesForTest(state *BrowserState) []ui.ListItem {

View File

@ -32,7 +32,7 @@ func makeTestState(t *testing.T, entryCount int, scrollIndex int, visibleCount i
// Build position maps for sort modes // Build position maps for sort modes
s.SortIndex = &DirectoryIndex{ s.SortIndex = &DirectoryIndex{
Entries: entries, Entries: entries,
SortOrders: map[string][]int{ SortOrders: map[string][]int{
"name_asc": buildPositionMap(entries, SortModeNameAsc), "name_asc": buildPositionMap(entries, SortModeNameAsc),
"date_desc": buildPositionMap(entries, SortModeDateDesc), "date_desc": buildPositionMap(entries, SortModeDateDesc),

View File

@ -145,7 +145,7 @@ func TestPixelScroll_EvictionTriggered(t *testing.T) {
entries[i] = NewEntry("/test/file.txt", "file.txt", 100, s.TapTimestamp, false) entries[i] = NewEntry("/test/file.txt", "file.txt", 100, s.TapTimestamp, false)
} }
s.SortIndex = &DirectoryIndex{ s.SortIndex = &DirectoryIndex{
Entries: entries, Entries: entries,
SortOrders: map[string][]int{ SortOrders: map[string][]int{
"name_asc": buildPositionMap(entries, SortModeNameAsc), "name_asc": buildPositionMap(entries, SortModeNameAsc),
"date_desc": buildPositionMap(entries, SortModeDateDesc), "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) entries[i] = NewEntry("/test/file.txt", "file.txt", 100, s.TapTimestamp, false)
} }
s.SortIndex = &DirectoryIndex{ s.SortIndex = &DirectoryIndex{
Entries: entries, Entries: entries,
SortOrders: map[string][]int{ SortOrders: map[string][]int{
"name_asc": buildPositionMap(entries, SortModeNameAsc), "name_asc": buildPositionMap(entries, SortModeNameAsc),
"date_desc": buildPositionMap(entries, SortModeDateDesc), "date_desc": buildPositionMap(entries, SortModeDateDesc),

View File

@ -83,7 +83,7 @@ func TestScroll_PrefetchTriggered(t *testing.T) {
} }
// Build position maps for sort modes // Build position maps for sort modes
s.SortIndex = &DirectoryIndex{ s.SortIndex = &DirectoryIndex{
Entries: entries, Entries: entries,
SortOrders: map[string][]int{ SortOrders: map[string][]int{
"name_asc": buildPositionMap(entries, SortModeNameAsc), "name_asc": buildPositionMap(entries, SortModeNameAsc),
"date_desc": buildPositionMap(entries, SortModeDateDesc), "date_desc": buildPositionMap(entries, SortModeDateDesc),
@ -131,7 +131,7 @@ func TestScroll_EvictionTriggered(t *testing.T) {
} }
// Build position maps for sort modes // Build position maps for sort modes
s.SortIndex = &DirectoryIndex{ s.SortIndex = &DirectoryIndex{
Entries: entries, Entries: entries,
SortOrders: map[string][]int{ SortOrders: map[string][]int{
"name_asc": buildPositionMap(entries, SortModeNameAsc), "name_asc": buildPositionMap(entries, SortModeNameAsc),
"date_desc": buildPositionMap(entries, SortModeDateDesc), "date_desc": buildPositionMap(entries, SortModeDateDesc),
@ -246,7 +246,7 @@ func TestScroll_PrefetchTriggeredOnPageBoundary(t *testing.T) {
} }
// Build position maps for sort modes // Build position maps for sort modes
s.SortIndex = &DirectoryIndex{ s.SortIndex = &DirectoryIndex{
Entries: entries, Entries: entries,
SortOrders: map[string][]int{ SortOrders: map[string][]int{
"name_asc": buildPositionMap(entries, SortModeNameAsc), "name_asc": buildPositionMap(entries, SortModeNameAsc),
"date_desc": buildPositionMap(entries, SortModeDateDesc), "date_desc": buildPositionMap(entries, SortModeDateDesc),

View File

@ -69,4 +69,3 @@ func comparator(mode SortMode) func(a, b Entry) int {
return func(a, b Entry) int { return 0 } return func(a, b Entry) int { return 0 }
} }
} }

View File

@ -19,20 +19,20 @@ type Entry struct {
// Page represents a chunk of directory entries loaded from disk. // Page represents a chunk of directory entries loaded from disk.
type Page struct { type Page struct {
Index int // Page number (0-based) Index int // Page number (0-based)
Entries []Entry // Entries in this page Entries []Entry // Entries in this page
Loaded bool // True if page data is in memory Loaded bool // True if page data is in memory
Dirty bool // True if page needs refresh (external change detected) Dirty bool // True if page needs refresh (external change detected)
} }
// BrowserState holds all mutable browser state owned by the logic goroutine. // BrowserState holds all mutable browser state owned by the logic goroutine.
type BrowserState struct { type BrowserState struct {
// Navigation // Navigation
CurrentPath string // Currently browsed directory (relative to root) CurrentPath string // Currently browsed directory (relative to root)
History []string // Path history for navigation History []string // Path history for navigation
ScrollOffset float64 // Vertical scroll offset in pixels (per-pixel scrolling) ScrollOffset float64 // Vertical scroll offset in pixels (per-pixel scrolling)
EntryHeight float64 // Height of a single entry in pixels EntryHeight float64 // Height of a single entry in pixels
VisibleCount int // Number of entries currently visible VisibleCount int // Number of entries currently visible
// Lazy loading // Lazy loading
Pages map[int]*Page // Loaded pages by page index Pages map[int]*Page // Loaded pages by page index
@ -44,8 +44,8 @@ type BrowserState struct {
SortMode SortMode // Current sort mode SortMode SortMode // Current sort mode
// Search // Search
Query string // Current search query (forwarded from the main-owned search widget) Query string // Current search query (forwarded from the main-owned search widget)
SearchResults []int // Indices of matching entries (empty = no filter) SearchResults []int // Indices of matching entries (empty = no filter)
// NOTE: the search bar's widget.Editor is intentionally NOT part of this // 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 // state: Gio mutates widget state on the main goroutine during draw, and
// this state is owned by the logic goroutine (architecture.md §1). The // this state is owned by the logic goroutine (architecture.md §1). The
@ -62,8 +62,8 @@ type BrowserState struct {
} }
const ( const (
PageSize = 100 // Entries per page (tunable; ~5KB per page in memory) PageSize = 100 // Entries per page (tunable; ~5KB per page in memory)
PrefetchDist = 2 // Pages to prefetch beyond visible region PrefetchDist = 2 // Pages to prefetch beyond visible region
) )
// NewEntry creates a new Entry from the given parameters. // 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. // EvictPages removes pages that are far from the current scroll position.
func (s *BrowserState) EvictPages() { func (s *BrowserState) EvictPages() {
minPage := s.GetScrollIndex()/PageSize - PrefetchDist 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 { for idx, page := range s.Pages {
if idx < minPage || idx > maxPage { if idx < minPage || idx > maxPage {
page.Entries = nil // Release memory page.Entries = nil // Release memory
page.Loaded = false page.Loaded = false
} }
} }

View File

@ -103,7 +103,7 @@ func TestFormatSize(t *testing.T) {
{0, "0 B"}, {0, "0 B"},
{500, "500 B"}, {500, "500 B"},
{1024, "1.0 KB"}, {1024, "1.0 KB"},
{1024*1024, "1.0 MB"}, {1024 * 1024, "1.0 MB"},
{1024 * 1024 * 1024, "1.0 GB"}, {1024 * 1024 * 1024, "1.0 GB"},
} }
@ -118,7 +118,7 @@ func TestFormatSize(t *testing.T) {
func TestBrowserStateEvictPages(t *testing.T) { func TestBrowserStateEvictPages(t *testing.T) {
s := NewBrowserState() s := NewBrowserState()
s.EntryHeight = 48.0 s.EntryHeight = 48.0
s.ScrollOffset = 500 * 48 // Page 5 s.ScrollOffset = 500 * 48 // Page 5
s.VisibleCount = 10 s.VisibleCount = 10
// With ScrollIndex=500, PageSize=100: // With ScrollIndex=500, PageSize=100:
@ -127,10 +127,10 @@ func TestBrowserStateEvictPages(t *testing.T) {
// Pages 3-7 should be kept, others evicted // Pages 3-7 should be kept, others evicted
// Add pages at various positions // Add pages at various positions
s.Pages[0] = NewPage(0, nil) // Should be evicted (far) s.Pages[0] = NewPage(0, nil) // Should be evicted (far)
s.Pages[3] = NewPage(3, nil) // Should be kept (at min boundary) s.Pages[3] = NewPage(3, nil) // Should be kept (at min boundary)
s.Pages[5] = NewPage(5, nil) // Should be kept (visible) s.Pages[5] = NewPage(5, nil) // Should be kept (visible)
s.Pages[7] = NewPage(7, nil) // Should be kept (at max boundary) s.Pages[7] = NewPage(7, nil) // Should be kept (at max boundary)
s.Pages[10] = NewPage(10, nil) // Should be evicted (far) s.Pages[10] = NewPage(10, nil) // Should be evicted (far)
s.EvictPages() s.EvictPages()

View File

@ -189,9 +189,9 @@ func TestLargeFileChunkBoundary(t *testing.T) {
// (The old fixed-slot model treated each chunk as an independent buffer and // (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.) // did NOT shift later chunks; that was the bug this design replaces.)
expectedStr := string(initialContent) expectedStr := string(initialContent)
expectedStr = expectedStr[:65000] + "CHUNK1" + expectedStr[65000:] // insert 1 @65000 expectedStr = expectedStr[:65000] + "CHUNK1" + expectedStr[65000:] // insert 1 @65000
expectedStr = expectedStr[:65535] + "BOUNDARY" + expectedStr[65535:] // insert 2 @65535 expectedStr = expectedStr[:65535] + "BOUNDARY" + expectedStr[65535:] // insert 2 @65535
expectedStr = expectedStr[:262000] + "CHUNK3" + expectedStr[262000:] // insert 3 @262000 expectedStr = expectedStr[:262000] + "CHUNK3" + expectedStr[262000:] // insert 3 @262000
expected := []byte(expectedStr) expected := []byte(expectedStr)
if len(savedContent) != len(expected) { if len(savedContent) != len(expected) {

View File

@ -1,8 +1,8 @@
package editor package editor
import ( import (
"testing"
"pad/internal/ui" "pad/internal/ui"
"testing"
) )
func TestEditorLayout_Filename(t *testing.T) { func TestEditorLayout_Filename(t *testing.T) {

View File

@ -40,8 +40,8 @@ func newChunkedState(t *testing.T, content string, chunkSize int) *State {
func TestRuneIndexToByteStr(t *testing.T) { func TestRuneIndexToByteStr(t *testing.T) {
cases := []struct { cases := []struct {
s string s string
n int n int
want int want int
}{ }{
{"", 0, 0}, {"", 0, 0},

View File

@ -111,7 +111,7 @@ func TestWordWrapFragmentStartY(t *testing.T) {
// Test case: Word wrap enabled, scroll to visual line 5 // Test case: Word wrap enabled, scroll to visual line 5
// With word wrap, visual lines don't correspond 1:1 with logical lines // With word wrap, visual lines don't correspond 1:1 with logical lines
wordWrap := true 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 scrollOffset := ui.Dp(5 * float64(lineHeight)) // Scroll to visual line 5
visualLine := int(scrollOffset / lineHeight) visualLine := int(scrollOffset / lineHeight)
@ -152,24 +152,24 @@ func TestByteOffsetAndYFromScroll(t *testing.T) {
} }
layout := ui.GlyphLayout{ layout := ui.GlyphLayout{
ByteOffsets: []int{0, 7, 14, 21}, ByteOffsets: []int{0, 7, 14, 21},
X: []ui.Dp{0, 0, 0, 0}, X: []ui.Dp{0, 0, 0, 0},
Y: []ui.Dp{0, 16.8, 33.6, 50.4}, Y: []ui.Dp{0, 16.8, 33.6, 50.4},
Advance: []ui.Dp{10, 10, 10, 10}, Advance: []ui.Dp{10, 10, 10, 10},
LineHeight: lineHeight, LineHeight: lineHeight,
VisualLineIndex: visualLineIndex, VisualLineIndex: visualLineIndex,
} }
// Test scrolling to different positions // Test scrolling to different positions
testCases := []struct { testCases := []struct {
scrollOffset ui.Dp scrollOffset ui.Dp
expectedByte int expectedByte int
expectedY ui.Dp expectedY ui.Dp
}{ }{
{ui.Dp(0), 0, ui.Dp(0)}, // Top of document {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(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(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(50.4), 21, ui.Dp(50.4)}, // Start of line 3
} }
for _, tc := range testCases { for _, tc := range testCases {

View File

@ -202,4 +202,3 @@ func byteOffsetOfLine(content string, i int) int {
} }
return o return o
} }

View File

@ -53,13 +53,13 @@ func (t *cancelTask) Execute() Result {
} }
} }
func (t *cancelTask) Priority() Priority { return t.priority } func (t *cancelTask) Priority() Priority { return t.priority }
func (t *cancelTask) TaskID() string { return t.id } func (t *cancelTask) TaskID() string { return t.id }
func (t *cancelTask) TaskType() TaskType { return t.taskType } func (t *cancelTask) TaskType() TaskType { return t.taskType }
func (t *cancelTask) DirPath() string { return "/test" } func (t *cancelTask) DirPath() string { return "/test" }
func (t *cancelTask) Context() context.Context { return t.ctx } func (t *cancelTask) Context() context.Context { return t.ctx }
func (t *cancelTask) Cancel() { t.cancel() } func (t *cancelTask) Cancel() { t.cancel() }
func (t *cancelTask) Timeout() time.Duration { return 0 } func (t *cancelTask) Timeout() time.Duration { return 0 }
// timeoutTask is a task that respects timeout. // timeoutTask is a task that respects timeout.
type timeoutTask struct { type timeoutTask struct {
@ -79,13 +79,13 @@ func (t *timeoutTask) Execute() Result {
} }
} }
func (t *timeoutTask) Priority() Priority { return t.priority } func (t *timeoutTask) Priority() Priority { return t.priority }
func (t *timeoutTask) TaskID() string { return t.id } func (t *timeoutTask) TaskID() string { return t.id }
func (t *timeoutTask) TaskType() TaskType { return t.taskType } func (t *timeoutTask) TaskType() TaskType { return t.taskType }
func (t *timeoutTask) DirPath() string { return "/test" } func (t *timeoutTask) DirPath() string { return "/test" }
func (t *timeoutTask) Context() context.Context { return context.Background() } func (t *timeoutTask) Context() context.Context { return context.Background() }
func (t *timeoutTask) Cancel() {} func (t *timeoutTask) Cancel() {}
func (t *timeoutTask) Timeout() time.Duration { return 50 * time.Millisecond } func (t *timeoutTask) Timeout() time.Duration { return 50 * time.Millisecond }
func TestTaskContextCancellation(t *testing.T) { func TestTaskContextCancellation(t *testing.T) {
task := newCancelTask("test-cancel", 1*time.Second) task := newCancelTask("test-cancel", 1*time.Second)

View File

@ -68,10 +68,10 @@ type notifyEvent struct {
// FileSystem is a thread-safe in-memory filesystem for testing. // FileSystem is a thread-safe in-memory filesystem for testing.
type FileSystem struct { type FileSystem struct {
mu sync.RWMutex mu sync.RWMutex
files map[string]*File // path -> file files map[string]*File // path -> file
delay time.Duration // uniform delay applied to all operations delay time.Duration // uniform delay applied to all operations
changes chan FileChangeEvent // async change notifications (nil = no notifications) changes chan FileChangeEvent // async change notifications (nil = no notifications)
writeError bool // Added to simulate write errors writeError bool // Added to simulate write errors
} }
// NewFileSystem creates an empty mock filesystem. // NewFileSystem creates an empty mock filesystem.

View File

@ -115,8 +115,6 @@ func (t TaskType) String() string {
} }
} }
// --- Specific Task Implementations --- // --- Specific Task Implementations ---
// ReadChunkTask reads a specific chunk of a file. // 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) Priority() Priority { return HighPriority }
func (t *ReadChunkTask) TaskType() TaskType { return TypeReadChunk } func (t *ReadChunkTask) TaskType() TaskType { return TypeReadChunk }
func (t *ReadChunkTask) TaskID() string { return t.taskID } func (t *ReadChunkTask) TaskID() string { return t.taskID }
func (t *ReadChunkTask) DirPath() string { return filepath.Dir(t.Path) } func (t *ReadChunkTask) DirPath() string { return filepath.Dir(t.Path) }
func (t *ReadChunkTask) Context() context.Context { return t.ctx } func (t *ReadChunkTask) Context() context.Context { return t.ctx }
func (t *ReadChunkTask) Timeout() time.Duration { return 5 * time.Second } func (t *ReadChunkTask) Timeout() time.Duration { return 5 * time.Second }
func (t *ReadChunkTask) Cancel() { if t.cancel != nil { t.cancel() } } func (t *ReadChunkTask) Cancel() {
if t.cancel != nil {
t.cancel()
}
}
// StatFileTask retrieves file metadata (like size and modification time). // StatFileTask retrieves file metadata (like size and modification time).
// The plan indicates this replaces the full-file ReadFileTask for opening. // 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) Priority() Priority { return MediumPriority }
func (t *StatFileTask) TaskType() TaskType { return TypeStatFile } func (t *StatFileTask) TaskType() TaskType { return TypeStatFile }
func (t *StatFileTask) TaskID() string { return t.taskID } func (t *StatFileTask) TaskID() string { return t.taskID }
func (t *StatFileTask) DirPath() string { return filepath.Dir(t.Path) } func (t *StatFileTask) DirPath() string { return filepath.Dir(t.Path) }
func (t *StatFileTask) Context() context.Context { return t.ctx } func (t *StatFileTask) Context() context.Context { return t.ctx }
func (t *StatFileTask) Timeout() time.Duration { return 5 * time.Second } func (t *StatFileTask) Timeout() time.Duration { return 5 * time.Second }
func (t *StatFileTask) Cancel() { if t.cancel != nil { t.cancel() } } func (t *StatFileTask) Cancel() {
if t.cancel != nil {
t.cancel()
}
}
// FileStat holds file metadata. // FileStat holds file metadata.
type FileStat struct { type FileStat struct {
@ -267,13 +273,17 @@ func (t *BuildLineIndexTask) Execute() Result {
} }
} }
func (t *BuildLineIndexTask) Priority() Priority { return LowPriority } func (t *BuildLineIndexTask) Priority() Priority { return LowPriority }
func (t *BuildLineIndexTask) TaskType() TaskType { return TypeBuildLineIndex } func (t *BuildLineIndexTask) TaskType() TaskType { return TypeBuildLineIndex }
func (t *BuildLineIndexTask) TaskID() string { return t.taskID } func (t *BuildLineIndexTask) TaskID() string { return t.taskID }
func (t *BuildLineIndexTask) DirPath() string { return filepath.Dir(t.Path) } func (t *BuildLineIndexTask) DirPath() string { return filepath.Dir(t.Path) }
func (t *BuildLineIndexTask) Context() context.Context { return t.ctx } func (t *BuildLineIndexTask) Context() context.Context { return t.ctx }
func (t *BuildLineIndexTask) Timeout() time.Duration { return 30 * time.Second } func (t *BuildLineIndexTask) Timeout() time.Duration { return 30 * time.Second }
func (t *BuildLineIndexTask) Cancel() { if t.cancel != nil { t.cancel() } } func (t *BuildLineIndexTask) Cancel() {
if t.cancel != nil {
t.cancel()
}
}
// BuildIndexTask builds the directory index for the browser. // BuildIndexTask builds the directory index for the browser.
type BuildIndexTask struct { type BuildIndexTask struct {
@ -304,13 +314,17 @@ func (t *BuildIndexTask) Execute() Result {
return Result{TaskID: t.taskID, TaskType: TypeBuildIndex, Success: true, Data: entries} return Result{TaskID: t.taskID, TaskType: TypeBuildIndex, Success: true, Data: entries}
} }
func (t *BuildIndexTask) Priority() Priority { return HighPriority } func (t *BuildIndexTask) Priority() Priority { return HighPriority }
func (t *BuildIndexTask) TaskType() TaskType { return TypeBuildIndex } func (t *BuildIndexTask) TaskType() TaskType { return TypeBuildIndex }
func (t *BuildIndexTask) TaskID() string { return t.taskID } func (t *BuildIndexTask) TaskID() string { return t.taskID }
func (t *BuildIndexTask) DirPath() string { return t.Dir } func (t *BuildIndexTask) DirPath() string { return t.Dir }
func (t *BuildIndexTask) Context() context.Context { return t.ctx } func (t *BuildIndexTask) Context() context.Context { return t.ctx }
func (t *BuildIndexTask) Timeout() time.Duration { return 5 * time.Second } func (t *BuildIndexTask) Timeout() time.Duration { return 5 * time.Second }
func (t *BuildIndexTask) Cancel() { if t.cancel != nil { t.cancel() } } func (t *BuildIndexTask) Cancel() {
if t.cancel != nil {
t.cancel()
}
}
// LoadPagesTask loads specific pages from a directory index. // LoadPagesTask loads specific pages from a directory index.
type LoadPagesTask struct { type LoadPagesTask struct {
@ -343,13 +357,17 @@ func (t *LoadPagesTask) Execute() Result {
return Result{TaskID: t.taskID, TaskType: TypeLoadPages, Success: true, Data: t.PageIdxs} return Result{TaskID: t.taskID, TaskType: TypeLoadPages, Success: true, Data: t.PageIdxs}
} }
func (t *LoadPagesTask) Priority() Priority { return HighPriority } func (t *LoadPagesTask) Priority() Priority { return HighPriority }
func (t *LoadPagesTask) TaskType() TaskType { return TypeLoadPages } func (t *LoadPagesTask) TaskType() TaskType { return TypeLoadPages }
func (t *LoadPagesTask) TaskID() string { return t.taskID } func (t *LoadPagesTask) TaskID() string { return t.taskID }
func (t *LoadPagesTask) DirPath() string { return t.Dir } func (t *LoadPagesTask) DirPath() string { return t.Dir }
func (t *LoadPagesTask) Context() context.Context { return t.ctx } func (t *LoadPagesTask) Context() context.Context { return t.ctx }
func (t *LoadPagesTask) Timeout() time.Duration { return 5 * time.Second } func (t *LoadPagesTask) Timeout() time.Duration { return 5 * time.Second }
func (t *LoadPagesTask) Cancel() { if t.cancel != nil { t.cancel() } } func (t *LoadPagesTask) Cancel() {
if t.cancel != nil {
t.cancel()
}
}
// ReadDirTask reads directory entries. // ReadDirTask reads directory entries.
type ReadDirTask struct { type ReadDirTask struct {
@ -381,13 +399,17 @@ func (t *ReadDirTask) Execute() Result {
return Result{TaskID: t.taskID, TaskType: TypeReadDir, Success: true, Data: entries} return Result{TaskID: t.taskID, TaskType: TypeReadDir, Success: true, Data: entries}
} }
func (t *ReadDirTask) Priority() Priority { return HighPriority } func (t *ReadDirTask) Priority() Priority { return HighPriority }
func (t *ReadDirTask) TaskType() TaskType { return TypeReadDir } func (t *ReadDirTask) TaskType() TaskType { return TypeReadDir }
func (t *ReadDirTask) TaskID() string { return t.taskID } func (t *ReadDirTask) TaskID() string { return t.taskID }
func (t *ReadDirTask) DirPath() string { return t.Dir } func (t *ReadDirTask) DirPath() string { return t.Dir }
func (t *ReadDirTask) Context() context.Context { return t.ctx } func (t *ReadDirTask) Context() context.Context { return t.ctx }
func (t *ReadDirTask) Timeout() time.Duration { return 5 * time.Second } func (t *ReadDirTask) Timeout() time.Duration { return 5 * time.Second }
func (t *ReadDirTask) Cancel() { if t.cancel != nil { t.cancel() } } func (t *ReadDirTask) Cancel() {
if t.cancel != nil {
t.cancel()
}
}
// SaveStateTask persists application state. // SaveStateTask persists application state.
type SaveStateTask struct { type SaveStateTask struct {
@ -421,13 +443,17 @@ func (t *SaveStateTask) Execute() Result {
return Result{TaskID: t.taskID, TaskType: TypeSaveState, Success: true} return Result{TaskID: t.taskID, TaskType: TypeSaveState, Success: true}
} }
func (t *SaveStateTask) Priority() Priority { return LowPriority } func (t *SaveStateTask) Priority() Priority { return LowPriority }
func (t *SaveStateTask) TaskType() TaskType { return TypeSaveState } func (t *SaveStateTask) TaskType() TaskType { return TypeSaveState }
func (t *SaveStateTask) TaskID() string { return t.taskID } func (t *SaveStateTask) TaskID() string { return t.taskID }
func (t *SaveStateTask) DirPath() string { return filepath.Dir(t.Path) } func (t *SaveStateTask) DirPath() string { return filepath.Dir(t.Path) }
func (t *SaveStateTask) Context() context.Context { return t.ctx } func (t *SaveStateTask) Context() context.Context { return t.ctx }
func (t *SaveStateTask) Timeout() time.Duration { return 5 * time.Second } func (t *SaveStateTask) Timeout() time.Duration { return 5 * time.Second }
func (t *SaveStateTask) Cancel() { if t.cancel != nil { t.cancel() } } func (t *SaveStateTask) Cancel() {
if t.cancel != nil {
t.cancel()
}
}
// SaveUndoTask persists undo stack. // SaveUndoTask persists undo stack.
type SaveUndoTask struct { type SaveUndoTask struct {
@ -461,13 +487,17 @@ func (t *SaveUndoTask) Execute() Result {
return Result{TaskID: t.taskID, TaskType: TypeSaveUndo, Success: true} return Result{TaskID: t.taskID, TaskType: TypeSaveUndo, Success: true}
} }
func (t *SaveUndoTask) Priority() Priority { return LowPriority } func (t *SaveUndoTask) Priority() Priority { return LowPriority }
func (t *SaveUndoTask) TaskType() TaskType { return TypeSaveUndo } func (t *SaveUndoTask) TaskType() TaskType { return TypeSaveUndo }
func (t *SaveUndoTask) TaskID() string { return t.taskID } func (t *SaveUndoTask) TaskID() string { return t.taskID }
func (t *SaveUndoTask) DirPath() string { return filepath.Dir(t.Path) } func (t *SaveUndoTask) DirPath() string { return filepath.Dir(t.Path) }
func (t *SaveUndoTask) Context() context.Context { return t.ctx } func (t *SaveUndoTask) Context() context.Context { return t.ctx }
func (t *SaveUndoTask) Timeout() time.Duration { return 5 * time.Second } func (t *SaveUndoTask) Timeout() time.Duration { return 5 * time.Second }
func (t *SaveUndoTask) Cancel() { if t.cancel != nil { t.cancel() } } func (t *SaveUndoTask) Cancel() {
if t.cancel != nil {
t.cancel()
}
}
// ReadFileTask reads the full content of a file. // ReadFileTask reads the full content of a file.
// Used as a fallback for small files or initial load before chunking is set up. // 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} return Result{TaskID: t.taskID, TaskType: TypeReadFile, FilePath: t.Path, Success: true, Data: content}
} }
func (t *ReadFileTask) Priority() Priority { return HighPriority } func (t *ReadFileTask) Priority() Priority { return HighPriority }
func (t *ReadFileTask) TaskType() TaskType { return TypeReadFile } func (t *ReadFileTask) TaskType() TaskType { return TypeReadFile }
func (t *ReadFileTask) TaskID() string { return t.taskID } func (t *ReadFileTask) TaskID() string { return t.taskID }
func (t *ReadFileTask) DirPath() string { return filepath.Dir(t.Path) } func (t *ReadFileTask) DirPath() string { return filepath.Dir(t.Path) }
func (t *ReadFileTask) Context() context.Context { return t.ctx } func (t *ReadFileTask) Context() context.Context { return t.ctx }
func (t *ReadFileTask) Timeout() time.Duration { return 5 * time.Second } func (t *ReadFileTask) Timeout() time.Duration { return 5 * time.Second }
func (t *ReadFileTask) Cancel() { if t.cancel != nil { t.cancel() } } func (t *ReadFileTask) Cancel() {
if t.cancel != nil {
t.cancel()
}
}
// SearchData is the payload of a completed SearchTask: the byte ranges // SearchData is the payload of a completed SearchTask: the byte ranges
// [start, end) of every match of Query in the scanned Text, ascending and // [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. // unit; it is the standard library's two-way search.
func indexOf(s, sub string) int { return strings.Index(s, sub) } func indexOf(s, sub string) int { return strings.Index(s, sub) }
func (t *SearchTask) Priority() Priority { return MediumPriority } func (t *SearchTask) Priority() Priority { return MediumPriority }
func (t *SearchTask) TaskType() TaskType { return TypeSearch } func (t *SearchTask) TaskType() TaskType { return TypeSearch }
func (t *SearchTask) TaskID() string { return t.taskID } func (t *SearchTask) TaskID() string { return t.taskID }
func (t *SearchTask) DirPath() string { return "" } func (t *SearchTask) DirPath() string { return "" }
func (t *SearchTask) Context() context.Context { return t.ctx } func (t *SearchTask) Context() context.Context { return t.ctx }
func (t *SearchTask) Timeout() time.Duration { return 10 * time.Second } func (t *SearchTask) Timeout() time.Duration { return 10 * time.Second }
func (t *SearchTask) Cancel() { if t.cancel != nil { t.cancel() } } func (t *SearchTask) Cancel() {
if t.cancel != nil {
t.cancel()
}
}
// WriteFileTask writes content to a file. // WriteFileTask writes content to a file.
type WriteFileTask struct { type WriteFileTask struct {
@ -626,13 +664,17 @@ func (t *WriteFileTask) Execute() Result {
return Result{TaskID: t.taskID, TaskType: TypeWriteFile, FilePath: t.Path, Success: true} return Result{TaskID: t.taskID, TaskType: TypeWriteFile, FilePath: t.Path, Success: true}
} }
func (t *WriteFileTask) Priority() Priority { return LowPriority } func (t *WriteFileTask) Priority() Priority { return LowPriority }
func (t *WriteFileTask) TaskType() TaskType { return TypeWriteFile } func (t *WriteFileTask) TaskType() TaskType { return TypeWriteFile }
func (t *WriteFileTask) TaskID() string { return t.taskID } func (t *WriteFileTask) TaskID() string { return t.taskID }
func (t *WriteFileTask) DirPath() string { return filepath.Dir(t.Path) } func (t *WriteFileTask) DirPath() string { return filepath.Dir(t.Path) }
func (t *WriteFileTask) Context() context.Context { return t.ctx } func (t *WriteFileTask) Context() context.Context { return t.ctx }
func (t *WriteFileTask) Timeout() time.Duration { return 5 * time.Second } func (t *WriteFileTask) Timeout() time.Duration { return 5 * time.Second }
func (t *WriteFileTask) Cancel() { if t.cancel != nil { t.cancel() } } func (t *WriteFileTask) Cancel() {
if t.cancel != nil {
t.cancel()
}
}
// --- Mock File System (for testing/development) --- // --- Mock File System (for testing/development) ---
// MockFS implements the pool.FileSystem interface for testing. // MockFS implements the pool.FileSystem interface for testing.
@ -709,12 +751,12 @@ type mockFileInfo struct {
modTime time.Time modTime time.Time
} }
func (f *mockFileInfo) Name() string { return f.name } func (f *mockFileInfo) Name() string { return f.name }
func (f *mockFileInfo) Size() int64 { return f.size } func (f *mockFileInfo) Size() int64 { return f.size }
func (f *mockFileInfo) Mode() os.FileMode { return os.FileMode(f.mode) } func (f *mockFileInfo) Mode() os.FileMode { return os.FileMode(f.mode) }
func (f *mockFileInfo) ModTime() time.Time { return f.modTime } func (f *mockFileInfo) ModTime() time.Time { return f.modTime }
func (f *mockFileInfo) IsDir() bool { return false } func (f *mockFileInfo) IsDir() bool { return false }
func (f *mockFileInfo) Sys() any { return nil } func (f *mockFileInfo) Sys() any { return nil }
// mockDirEntry implements types.DirEntry for MockFS ReadDir. // mockDirEntry implements types.DirEntry for MockFS ReadDir.
type mockDirEntry struct { type mockDirEntry struct {
@ -722,8 +764,8 @@ type mockDirEntry struct {
isDir bool isDir bool
} }
func (e *mockDirEntry) Name() string { return e.name } func (e *mockDirEntry) Name() string { return e.name }
func (e *mockDirEntry) IsDir() bool { return e.isDir } func (e *mockDirEntry) IsDir() bool { return e.isDir }
func (e *mockDirEntry) Info() (os.FileInfo, error) { func (e *mockDirEntry) Info() (os.FileInfo, error) {
return &mockFileInfo{name: e.name, size: 0}, nil 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 var _ FileSystem = (*MockFS)(nil) // Compile-time interface check

View File

@ -73,18 +73,18 @@ func (li *LineIndex) FindLogicalLineForByteOffset(byteOffset int) int {
low, high := 0, len(li.Offsets)-1 low, high := 0, len(li.Offsets)-1
for low <= high { for low <= high {
mid := (low + high) / 2 mid := (low + high) / 2
midOffset := int(li.Offsets[mid]) midOffset := int(li.Offsets[mid])
if byteOffset >= midOffset { if byteOffset >= midOffset {
// This line starts at or before our byte offset // This line starts at or before our byte offset
// Check if the next line starts after 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 { if mid == len(li.Offsets)-1 || int(li.Offsets[mid+1]) > byteOffset {
return mid // Found the line return mid // Found the line
}
low = mid + 1
} else {
high = mid - 1
} }
low = mid + 1
} else {
high = mid - 1
}
} }
return -1 // Not found return -1 // Not found

View File

@ -13,15 +13,15 @@ import (
// - Workers execute tasks and post results on resultChan // - Workers execute tasks and post results on resultChan
// - Workers never access state directly // - Workers never access state directly
type WorkerPool struct { type WorkerPool struct {
highWorkChan chan Task highWorkChan chan Task
lowWorkChan chan Task lowWorkChan chan Task
resultChan chan Result resultChan chan Result
workerCount int workerCount int
stopOnce sync.Once stopOnce sync.Once
stopChan chan struct{} stopChan chan struct{}
wg sync.WaitGroup wg sync.WaitGroup
taskCounter atomic.Int64 taskCounter atomic.Int64
running atomic.Bool running atomic.Bool
// pendingTasks tracks in-flight tasks for cancellation by directory. // pendingTasks tracks in-flight tasks for cancellation by directory.
pendingTasks map[string][]Task pendingTasks map[string][]Task

View File

@ -42,13 +42,13 @@ func (t *stubTask) Execute() Result {
} }
} }
func (t *stubTask) Priority() Priority { return t.priority } func (t *stubTask) Priority() Priority { return t.priority }
func (t *stubTask) TaskID() string { return t.id } func (t *stubTask) TaskID() string { return t.id }
func (t *stubTask) TaskType() TaskType { return t.taskType } func (t *stubTask) TaskType() TaskType { return t.taskType }
func (t *stubTask) DirPath() string { return "" } func (t *stubTask) DirPath() string { return "" }
func (t *stubTask) Context() context.Context { return context.Background() } func (t *stubTask) Context() context.Context { return context.Background() }
func (t *stubTask) Cancel() {} func (t *stubTask) Cancel() {}
func (t *stubTask) Timeout() time.Duration { return 5 * time.Second } func (t *stubTask) Timeout() time.Duration { return 5 * time.Second }
func TestWorkerPool_StartStop(t *testing.T) { func TestWorkerPool_StartStop(t *testing.T) {
pool := NewWorkerPool(4) pool := NewWorkerPool(4)
@ -672,9 +672,9 @@ func TestWorkerPool_ResultIsSuccess(t *testing.T) {
} }
result2 := Result{ result2 := Result{
TaskID: "test", TaskID: "test",
Success: false, Success: false,
Error: fmt.Errorf("error"), Error: fmt.Errorf("error"),
} }
if result2.IsSuccess() { if result2.IsSuccess() {
t.Error("Result should not be successful") t.Error("Result should not be successful")
@ -683,7 +683,7 @@ func TestWorkerPool_ResultIsSuccess(t *testing.T) {
func TestWorkerPool_ResultIsError(t *testing.T) { func TestWorkerPool_ResultIsError(t *testing.T) {
result := Result{ result := Result{
TaskID: "test", TaskID: "test",
Success: false, Success: false,
Error: fmt.Errorf("error"), Error: fmt.Errorf("error"),
} }

View File

@ -14,7 +14,7 @@ type TestScenario struct {
Setup func(*Harness) Setup func(*Harness)
Actions []HarnessAction Actions []HarnessAction
Assertions []FrameAssertion 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 Timeout time.Duration
} }

View File

@ -646,7 +646,7 @@ func TestRestore_LinePinHoldsAcrossLateWrapFeedback(t *testing.T) {
File: "/wrap.txt", File: "/wrap.txt",
Cursor: 0, Cursor: 0,
Scroll: float64(ui.Dp(500 * lh)), // the saving session's visual-space offset 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, ScrollSub: 0,
} }

View File

@ -2,14 +2,14 @@ package ui
const ( const (
// Standard dimensions in Dp // Standard dimensions in Dp
StatusBarLineHeight = Dp(24) StatusBarLineHeight = Dp(24)
StatusBarFilenameLine = Dp(24) StatusBarFilenameLine = Dp(24)
StatusBarIconsLine = Dp(24) StatusBarIconsLine = Dp(24)
BottomBarHeight = Dp(24) BottomBarHeight = Dp(24)
IconSize = Dp(24) IconSize = Dp(24)
IconGap = Dp(36) IconGap = Dp(36)
Padding = Dp(8) Padding = Dp(8)
ButtonPadding = Dp(8) ButtonPadding = Dp(8)
) )
// LineHeightScale is the baseline-to-baseline spacing multiplier for editor text. // LineHeightScale is the baseline-to-baseline spacing multiplier for editor text.