- Add ChunkedBuffer for 64KB chunked file access with dirty-chunk eviction protection - Add LineIndex for precise byte-offset-to-line-number mapping - Refactor IO task system with context cancellation, typed priorities, and new task types (ReadChunk, BuildLineIndex, StatFile) - Add ReadFileAt to FileSystem interface (mock + real implementations) - Integrate virtual scrolling into editor layout - Add comprehensive tests for chunked buffer eviction, dirty-chunk safety, and full edit lifecycle
95 lines
2.5 KiB
Go
95 lines
2.5 KiB
Go
package real
|
|
|
|
import (
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"pad/internal/io/pool/types"
|
|
)
|
|
|
|
// RealFileSystem implements the pool.FileSystem interface using the real OS filesystem.
|
|
type RealFileSystem struct {
|
|
Root string
|
|
}
|
|
|
|
func (fs *RealFileSystem) ReadDir(path string) ([]types.DirEntry, error) {
|
|
entries, err := os.ReadDir(filepath.Join(fs.Root, path))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var res []types.DirEntry
|
|
for _, e := range entries {
|
|
res = append(res, &realDirEntry{e})
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func (fs *RealFileSystem) DirExists(path string) bool {
|
|
info, err := os.Stat(filepath.Join(fs.Root, path))
|
|
return err == nil && info.IsDir()
|
|
}
|
|
|
|
func (fs *RealFileSystem) FileExists(path string) bool {
|
|
info, err := os.Stat(filepath.Join(fs.Root, path))
|
|
return err == nil && !info.IsDir()
|
|
}
|
|
|
|
func (fs *RealFileSystem) ReadFile(path string) ([]byte, error) {
|
|
return os.ReadFile(filepath.Join(fs.Root, path))
|
|
}
|
|
|
|
func (fs *RealFileSystem) ReadFileAt(path string, offset, size int) ([]byte, error) {
|
|
fullPath := filepath.Join(fs.Root, path)
|
|
f, err := os.Open(fullPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
buf := make([]byte, size)
|
|
n, err := f.ReadAt(buf, int64(offset))
|
|
if err != nil && err != io.EOF {
|
|
return nil, err
|
|
}
|
|
return buf[:n], nil
|
|
}
|
|
|
|
func (fs *RealFileSystem) WriteFile(path string, content []byte) error {
|
|
// Simple write for backward compatibility if needed,
|
|
// but defer to Atomic implementation.
|
|
return fs.WriteFileAtomic(path, content)
|
|
}
|
|
|
|
func (fs *RealFileSystem) WriteFileAtomic(path string, content []byte) error {
|
|
// Atomic write implementation
|
|
fullPath := filepath.Join(fs.Root, path)
|
|
// Temp file in the same directory as the target to ensure same filesystem rename
|
|
tmpPath := filepath.Join(filepath.Dir(fullPath), "."+filepath.Base(path)+".tmp")
|
|
|
|
if err := os.MkdirAll(filepath.Dir(tmpPath), 0755); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := os.WriteFile(tmpPath, content, 0644); err != nil {
|
|
return err
|
|
}
|
|
|
|
return os.Rename(tmpPath, fullPath)
|
|
}
|
|
|
|
func (fs *RealFileSystem) DeleteFile(path string) error {
|
|
return os.Remove(filepath.Join(fs.Root, path))
|
|
}
|
|
|
|
func (fs *RealFileSystem) CreateDir(path string) error {
|
|
return os.MkdirAll(filepath.Join(fs.Root, path), 0755)
|
|
}
|
|
|
|
// realDirEntry wraps os.DirEntry
|
|
type realDirEntry struct {
|
|
entry os.DirEntry
|
|
}
|
|
|
|
func (e *realDirEntry) Name() string { return e.entry.Name() }
|
|
func (e *realDirEntry) IsDir() bool { return e.entry.IsDir() }
|
|
func (e *realDirEntry) Info() (os.FileInfo, error) { return e.entry.Info() }
|