Description: Simpler implementation of dirpreviews
Author: Joe Lim
Origin: upstream
Bug: https://github.com/gokcehan/lf/issues/1084
Applied-Upstream: https://github.com/gokcehan/lf/pull/1958/commits/90b9f8f07f037a2890c46514ec85346b65607ba0
Reviewed-by: Nick Morrott <nickm@debian.org>
Last-Update: 2025-05-04
---
--- a/app.go
+++ b/app.go
@@ -258,7 +258,6 @@
 // separate goroutines and sent here for update.
 func (app *app) loop() {
 	go app.nav.previewLoop(app.ui)
-	go app.nav.dirPreviewLoop(app.ui)
 
 	var serverChan <-chan expr
 	if !gSingleMode {
@@ -336,7 +335,6 @@
 			app.quit()
 
 			app.nav.previewChan <- ""
-			app.nav.dirPreviewChan <- nil
 
 			log.Print("bye!")
 
@@ -510,7 +508,6 @@
 
 func (app *app) runCmdSync(cmd *exec.Cmd, pause_after bool) {
 	app.nav.previewChan <- ""
-	app.nav.dirPreviewChan <- nil
 
 	if err := app.ui.suspend(); err != nil {
 		log.Printf("suspend: %s", err)
--- a/nav.go
+++ b/nav.go
@@ -174,7 +174,6 @@
 	ignoredia   bool       // ignoredia value from last sort
 	locale      string     // locale value from last sort
 	noPerm      bool       // whether lf has no permission to open the directory
-	lines       []string   // lines of text to display if directory previews are enabled
 }
 
 func newDir(path string) *dir {
@@ -186,7 +185,6 @@
 	}
 
 	return &dir{
-		loading:  gOpts.dirpreviews, // Directory is loaded after previewer function exits.
 		loadTime: time,
 		path:     path,
 		files:    files,
@@ -449,7 +447,6 @@
 	deleteCountChan chan int
 	deleteTotalChan chan int
 	previewChan     chan string
-	dirPreviewChan  chan *dir
 	dirChan         chan *dir
 	regChan         chan *reg
 	fileChan        chan *file
@@ -479,8 +476,6 @@
 }
 
 func (nav *nav) loadDirInternal(path string) *dir {
-	nav.startPreview()
-
 	d := &dir{
 		loading:     true,
 		loadTime:    time.Now(),
@@ -499,9 +494,6 @@
 		d := newDir(path)
 		d.sort()
 		d.ind, d.pos = 0, 0
-		if gOpts.dirpreviews {
-			nav.dirPreviewChan <- d
-		}
 		nav.dirChan <- d
 	}()
 	return d
@@ -540,14 +532,10 @@
 			return
 		}
 
-		nav.startPreview()
 		dir.loading = true
 		dir.loadTime = now
 		go func() {
 			nd := newDir(dir.path)
-			if gOpts.dirpreviews {
-				nav.dirPreviewChan <- nd
-			}
 			nav.dirChan <- nd
 		}()
 	case dir.sortby != getSortBy(dir.path) ||
@@ -598,7 +586,6 @@
 		deleteCountChan: make(chan int, 1024),
 		deleteTotalChan: make(chan int, 1024),
 		previewChan:     make(chan string, 1024),
-		dirPreviewChan:  make(chan *dir, 1024),
 		dirChan:         make(chan *dir),
 		regChan:         make(chan *reg),
 		fileChan:        make(chan *file),
@@ -717,23 +704,6 @@
 	}
 }
 
-func (nav *nav) dirPreviewLoop(ui *ui) {
-	var prevPath string
-	for dir := range nav.dirPreviewChan {
-		if dir == nil && len(gOpts.previewer) != 0 && len(gOpts.cleaner) != 0 && nav.volatilePreview {
-			cmd := exec.Command(gOpts.cleaner, prevPath)
-			if err := cmd.Run(); err != nil {
-				log.Printf("cleaning preview: %s", err)
-			}
-			nav.volatilePreview = false
-		} else if dir != nil {
-			win := ui.wins[len(ui.wins)-1]
-			nav.previewDir(dir, win)
-			prevPath = dir.path
-		}
-	}
-}
-
 func (nav *nav) previewLoop(ui *ui) {
 	var prev string
 	for path := range nav.previewChan {
@@ -782,64 +752,6 @@
 	return matched
 }
 
-func (nav *nav) previewDir(dir *dir, win *win) {
-	defer func() {
-		dir.loading = false
-		nav.dirChan <- dir
-	}()
-
-	var reader io.Reader
-
-	if len(gOpts.previewer) != 0 {
-		cmd := exec.Command(gOpts.previewer, dir.path,
-			strconv.Itoa(win.w),
-			strconv.Itoa(win.h),
-			strconv.Itoa(win.x),
-			strconv.Itoa(win.y))
-
-		out, err := cmd.StdoutPipe()
-		if err != nil {
-			log.Printf("previewing dir: %s", err)
-			return
-		}
-
-		if err := cmd.Start(); err != nil {
-			log.Printf("previewing dir: %s", err)
-			out.Close()
-			return
-		}
-
-		defer func() {
-			if err := cmd.Wait(); err != nil {
-				if e, ok := err.(*exec.ExitError); ok {
-					if e.ExitCode() != 0 {
-						nav.volatilePreview = true
-					}
-				} else {
-					log.Printf("loading dir: %s", err)
-				}
-			}
-		}()
-		defer out.Close()
-		reader = out
-		buf := bufio.NewScanner(reader)
-
-		for i := 0; i < win.h && buf.Scan(); i++ {
-			for _, r := range buf.Text() {
-				if r == 0 {
-					dir.lines = []string{"\033[7mbinary\033[0m"}
-					return
-				}
-			}
-			dir.lines = append(dir.lines, buf.Text())
-		}
-
-		if buf.Err() != nil {
-			log.Printf("loading dir: %s", buf.Err())
-		}
-	}
-}
-
 func (nav *nav) preview(path string, win *win) {
 	reg := &reg{loadTime: time.Now(), path: path}
 	defer func() { nav.regChan <- reg }()
--- a/ui.go
+++ b/ui.go
@@ -356,7 +356,7 @@
 	role   dirRole
 }
 
-func (win *win) printDir(ui *ui, dir *dir, context *dirContext, dirStyle *dirStyle, previewLoading bool) {
+func (win *win) printDir(ui *ui, dir *dir, context *dirContext, dirStyle *dirStyle) {
 	if win.w < 5 || dir == nil {
 		return
 	}
@@ -368,25 +368,11 @@
 		return
 	}
 	fileslen := len(dir.files)
-	if (dir.loading && fileslen == 0) || (dirStyle.role == Preview && dir.loading && gOpts.dirpreviews) {
-		if dirStyle.role != Preview || previewLoading {
-			win.print(ui.screen, 2, 0, messageStyle, "loading...")
-		}
+	if dir.loading && fileslen == 0 {
+		win.print(ui.screen, 2, 0, messageStyle, "loading...")
 		return
 	}
 
-	if dirStyle.role == Preview && gOpts.dirpreviews && len(gOpts.previewer) > 0 {
-		// Print previewer result instead of default directory print operation.
-		st := tcell.StyleDefault
-		for i, l := range dir.lines {
-			if i > win.h-1 {
-				break
-			}
-
-			st = win.print(ui.screen, 2, i, st, l)
-		}
-		return
-	}
 	if fileslen == 0 {
 		win.print(ui.screen, 2, 0, messageStyle, "empty")
 		return
@@ -735,6 +721,9 @@
 	ui.echoerr(fmt.Sprintf(format, a...))
 }
 
+// This represents the preview for a regular file.
+// This can also be used to represent the preview of a directory if
+// `dirpreviews` is enabled.
 type reg struct {
 	loading  bool
 	volatile bool
@@ -767,10 +756,10 @@
 		return
 	}
 
-	if curr.IsDir() {
-		ui.dirPrev = app.nav.loadDir(curr.path)
-	} else if curr.Mode().IsRegular() {
+	if curr.Mode().IsRegular() || (curr.IsDir() && gOpts.dirpreviews) {
 		ui.regPrev = app.nav.loadReg(curr.path, volatile)
+	} else if curr.IsDir() {
+		ui.dirPrev = app.nav.loadDir(curr.path)
 	}
 }
 
@@ -1052,8 +1041,7 @@
 		}
 		if dir := ui.dirOfWin(nav, i); dir != nil {
 			ui.wins[i].printDir(ui, dir, &context,
-				&dirStyle{colors: ui.styles, icons: ui.icons, role: role},
-				nav.previewLoading)
+				&dirStyle{colors: ui.styles, icons: ui.icons, role: role})
 		}
 	}
 
@@ -1081,12 +1069,11 @@
 		if err == nil {
 			preview := ui.wins[len(ui.wins)-1]
 
-			if curr.IsDir() {
-				preview.printDir(ui, ui.dirPrev, &context,
-					&dirStyle{colors: ui.styles, icons: ui.icons, role: Preview},
-					nav.previewLoading)
-			} else if curr.Mode().IsRegular() {
+			if curr.Mode().IsRegular() || (curr.IsDir() && gOpts.dirpreviews) {
 				preview.printReg(ui.screen, ui.regPrev, nav.previewLoading, &ui.sxScreen)
+			} else if curr.IsDir() {
+				preview.printDir(ui, ui.dirPrev, &context,
+						&dirStyle{colors: ui.styles, icons: ui.icons, role: Preview})
 			}
 		}
 	}
