Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,8 @@ func (app *app) loop() {
}

app.ui.draw(app.nav)
case fn := <-app.nav.checkChan:
fn()
case r := <-app.nav.regChan:
if r.height != app.nav.height {
delete(app.nav.regCache, r.path)
Expand Down
3 changes: 2 additions & 1 deletion eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -1597,7 +1597,8 @@ func (e *callExpr) eval(app *app, _ []string) {

dir := app.nav.currDir()
app.nav.checkDir(dir)
if dir.loading {
// the directory is checked asynchronously, so show the file in the meantime
if (dir.loading || dir.checking) && !slices.ContainsFunc(dir.files, func(f *file) bool { return f.path == path }) {
dir.files = append(dir.files, &file{FileInfo: lstat})
}
dir.sel(filepath.Base(path), app.nav.height)
Expand Down
35 changes: 31 additions & 4 deletions nav.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ func readdir(path string) ([]*file, error) {

type dir struct {
loading bool // whether directory is loading from disk
checking bool // whether directory is being checked for changes
loadTime time.Time // last load time
ind int // 0-based index of current entry in dir.files
pos int // 0-based cursor row in directory window
Expand Down Expand Up @@ -453,6 +454,7 @@ type nav struct {
preloadChan chan string
previewChan chan string
dirChan chan *dir
checkChan chan func()
regChan chan *reg
fileChan chan *file
delChan chan string
Expand Down Expand Up @@ -510,11 +512,21 @@ func (nav *nav) getDir(path string) *dir {
}

func (nav *nav) checkDir(dir *dir) {
if dir.loading {
if dir.loading || dir.checking {
return
}

s, err := os.Stat(dir.path)
// os.Stat can block forever on an unresponsive filesystem, so keep it off the ui goroutine
dir.checking = true
go func() {
s, err := os.Stat(dir.path)
nav.checkChan <- func() { nav.checkedDir(dir, s, err) }
}()
}

func (nav *nav) checkedDir(dir *dir, s os.FileInfo, err error) {
dir.checking = false

if err != nil {
log.Printf("getting directory info: %s", err)
return
Expand Down Expand Up @@ -586,6 +598,7 @@ func newNav(ui *ui) *nav {
preloadChan: make(chan string, 1024),
previewChan: make(chan string, 1024),
dirChan: make(chan *dir),
checkChan: make(chan func()),
regChan: make(chan *reg),
fileChan: make(chan *file),
delChan: make(chan string),
Expand Down Expand Up @@ -989,7 +1002,21 @@ func (nav *nav) loadReg(path string, volatile bool) *reg {
}

func (nav *nav) checkReg(reg *reg) {
s, err := os.Stat(reg.path)
if reg.checking {
return
}

// os.Stat can block forever on an unresponsive filesystem, so keep it off the ui goroutine
reg.checking = true
go func() {
s, err := os.Stat(reg.path)
nav.checkChan <- func() { nav.checkedReg(reg, s, err) }
}()
}

func (nav *nav) checkedReg(reg *reg, s os.FileInfo, err error) {
reg.checking = false

if err != nil {
return
}
Expand Down Expand Up @@ -1584,7 +1611,7 @@ func (nav *nav) rename() error {
dir := nav.getDir(filepath.Dir(newPath))
nav.checkDir(dir)

if dir.loading {
if dir.loading || dir.checking {
for i := range dir.allFiles {
if dir.allFiles[i].path == oldPath {
dir.allFiles[i] = &file{FileInfo: lstat}
Expand Down
1 change: 1 addition & 0 deletions ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,7 @@ func (ui *ui) echoerrf(format string, a ...any) {
// file preview, but `previewer` now also supports non-regular files.
type reg struct {
loading bool
checking bool
volatile bool
loadTime time.Time
path string
Expand Down