diff --git a/internal/files/disk.go b/internal/files/disk.go new file mode 100644 index 0000000..70483cc --- /dev/null +++ b/internal/files/disk.go @@ -0,0 +1,175 @@ +package files + +import ( + "io/fs" + "os" + "path/filepath" + "strings" + "time" + + "git.burning.moe/celediel/gt/internal/filter" + + "github.com/charmbracelet/log" + "github.com/dustin/go-humanize" +) + +type DiskFile struct { + name, path string + filesize int64 + modified time.Time + isdir bool +} + +func (f DiskFile) Name() string { return f.name } +func (f DiskFile) Path() string { return filepath.Join(f.path, f.name) } +func (f DiskFile) Date() time.Time { return f.modified } +func (f DiskFile) Filesize() int64 { return f.filesize } +func (f DiskFile) IsDir() bool { return f.isdir } + +func NewDisk(path string) (DiskFile, error) { + info, err := os.Stat(path) + if err != nil { + return DiskFile{}, err + } + + abs, err := filepath.Abs(path) + if err != nil { + log.Errorf("couldn't get absolute path for %s", path) + abs = path + } + + name := filepath.Base(abs) + base_path := filepath.Dir(abs) + + log.Debugf("%s (base:%s) (size:%s) (modified:%s) exists", + name, base_path, humanize.Bytes(uint64(info.Size())), info.ModTime()) + + return DiskFile{ + name: name, + path: base_path, + filesize: info.Size(), + modified: info.ModTime(), + isdir: info.IsDir(), + }, nil +} + +func FindDisk(dir string, recursive bool, f *filter.Filter) (files Files, err error) { + if dir == "." || dir == "" { + var d string + if d, err = os.Getwd(); err != nil { + return + } else { + dir = d + } + } + + var recursively string + if recursive { + recursively = " recursively" + } + + log.Debugf("gonna find files%s in %s matching %s", recursively, dir, f) + + if recursive { + files = append(files, walk_dir(dir, f)...) + } else { + files = append(files, read_dir(dir, f)...) + } + + return +} + +// is_in_recursive_dir checks `path` and parent directories +// of `path` up to `base` for a hidden parent +func is_in_recursive_dir(base, path string) bool { + me := path + for { + me = filepath.Clean(me) + if me == base { + break + } + if strings.HasPrefix(filepath.Base(me), ".") { + return true + } + me += string(os.PathSeparator) + ".." + } + return false +} + +func walk_dir(dir string, f *filter.Filter) (files Files) { + err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error { + if dir == path { + return nil + } + + if is_in_recursive_dir(dir, path) && !f.IgnoreHidden() { + return nil + } + + p, e := filepath.Abs(path) + if e != nil { + return err + } + + name := d.Name() + info, _ := d.Info() + if f.Match(name, info.ModTime(), info.Size(), info.IsDir()) { + log.Debugf("found matching file: %s %s", name, info.ModTime()) + i, err := os.Stat(p) + if err != nil { + log.Debugf("error in file stat: %s", err) + return nil + } + files = append(files, DiskFile{ + path: filepath.Dir(p), + name: name, + filesize: i.Size(), + modified: i.ModTime(), + isdir: i.IsDir(), + }) + } else { + log.Debugf("ignoring file %s (%s)", name, info.ModTime()) + } + return nil + }) + if err != nil { + log.Errorf("error walking directory %s: %s", dir, err) + return Files{} + } + return +} + +func read_dir(dir string, f *filter.Filter) (files Files) { + fs, err := os.ReadDir(dir) + if err != nil { + return Files{} + } + for _, file := range fs { + name := file.Name() + + if name == dir { + continue + } + + info, err := file.Info() + if err != nil { + return Files{} + } + + path := filepath.Dir(filepath.Join(dir, name)) + + if f.Match(name, info.ModTime(), info.Size(), info.IsDir()) { + log.Debugf("found matching file: %s %s", name, info.ModTime()) + files = append(files, DiskFile{ + name: name, + path: path, + modified: info.ModTime(), + filesize: info.Size(), + isdir: info.IsDir(), + }) + } else { + log.Debugf("ignoring file %s (%s)", name, info.ModTime()) + } + } + return +} diff --git a/internal/files/files.go b/internal/files/files.go index 81cfd52..a050984 100644 --- a/internal/files/files.go +++ b/internal/files/files.go @@ -1,186 +1,22 @@ // Package files finds and displays files on disk package files -import ( - "io/fs" - "os" - "path/filepath" - "strings" - "time" +import "time" - "git.burning.moe/celediel/gt/internal/filter" - "github.com/charmbracelet/log" - "github.com/dustin/go-humanize" -) - -type File struct { - name, path string - filesize int64 - modified time.Time - isdir bool +type File interface { + Name() string + Path() string + Date() time.Time + Filesize() int64 + IsDir() bool } type Files []File -func (f File) Name() string { return f.name } -func (f File) Path() string { return f.path } -func (f File) Filename() string { return filepath.Join(f.path, f.name) } -func (f File) Modified() time.Time { return f.modified } -func (f File) Filesize() int64 { return f.filesize } -func (f File) IsDir() bool { return f.isdir } - -func New(path string) (File, error) { - info, err := os.Stat(path) - if err != nil { - return File{}, err - } - - abs, err := filepath.Abs(path) - if err != nil { - log.Errorf("couldn't get absolute path for %s", path) - abs = path - } - - name := filepath.Base(abs) - base_path := filepath.Dir(abs) - - log.Debugf("%s (base:%s) (size:%s) (modified:%s) exists", - name, base_path, humanize.Bytes(uint64(info.Size())), info.ModTime()) - - return File{ - name: name, - path: base_path, - filesize: info.Size(), - modified: info.ModTime(), - isdir: info.IsDir(), - }, nil -} - -func Find(dir string, recursive bool, f *filter.Filter) (files Files, err error) { - if dir == "." || dir == "" { - var d string - if d, err = os.Getwd(); err != nil { - return - } else { - dir = d - } - } - - var recursively string - if recursive { - recursively = " recursively" - } - - log.Debugf("gonna find files%s in %s matching %s", recursively, dir, f) - - if recursive { - files = append(files, walk_dir(dir, f)...) - } else { - files = append(files, read_dir(dir, f)...) - } - - return -} - -// is_in_recursive_dir checks `path` and parent directories -// of `path` up to `base` for a hidden parent -func is_in_recursive_dir(base, path string) bool { - me := path - for { - me = filepath.Clean(me) - if me == base { - break - } - if strings.HasPrefix(filepath.Base(me), ".") { - return true - } - me += string(os.PathSeparator) + ".." - } - return false -} - -func walk_dir(dir string, f *filter.Filter) (files Files) { - err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error { - if dir == path { - return nil - } - - if is_in_recursive_dir(dir, path) && !f.IgnoreHidden() { - return nil - } - - p, e := filepath.Abs(path) - if e != nil { - return err - } - - name := d.Name() - info, _ := d.Info() - if f.Match(name, info.ModTime(), info.Size(), info.IsDir()) { - log.Debugf("found matching file: %s %s", name, info.ModTime()) - i, err := os.Stat(p) - if err != nil { - log.Debugf("error in file stat: %s", err) - return nil - } - files = append(files, File{ - path: filepath.Dir(p), - name: name, - filesize: i.Size(), - modified: i.ModTime(), - isdir: i.IsDir(), - }) - } else { - log.Debugf("ignoring file %s (%s)", name, info.ModTime()) - } - return nil - }) - if err != nil { - log.Errorf("error walking directory %s: %s", dir, err) - return []File{} - } - return -} - -func read_dir(dir string, f *filter.Filter) (files Files) { - fs, err := os.ReadDir(dir) - if err != nil { - return []File{} - } - for _, file := range fs { - name := file.Name() - - if name == dir { - continue - } - - info, err := file.Info() - if err != nil { - return []File{} - } - - path := filepath.Dir(filepath.Join(dir, name)) - - if f.Match(name, info.ModTime(), info.Size(), info.IsDir()) { - log.Debugf("found matching file: %s %s", name, info.ModTime()) - files = append(files, File{ - name: name, - path: path, - modified: info.ModTime(), - filesize: info.Size(), - isdir: info.IsDir(), - }) - } else { - log.Debugf("ignoring file %s (%s)", name, info.ModTime()) - } - } - return -} - func SortByModified(a, b File) int { - if a.modified.After(b.modified) { + if a.Date().After(b.Date()) { return 1 - } else if a.modified.Before(b.modified) { + } else if a.Date().Before(b.Date()) { return -1 } else { return 0 @@ -188,9 +24,9 @@ func SortByModified(a, b File) int { } func SortByModifiedReverse(a, b File) int { - if a.modified.Before(b.modified) { + if a.Date().Before(b.Date()) { return 1 - } else if a.modified.After(b.modified) { + } else if a.Date().After(b.Date()) { return -1 } else { return 0 @@ -198,9 +34,9 @@ func SortByModifiedReverse(a, b File) int { } func SortBySize(a, b File) int { - if a.filesize > b.filesize { + if a.Filesize() > b.Filesize() { return 1 - } else if a.filesize < b.filesize { + } else if a.Filesize() < b.Filesize() { return -1 } else { return 0 @@ -208,9 +44,49 @@ func SortBySize(a, b File) int { } func SortBySizeReverse(a, b File) int { - if a.filesize < b.filesize { + if a.Filesize() < b.Filesize() { return 1 - } else if a.filesize > b.filesize { + } else if a.Filesize() > b.Filesize() { + return -1 + } else { + return 0 + } +} + +func SortByName(a, b File) int { + if a.Name() > b.Name() { + return 1 + } else if a.Name() < b.Name() { + return -1 + } else { + return 0 + } +} + +func SortByNameReverse(a, b File) int { + if a.Name() < b.Name() { + return 1 + } else if a.Name() > b.Name() { + return -1 + } else { + return 0 + } +} + +func SortByPath(a, b File) int { + if a.Path() > b.Path() { + return 1 + } else if a.Path() < b.Path() { + return -1 + } else { + return 0 + } +} + +func SortByPathReverse(a, b File) int { + if a.Path() < b.Path() { + return 1 + } else if a.Path() > b.Path() { return -1 } else { return 0 diff --git a/internal/trash/trash.go b/internal/files/trash.go similarity index 79% rename from internal/trash/trash.go rename to internal/files/trash.go index 0a72ff8..87f898f 100644 --- a/internal/trash/trash.go +++ b/internal/files/trash.go @@ -1,6 +1,4 @@ -// Package trash finds and displays files located in the trash, and moves -// files into the trash, creating cooresponding .trashinfo files -package trash +package files import ( "fmt" @@ -14,6 +12,7 @@ import ( "git.burning.moe/celediel/gt/internal/dirs" "git.burning.moe/celediel/gt/internal/filter" "git.burning.moe/celediel/gt/internal/prompt" + "github.com/charmbracelet/huh" "github.com/charmbracelet/log" "github.com/dustin/go-humanize" @@ -34,7 +33,7 @@ DeletionDate={date} ` ) -type Info struct { +type TrashInfo struct { name, ogpath string path, trashinfo string isdir bool @@ -42,17 +41,15 @@ type Info struct { filesize int64 } -type Infos []Info +func (t TrashInfo) Name() string { return t.name } +func (t TrashInfo) TrashPath() string { return t.path } +func (t TrashInfo) Path() string { return t.ogpath } +func (t TrashInfo) TrashInfo() string { return t.trashinfo } +func (t TrashInfo) Date() time.Time { return t.trashed } +func (t TrashInfo) Filesize() int64 { return t.filesize } +func (t TrashInfo) IsDir() bool { return t.isdir } -func (i Info) Name() string { return i.name } -func (i Info) Path() string { return i.path } -func (i Info) OGPath() string { return i.ogpath } -func (i Info) TrashInfo() string { return i.trashinfo } -func (i Info) Trashed() time.Time { return i.trashed } -func (i Info) Filesize() int64 { return i.filesize } -func (i Info) IsDir() bool { return i.isdir } - -func FindFiles(trashdir, ogdir string, f *filter.Filter) (files Infos, outerr error) { +func FindTrash(trashdir, ogdir string, f *filter.Filter) (files Files, outerr error) { outerr = filepath.WalkDir(trashdir, func(path string, d fs.DirEntry, err error) error { if err != nil { log.Debugf("what happened?? what is %s?", err) @@ -91,7 +88,7 @@ func FindFiles(trashdir, ogdir string, f *filter.Filter) (files Infos, outerr er if f.Match(filename, date, info.Size(), info.IsDir()) { log.Debugf("%s: deleted on %s", filename, date.Format(trash_info_date_fmt)) - files = append(files, Info{ + files = append(files, TrashInfo{ name: filename, path: trashedpath, ogpath: basepath, @@ -108,13 +105,18 @@ func FindFiles(trashdir, ogdir string, f *filter.Filter) (files Infos, outerr er return nil }) if outerr != nil { - return []Info{}, outerr + return Files{}, outerr } return } -func Restore(files []Info) (restored int, err error) { - for _, file := range files { +func Restore(files Files) (restored int, err error) { + for _, maybeFile := range files { + file, ok := maybeFile.(TrashInfo) + if !ok { + return restored, fmt.Errorf("bad file?? %s", maybeFile.Name()) + } + var outpath string = dirs.UnEscape(file.ogpath) var cancel bool log.Infof("restoring %s back to %s\n", file.name, outpath) @@ -135,8 +137,13 @@ func Restore(files []Info) (restored int, err error) { return restored, err } -func Remove(files []Info) (removed int, err error) { - for _, file := range files { +func Remove(files Files) (removed int, err error) { + for _, maybeFile := range files { + file, ok := maybeFile.(TrashInfo) + if !ok { + 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 i, e := os.Stat(file.path); e == nil && i.IsDir() { @@ -191,46 +198,6 @@ func TrashFiles(trashDir string, files ...string) (trashed int, err error) { return trashed, err } -func SortByTrashed(a, b Info) int { - if a.trashed.After(b.trashed) { - return 1 - } else if a.trashed.Before(b.trashed) { - return -1 - } else { - return 0 - } -} - -func SortByTrashedReverse(a, b Info) int { - if a.trashed.Before(b.trashed) { - return 1 - } else if a.trashed.After(b.trashed) { - return -1 - } else { - return 0 - } -} - -func SortBySize(a, b Info) int { - if a.filesize > b.filesize { - return 1 - } else if a.filesize < b.filesize { - return -1 - } else { - return 0 - } -} - -func SortBySizeReverse(a, b Info) int { - if a.filesize < b.filesize { - return 1 - } else if a.filesize > b.filesize { - return -1 - } else { - return 0 - } -} - func randomFilename(length int) string { out := strings.Builder{} for range length { diff --git a/internal/modes/modes.go b/internal/tables/modes/modes.go similarity index 100% rename from internal/modes/modes.go rename to internal/tables/modes/modes.go diff --git a/internal/tables/sorting/sorting.go b/internal/tables/sorting/sorting.go new file mode 100644 index 0000000..64c9b5e --- /dev/null +++ b/internal/tables/sorting/sorting.go @@ -0,0 +1,80 @@ +package sorting + +import "git.burning.moe/celediel/gt/internal/files" + +type Sorting int + +const ( + Name Sorting = iota + 1 + NameReverse + Date + DateReverse + Path + PathReverse + Size + SizeReverse +) + +func (s Sorting) Next() Sorting { + switch s { + case SizeReverse: + return Name + default: + return s + 1 + } +} + +func (s Sorting) Prev() Sorting { + switch s { + case Name: + return SizeReverse + default: + return s - 1 + } +} + +func (s Sorting) String() string { + switch s { + case Name: + return "name" + case NameReverse: + return "name (r)" + case Date: + return "date" + case DateReverse: + return "date (r)" + case Path: + return "path" + case PathReverse: + return "path (r)" + case Size: + return "size" + case SizeReverse: + return "size (r)" + default: + return "0" + } +} + +func (s Sorting) Sorter() func(a, b files.File) int { + switch s { + case Name: + return files.SortByName + case NameReverse: + return files.SortByNameReverse + case Date: + return files.SortByModified + case DateReverse: + return files.SortByModifiedReverse + case Path: + return files.SortByPath + case PathReverse: + return files.SortByPathReverse + case Size: + return files.SortBySize + case SizeReverse: + return files.SortBySizeReverse + default: + return files.SortByName + } +} diff --git a/internal/tables/tables.go b/internal/tables/tables.go index 0097f1c..929fff9 100644 --- a/internal/tables/tables.go +++ b/internal/tables/tables.go @@ -9,8 +9,9 @@ import ( "git.burning.moe/celediel/gt/internal/dirs" "git.burning.moe/celediel/gt/internal/files" - "git.burning.moe/celediel/gt/internal/modes" - "git.burning.moe/celediel/gt/internal/trash" + "git.burning.moe/celediel/gt/internal/tables/modes" + "git.burning.moe/celediel/gt/internal/tables/sorting" + "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" @@ -49,79 +50,19 @@ var ( ) type model struct { - table table.Model - keys keyMap - selected map[int]bool - readonly bool - termheight int - mode modes.Mode - subtitle string + table table.Model + keys keyMap + selected map[int]bool + readonly bool + preselected bool + termheight int + mode modes.Mode + sorting sorting.Sorting + workdir string + files files.Files } -// TODO: reconcile trash.Info and files.File into an interface so I can shorten this up - -func newInfosModel(is trash.Infos, width, height int, readonly, preselected bool, mode modes.Mode) model { - var ( - fwidth int = int(math.Round(float64(width-woffset) * 0.4)) - owidth int = int(math.Round(float64(width-woffset) * 0.2)) - dwidth int = int(math.Round(float64(width-woffset) * 0.25)) - swidth int = int(math.Round(float64(width-woffset) * 0.12)) - cwidth int = int(math.Round(float64(width-woffset) * 0.03)) - theight int = min(height-hoffset, len(is)) - - m = model{ - keys: defaultKeyMap(), - readonly: readonly, - termheight: height, - mode: mode, - selected: map[int]bool{}, - } - ) - slices.SortStableFunc(is, trash.SortByTrashedReverse) - - rows := []table.Row{} - for j, i := range is { - var t, b string - t = humanize.Time(i.Trashed()) - if i.IsDir() { - b = strings.Repeat("─", 3) - } else { - b = humanize.Bytes(uint64(i.Filesize())) - } - r := table.Row{ - dirs.UnEscape(i.Name()), - dirs.UnExpand(filepath.Dir(i.OGPath()), ""), - t, - b, - } - - if !m.readonly { - r = append(r, getCheck(preselected)) - } - if preselected { - m.selected[j] = true - } - rows = append(rows, r) - } - - columns := []table.Column{ - {Title: "filename", Width: fwidth}, - {Title: "original path", Width: owidth}, - {Title: "deleted", Width: dwidth}, - {Title: "size", Width: swidth}, - } - if !m.readonly { - columns = append(columns, table.Column{Title: uncheck, Width: cwidth}) - } else { - columns[0].Width += cwidth - } - - m.table = createTable(columns, rows, theight, m.readonlyOnePage()) - - return m -} - -func newFilesModel(fs files.Files, width, height int, readonly, preselected bool, workdir string) model { +func newModel(fs []files.File, width, height int, readonly, preselected bool, workdir string, mode modes.Mode) model { var ( fwidth int = int(math.Round(float64(width-woffset) * 0.4)) owidth int = int(math.Round(float64(width-woffset) * 0.2)) @@ -131,40 +72,18 @@ func newFilesModel(fs files.Files, width, height int, readonly, preselected bool theight int = min(height-hoffset, len(fs)) m = model{ - keys: defaultKeyMap(), - readonly: readonly, - mode: modes.Trashing, - selected: map[int]bool{}, - subtitle: workdir, + keys: defaultKeyMap(), + readonly: readonly, + preselected: preselected, + termheight: height, + mode: mode, + selected: map[int]bool{}, + workdir: workdir, + files: fs, } ) - slices.SortStableFunc(fs, files.SortByModifiedReverse) - - rows := []table.Row{} - for j, f := range fs { - var t, b string - t = humanize.Time(f.Modified()) - if f.IsDir() { - b = strings.Repeat("─", 3) - } else { - b = humanize.Bytes(uint64(f.Filesize())) - } - r := table.Row{ - dirs.UnEscape(f.Name()), - dirs.UnExpand(f.Path(), workdir), - t, - b, - } - - if !m.readonly { - r = append(r, getCheck(preselected)) - } - if preselected { - m.selected[j] = true - } - rows = append(rows, r) - } + rows := m.makeRows() columns := []table.Column{ {Title: "filename", Width: fwidth}, @@ -180,6 +99,9 @@ func newFilesModel(fs files.Files, width, height int, readonly, preselected bool m.table = createTable(columns, rows, theight, m.readonlyOnePage()) + m.sorting = sorting.Size + m.sort() + return m } @@ -191,6 +113,8 @@ type keyMap struct { invr key.Binding rstr key.Binding clen key.Binding + sort key.Binding + rort key.Binding quit key.Binding } @@ -224,6 +148,14 @@ func defaultKeyMap() keyMap { key.WithKeys("r"), key.WithHelp("r", "restore"), ), + sort: key.NewBinding( + key.WithKeys("s"), + key.WithHelp("s", "sort"), + ), + rort: key.NewBinding( + key.WithKeys("S"), + key.WithHelp("S", "change sort (reverse)"), + ), quit: key.NewBinding( key.WithKeys("q", "ctrl+c"), key.WithHelp("q", "quit"), @@ -266,6 +198,16 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.mode = modes.Restoring return m.quit(false) } + case key.Matches(msg, m.keys.sort): + // if !m.readonly { + m.sorting = m.sorting.Next() + m.sort() + // } + case key.Matches(msg, m.keys.rort): + // if !m.readonly { + m.sorting = m.sorting.Prev() + m.sort() + // } case key.Matches(msg, m.keys.quit): return m.quit(true) } @@ -305,6 +247,7 @@ func (m model) readonlyOnePage() bool { func (m model) showHelp() string { // TODO: maybe use bubbletea built in help var keys []string = []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)), } if !m.readonly { @@ -341,8 +284,8 @@ func (m model) header() string { mode = strings.Join(keys, wide_dot) default: mode = m.mode.String() - if m.subtitle != "" { - mode += fmt.Sprintf(" in %s ", dirs.UnExpand(m.subtitle, "")) + if m.workdir != "" { + mode += fmt.Sprintf(" in %s ", dirs.UnExpand(m.workdir, "")) } } mode += fmt.Sprintf(" %s %s", dot, strings.Join(select_keys, wide_dot)) @@ -364,6 +307,33 @@ func (m model) quit(unselect_all bool) (model, tea.Cmd) { return m, tea.Quit } +func (m *model) makeRows() (rows []table.Row) { + for j, f := range m.files { + var t, b string + t = humanize.Time(f.Date()) + if f.IsDir() { + b = strings.Repeat("─", 3) + } else { + b = humanize.Bytes(uint64(f.Filesize())) + } + r := table.Row{ + dirs.UnEscape(f.Name()), + dirs.UnExpand(filepath.Dir(f.Path()), m.workdir), + t, + b, + } + + if !m.readonly { + r = append(r, getCheck(m.preselected)) + } + if m.preselected { + m.selected[j] = true + } + rows = append(rows, r) + } + return +} + func (m *model) onlySelected() { var rows = make([]table.Row, 0) for _, row := range m.table.Rows() { @@ -478,8 +448,13 @@ func (m *model) invertSelection() { m.table.SetRows(newrows) } -func InfoTable(is trash.Infos, width, height int, readonly, preselected bool, mode modes.Mode) ([]int, modes.Mode, error) { - if endmodel, err := tea.NewProgram(newInfosModel(is, width, height, readonly, preselected, mode)).Run(); err != nil { +func (m *model) sort() { + slices.SortStableFunc(m.files, m.sorting.Sorter()) + m.table.SetRows(m.makeRows()) +} + +func Show(fs []files.File, width, height int, readonly, preselected bool, workdir string, mode modes.Mode) ([]int, modes.Mode, error) { + if endmodel, err := tea.NewProgram(newModel(fs, width, height, readonly, preselected, workdir, mode)).Run(); err != nil { return []int{}, 0, err } else { m, ok := endmodel.(model) @@ -496,24 +471,6 @@ func InfoTable(is trash.Infos, width, height int, readonly, preselected bool, mo } } -func FilesTable(fs files.Files, width, height int, readonly, preselected bool, workdir string) ([]int, error) { - if endmodel, err := tea.NewProgram(newFilesModel(fs, width, height, readonly, preselected, workdir)).Run(); err != nil { - return []int{}, err - } else { - m, ok := endmodel.(model) - if ok { - selected := make([]int, 0, len(m.selected)) - for k := range m.selected { - selected = append(selected, k) - } - - return selected, nil - } else { - return []int{}, fmt.Errorf("model isn't the right type??") - } - } -} - func getCheck(selected bool) (ourcheck string) { if selected { ourcheck = check diff --git a/main.go b/main.go index f2a1ced..5647f92 100644 --- a/main.go +++ b/main.go @@ -10,10 +10,9 @@ import ( "git.burning.moe/celediel/gt/internal/files" "git.burning.moe/celediel/gt/internal/filter" - "git.burning.moe/celediel/gt/internal/modes" "git.burning.moe/celediel/gt/internal/prompt" "git.burning.moe/celediel/gt/internal/tables" - "git.burning.moe/celediel/gt/internal/trash" + "git.burning.moe/celediel/gt/internal/tables/modes" "github.com/adrg/xdg" "github.com/charmbracelet/log" @@ -101,7 +100,7 @@ var ( if len(ctx.Args().Slice()) != 0 { var files_to_trash files.Files for _, arg := range ctx.Args().Slice() { - file, e := files.New(arg) + file, e := files.NewDisk(arg) if e != nil { log.Fatalf("cannot trash '%s': No such file or directory", arg) } @@ -144,7 +143,7 @@ var ( var files_to_trash files.Files var selectall bool for _, arg := range ctx.Args().Slice() { - file, e := files.New(arg) + file, e := files.NewDisk(arg) if e != nil { log.Debugf("%s wasn't really a file", arg) f.AddFileName(arg) @@ -156,7 +155,7 @@ var ( // if none of the args were files, then process find files based on filter if len(files_to_trash) == 0 { - fls, err := files.Find(workdir, recursive, f) + fls, err := files.FindDisk(workdir, recursive, f) if err != nil { return err } @@ -168,8 +167,7 @@ var ( selectall = !f.Blank() } - log.Debugf("what is workdir? it's %s", workdir) - indices, err := tables.FilesTable(files_to_trash, termwidth, termheight, false, selectall, workdir) + indices, _, err := tables.Show(files_to_trash, termwidth, termheight, false, selectall, workdir, modes.Trashing) if err != nil { return err } @@ -197,7 +195,8 @@ var ( log.Debugf("searching in directory %s for files", trashDir) // look for files - fls, err := trash.FindFiles(trashDir, ogdir, f) + // fls, err := trash.FindFiles(trashDir, ogdir, f) + fls, err := files.FindTrash(trashDir, ogdir, f) var msg string log.Debugf("filter '%s' is blark? %t in %s", f, f.Blank(), ogdir) @@ -215,7 +214,7 @@ var ( } // display them - _, _, err = tables.InfoTable(fls, termwidth, termheight, true, false, modes.Listing) + _, _, err = tables.Show(fls, termwidth, termheight, true, false, workdir, modes.Listing) return err }, @@ -231,7 +230,7 @@ var ( log.Debugf("searching in directory %s for files", trashDir) // look for files - fls, err := trash.FindFiles(trashDir, ogdir, f) + fls, err := files.FindTrash(trashDir, ogdir, f) if len(fls) == 0 { fmt.Println("no files to restore") return nil @@ -239,12 +238,12 @@ var ( return err } - indices, _, err := tables.InfoTable(fls, termwidth, termheight, false, !f.Blank(), modes.Restoring) + indices, _, err := tables.Show(fls, termwidth, termheight, false, !f.Blank(), workdir, modes.Restoring) if err != nil { return err } - var selected trash.Infos + var selected files.Files for _, i := range indices { selected = append(selected, fls[i]) } @@ -264,7 +263,7 @@ var ( Flags: slices.Concat(alreadyintrashFlags, filterFlags), Before: beforeCommands, Action: func(ctx *cli.Context) error { - fls, err := trash.FindFiles(trashDir, ogdir, f) + fls, err := files.FindTrash(trashDir, ogdir, f) if len(fls) == 0 { fmt.Println("no files to clean") return nil @@ -272,12 +271,12 @@ var ( return err } - indices, _, err := tables.InfoTable(fls, termwidth, termheight, false, !f.Blank(), modes.Cleaning) + indices, _, err := tables.Show(fls, termwidth, termheight, false, !f.Blank(), workdir, modes.Cleaning) if err != nil { return err } - var selected trash.Infos + var selected files.Files for _, i := range indices { selected = append(selected, fls[i]) } @@ -434,13 +433,13 @@ func main() { func interactiveMode() error { var ( - fls trash.Infos + fls files.Files indicies []int mode modes.Mode err error ) - fls, err = trash.FindFiles(trashDir, ogdir, f) + fls, err = files.FindTrash(trashDir, ogdir, f) if err != nil { return err } @@ -456,12 +455,12 @@ func interactiveMode() error { return nil } - indicies, mode, err = tables.InfoTable(fls, termwidth, termheight, false, false, modes.Interactive) + indicies, mode, err = tables.Show(fls, termwidth, termheight, false, false, workdir, modes.Interactive) if err != nil { return err } - var selected trash.Infos + var selected files.Files for _, i := range indicies { selected = append(selected, fls[i]) } @@ -489,10 +488,10 @@ func interactiveMode() error { return nil } -func confirmRestore(is trash.Infos) error { - if !askconfirm || prompt.YesNo(fmt.Sprintf("restore %d selected files?", len(is))) { +func confirmRestore(fs files.Files) error { + if !askconfirm || prompt.YesNo(fmt.Sprintf("restore %d selected files?", len(fs))) { log.Info("doing the thing") - restored, err := trash.Restore(is) + restored, err := files.Restore(fs) if err != nil { return fmt.Errorf("restored %d files before error %s", restored, err) } @@ -503,11 +502,11 @@ func confirmRestore(is trash.Infos) error { return nil } -func confirmClean(is trash.Infos) error { - if prompt.YesNo(fmt.Sprintf("remove %d selected files permanently from the trash?", len(is))) && - (!askconfirm || prompt.YesNo(fmt.Sprintf("really remove all these %d selected files permanently from the trash forever??", len(is)))) { +func confirmClean(fs files.Files) error { + if prompt.YesNo(fmt.Sprintf("remove %d selected files permanently from the trash?", len(fs))) && + (!askconfirm || 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 := trash.Remove(is) + removed, err := files.Remove(fs) if err != nil { return fmt.Errorf("removed %d files before error %s", removed, err) } @@ -522,11 +521,11 @@ func confirmTrash(fs files.Files) error { if !askconfirm || prompt.YesNo(fmt.Sprintf("trash %d selected files?", len(fs))) { tfs := make([]string, 0, len(fs)) for _, file := range fs { - log.Debugf("gonna trash %s", file.Filename()) - tfs = append(tfs, file.Filename()) + log.Debugf("gonna trash %s", file.Path()) + tfs = append(tfs, file.Path()) } - trashed, err := trash.TrashFiles(trashDir, tfs...) + trashed, err := files.TrashFiles(trashDir, tfs...) if err != nil { return err }