From cb3090956cfdc0ff4c2f06e4ef3c5eb73b73f9c0 Mon Sep 17 00:00:00 2001
From: Koni Marti <koni.marti@gmail.com>
Date: Sun, 23 Jan 2022 10:31:41 +0100
Subject: [PATCH] dirlist: skip unnecessary change-folder action

when traversing the directory list, aerc will fetch the contents for
every directory even though the user might just move on to the next.
This causes an unnecessary delay (and load on the worker) and can be
avoided by skipping the old change-folder action when a newer one
arrives within a predefined time interval.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
---
 widgets/dirlist.go | 94 +++++++++++++++++++++++++++-------------------
 1 file changed, 55 insertions(+), 39 deletions(-)

diff --git a/widgets/dirlist.go b/widgets/dirlist.go
index e6f95e1..53afc1d 100644
--- a/widgets/dirlist.go
+++ b/widgets/dirlist.go
@@ -6,6 +6,7 @@ import (
 	"math"
 	"regexp"
 	"sort"
+	"time"
 
 	"github.com/gdamore/tcell/v2"
 	"github.com/mattn/go-runewidth"
@@ -20,27 +21,29 @@ import (
 
 type DirectoryList struct {
 	ui.Invalidatable
-	aercConf  *config.AercConfig
-	acctConf  *config.AccountConfig
-	store     *lib.DirStore
-	dirs      []string
-	logger    *log.Logger
-	selecting string
-	selected  string
-	scroll    int
-	spinner   *Spinner
-	worker    *types.Worker
+	aercConf   *config.AercConfig
+	acctConf   *config.AccountConfig
+	store      *lib.DirStore
+	dirs       []string
+	logger     *log.Logger
+	selecting  string
+	selected   string
+	scroll     int
+	spinner    *Spinner
+	worker     *types.Worker
+	skipSelect chan bool
 }
 
 func NewDirectoryList(conf *config.AercConfig, acctConf *config.AccountConfig,
 	logger *log.Logger, worker *types.Worker) *DirectoryList {
 
 	dirlist := &DirectoryList{
-		aercConf: conf,
-		acctConf: acctConf,
-		logger:   logger,
-		store:    lib.NewDirStore(),
-		worker:   worker,
+		aercConf:   conf,
+		acctConf:   acctConf,
+		logger:     logger,
+		store:      lib.NewDirStore(),
+		worker:     worker,
+		skipSelect: make(chan bool),
 	}
 	uiConf := dirlist.UiConfig()
 	dirlist.spinner = NewSpinner(&uiConf)
@@ -87,32 +90,45 @@ func (dirlist *DirectoryList) UpdateList(done func(dirs []string)) {
 
 func (dirlist *DirectoryList) Select(name string) {
 	dirlist.selecting = name
-	dirlist.worker.PostAction(&types.OpenDirectory{Directory: name},
-		func(msg types.WorkerMessage) {
-			switch msg.(type) {
-			case *types.Error:
-				dirlist.selecting = ""
-			case *types.Done:
-				dirlist.selected = dirlist.selecting
-				dirlist.filterDirsByFoldersConfig()
-				hasSelected := false
-				for _, d := range dirlist.dirs {
-					if d == dirlist.selected {
-						hasSelected = true
-						break
+
+	close(dirlist.skipSelect)
+	dirlist.skipSelect = make(chan bool)
+
+	go func() {
+		select {
+		case <-time.After(1 * time.Second):
+			dirlist.worker.PostAction(&types.OpenDirectory{Directory: name},
+				func(msg types.WorkerMessage) {
+					switch msg.(type) {
+					case *types.Error:
+						dirlist.selecting = ""
+						dirlist.selected = ""
+					case *types.Done:
+						dirlist.selected = dirlist.selecting
+						dirlist.filterDirsByFoldersConfig()
+						hasSelected := false
+						for _, d := range dirlist.dirs {
+							if d == dirlist.selected {
+								hasSelected = true
+								break
+							}
+						}
+						if !hasSelected && dirlist.selected != "" {
+							dirlist.dirs = append(dirlist.dirs, dirlist.selected)
+						}
+						if dirlist.acctConf.EnableFoldersSort {
+							sort.Strings(dirlist.dirs)
+						}
+						dirlist.sortDirsByFoldersSortConfig()
 					}
-				}
-				if !hasSelected && dirlist.selected != "" {
-					dirlist.dirs = append(dirlist.dirs, dirlist.selected)
-				}
-				if dirlist.acctConf.EnableFoldersSort {
-					sort.Strings(dirlist.dirs)
-				}
-				dirlist.sortDirsByFoldersSortConfig()
-			}
+					dirlist.Invalidate()
+				})
 			dirlist.Invalidate()
-		})
-	dirlist.Invalidate()
+		case <-dirlist.skipSelect:
+			dirlist.logger.Println("dirlist: skip", name)
+			return
+		}
+	}()
 }
 
 func (dirlist *DirectoryList) Selected() string {