From 673dad9f070edd86494232232c620058d49ba5ef Mon Sep 17 00:00:00 2001 From: Lucas Mior <49657055+lucas-mior@users.noreply.github.com> Date: Sat, 25 Dec 2021 14:49:30 -0300 Subject: [PATCH] dirtyfiles: files that don't require cleaning before previewing them (#729) * dirtyfiles * wrong default on man page * respect alphabetic order for options * clean on shell commands * formating if --- app.go | 1 + complete.go | 1 + doc.go | 9 +++++++++ docstring.go | 10 ++++++++++ eval.go | 18 ++++++++++++++++++ lf.1 | 7 +++++++ nav.go | 16 ++++++++++++---- opts.go | 2 ++ os.go | 13 +++++++++++++ 9 files changed, 73 insertions(+), 4 deletions(-) diff --git a/app.go b/app.go index 4b80278..3dd8d72 100644 --- a/app.go +++ b/app.go @@ -481,6 +481,7 @@ func (app *app) runShell(s string, args []string, prefix string) { cmd.Stderr = os.Stderr app.nav.previewChan <- "" + app.nav.previewChan <- "!" if err := app.ui.suspend(); err != nil { log.Printf("suspend: %s", err) } diff --git a/complete.go b/complete.go index 00ed30c..6ccccb5 100644 --- a/complete.go +++ b/complete.go @@ -87,6 +87,7 @@ var ( "dironly", "nodironly", "dironly!", + "dirtyfiles", "drawbox", "nodrawbox", "drawbox!", diff --git a/doc.go b/doc.go index ae31614..9a0e8f5 100644 --- a/doc.go +++ b/doc.go @@ -105,6 +105,7 @@ The following options can be used to customize the behavior of lf: dircounts bool (default off) dirfirst bool (default on) dironly bool (default off) + dirtyfiles []string (default '!*') drawbox bool (default off) errorfmt string (default "\033[7;31;47m%s\033[0m") filesep string (default "\n") @@ -534,6 +535,14 @@ Show directories first above regular files. Show only directories. + dirtyfiles []string (default '!*') + +List of dirty file glob patterns. +These files won't have 'cleaner' executed before previewing them. +Patterns can be given as relative or absolute paths. +Globbing supports the usual special characters, '*' to match any sequence, '?' to match any character, and '[...]' or '[^...] to match character sets or ranges. +In addition, if a pattern starts with '!', then its matches are excluded from dirty files. + drawbox bool (default off) Draw boxes around panes with box drawing characters. diff --git a/docstring.go b/docstring.go index c0e4a76..d1e899a 100644 --- a/docstring.go +++ b/docstring.go @@ -109,6 +109,7 @@ The following options can be used to customize the behavior of lf: dircounts bool (default off) dirfirst bool (default on) dironly bool (default off) + dirtyfiles []string (default '!*') drawbox bool (default off) errorfmt string (default "\033[7;31;47m%s\033[0m") filesep string (default "\n") @@ -565,6 +566,15 @@ Show directories first above regular files. Show only directories. + dirtyfiles []string (default '!*') + +List of dirty file glob patterns. These files won't have 'cleaner' called +before previewing them. Patterns can be given as relative or +absolute paths. Globbing supports the usual special characters, '*' to match +any sequence, '?' to match any character, and '[...]' or '[^...] to match +character sets or ranges. In addition, if a pattern starts with '!', then +its matches are excluded from dirty files. + drawbox bool (default off) Draw boxes around panes with box drawing characters. diff --git a/eval.go b/eval.go index 22eb92f..a2d80b8 100644 --- a/eval.go +++ b/eval.go @@ -68,6 +68,24 @@ func (e *setExpr) eval(app *app, args []string) { gOpts.sortType.option ^= dirfirstSort app.nav.sort() app.ui.sort() + case "dirtyfiles": + toks := strings.Split(e.val, ":") + for _, s := range toks { + if s == "" { + app.ui.echoerr("dirtyfiles: glob should be non-empty") + return + } + _, err := filepath.Match(s, "a") + if err != nil { + app.ui.echoerrf("dirtyfiles: %s", err) + return + } + } + gOpts.dirtyfiles = toks + app.nav.sort() + app.nav.position() + app.ui.sort() + app.ui.loadFile(app.nav, true) case "drawbox": gOpts.drawbox = true app.ui.renew() diff --git a/lf.1 b/lf.1 index 00962d3..f1c749f 100644 --- a/lf.1 +++ b/lf.1 @@ -131,6 +131,7 @@ The following options can be used to customize the behavior of lf: globsearch bool (default off) hidden bool (default off) hiddenfiles []string (default '.*') + dirtyfiles []string (default '!*') icons bool (default off) ifs string (default '') ignorecase bool (default on) @@ -704,6 +705,12 @@ Show hidden files. On unix systems, hidden files are determined by the value of .PP List of hidden file glob patterns. Patterns can be given as relative or absolute paths. Globbing supports the usual special characters, '*' to match any sequence, '?' to match any character, and '[...]' or '[^...] to match character sets or ranges. In addition, if a pattern starts with '!', then its matches are excluded from hidden files. .PP +.EX + dirtyfiles []string (default '!*') +.EE +.PP +List of dirty file glob patterns. Those files won't have 'cleaner' executed before previewing them. Patterns can be given as relative or absolute paths. Globbing supports the usual special characters, '*' to match any sequence, '?' to match any character, and '[...]' or '[^...] to match character sets or ranges. In addition, if a pattern starts with '!', then its matches are excluded from dirty files. +.PP .EX icons bool (default off) .EE diff --git a/nav.go b/nav.go index 3f4cd8a..5dee4dd 100644 --- a/nav.go +++ b/nav.go @@ -115,6 +115,7 @@ type dir struct { sortType sortType // sort method and options from last sort dironly bool // dironly value from last sort hiddenfiles []string // hiddenfiles value from last sort + dirtyfiles []string // files that don't require cleaning filter []string // last filter for this directory ignorecase bool // ignorecase value from last sort ignoredia bool // ignoredia value from last sort @@ -154,6 +155,7 @@ func (dir *dir) sort() { dir.sortType = gOpts.sortType dir.dironly = gOpts.dironly dir.hiddenfiles = gOpts.hiddenfiles + dir.dirtyfiles = gOpts.dirtyfiles dir.ignorecase = gOpts.ignorecase dir.ignoredia = gOpts.ignoredia @@ -361,6 +363,7 @@ func (nav *nav) loadDirInternal(path string) *dir { path: path, sortType: gOpts.sortType, hiddenfiles: gOpts.hiddenfiles, + dirtyfiles: gOpts.dirtyfiles, ignorecase: gOpts.ignorecase, ignoredia: gOpts.ignoredia, } @@ -522,21 +525,26 @@ func (nav *nav) previewLoop(ui *ui) { var prev string for path := range nav.previewChan { clear := len(path) == 0 + forceClear := path == "!" loop: for { select { case path = <-nav.previewChan: clear = clear || len(path) == 0 + forceClear = forceClear || path == "!" default: break loop } } + dir := nav.currDir() if clear && len(gOpts.previewer) != 0 && len(gOpts.cleaner) != 0 && nav.volatilePreview { - cmd := exec.Command(gOpts.cleaner, prev) - if err := cmd.Run(); err != nil { - log.Printf("cleaning preview: %s", err) + if forceClear || !isDirty(dir.files[dir.ind], dir.path, dir.dirtyfiles) { + cmd := exec.Command(gOpts.cleaner, prev) + if err := cmd.Run(); err != nil { + log.Printf("cleaning preview: %s", err) + } + nav.volatilePreview = false } - nav.volatilePreview = false } if len(path) != 0 { win := ui.wins[len(ui.wins)-1] diff --git a/opts.go b/opts.go index 724c93d..eb04b64 100644 --- a/opts.go +++ b/opts.go @@ -65,6 +65,7 @@ var gOpts struct { truncatechar string ratios []int hiddenfiles []string + dirtyfiles []string info []string shellopts []string keys map[string]expr @@ -111,6 +112,7 @@ func init() { gOpts.truncatechar = "~" gOpts.ratios = []int{1, 2, 3} gOpts.hiddenfiles = []string{".*"} + gOpts.dirtyfiles = []string{"!*"} gOpts.info = nil gOpts.shellopts = nil gOpts.sortType = sortType{naturalSort, dirfirstSort} diff --git a/os.go b/os.go index 8924e6d..db70607 100644 --- a/os.go +++ b/os.go @@ -136,6 +136,19 @@ func isHidden(f os.FileInfo, path string, hiddenfiles []string) bool { return hidden } +func isDirty(f os.FileInfo, path string, dirtyfiles []string) bool { + dirty := false + for _, pattern := range dirtyfiles { + matched := matchPattern(strings.TrimPrefix(pattern, "!"), f.Name(), path) + if strings.HasPrefix(pattern, "!") && matched { + dirty = false + } else if matched { + dirty = true + } + } + return dirty +} + func userName(f os.FileInfo) string { if stat, ok := f.Sys().(*syscall.Stat_t); ok { if u, err := user.LookupId(fmt.Sprint(stat.Uid)); err == nil {