From cbb80a0d4486dd3f5cdcf031666135c4c5aab358 Mon Sep 17 00:00:00 2001 From: Christian Zangl Date: Sat, 12 Feb 2022 10:21:49 +0100 Subject: [PATCH] add get-dirsize command (#750) --- complete.go | 1 + doc.go | 5 +++++ docstring.go | 5 +++++ eval.go | 9 +++++++++ lf.1 | 7 +++++++ nav.go | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++- ui.go | 10 ++++++++-- 7 files changed, 90 insertions(+), 3 deletions(-) diff --git a/complete.go b/complete.go index b233679..d985dd2 100644 --- a/complete.go +++ b/complete.go @@ -60,6 +60,7 @@ var ( "echomsg", "echoerr", "cd", + "get-dirsize", "select", "glob-select", "glob-unselect", diff --git a/doc.go b/doc.go index 328c3c7..bf13f2c 100644 --- a/doc.go +++ b/doc.go @@ -31,6 +31,7 @@ The following commands are provided by lf: unselect (default 'u') glob-select glob-unselect + get-dirsize copy (default 'y') cut (default 'd') paste (default 'p') @@ -274,6 +275,10 @@ Select files that match the given glob. Unselect files that match the given glob. + get-dirsize + +Get the total size for each of the selected directories. + copy (default 'y') If there are no selections, save the path of the current file to the copy buffer, otherwise, copy the paths of selected files. diff --git a/docstring.go b/docstring.go index da8c0e5..56071d9 100644 --- a/docstring.go +++ b/docstring.go @@ -35,6 +35,7 @@ The following commands are provided by lf: unselect (default 'u') glob-select glob-unselect + get-dirsize copy (default 'y') cut (default 'd') paste (default 'p') @@ -286,6 +287,10 @@ Select files that match the given glob. Unselect files that match the given glob. + get-dirsize + +Get the total size for each of the selected directories. + copy (default 'y') If there are no selections, save the path of the current file to the copy diff --git a/eval.go b/eval.go index f8d3204..780084c 100644 --- a/eval.go +++ b/eval.go @@ -913,6 +913,15 @@ func (e *callExpr) eval(app *app, args []string) { app.nav.invert() case "unselect": app.nav.unselect() + case "get-dirsize": + err := app.nav.getDirSize() + if err != nil { + app.ui.echoerrf("get-dirsize: %s", err) + return + } + app.ui.loadFileInfo(app.nav) + app.nav.sort() + app.ui.sort() case "copy": if err := app.nav.save(true); err != nil { app.ui.echoerrf("copy: %s", err) diff --git a/lf.1 b/lf.1 index c911493..dbd4c74 100644 --- a/lf.1 +++ b/lf.1 @@ -47,6 +47,7 @@ The following commands are provided by lf: unselect (default 'u') glob-select glob-unselect + get-dirsize copy (default 'y') cut (default 'd') paste (default 'p') @@ -320,6 +321,12 @@ Select files that match the given glob. .PP Unselect files that match the given glob. .PP +.EX + get-dirsize +.EE +.PP +Get the total size for each of the selected directories. +.PP .EX copy (default 'y') .EE diff --git a/nav.go b/nav.go index 9df0b92..a5a5010 100644 --- a/nav.go +++ b/nav.go @@ -32,11 +32,22 @@ type file struct { linkTarget string path string dirCount int + dirSize int64 accessTime time.Time changeTime time.Time ext string } +func (file *file) TotalSize() int64 { + if file.IsDir() { + if file.dirSize >= 0 { + return file.dirSize + } + return 0 + } + return file.Size() +} + func readdir(path string) ([]*file, error) { f, err := os.Open(path) if err != nil { @@ -95,6 +106,7 @@ func readdir(path string) ([]*file, error) { linkTarget: linkTarget, path: fpath, dirCount: -1, + dirSize: -1, accessTime: at, changeTime: ct, ext: ext, @@ -172,7 +184,7 @@ func (dir *dir) sort() { }) case sizeSort: sort.SliceStable(dir.files, func(i, j int) bool { - return dir.files[i].Size() < dir.files[j].Size() + return dir.files[i].TotalSize() < dir.files[j].TotalSize() }) case timeSort: sort.SliceStable(dir.files, func(i, j int) bool { @@ -1487,3 +1499,45 @@ func (nav *nav) currFileOrSelections() (list []string, err error) { return nav.currSelections(), nil } + +func (nav *nav) getDirSize() error { + + calc := func(f *file) error { + if f.IsDir() { + total, err := copySize([]string{f.path}) + if err != nil { + return err + } + f.dirSize = total + } + return nil + } + + if len(nav.selections) == 0 { + curr, err := nav.currFile() + if err != nil { + return errors.New("no file selected") + } + return calc(curr) + } else { + for sel, _ := range nav.selections { + lstat, err := os.Lstat(sel) + if err != nil || !lstat.IsDir() { + continue + } + path, name := filepath.Dir(sel), filepath.Base(sel) + dir := nav.loadDir(path) + + for _, f := range dir.files { + if f.Name() == name { + err := calc(f) + if err != nil { + return err + } + break + } + } + } + } + return nil +} diff --git a/ui.go b/ui.go index ca7d011..f84d8d4 100644 --- a/ui.go +++ b/ui.go @@ -292,8 +292,14 @@ func fileInfo(f *file, d *dir) string { for _, s := range gOpts.info { switch s { case "size": - if !(gOpts.dircounts && f.IsDir()) { - info = fmt.Sprintf("%s %4s", info, humanize(f.Size())) + if !(f.IsDir() && gOpts.dircounts) { + var sz string + if f.IsDir() && f.dirSize < 0 { + sz = "-" + } else { + sz = humanize(f.TotalSize()) + } + info = fmt.Sprintf("%s %4s", info, sz) continue }