make linters happy
fix typos, less short and more idomatic variable names, package comments, etc.
This commit is contained in:
parent
50e8c992d1
commit
9b87c02744
|
@ -1,3 +1,4 @@
|
||||||
|
// Package dirs provides functions sanitize directory names.
|
||||||
package dirs
|
package dirs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -15,11 +16,11 @@ var (
|
||||||
|
|
||||||
// UnExpand returns dir after expanding some directory shortcuts
|
// UnExpand returns dir after expanding some directory shortcuts
|
||||||
//
|
//
|
||||||
// $HOME -> ~
|
// $HOME -> ~
|
||||||
//
|
//
|
||||||
// $PWD -> .
|
// $PWD -> .
|
||||||
//
|
//
|
||||||
// workdir -> /
|
// workdir -> /
|
||||||
func UnExpand(dir, workdir string) (outdir string) {
|
func UnExpand(dir, workdir string) (outdir string) {
|
||||||
if dir != "" {
|
if dir != "" {
|
||||||
outdir = cleanDir(dir, pwd)
|
outdir = cleanDir(dir, pwd)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Package filemode does things io/fs doesn't do
|
||||||
package filemode
|
package filemode
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -7,19 +8,21 @@ import (
|
||||||
|
|
||||||
// Parse parses a string of 3 or 4 numbers as a *NIX filesystem permission.
|
// Parse parses a string of 3 or 4 numbers as a *NIX filesystem permission.
|
||||||
//
|
//
|
||||||
// "0777" or "777" -> fs.FileMode(0777)
|
// "0777" or "777" -> fs.FileMode(0777)
|
||||||
//
|
//
|
||||||
// "0644" or "644" -> fs.FileMode(0644)
|
// "0644" or "644" -> fs.FileMode(0644)
|
||||||
func Parse(in string) (fs.FileMode, error) {
|
func Parse(input string) (fs.FileMode, error) {
|
||||||
if in == "" {
|
const simplemodelen = 3
|
||||||
|
if input == "" {
|
||||||
return fs.FileMode(0), nil
|
return fs.FileMode(0), nil
|
||||||
}
|
}
|
||||||
if len(in) == 3 {
|
if len(input) == simplemodelen {
|
||||||
in = "0" + in
|
input = "0" + input
|
||||||
}
|
}
|
||||||
md, e := strconv.ParseUint(in, 8, 64)
|
md, e := strconv.ParseUint(input, 8, 64)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return 0, e
|
return 0, e
|
||||||
}
|
}
|
||||||
|
|
||||||
return fs.FileMode(md), nil
|
return fs.FileMode(md), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,14 +52,14 @@ func NewDisk(path string) (DiskFile, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
name := filepath.Base(abs)
|
name := filepath.Base(abs)
|
||||||
base_path := filepath.Dir(abs)
|
basePath := filepath.Dir(abs)
|
||||||
|
|
||||||
log.Debugf("%s (base:%s) (size:%s) (modified:%s) exists",
|
log.Debugf("%s (base:%s) (size:%s) (modified:%s) exists",
|
||||||
name, base_path, humanize.Bytes(uint64(info.Size())), info.ModTime())
|
name, basePath, humanize.Bytes(uint64(info.Size())), info.ModTime())
|
||||||
|
|
||||||
return DiskFile{
|
return DiskFile{
|
||||||
name: name,
|
name: name,
|
||||||
path: filepath.Join(base_path, name),
|
path: filepath.Join(basePath, name),
|
||||||
filesize: info.Size(),
|
filesize: info.Size(),
|
||||||
modified: info.ModTime(),
|
modified: info.ModTime(),
|
||||||
isdir: info.IsDir(),
|
isdir: info.IsDir(),
|
||||||
|
@ -67,14 +67,14 @@ func NewDisk(path string) (DiskFile, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindDisk(dir string, recursive bool, f *filter.Filter) (files Files, err error) {
|
func FindDisk(dir string, recursive bool, fltr *filter.Filter) (Files, error) {
|
||||||
|
var files Files
|
||||||
dir = filepath.Clean(dir)
|
dir = filepath.Clean(dir)
|
||||||
if dir == "." || dir == "" {
|
if dir == "." || dir == "" {
|
||||||
var d string
|
if pwd, err := os.Getwd(); err != nil {
|
||||||
if d, err = os.Getwd(); err != nil {
|
dir = filepath.Clean(dir)
|
||||||
return
|
|
||||||
} else {
|
} else {
|
||||||
dir = d
|
dir = pwd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,54 +83,55 @@ func FindDisk(dir string, recursive bool, f *filter.Filter) (files Files, err er
|
||||||
recursively = " recursively"
|
recursively = " recursively"
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("gonna find files%s in %s matching %s", recursively, dir, f)
|
log.Debugf("gonna find files%s in %s matching %s", recursively, dir, fltr)
|
||||||
|
|
||||||
if recursive {
|
if recursive {
|
||||||
files = append(files, walk_dir(dir, f)...)
|
files = append(files, walkDir(dir, fltr)...)
|
||||||
} else {
|
} else {
|
||||||
files = append(files, read_dir(dir, f)...)
|
files = append(files, readDir(dir, fltr)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// is_in_hidden_dir checks `path` and parent directories
|
// isInHiddenDir checks `path` and parent directories
|
||||||
// of `path` up to `base` for a hidden parent
|
// of `path` up to `base` for a hidden parent.
|
||||||
func is_in_hidden_dir(base, path string) bool {
|
func isInHiddenDir(base, path string) bool {
|
||||||
me := path
|
current := path
|
||||||
for {
|
for {
|
||||||
me = filepath.Clean(me)
|
current = filepath.Clean(current)
|
||||||
if me == base {
|
if current == base {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(filepath.Base(me), ".") {
|
if strings.HasPrefix(filepath.Base(current), ".") {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
me += string(os.PathSeparator) + ".."
|
current += string(os.PathSeparator) + ".."
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func walk_dir(dir string, f *filter.Filter) (files Files) {
|
func walkDir(dir string, fltr *filter.Filter) Files {
|
||||||
err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
|
var files Files
|
||||||
|
err := filepath.WalkDir(dir, func(path string, dirEntry fs.DirEntry, err error) error {
|
||||||
if dir == path {
|
if dir == path {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_in_hidden_dir(dir, path) && f.IgnoreHidden() {
|
if isInHiddenDir(dir, path) && fltr.IgnoreHidden() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
p, e := filepath.Abs(path)
|
actualPath, e := filepath.Abs(path)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
name := d.Name()
|
name := dirEntry.Name()
|
||||||
info, _ := d.Info()
|
info, _ := dirEntry.Info()
|
||||||
if f.Match(info) {
|
if fltr.Match(info) {
|
||||||
files = append(files, DiskFile{
|
files = append(files, DiskFile{
|
||||||
path: p,
|
path: actualPath,
|
||||||
name: name,
|
name: name,
|
||||||
filesize: info.Size(),
|
filesize: info.Size(),
|
||||||
modified: info.ModTime(),
|
modified: info.ModTime(),
|
||||||
|
@ -144,10 +145,11 @@ func walk_dir(dir string, f *filter.Filter) (files Files) {
|
||||||
log.Errorf("error walking directory %s: %s", dir, err)
|
log.Errorf("error walking directory %s: %s", dir, err)
|
||||||
return Files{}
|
return Files{}
|
||||||
}
|
}
|
||||||
return
|
return files
|
||||||
}
|
}
|
||||||
|
|
||||||
func read_dir(dir string, f *filter.Filter) (files Files) {
|
func readDir(dir string, fltr *filter.Filter) Files {
|
||||||
|
var files Files
|
||||||
fs, err := os.ReadDir(dir)
|
fs, err := os.ReadDir(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Files{}
|
return Files{}
|
||||||
|
@ -166,7 +168,7 @@ func read_dir(dir string, f *filter.Filter) (files Files) {
|
||||||
|
|
||||||
path := filepath.Dir(filepath.Join(dir, name))
|
path := filepath.Dir(filepath.Join(dir, name))
|
||||||
|
|
||||||
if f.Match(info) {
|
if fltr.Match(info) {
|
||||||
files = append(files, DiskFile{
|
files = append(files, DiskFile{
|
||||||
name: name,
|
name: name,
|
||||||
path: filepath.Join(path, name),
|
path: filepath.Join(path, name),
|
||||||
|
@ -177,5 +179,5 @@ func read_dir(dir string, f *filter.Filter) (files Files) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return files
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,17 +103,17 @@ func SortDirectoriesLast(a, b File) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func doNameSort(a, b File) int {
|
func doNameSort(a, b File) int {
|
||||||
an := strings.ToLower(a.Name())
|
aname := strings.ToLower(a.Name())
|
||||||
bn := strings.ToLower(b.Name())
|
bname := strings.ToLower(b.Name())
|
||||||
// check if filename is a number
|
// check if filename is a number
|
||||||
abase := strings.Replace(an, filepath.Ext(an), "", 1)
|
abase := strings.Replace(aname, filepath.Ext(aname), "", 1)
|
||||||
bbase := strings.Replace(bn, filepath.Ext(bn), "", 1)
|
bbase := strings.Replace(bname, filepath.Ext(bname), "", 1)
|
||||||
ai, aerr := strconv.Atoi(abase)
|
ai, aerr := strconv.Atoi(abase)
|
||||||
bi, berr := strconv.Atoi(bbase)
|
bi, berr := strconv.Atoi(bbase)
|
||||||
if aerr == nil && berr == nil {
|
if aerr == nil && berr == nil {
|
||||||
return cmp.Compare(ai, bi)
|
return cmp.Compare(ai, bi)
|
||||||
}
|
}
|
||||||
return cmp.Compare(an, bn)
|
return cmp.Compare(aname, bname)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSortingSize(f File) int64 {
|
func getSortingSize(f File) int64 {
|
||||||
|
|
|
@ -20,13 +20,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
random_str_length int = 8
|
executePerm = fs.FileMode(0755)
|
||||||
trash_info_ext string = ".trashinfo"
|
noExecuteUserPerm = fs.FileMode(0600)
|
||||||
trash_info_sec string = "Trash Info"
|
randomStrLength int = 8
|
||||||
trash_info_path string = "Path"
|
trashInfoExt string = ".trashinfo"
|
||||||
trash_info_date string = "DeletionDate"
|
trashInfoSec string = "Trash Info"
|
||||||
trash_info_date_fmt string = "2006-01-02T15:04:05"
|
trashInfoPath string = "Path"
|
||||||
trash_info_template string = `[Trash Info]
|
trashInfoDate string = "DeletionDate"
|
||||||
|
trashInfoDateFmt string = "2006-01-02T15:04:05"
|
||||||
|
trashInfoTemplate string = `[Trash Info]
|
||||||
Path={path}
|
Path={path}
|
||||||
DeletionDate={date}
|
DeletionDate={date}
|
||||||
`
|
`
|
||||||
|
@ -59,15 +61,16 @@ func (t TrashInfo) String() string {
|
||||||
return t.name + t.path + t.ogpath + t.trashinfo
|
return t.name + t.path + t.ogpath + t.trashinfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindTrash(trashdir, ogdir string, f *filter.Filter) (files Files, outerr error) {
|
func FindTrash(trashdir, ogdir string, fltr *filter.Filter) (Files, error) {
|
||||||
outerr = filepath.WalkDir(trashdir, func(path string, d fs.DirEntry, err error) error {
|
var files Files
|
||||||
|
outerr := filepath.WalkDir(trashdir, func(path string, dirEntry fs.DirEntry, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("what happened?? what is %s?", err)
|
log.Debugf("what happened?? what is %s?", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore self, directories, and non trashinfo files
|
// ignore self, directories, and non trashinfo files
|
||||||
if path == trashdir || d.IsDir() || filepath.Ext(path) != trash_info_ext {
|
if path == trashdir || dirEntry.IsDir() || filepath.Ext(path) != trashInfoExt {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,19 +79,19 @@ func FindTrash(trashdir, ogdir string, f *filter.Filter) (files Files, outerr er
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if s := c.Section(trash_info_sec); s != nil {
|
if section := c.Section(trashInfoSec); section != nil {
|
||||||
basepath := s.Key(trash_info_path).String()
|
basepath := section.Key(trashInfoPath).String()
|
||||||
|
|
||||||
filename := filepath.Base(basepath)
|
filename := filepath.Base(basepath)
|
||||||
trashedpath := strings.Replace(strings.Replace(path, "info", "files", 1), trash_info_ext, "", 1)
|
trashedpath := strings.Replace(strings.Replace(path, "info", "files", 1), trashInfoExt, "", 1)
|
||||||
info, err := os.Lstat(trashedpath)
|
info, err := os.Lstat(trashedpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error reading %s: %s", trashedpath, err)
|
log.Errorf("error reading %s: %s", trashedpath, err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
s := s.Key(trash_info_date).Value()
|
s := section.Key(trashInfoDate).Value()
|
||||||
date, err := time.ParseInLocation(trash_info_date_fmt, s, time.Local)
|
date, err := time.ParseInLocation(trashInfoDateFmt, s, time.Local)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -97,7 +100,7 @@ func FindTrash(trashdir, ogdir string, f *filter.Filter) (files Files, outerr er
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.Match(info) {
|
if fltr.Match(info) {
|
||||||
files = append(files, TrashInfo{
|
files = append(files, TrashInfo{
|
||||||
name: filename,
|
name: filename,
|
||||||
path: trashedpath,
|
path: trashedpath,
|
||||||
|
@ -108,14 +111,13 @@ func FindTrash(trashdir, ogdir string, f *filter.Filter) (files Files, outerr er
|
||||||
filesize: info.Size(),
|
filesize: info.Size(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if outerr != nil {
|
if outerr != nil {
|
||||||
return Files{}, outerr
|
return Files{}, outerr
|
||||||
}
|
}
|
||||||
return
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Restore(files Files) (restored int, err error) {
|
func Restore(files Files) (restored int, err error) {
|
||||||
|
@ -125,8 +127,8 @@ func Restore(files Files) (restored int, err error) {
|
||||||
return restored, fmt.Errorf("bad file?? %s", maybeFile.Name())
|
return restored, fmt.Errorf("bad file?? %s", maybeFile.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
var outpath string = dirs.UnEscape(file.ogpath)
|
|
||||||
var cancel bool
|
var cancel bool
|
||||||
|
outpath := dirs.UnEscape(file.ogpath)
|
||||||
log.Infof("restoring %s back to %s\n", file.name, outpath)
|
log.Infof("restoring %s back to %s\n", file.name, outpath)
|
||||||
if _, e := os.Lstat(outpath); e == nil {
|
if _, e := os.Lstat(outpath); e == nil {
|
||||||
outpath, cancel = prompt.NewPath(outpath)
|
outpath, cancel = prompt.NewPath(outpath)
|
||||||
|
@ -138,7 +140,7 @@ func Restore(files Files) (restored int, err error) {
|
||||||
|
|
||||||
basedir := filepath.Dir(outpath)
|
basedir := filepath.Dir(outpath)
|
||||||
if _, e := os.Stat(basedir); e != nil {
|
if _, e := os.Stat(basedir); e != nil {
|
||||||
if err = os.MkdirAll(basedir, fs.FileMode(0755)); err != nil {
|
if err = os.MkdirAll(basedir, executePerm); err != nil {
|
||||||
return restored, err
|
return restored, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,11 +163,11 @@ func ConfirmRestore(confirm bool, fs Files) error {
|
||||||
log.Info("doing the thing")
|
log.Info("doing the thing")
|
||||||
restored, err := Restore(fs)
|
restored, err := Restore(fs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("restored %d files before error %s", restored, err)
|
return fmt.Errorf("restored %d files before error %w", restored, err)
|
||||||
}
|
}
|
||||||
fmt.Printf("restored %d files\n", restored)
|
fmt.Fprintf(os.Stdout, "restored %d files\n", restored)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("not doing anything\n")
|
fmt.Fprintf(os.Stdout, "not doing anything\n")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -177,7 +179,6 @@ func Remove(files Files) (removed int, err error) {
|
||||||
return removed, fmt.Errorf("bad file?? %s", maybeFile.Name())
|
return removed, fmt.Errorf("bad file?? %s", maybeFile.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("removing %s permanently forever!!!", file.name)
|
|
||||||
if err = os.Remove(file.path); err != nil {
|
if err = os.Remove(file.path); err != nil {
|
||||||
if i, e := os.Lstat(file.path); e == nil && i.IsDir() {
|
if i, e := os.Lstat(file.path); e == nil && i.IsDir() {
|
||||||
err = os.RemoveAll(file.path)
|
err = os.RemoveAll(file.path)
|
||||||
|
@ -199,38 +200,37 @@ func Remove(files Files) (removed int, err error) {
|
||||||
func ConfirmClean(confirm bool, fs Files) error {
|
func ConfirmClean(confirm bool, fs Files) error {
|
||||||
if prompt.YesNo(fmt.Sprintf("remove %d selected files permanently from the trash?", len(fs))) &&
|
if prompt.YesNo(fmt.Sprintf("remove %d selected files permanently from the trash?", len(fs))) &&
|
||||||
(!confirm || prompt.YesNo(fmt.Sprintf("really remove all these %d selected files permanently from the trash forever??", len(fs)))) {
|
(!confirm || prompt.YesNo(fmt.Sprintf("really remove all these %d selected files permanently from the trash forever??", len(fs)))) {
|
||||||
log.Info("gonna remove some files forever")
|
|
||||||
removed, err := Remove(fs)
|
removed, err := Remove(fs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("removed %d files before error %s", removed, err)
|
return fmt.Errorf("removed %d files before error %w", removed, err)
|
||||||
}
|
}
|
||||||
fmt.Printf("removed %d files\n", removed)
|
fmt.Fprintf(os.Stdout, "removed %d files\n", removed)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("not doing anything\n")
|
fmt.Fprintf(os.Stdout, "not doing anything\n")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TrashFile(trashDir, name string) error {
|
func TrashFile(trashDir, name string) error {
|
||||||
trashinfo_filename, out_path := ensureUniqueName(filepath.Base(name), trashDir)
|
trashinfoFilename, outPath := ensureUniqueName(filepath.Base(name), trashDir)
|
||||||
|
|
||||||
// TODO: write across filesystems
|
// TODO: write across filesystems
|
||||||
if err := os.Rename(name, out_path); err != nil {
|
if err := os.Rename(name, outPath); err != nil {
|
||||||
if strings.Contains(err.Error(), "invalid cross-device link") {
|
if strings.Contains(err.Error(), "invalid cross-device link") {
|
||||||
return fmt.Errorf("not trashing file '%s': On different filesystem from trash directory", name)
|
return fmt.Errorf("not trashing file '%s': On different filesystem from trash directory", name)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
trash_info, err := formatter.Format(trash_info_template, formatter.Named{
|
trashInfo, err := formatter.Format(trashInfoTemplate, formatter.Named{
|
||||||
"path": name,
|
"path": name,
|
||||||
"date": time.Now().Format(trash_info_date_fmt),
|
"date": time.Now().Format(trashInfoDateFmt),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.WriteFile(trashinfo_filename, []byte(trash_info), fs.FileMode(0600)); err != nil {
|
if err := os.WriteFile(trashinfoFilename, []byte(trashInfo), noExecuteUserPerm); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -258,15 +258,15 @@ func ConfirmTrash(confirm bool, fs Files, trashDir string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var f string
|
var files string
|
||||||
if trashed == 1 {
|
if trashed == 1 {
|
||||||
f = "file"
|
files = "file"
|
||||||
} else {
|
} else {
|
||||||
f = "files"
|
files = "files"
|
||||||
}
|
}
|
||||||
fmt.Printf("trashed %d %s\n", trashed, f)
|
fmt.Fprintf(os.Stdout, "trashed %d %s\n", trashed, files)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("not doing anything\n")
|
fmt.Fprintf(os.Stdout, "not doing anything\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -291,7 +291,7 @@ func ensureUniqueName(filename, trashDir string) (string, string) {
|
||||||
infodir = filepath.Join(trashDir, "info")
|
infodir = filepath.Join(trashDir, "info")
|
||||||
)
|
)
|
||||||
|
|
||||||
info := filepath.Join(infodir, filename+trash_info_ext)
|
info := filepath.Join(infodir, filename+trashInfoExt)
|
||||||
if _, err := os.Stat(info); os.IsNotExist(err) {
|
if _, err := os.Stat(info); os.IsNotExist(err) {
|
||||||
// doesn't exist, so use it
|
// doesn't exist, so use it
|
||||||
path := filepath.Join(filedir, filename)
|
path := filepath.Join(filedir, filename)
|
||||||
|
@ -302,12 +302,12 @@ func ensureUniqueName(filename, trashDir string) (string, string) {
|
||||||
var tries int
|
var tries int
|
||||||
for {
|
for {
|
||||||
tries++
|
tries++
|
||||||
rando := randomFilename(random_str_length)
|
rando := randomFilename(randomStrLength)
|
||||||
new_name := filepath.Join(infodir, filename+rando+trash_info_ext)
|
newName := filepath.Join(infodir, filename+rando+trashInfoExt)
|
||||||
if _, err := os.Stat(new_name); os.IsNotExist(err) {
|
if _, err := os.Stat(newName); os.IsNotExist(err) {
|
||||||
path := filepath.Join(filedir, filename+rando)
|
path := filepath.Join(filedir, filename+rando)
|
||||||
log.Debugf("settled on random name %s%s on the %s try", filename, rando, humanize.Ordinal(tries))
|
log.Debugf("settled on random name %s%s on the %s try", filename, rando, humanize.Ordinal(tries))
|
||||||
return new_name, path
|
return newName, path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Package filter filters files based on specific critera
|
// Package filter filters files based on specific criteria
|
||||||
package filter
|
package filter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -61,7 +61,7 @@ func (f *Filter) Match(info fs.FileInfo) bool {
|
||||||
|
|
||||||
// on or before/after, not both
|
// on or before/after, not both
|
||||||
if !f.on.IsZero() {
|
if !f.on.IsZero() {
|
||||||
if !same_day(f.on, modified) {
|
if !sameDay(f.on, modified) {
|
||||||
log.Debugf("%s: %s isn't on %s, bye!", filename, modified, f.on)
|
log.Debugf("%s: %s isn't on %s, bye!", filename, modified, f.on)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ func (f *Filter) Match(info fs.FileInfo) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.has_regex() && !f.matcher.MatchString(filename) {
|
if f.hasRegex() && !f.matcher.MatchString(filename) {
|
||||||
log.Debugf("%s doesn't match `%s`, bye!", filename, f.matcher.String())
|
log.Debugf("%s doesn't match `%s`, bye!", filename, f.matcher.String())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ func (f *Filter) Match(info fs.FileInfo) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.has_unregex() && f.unmatcher.MatchString(filename) {
|
if f.hasUnregex() && f.unmatcher.MatchString(filename) {
|
||||||
log.Debugf("%s matches `%s`, bye!", filename, f.unmatcher.String())
|
log.Debugf("%s matches `%s`, bye!", filename, f.unmatcher.String())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -155,14 +155,14 @@ func (f *Filter) SetUnPattern(unpattern string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Filter) Blank() bool {
|
func (f *Filter) Blank() bool {
|
||||||
t := time.Time{}
|
blank := time.Time{}
|
||||||
return !f.has_regex() &&
|
return !f.hasRegex() &&
|
||||||
!f.has_unregex() &&
|
!f.hasUnregex() &&
|
||||||
f.glob == "" &&
|
f.glob == "" &&
|
||||||
f.unglob == "" &&
|
f.unglob == "" &&
|
||||||
f.after.Equal(t) &&
|
f.after.Equal(blank) &&
|
||||||
f.before.Equal(t) &&
|
f.before.Equal(blank) &&
|
||||||
f.on.Equal(t) &&
|
f.on.Equal(blank) &&
|
||||||
len(f.filenames) == 0 &&
|
len(f.filenames) == 0 &&
|
||||||
!f.ignorehidden &&
|
!f.ignorehidden &&
|
||||||
!f.filesonly &&
|
!f.filesonly &&
|
||||||
|
@ -173,31 +173,31 @@ func (f *Filter) Blank() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Filter) String() string {
|
func (f *Filter) String() string {
|
||||||
var m, unm string
|
var match, unmatch string
|
||||||
if f.matcher != nil {
|
if f.matcher != nil {
|
||||||
m = f.matcher.String()
|
match = f.matcher.String()
|
||||||
}
|
}
|
||||||
if f.unmatcher != nil {
|
if f.unmatcher != nil {
|
||||||
unm = f.unmatcher.String()
|
unmatch = f.unmatcher.String()
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("on:'%s' before:'%s' after:'%s' glob:'%s' regex:'%s' unglob:'%s' "+
|
return fmt.Sprintf("on:'%s' before:'%s' after:'%s' glob:'%s' regex:'%s' unglob:'%s' "+
|
||||||
"unregex:'%s' filenames:'%v' filesonly:'%t' dirsonly:'%t' ignorehidden:'%t' "+
|
"unregex:'%s' filenames:'%v' filesonly:'%t' dirsonly:'%t' ignorehidden:'%t' "+
|
||||||
"minsize:'%d' maxsize:'%d' mode:'%s'",
|
"minsize:'%d' maxsize:'%d' mode:'%s'",
|
||||||
f.on, f.before, f.after,
|
f.on, f.before, f.after,
|
||||||
f.glob, m, f.unglob, unm,
|
f.glob, match, f.unglob, unmatch,
|
||||||
f.filenames, f.filesonly, f.dirsonly,
|
f.filenames, f.filesonly, f.dirsonly,
|
||||||
f.ignorehidden, f.minsize, f.maxsize, f.mode,
|
f.ignorehidden, f.minsize, f.maxsize, f.mode,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Filter) has_regex() bool {
|
func (f *Filter) hasRegex() bool {
|
||||||
if f.matcher == nil {
|
if f.matcher == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return f.matcher.String() != ""
|
return f.matcher.String() != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Filter) has_unregex() bool {
|
func (f *Filter) hasUnregex() bool {
|
||||||
if f.unmatcher == nil {
|
if f.unmatcher == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,7 @@ func New(on, before, after, glob, pattern, unglob, unpattern string, filesonly,
|
||||||
now = time.Now()
|
now = time.Now()
|
||||||
)
|
)
|
||||||
|
|
||||||
f := &Filter{
|
filter := &Filter{
|
||||||
glob: glob,
|
glob: glob,
|
||||||
unglob: unglob,
|
unglob: unglob,
|
||||||
filesonly: filesonly,
|
filesonly: filesonly,
|
||||||
|
@ -219,14 +219,14 @@ func New(on, before, after, glob, pattern, unglob, unpattern string, filesonly,
|
||||||
mode: mode,
|
mode: mode,
|
||||||
}
|
}
|
||||||
|
|
||||||
f.AddFileNames(names...)
|
filter.AddFileNames(names...)
|
||||||
|
|
||||||
if on != "" {
|
if on != "" {
|
||||||
o, err := anytime.Parse(on, now)
|
o, err := anytime.Parse(on, now)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &Filter{}, err
|
return &Filter{}, err
|
||||||
}
|
}
|
||||||
f.on = o
|
filter.on = o
|
||||||
}
|
}
|
||||||
|
|
||||||
if after != "" {
|
if after != "" {
|
||||||
|
@ -234,7 +234,7 @@ func New(on, before, after, glob, pattern, unglob, unpattern string, filesonly,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &Filter{}, err
|
return &Filter{}, err
|
||||||
}
|
}
|
||||||
f.after = a
|
filter.after = a
|
||||||
}
|
}
|
||||||
|
|
||||||
if before != "" {
|
if before != "" {
|
||||||
|
@ -242,14 +242,14 @@ func New(on, before, after, glob, pattern, unglob, unpattern string, filesonly,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &Filter{}, err
|
return &Filter{}, err
|
||||||
}
|
}
|
||||||
f.before = b
|
filter.before = b
|
||||||
}
|
}
|
||||||
|
|
||||||
err = f.SetPattern(pattern)
|
err = filter.SetPattern(pattern)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = f.SetUnPattern(unpattern)
|
err = filter.SetUnPattern(unpattern)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -259,7 +259,7 @@ func New(on, before, after, glob, pattern, unglob, unpattern string, filesonly,
|
||||||
if e != nil {
|
if e != nil {
|
||||||
log.Errorf("invalid input size '%s'", minsize)
|
log.Errorf("invalid input size '%s'", minsize)
|
||||||
}
|
}
|
||||||
f.minsize = int64(m)
|
filter.minsize = int64(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
if maxsize != "" {
|
if maxsize != "" {
|
||||||
|
@ -267,13 +267,13 @@ func New(on, before, after, glob, pattern, unglob, unpattern string, filesonly,
|
||||||
if e != nil {
|
if e != nil {
|
||||||
log.Errorf("invalid input size '%s'", maxsize)
|
log.Errorf("invalid input size '%s'", maxsize)
|
||||||
}
|
}
|
||||||
f.maxsize = int64(m)
|
filter.maxsize = int64(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
return f, nil
|
return filter, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func same_day(a, b time.Time) bool {
|
func sameDay(a, b time.Time) bool {
|
||||||
ay, am, ad := a.Date()
|
ay, am, ad := a.Date()
|
||||||
by, bm, bd := b.Date()
|
by, bm, bd := b.Date()
|
||||||
return ay == by && am == bm && ad == bd
|
return ay == by && am == bm && ad == bd
|
||||||
|
|
|
@ -66,13 +66,14 @@ func (s singletest) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testmatch(t *testing.T, testers []testholder) {
|
func testmatch(t *testing.T, testers []testholder) {
|
||||||
|
t.Helper() // I don't think this is a helper function but w/e
|
||||||
const testnamefmt string = "file %s modified on %s"
|
const testnamefmt string = "file %s modified on %s"
|
||||||
var (
|
var (
|
||||||
f *filter.Filter
|
fltr *filter.Filter
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
for _, tester := range testers {
|
for _, tester := range testers {
|
||||||
f, err = filter.New(
|
fltr, err = filter.New(
|
||||||
tester.on, tester.before, tester.after, tester.glob, tester.pattern,
|
tester.on, tester.before, tester.after, tester.glob, tester.pattern,
|
||||||
tester.unglob, tester.unpattern, tester.filesonly, tester.dirsonly,
|
tester.unglob, tester.unpattern, tester.filesonly, tester.dirsonly,
|
||||||
tester.ignorehidden, tester.minsize, tester.maxsize, tester.mode,
|
tester.ignorehidden, tester.minsize, tester.maxsize, tester.mode,
|
||||||
|
@ -84,7 +85,7 @@ func testmatch(t *testing.T, testers []testholder) {
|
||||||
|
|
||||||
for _, tst := range tester.good {
|
for _, tst := range tester.good {
|
||||||
t.Run(fmt.Sprintf(testnamefmt+"_good", tst.filename, tst.modified), func(t *testing.T) {
|
t.Run(fmt.Sprintf(testnamefmt+"_good", tst.filename, tst.modified), func(t *testing.T) {
|
||||||
if !f.Match(tst) {
|
if !fltr.Match(tst) {
|
||||||
t.Fatalf("(%s) didn't match (%s) but should have", tst, tester)
|
t.Fatalf("(%s) didn't match (%s) but should have", tst, tester)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -92,7 +93,7 @@ func testmatch(t *testing.T, testers []testholder) {
|
||||||
|
|
||||||
for _, tst := range tester.bad {
|
for _, tst := range tester.bad {
|
||||||
t.Run(fmt.Sprintf(testnamefmt+"_bad", tst.filename, tst.modified), func(t *testing.T) {
|
t.Run(fmt.Sprintf(testnamefmt+"_bad", tst.filename, tst.modified), func(t *testing.T) {
|
||||||
if f.Match(tst) {
|
if fltr.Match(tst) {
|
||||||
t.Fatalf("(%s) matched (%s) but shouldn't have", tst, tester)
|
t.Fatalf("(%s) matched (%s) but shouldn't have", tst, tester)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -116,10 +117,10 @@ func timeonly(dir bool, times ...time.Time) []singletest {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func sizeonly(dir bool, sizes ...int64) []singletest {
|
func sizeonly(sizes ...int64) []singletest {
|
||||||
out := make([]singletest, 0, len(sizes))
|
out := make([]singletest, 0, len(sizes))
|
||||||
for _, size := range sizes {
|
for _, size := range sizes {
|
||||||
out = append(out, singletest{filename: "blank", modified: time.Time{}, isdir: dir, size: size, mode: 0000})
|
out = append(out, singletest{filename: "blank", modified: time.Time{}, isdir: false, size: size, mode: 0000})
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
@ -301,7 +302,7 @@ func TestFilterGlob(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
glob: "t?st",
|
glob: "t?st",
|
||||||
good: nameonly(false, "test", "tast", "tfst", "tnst"),
|
good: nameonly(false, "test", "tist", "tfst", "tnst"),
|
||||||
bad: nameonly(false, "best", "fast", "most", "past"),
|
bad: nameonly(false, "best", "fast", "most", "past"),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -342,7 +343,7 @@ func TestFilterUnGlob(t *testing.T) {
|
||||||
{
|
{
|
||||||
unglob: "t?st",
|
unglob: "t?st",
|
||||||
good: nameonly(false, "best", "fast", "most", "past"),
|
good: nameonly(false, "best", "fast", "most", "past"),
|
||||||
bad: nameonly(false, "test", "tast", "tfst", "tnst"),
|
bad: nameonly(false, "test", "tist", "tfst", "tnst"),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -410,13 +411,13 @@ func TestFilesize(t *testing.T) {
|
||||||
testmatch(t, []testholder{
|
testmatch(t, []testholder{
|
||||||
{
|
{
|
||||||
minsize: "9001B",
|
minsize: "9001B",
|
||||||
good: sizeonly(false, 10000, 9002, 424242, math.MaxInt64),
|
good: sizeonly(10000, 9002, 424242, math.MaxInt64),
|
||||||
bad: sizeonly(false, 9000, math.MinInt64, 0, -9001),
|
bad: sizeonly(9000, math.MinInt64, 0, -9001),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
maxsize: "9001B",
|
maxsize: "9001B",
|
||||||
good: sizeonly(false, 9000, math.MinInt64, 0, -9001),
|
good: sizeonly(9000, math.MinInt64, 0, -9001),
|
||||||
bad: sizeonly(false, 10000, 9002, 424242, math.MaxInt64),
|
bad: sizeonly(10000, 9002, 424242, math.MaxInt64),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -580,25 +581,25 @@ func TestFilterMultipleParameters(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFilterBlank(t *testing.T) {
|
func TestFilterBlank(t *testing.T) {
|
||||||
var f *filter.Filter
|
var fltr *filter.Filter
|
||||||
t.Run("new", func(t *testing.T) {
|
t.Run("new", func(t *testing.T) {
|
||||||
f, _ = filter.New("", "", "", "", "", "", "", false, false, false, "0", "0", 0)
|
fltr, _ = filter.New("", "", "", "", "", "", "", false, false, false, "0", "0", 0)
|
||||||
if !f.Blank() {
|
if !fltr.Blank() {
|
||||||
t.Fatalf("filter isn't blank? %s", f)
|
t.Fatalf("filter isn't blank? %s", fltr)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("blank", func(t *testing.T) {
|
t.Run("blank", func(t *testing.T) {
|
||||||
f = &filter.Filter{}
|
fltr = &filter.Filter{}
|
||||||
if !f.Blank() {
|
if !fltr.Blank() {
|
||||||
t.Fatalf("filter isn't blank? %s", f)
|
t.Fatalf("filter isn't blank? %s", fltr)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFilterNotBlank(t *testing.T) {
|
func TestFilterNotBlank(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
f *filter.Filter
|
fltr *filter.Filter
|
||||||
testers = []testholder{
|
testers = []testholder{
|
||||||
{
|
{
|
||||||
pattern: "[Ttest]",
|
pattern: "[Ttest]",
|
||||||
|
@ -642,14 +643,14 @@ func TestFilterNotBlank(t *testing.T) {
|
||||||
|
|
||||||
for _, tester := range testers {
|
for _, tester := range testers {
|
||||||
t.Run("notblank"+tester.String(), func(t *testing.T) {
|
t.Run("notblank"+tester.String(), func(t *testing.T) {
|
||||||
f, _ = filter.New(
|
fltr, _ = filter.New(
|
||||||
tester.on, tester.before, tester.after, tester.glob, tester.pattern,
|
tester.on, tester.before, tester.after, tester.glob, tester.pattern,
|
||||||
tester.unglob, tester.unpattern, tester.filesonly, tester.dirsonly,
|
tester.unglob, tester.unpattern, tester.filesonly, tester.dirsonly,
|
||||||
tester.ignorehidden, tester.minsize, tester.maxsize, tester.mode,
|
tester.ignorehidden, tester.minsize, tester.maxsize, tester.mode,
|
||||||
tester.filenames...,
|
tester.filenames...,
|
||||||
)
|
)
|
||||||
if f.Blank() {
|
if fltr.Blank() {
|
||||||
t.Fatalf("filter is blank?? %s", f)
|
t.Fatalf("filter is blank?? %s", fltr)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Package interactive implements a charm-powered table to display files.
|
||||||
package interactive
|
package interactive
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -64,7 +65,7 @@ type model struct {
|
||||||
files files.Files
|
files files.Files
|
||||||
}
|
}
|
||||||
|
|
||||||
func newModel(fs []files.File, width, height int, readonly, preselected, once bool, workdir string, mode modes.Mode) model {
|
func newModel(fls []files.File, width, height int, readonly, preselected, once bool, workdir string, mode modes.Mode) model {
|
||||||
var (
|
var (
|
||||||
// TODO: figure this out dynamically based on longest of each
|
// TODO: figure this out dynamically based on longest of each
|
||||||
fwidth int = int(math.Round(float64(width-woffset) * 0.46))
|
fwidth int = int(math.Round(float64(width-woffset) * 0.46))
|
||||||
|
@ -72,9 +73,9 @@ func newModel(fs []files.File, width, height int, readonly, preselected, once bo
|
||||||
dwidth int = int(math.Round(float64(width-woffset) * 0.15))
|
dwidth int = int(math.Round(float64(width-woffset) * 0.15))
|
||||||
swidth int = int(math.Round(float64(width-woffset) * 0.12))
|
swidth int = int(math.Round(float64(width-woffset) * 0.12))
|
||||||
cwidth int = int(math.Round(float64(width-woffset) * 0.02))
|
cwidth int = int(math.Round(float64(width-woffset) * 0.02))
|
||||||
theight int = min(height-hoffset, len(fs))
|
theight int = min(height-hoffset, len(fls))
|
||||||
|
|
||||||
m = model{
|
mdl = model{
|
||||||
keys: defaultKeyMap(),
|
keys: defaultKeyMap(),
|
||||||
readonly: readonly,
|
readonly: readonly,
|
||||||
once: once,
|
once: once,
|
||||||
|
@ -83,15 +84,15 @@ func newModel(fs []files.File, width, height int, readonly, preselected, once bo
|
||||||
mode: mode,
|
mode: mode,
|
||||||
selected: map[string]bool{},
|
selected: map[string]bool{},
|
||||||
selectsize: 0,
|
selectsize: 0,
|
||||||
files: fs,
|
files: fls,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if workdir != "" {
|
if workdir != "" {
|
||||||
m.workdir = filepath.Clean(workdir)
|
mdl.workdir = filepath.Clean(workdir)
|
||||||
}
|
}
|
||||||
|
|
||||||
rows := m.freshRows(preselected)
|
rows := mdl.freshRows(preselected)
|
||||||
|
|
||||||
columns := []table.Column{
|
columns := []table.Column{
|
||||||
{Title: "filename", Width: fwidth},
|
{Title: "filename", Width: fwidth},
|
||||||
|
@ -99,18 +100,18 @@ func newModel(fs []files.File, width, height int, readonly, preselected, once bo
|
||||||
{Title: "modified", Width: dwidth},
|
{Title: "modified", Width: dwidth},
|
||||||
{Title: "size", Width: swidth},
|
{Title: "size", Width: swidth},
|
||||||
}
|
}
|
||||||
if !m.readonly {
|
if !mdl.readonly {
|
||||||
columns = append(columns, table.Column{Title: uncheck, Width: cwidth})
|
columns = append(columns, table.Column{Title: uncheck, Width: cwidth})
|
||||||
} else {
|
} else {
|
||||||
columns[0].Width += cwidth
|
columns[0].Width += cwidth
|
||||||
}
|
}
|
||||||
|
|
||||||
m.table = createTable(columns, rows, theight)
|
mdl.table = createTable(columns, rows, theight)
|
||||||
|
|
||||||
m.sorting = sorting.Name
|
mdl.sorting = sorting.Name
|
||||||
m.sort()
|
mdl.sort()
|
||||||
|
|
||||||
return m
|
return mdl
|
||||||
}
|
}
|
||||||
|
|
||||||
type keyMap struct {
|
type keyMap struct {
|
||||||
|
@ -235,7 +236,7 @@ func (m model) View() string {
|
||||||
|
|
||||||
func (m model) showHelp() string {
|
func (m model) showHelp() string {
|
||||||
// TODO: maybe use bubbletea built in help
|
// TODO: maybe use bubbletea built in help
|
||||||
var keys []string = []string{
|
var keys = []string{
|
||||||
fmt.Sprintf("%s %s (%s)", darktext.Render(m.keys.sort.Help().Key), darkertext.Render(m.keys.sort.Help().Desc), m.sorting.String()),
|
fmt.Sprintf("%s %s (%s)", darktext.Render(m.keys.sort.Help().Key), darkertext.Render(m.keys.sort.Help().Desc), m.sorting.String()),
|
||||||
fmt.Sprintf("%s %s", darktext.Render(m.keys.quit.Help().Key), darkertext.Render(m.keys.quit.Help().Desc)),
|
fmt.Sprintf("%s %s", darktext.Render(m.keys.quit.Help().Key), darkertext.Render(m.keys.quit.Help().Desc)),
|
||||||
}
|
}
|
||||||
|
@ -254,50 +255,50 @@ func (m model) showHelp() string {
|
||||||
|
|
||||||
func (m model) header() string {
|
func (m model) header() string {
|
||||||
var (
|
var (
|
||||||
right, left string
|
right, left string
|
||||||
spacer_width int
|
spacerWidth int
|
||||||
keys = []string{
|
keys = []string{
|
||||||
fmt.Sprintf("%s %s", darktext.Render(m.keys.rstr.Help().Key), darkertext.Render(m.keys.rstr.Help().Desc)),
|
fmt.Sprintf("%s %s", darktext.Render(m.keys.rstr.Help().Key), darkertext.Render(m.keys.rstr.Help().Desc)),
|
||||||
fmt.Sprintf("%s %s", darktext.Render(m.keys.clen.Help().Key), darkertext.Render(m.keys.clen.Help().Desc)),
|
fmt.Sprintf("%s %s", darktext.Render(m.keys.clen.Help().Key), darkertext.Render(m.keys.clen.Help().Desc)),
|
||||||
}
|
}
|
||||||
select_keys = []string{
|
selectKeys = []string{
|
||||||
fmt.Sprintf("%s %s", darktext.Render(m.keys.todo.Help().Key), darkertext.Render(m.keys.todo.Help().Desc)),
|
fmt.Sprintf("%s %s", darktext.Render(m.keys.todo.Help().Key), darkertext.Render(m.keys.todo.Help().Desc)),
|
||||||
fmt.Sprintf("%s %s", darktext.Render(m.keys.nada.Help().Key), darkertext.Render(m.keys.nada.Help().Desc)),
|
fmt.Sprintf("%s %s", darktext.Render(m.keys.nada.Help().Key), darkertext.Render(m.keys.nada.Help().Desc)),
|
||||||
fmt.Sprintf("%s %s", darktext.Render(m.keys.invr.Help().Key), darkertext.Render(m.keys.invr.Help().Desc)),
|
fmt.Sprintf("%s %s", darktext.Render(m.keys.invr.Help().Key), darkertext.Render(m.keys.invr.Help().Desc)),
|
||||||
}
|
}
|
||||||
dot = darkesttext.Render("•")
|
dot = darkesttext.Render("•")
|
||||||
wide_dot = darkesttext.Render(" • ")
|
wideDot = darkesttext.Render(" • ")
|
||||||
)
|
)
|
||||||
|
|
||||||
right = " " // to offset from the table border
|
right = " " // to offset from the table border
|
||||||
switch m.mode {
|
switch m.mode {
|
||||||
case modes.Interactive:
|
case modes.Interactive:
|
||||||
right += strings.Join(keys, wide_dot)
|
right += strings.Join(keys, wideDot)
|
||||||
default:
|
default:
|
||||||
right += m.mode.String()
|
right += m.mode.String()
|
||||||
if m.workdir != "" {
|
if m.workdir != "" {
|
||||||
right += fmt.Sprintf(" in %s", dirs.UnExpand(m.workdir, ""))
|
right += fmt.Sprintf(" in %s", dirs.UnExpand(m.workdir, ""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
right += fmt.Sprintf(" %s %s", dot, strings.Join(select_keys, wide_dot))
|
right += fmt.Sprintf(" %s %s", dot, strings.Join(selectKeys, wideDot))
|
||||||
|
|
||||||
left = fmt.Sprintf("%d/%d %s %s", len(m.selected), len(m.table.Rows()), dot, humanize.Bytes(uint64(m.selectsize)))
|
left = fmt.Sprintf("%d/%d %s %s", len(m.selected), len(m.table.Rows()), dot, humanize.Bytes(uint64(m.selectsize)))
|
||||||
|
|
||||||
// offset of 2 again because of table border
|
// offset of 2 again because of table border
|
||||||
spacer_width = m.termwidth - lipgloss.Width(right) - lipgloss.Width(left) - 2
|
spacerWidth = m.termwidth - lipgloss.Width(right) - lipgloss.Width(left) - 2
|
||||||
if spacer_width <= 0 {
|
if spacerWidth <= 0 {
|
||||||
spacer_width = 1 // always at least one space
|
spacerWidth = 1 // always at least one space
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("%s%s%s", right, strings.Repeat(" ", spacer_width), left)
|
return fmt.Sprintf("%s%s%s", right, strings.Repeat(" ", spacerWidth), left)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m model) footer() string {
|
func (m model) footer() string {
|
||||||
return regulartext.Render(m.showHelp())
|
return regulartext.Render(m.showHelp())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m model) quit(unselect_all bool) (model, tea.Cmd) {
|
func (m model) quit(unselectAll bool) (model, tea.Cmd) {
|
||||||
if unselect_all {
|
if unselectAll {
|
||||||
m.unselectAll()
|
m.unselectAll()
|
||||||
} else {
|
} else {
|
||||||
m.onlySelected()
|
m.onlySelected()
|
||||||
|
@ -337,17 +338,17 @@ func (m model) selectedFiles() (outfile files.Files) {
|
||||||
} */
|
} */
|
||||||
|
|
||||||
func (m *model) freshRows(preselected bool) (rows []table.Row) {
|
func (m *model) freshRows(preselected bool) (rows []table.Row) {
|
||||||
for _, f := range m.files {
|
for _, file := range m.files {
|
||||||
r := newRow(f, m.workdir)
|
row := newRow(file, m.workdir)
|
||||||
|
|
||||||
if !m.readonly {
|
if !m.readonly {
|
||||||
r = append(r, getCheck(preselected))
|
row = append(row, getCheck(preselected))
|
||||||
}
|
}
|
||||||
if preselected {
|
if preselected {
|
||||||
m.selected[f.String()] = true
|
m.selected[file.String()] = true
|
||||||
m.selectsize += f.Filesize()
|
m.selectsize += file.Filesize()
|
||||||
}
|
}
|
||||||
rows = append(rows, r)
|
rows = append(rows, row)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -364,7 +365,7 @@ func (m *model) onlySelected() {
|
||||||
m.table.SetRows(rows)
|
m.table.SetRows(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateRow updates row of `index` with `row`
|
// updateRow updates row of provided index with provided row.
|
||||||
func (m *model) updateRow(index int, selected bool) {
|
func (m *model) updateRow(index int, selected bool) {
|
||||||
rows := m.table.Rows()
|
rows := m.table.Rows()
|
||||||
row := rows[index]
|
row := rows[index]
|
||||||
|
@ -380,17 +381,17 @@ func (m *model) updateRow(index int, selected bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *model) updateRows(selected bool) {
|
func (m *model) updateRows(selected bool) {
|
||||||
var newrows []table.Row
|
var newrows = []table.Row{}
|
||||||
|
|
||||||
for _, row := range m.table.Rows() {
|
for _, row := range m.table.Rows() {
|
||||||
r := table.Row{
|
newRow := table.Row{
|
||||||
row[0],
|
row[0],
|
||||||
row[1],
|
row[1],
|
||||||
row[2],
|
row[2],
|
||||||
row[3],
|
row[3],
|
||||||
getCheck(selected),
|
getCheck(selected),
|
||||||
}
|
}
|
||||||
newrows = append(newrows, r)
|
newrows = append(newrows, newRow)
|
||||||
}
|
}
|
||||||
m.table.SetRows(newrows)
|
m.table.SetRows(newrows)
|
||||||
}
|
}
|
||||||
|
@ -483,7 +484,7 @@ func (m *model) invertSelection() {
|
||||||
|
|
||||||
func (m *model) sort() {
|
func (m *model) sort() {
|
||||||
slices.SortStableFunc(m.files, m.sorting.Sorter())
|
slices.SortStableFunc(m.files, m.sorting.Sorter())
|
||||||
var rows []table.Row
|
var rows = []table.Row{}
|
||||||
for _, file := range m.files {
|
for _, file := range m.files {
|
||||||
r := newRow(file, m.workdir)
|
r := newRow(file, m.workdir)
|
||||||
if !m.readonly {
|
if !m.readonly {
|
||||||
|
@ -495,32 +496,32 @@ func (m *model) sort() {
|
||||||
m.table.SetRows(rows)
|
m.table.SetRows(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Select(fs files.Files, width, height int, readonly, preselected, once bool, workdir string, mode modes.Mode) (files.Files, modes.Mode, error) {
|
func Select(fls files.Files, width, height int, readonly, preselected, once bool, workdir string, mode modes.Mode) (files.Files, modes.Mode, error) {
|
||||||
mdl := newModel(fs, width, height, readonly, preselected, once, workdir, mode)
|
mdl := newModel(fls, width, height, readonly, preselected, once, workdir, mode)
|
||||||
endmodel, err := tea.NewProgram(mdl).Run()
|
endmodel, err := tea.NewProgram(mdl).Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fs, 0, err
|
return fls, 0, err
|
||||||
}
|
}
|
||||||
m, ok := endmodel.(model)
|
m, ok := endmodel.(model)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fs, 0, fmt.Errorf("model isn't the right type?? what has happened")
|
return fls, 0, fmt.Errorf("model isn't the right type?? what has happened")
|
||||||
}
|
}
|
||||||
return m.selectedFiles(), m.mode, nil
|
return m.selectedFiles(), m.mode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRow(file files.File, workdir string) table.Row {
|
func newRow(file files.File, workdir string) table.Row {
|
||||||
var t, b string
|
var time, bar string
|
||||||
t = humanize.Time(file.Date())
|
time = humanize.Time(file.Date())
|
||||||
if file.IsDir() {
|
if file.IsDir() {
|
||||||
b = strings.Repeat("─", 3)
|
bar = strings.Repeat("─", 3)
|
||||||
} else {
|
} else {
|
||||||
b = humanize.Bytes(uint64(file.Filesize()))
|
bar = humanize.Bytes(uint64(file.Filesize()))
|
||||||
}
|
}
|
||||||
return table.Row{
|
return table.Row{
|
||||||
dirs.UnEscape(file.Name()),
|
dirs.UnEscape(file.Name()),
|
||||||
dirs.UnExpand(filepath.Dir(file.Path()), workdir),
|
dirs.UnExpand(filepath.Dir(file.Path()), workdir),
|
||||||
t,
|
time,
|
||||||
b,
|
bar,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,43 +535,43 @@ func getCheck(selected bool) (ourcheck string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTable(columns []table.Column, rows []table.Row, height int) table.Model {
|
func createTable(columns []table.Column, rows []table.Row, height int) table.Model {
|
||||||
t := table.New(
|
tbl := table.New(
|
||||||
table.WithColumns(columns),
|
table.WithColumns(columns),
|
||||||
table.WithRows(rows),
|
table.WithRows(rows),
|
||||||
table.WithFocused(true),
|
table.WithFocused(true),
|
||||||
table.WithHeight(height),
|
table.WithHeight(height),
|
||||||
)
|
)
|
||||||
t.KeyMap = fixTableKeymap()
|
tbl.KeyMap = fixTableKeymap()
|
||||||
t.SetStyles(makeStyle())
|
tbl.SetStyles(makeStyle())
|
||||||
return t
|
return tbl
|
||||||
}
|
}
|
||||||
|
|
||||||
func fixTableKeymap() table.KeyMap {
|
func fixTableKeymap() table.KeyMap {
|
||||||
t := table.DefaultKeyMap()
|
tbl := table.DefaultKeyMap()
|
||||||
|
|
||||||
// remove spacebar from default page down keybind, but keep the rest
|
// remove spacebar from default page down keybind, but keep the rest
|
||||||
t.PageDown.SetKeys(
|
tbl.PageDown.SetKeys(
|
||||||
slices.DeleteFunc(t.PageDown.Keys(), func(s string) bool {
|
slices.DeleteFunc(tbl.PageDown.Keys(), func(s string) bool {
|
||||||
return s == space
|
return s == space
|
||||||
})...,
|
})...,
|
||||||
)
|
)
|
||||||
|
|
||||||
return t
|
return tbl
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeStyle() table.Styles {
|
func makeStyle() table.Styles {
|
||||||
s := table.DefaultStyles()
|
style := table.DefaultStyles()
|
||||||
s.Header = s.Header.
|
style.Header = style.Header.
|
||||||
BorderStyle(lipgloss.NormalBorder()).
|
BorderStyle(lipgloss.NormalBorder()).
|
||||||
BorderForeground(lipgloss.Color(black)).
|
BorderForeground(lipgloss.Color(black)).
|
||||||
BorderBottom(true).
|
BorderBottom(true).
|
||||||
Bold(false)
|
Bold(false)
|
||||||
s.Selected = s.Selected.
|
style.Selected = style.Selected.
|
||||||
Foreground(lipgloss.Color(white)).
|
Foreground(lipgloss.Color(white)).
|
||||||
Background(lipgloss.Color(hoveritembg)).
|
Background(lipgloss.Color(hoveritembg)).
|
||||||
Bold(false)
|
Bold(false)
|
||||||
|
|
||||||
return s
|
return style
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeUnselectedStyle() table.Styles {
|
func makeUnselectedStyle() table.Styles {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Package modes implements Mode type for interactive table.
|
||||||
package modes
|
package modes
|
||||||
|
|
||||||
type Mode int
|
type Mode int
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Package sorting implements Sorting type for interactive table.
|
||||||
package sorting
|
package sorting
|
||||||
|
|
||||||
import "git.burning.moe/celediel/gt/internal/files"
|
import "git.burning.moe/celediel/gt/internal/files"
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Package prompt implements prompt functions for runes and strings.
|
||||||
package prompt
|
package prompt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -28,16 +29,16 @@ func AskRune(prompt, options string) byte {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
fmt.Printf("%s [%s]: ", prompt, options)
|
fmt.Fprintf(os.Stdout, "%s [%s]: ", prompt, options)
|
||||||
|
|
||||||
// read one byte from stdin
|
// read one byte from stdin
|
||||||
b := make([]byte, 1)
|
one := make([]byte, 1)
|
||||||
_, err = os.Stdin.Read(b)
|
_, err = os.Stdin.Read(one)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytes.ToLower(b)[0]
|
return bytes.ToLower(one)[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPath(path string) (string, bool) {
|
func NewPath(path string) (string, bool) {
|
||||||
|
|
87
main.go
87
main.go
|
@ -21,9 +21,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
appname string = "gt"
|
appname string = "gt"
|
||||||
appdesc string = "xdg trash cli"
|
appdesc string = "xdg trash cli"
|
||||||
appversion string = "v0.0.1"
|
appversion string = "v0.0.1"
|
||||||
|
executePerm = fs.FileMode(0755)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -43,12 +44,12 @@ var (
|
||||||
|
|
||||||
trashDir = filepath.Join(xdg.DataHome, "Trash")
|
trashDir = filepath.Join(xdg.DataHome, "Trash")
|
||||||
|
|
||||||
beforeAll = func(ctx *cli.Context) (err error) {
|
beforeAll = func(_ *cli.Context) error {
|
||||||
// setup log
|
// setup log
|
||||||
log.SetReportTimestamp(true)
|
log.SetReportTimestamp(true)
|
||||||
log.SetTimeFormat(time.TimeOnly)
|
log.SetTimeFormat(time.TimeOnly)
|
||||||
if l, e := log.ParseLevel(loglvl); e == nil {
|
if level, err := log.ParseLevel(loglvl); err == nil {
|
||||||
log.SetLevel(l)
|
log.SetLevel(level)
|
||||||
// Some extra info for debug level
|
// Some extra info for debug level
|
||||||
if log.GetLevel() == log.DebugLevel {
|
if log.GetLevel() == log.DebugLevel {
|
||||||
log.SetReportCaller(true)
|
log.SetReportCaller(true)
|
||||||
|
@ -58,35 +59,35 @@ var (
|
||||||
}
|
}
|
||||||
|
|
||||||
// read the term height and width for tables
|
// read the term height and width for tables
|
||||||
w, h, e := term.GetSize(int(os.Stdout.Fd()))
|
width, height, e := term.GetSize(int(os.Stdout.Fd()))
|
||||||
if e != nil {
|
if e != nil {
|
||||||
w = 80
|
width = 80
|
||||||
h = 24
|
height = 24
|
||||||
}
|
}
|
||||||
termwidth = w
|
termwidth = width
|
||||||
termheight = h
|
termheight = height
|
||||||
|
|
||||||
// ensure trash directories exist
|
// ensure trash directories exist
|
||||||
if _, e := os.Stat(trashDir); os.IsNotExist(e) {
|
if _, e := os.Stat(trashDir); os.IsNotExist(e) {
|
||||||
if err := os.Mkdir(trashDir, fs.FileMode(0755)); err != nil {
|
if err := os.Mkdir(trashDir, executePerm); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, e := os.Stat(filepath.Join(trashDir, "info")); os.IsNotExist(e) {
|
if _, e := os.Stat(filepath.Join(trashDir, "info")); os.IsNotExist(e) {
|
||||||
if err := os.Mkdir(filepath.Join(trashDir, "info"), fs.FileMode(0755)); err != nil {
|
if err := os.Mkdir(filepath.Join(trashDir, "info"), executePerm); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, e := os.Stat(filepath.Join(trashDir, "files")); os.IsNotExist(e) {
|
if _, e := os.Stat(filepath.Join(trashDir, "files")); os.IsNotExist(e) {
|
||||||
if err := os.Mkdir(filepath.Join(trashDir, "files"), fs.FileMode(0755)); err != nil {
|
if err := os.Mkdir(filepath.Join(trashDir, "files"), executePerm); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// action launches interactive mode if run without args, or trashes files as args
|
// action launches interactive mode if run without args, or trashes files as args.
|
||||||
action = func(ctx *cli.Context) error {
|
action = func(ctx *cli.Context) error {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
|
@ -103,18 +104,7 @@ var (
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ctx.Args().Slice()) != 0 {
|
if len(ctx.Args().Slice()) == 0 {
|
||||||
// args, so try to trash files
|
|
||||||
var files_to_trash files.Files
|
|
||||||
for _, arg := range ctx.Args().Slice() {
|
|
||||||
file, e := files.NewDisk(arg)
|
|
||||||
if e != nil {
|
|
||||||
log.Fatalf("cannot trash '%s': No such file or directory", arg)
|
|
||||||
}
|
|
||||||
files_to_trash = append(files_to_trash, file)
|
|
||||||
}
|
|
||||||
return files.ConfirmTrash(askconfirm, files_to_trash, trashDir)
|
|
||||||
} else {
|
|
||||||
// no ags, so do interactive mode
|
// no ags, so do interactive mode
|
||||||
var (
|
var (
|
||||||
infiles files.Files
|
infiles files.Files
|
||||||
|
@ -133,7 +123,7 @@ var (
|
||||||
} else {
|
} else {
|
||||||
msg = "no files to show"
|
msg = "no files to show"
|
||||||
}
|
}
|
||||||
fmt.Println(msg)
|
fmt.Fprint(os.Stdout, msg)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
selected, mode, err = interactive.Select(infiles, termwidth, termheight, false, false, false, workdir, modes.Interactive)
|
selected, mode, err = interactive.Select(infiles, termwidth, termheight, false, false, false, workdir, modes.Interactive)
|
||||||
|
@ -162,6 +152,17 @@ var (
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// args, so try to trash files
|
||||||
|
var filesToTrash files.Files
|
||||||
|
for _, arg := range ctx.Args().Slice() {
|
||||||
|
file, e := files.NewDisk(arg)
|
||||||
|
if e != nil {
|
||||||
|
log.Fatalf("cannot trash '%s': No such file or directory", arg)
|
||||||
|
}
|
||||||
|
filesToTrash = append(filesToTrash, file)
|
||||||
|
}
|
||||||
|
return files.ConfirmTrash(askconfirm, filesToTrash, trashDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeCommands = func(ctx *cli.Context) (err error) {
|
beforeCommands = func(ctx *cli.Context) (err error) {
|
||||||
|
@ -189,7 +190,7 @@ var (
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
after = func(ctx *cli.Context) error {
|
after = func(_ *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +201,7 @@ var (
|
||||||
Flags: slices.Concat(trashFlags, filterFlags),
|
Flags: slices.Concat(trashFlags, filterFlags),
|
||||||
Before: beforeTrash,
|
Before: beforeTrash,
|
||||||
Action: func(ctx *cli.Context) error {
|
Action: func(ctx *cli.Context) error {
|
||||||
var files_to_trash files.Files
|
var filesToTrash files.Files
|
||||||
var selectall bool
|
var selectall bool
|
||||||
for _, arg := range ctx.Args().Slice() {
|
for _, arg := range ctx.Args().Slice() {
|
||||||
file, e := files.NewDisk(arg)
|
file, e := files.NewDisk(arg)
|
||||||
|
@ -209,25 +210,25 @@ var (
|
||||||
fltr.AddFileName(arg)
|
fltr.AddFileName(arg)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
files_to_trash = append(files_to_trash, file)
|
filesToTrash = append(filesToTrash, file)
|
||||||
selectall = true
|
selectall = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// if none of the args were files, then process find files based on filter
|
// if none of the args were files, then process find files based on filter
|
||||||
if len(files_to_trash) == 0 {
|
if len(filesToTrash) == 0 {
|
||||||
fls, err := files.FindDisk(workdir, recursive, fltr)
|
fls, err := files.FindDisk(workdir, recursive, fltr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(fls) == 0 {
|
if len(fls) == 0 {
|
||||||
fmt.Println("no files to trash")
|
fmt.Fprintf(os.Stdout, "no files to trash")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
files_to_trash = append(files_to_trash, fls...)
|
filesToTrash = append(filesToTrash, fls...)
|
||||||
selectall = !fltr.Blank()
|
selectall = !fltr.Blank()
|
||||||
}
|
}
|
||||||
|
|
||||||
selected, _, err := interactive.Select(files_to_trash, termwidth, termheight, false, selectall, false, workdir, modes.Trashing)
|
selected, _, err := interactive.Select(filesToTrash, termwidth, termheight, false, selectall, false, workdir, modes.Trashing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -246,14 +247,14 @@ var (
|
||||||
Usage: "List trashed files",
|
Usage: "List trashed files",
|
||||||
Flags: slices.Concat(listFlags, alreadyintrashFlags, filterFlags),
|
Flags: slices.Concat(listFlags, alreadyintrashFlags, filterFlags),
|
||||||
Before: beforeCommands,
|
Before: beforeCommands,
|
||||||
Action: func(ctx *cli.Context) error {
|
Action: func(_ *cli.Context) error {
|
||||||
log.Debugf("searching in directory %s for files", trashDir)
|
log.Debugf("searching in directory %s for files", trashDir)
|
||||||
|
|
||||||
// look for files
|
// look for files
|
||||||
fls, err := files.FindTrash(trashDir, ogdir, fltr)
|
fls, err := files.FindTrash(trashDir, ogdir, fltr)
|
||||||
|
|
||||||
var msg string
|
var msg string
|
||||||
log.Debugf("filter '%s' is blark? %t in %s", fltr, fltr.Blank(), ogdir)
|
log.Debugf("filter '%s' is blank? %t in %s", fltr, fltr.Blank(), ogdir)
|
||||||
if fltr.Blank() && ogdir == "" {
|
if fltr.Blank() && ogdir == "" {
|
||||||
msg = "trash is empty"
|
msg = "trash is empty"
|
||||||
} else {
|
} else {
|
||||||
|
@ -261,7 +262,7 @@ var (
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(fls) == 0 {
|
if len(fls) == 0 {
|
||||||
fmt.Println(msg)
|
fmt.Fprint(os.Stdout, msg)
|
||||||
return nil
|
return nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -280,13 +281,13 @@ var (
|
||||||
Usage: "Restore a trashed file or files",
|
Usage: "Restore a trashed file or files",
|
||||||
Flags: slices.Concat(cleanRestoreFlags, alreadyintrashFlags, filterFlags),
|
Flags: slices.Concat(cleanRestoreFlags, alreadyintrashFlags, filterFlags),
|
||||||
Before: beforeCommands,
|
Before: beforeCommands,
|
||||||
Action: func(ctx *cli.Context) error {
|
Action: func(_ *cli.Context) error {
|
||||||
log.Debugf("searching in directory %s for files", trashDir)
|
log.Debugf("searching in directory %s for files", trashDir)
|
||||||
|
|
||||||
// look for files
|
// look for files
|
||||||
fls, err := files.FindTrash(trashDir, ogdir, fltr)
|
fls, err := files.FindTrash(trashDir, ogdir, fltr)
|
||||||
if len(fls) == 0 {
|
if len(fls) == 0 {
|
||||||
fmt.Println("no files to restore")
|
fmt.Fprintf(os.Stdout, "no files to restore")
|
||||||
return nil
|
return nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -311,10 +312,10 @@ var (
|
||||||
Usage: "Clean files from trash",
|
Usage: "Clean files from trash",
|
||||||
Flags: slices.Concat(cleanRestoreFlags, alreadyintrashFlags, filterFlags),
|
Flags: slices.Concat(cleanRestoreFlags, alreadyintrashFlags, filterFlags),
|
||||||
Before: beforeCommands,
|
Before: beforeCommands,
|
||||||
Action: func(ctx *cli.Context) error {
|
Action: func(_ *cli.Context) error {
|
||||||
fls, err := files.FindTrash(trashDir, ogdir, fltr)
|
fls, err := files.FindTrash(trashDir, ogdir, fltr)
|
||||||
if len(fls) == 0 {
|
if len(fls) == 0 {
|
||||||
fmt.Println("no files to clean")
|
fmt.Fprintf(os.Stdout, "no files to clean")
|
||||||
return nil
|
return nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
Loading…
Reference in a new issue