sorting preserves selection state

This commit is contained in:
Lilian Jónsdóttir 2024-07-15 15:32:33 -07:00
parent de81cfbfed
commit 0e147e283b
5 changed files with 108 additions and 115 deletions

View file

@ -1,6 +1,7 @@
package files
import (
"fmt"
"io/fs"
"os"
"path/filepath"
@ -31,6 +32,10 @@ func (f DiskFile) Filesize() int64 {
return f.filesize
}
func (f DiskFile) String() string {
return fmt.Sprintf(string_format, f.name, f.path, f.modified.Format(time.UnixDate), f.filesize, f.isdir)
}
func NewDisk(path string) (DiskFile, error) {
info, err := os.Stat(path)
if err != nil {

View file

@ -6,12 +6,15 @@ import (
"time"
)
const string_format = "%s %s %s %d %t"
type File interface {
Name() string
Path() string
Date() time.Time
Filesize() int64
IsDir() bool
String() string
}
type Files []File

View file

@ -54,6 +54,10 @@ func (t TrashInfo) Filesize() int64 {
return t.filesize
}
func (t TrashInfo) String() string {
return fmt.Sprintf(string_format, t.name, t.path, t.trashed.Format(time.UnixDate), t.filesize, t.isdir)
}
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 {

View file

@ -52,9 +52,8 @@ var (
type model struct {
table table.Model
keys keyMap
selected map[int]bool
selected map[string]bool
readonly bool
preselected bool
termheight int
mode modes.Mode
sorting sorting.Sorting
@ -74,16 +73,15 @@ func newModel(fs []files.File, width, height int, readonly, preselected bool, wo
m = model{
keys: defaultKeyMap(),
readonly: readonly,
preselected: preselected,
termheight: height,
mode: mode,
selected: map[int]bool{},
selected: map[string]bool{},
workdir: workdir,
files: fs,
}
)
rows := m.makeRows()
rows := m.freshRows(preselected)
columns := []table.Column{
{Title: "filename", Width: fwidth},
@ -97,7 +95,7 @@ func newModel(fs []files.File, width, height int, readonly, preselected bool, wo
columns[0].Width += cwidth
}
m.table = createTable(columns, rows, theight, m.readonlyOnePage())
m.table = createTable(columns, rows, theight)
m.sorting = sorting.Name
m.sort()
@ -164,9 +162,6 @@ func defaultKeyMap() keyMap {
}
func (m model) Init() tea.Cmd {
if m.readonlyOnePage() {
return tea.Quit
}
return nil
}
@ -199,15 +194,11 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
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)
}
@ -226,11 +217,7 @@ func (m model) View() (out string) {
}
)
if m.readonlyOnePage() {
n = "\n"
} else {
panels = append(panels, m.footer())
}
if m.mode != modes.Listing {
panels = append([]string{m.header()}, panels...)
@ -240,10 +227,6 @@ func (m model) View() (out string) {
return out + n
}
func (m model) readonlyOnePage() bool {
return m.readonly && m.termheight > m.table.Height()
}
func (m model) showHelp() string {
// TODO: maybe use bubbletea built in help
var keys []string = []string{
@ -307,27 +290,40 @@ 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 {
func (m model) selectedFiles() (outfile files.Files) {
for _, file := range m.files {
if m.selected[file.String()] {
outfile = append(outfile, file)
}
}
return
}
func newRow(file files.File, workdir string) table.Row {
var t, b string
t = humanize.Time(f.Date())
if f.IsDir() {
t = humanize.Time(file.Date())
if file.IsDir() {
b = strings.Repeat("─", 3)
} else {
b = humanize.Bytes(uint64(f.Filesize()))
b = humanize.Bytes(uint64(file.Filesize()))
}
r := table.Row{
dirs.UnEscape(f.Name()),
dirs.UnExpand(filepath.Dir(f.Path()), m.workdir),
return table.Row{
dirs.UnEscape(file.Name()),
dirs.UnExpand(filepath.Dir(file.Path()), workdir),
t,
b,
}
}
func (m *model) freshRows(preselected bool) (rows []table.Row) {
for _, f := range m.files {
r := newRow(f, m.workdir)
if !m.readonly {
r = append(r, getCheck(m.preselected))
r = append(r, getCheck(preselected))
}
if m.preselected {
m.selected[j] = true
if preselected {
m.selected[f.String()] = true
}
rows = append(rows, r)
}
@ -377,20 +373,21 @@ func (m *model) updateRows(selected bool) {
m.table.SetRows(newrows)
}
// toggleItem toggles an item's selected state, and returns the state
func (m *model) toggleItem(index int) (selected bool) {
if m.readonly {
return false
}
name := m.files[index].String()
// select the thing
if v, ok := m.selected[index]; v && ok {
if v, ok := m.selected[name]; v && ok {
// already selected
delete(m.selected, index)
delete(m.selected, name)
selected = false
} else {
// not selected
m.selected[index] = true
m.selected[name] = true
selected = true
}
@ -404,9 +401,9 @@ func (m *model) selectAll() {
return
}
m.selected = map[int]bool{}
m.selected = map[string]bool{}
for i := range len(m.table.Rows()) {
m.selected[i] = true
m.selected[m.files[i].String()] = true
}
m.updateRows(true)
}
@ -416,16 +413,21 @@ func (m *model) unselectAll() {
return
}
m.selected = map[int]bool{}
m.selected = map[string]bool{}
m.updateRows(false)
}
func (m *model) invertSelection() {
if m.readonly {
return
}
var newrows []table.Row
for index, row := range m.table.Rows() {
if v, ok := m.selected[index]; v && ok {
delete(m.selected, index)
name := m.files[index].String()
if v, ok := m.selected[name]; v && ok {
delete(m.selected, name)
newrows = append(newrows, table.Row{
row[0],
row[1],
@ -434,7 +436,7 @@ func (m *model) invertSelection() {
getCheck(false),
})
} else {
m.selected[index] = true
m.selected[name] = true
newrows = append(newrows, table.Row{
row[0],
row[1],
@ -450,25 +452,29 @@ func (m *model) invertSelection() {
func (m *model) sort() {
slices.SortStableFunc(m.files, m.sorting.Sorter())
m.table.SetRows(m.makeRows())
var rows []table.Row
for _, file := range m.files {
r := newRow(file, m.workdir)
if !m.readonly {
r = append(r, getCheck(m.selected[file.String()]))
}
rows = append(rows, r)
}
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.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) {
mdl := newModel(fs, width, height, readonly, preselected, once, workdir, mode)
endmodel, err := tea.NewProgram(mdl).Run()
if err != nil {
return fs, 0, err
}
m, ok := endmodel.(model)
if ok {
selected := make([]int, 0, len(m.selected))
for k := range m.selected {
selected = append(selected, k)
}
return selected, m.mode, nil
} else {
return []int{}, 0, fmt.Errorf("model isn't the right type??")
}
if !ok {
return fs, 0, fmt.Errorf("model isn't the right type?? what has happened")
}
return m.selectedFiles(), m.mode, nil
}
func getCheck(selected bool) (ourcheck string) {
@ -480,7 +486,7 @@ func getCheck(selected bool) (ourcheck string) {
return
}
func createTable(columns []table.Column, rows []table.Row, height int, readonlyonepage bool) table.Model {
func createTable(columns []table.Column, rows []table.Row, height int) table.Model {
t := table.New(
table.WithColumns(columns),
table.WithRows(rows),
@ -488,11 +494,7 @@ func createTable(columns []table.Column, rows []table.Row, height int, readonlyo
table.WithHeight(height),
)
t.KeyMap = fixTableKeymap()
if readonlyonepage {
t.SetStyles(makeUnselectedStyle())
} else {
t.SetStyles(makeStyle())
}
return t
}

39
main.go
View file

@ -167,16 +167,11 @@ var (
selectall = !f.Blank()
}
indices, _, err := tables.Show(files_to_trash, termwidth, termheight, false, selectall, workdir, modes.Trashing)
selected, _, err := tables.Select(files_to_trash, termwidth, termheight, false, selectall, false, workdir, modes.Trashing)
if err != nil {
return err
}
var selected files.Files
for _, i := range indices {
selected = append(selected, files_to_trash[i])
}
if len(selected) <= 0 {
return nil
}
@ -195,7 +190,6 @@ 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)
var msg string
@ -214,7 +208,7 @@ var (
}
// display them
_, _, err = tables.Show(fls, termwidth, termheight, true, false, workdir, modes.Listing)
_, _, err = tables.Select(fls, termwidth, termheight, true, false, ni, workdir, modes.Listing)
return err
},
@ -238,16 +232,11 @@ var (
return err
}
indices, _, err := tables.Show(fls, termwidth, termheight, false, !f.Blank(), workdir, modes.Restoring)
selected, _, err := tables.Select(fls, termwidth, termheight, false, !f.Blank(), ni, workdir, modes.Restoring)
if err != nil {
return err
}
var selected files.Files
for _, i := range indices {
selected = append(selected, fls[i])
}
if len(selected) <= 0 {
return nil
}
@ -271,16 +260,11 @@ var (
return err
}
indices, _, err := tables.Show(fls, termwidth, termheight, false, !f.Blank(), workdir, modes.Cleaning)
selected, _, err := tables.Select(fls, termwidth, termheight, false, !f.Blank(), ni, workdir, modes.Cleaning)
if err != nil {
return err
}
var selected files.Files
for _, i := range indices {
selected = append(selected, fls[i])
}
if len(selected) <= 0 {
return nil
}
@ -433,18 +417,18 @@ func main() {
func interactiveMode() error {
var (
fls files.Files
indicies []int
infiles files.Files
selected files.Files
mode modes.Mode
err error
)
fls, err = files.FindTrash(trashDir, ogdir, f)
infiles, err = files.FindTrash(trashDir, ogdir, f)
if err != nil {
return err
}
if len(fls) <= 0 {
if len(infiles) <= 0 {
var msg string
if f.Blank() {
msg = "trash is empty"
@ -455,16 +439,11 @@ func interactiveMode() error {
return nil
}
indicies, mode, err = tables.Show(fls, termwidth, termheight, false, false, workdir, modes.Interactive)
selected, mode, err = tables.Select(infiles, termwidth, termheight, false, false, false, workdir, modes.Interactive)
if err != nil {
return err
}
var selected files.Files
for _, i := range indicies {
selected = append(selected, fls[i])
}
switch mode {
case modes.Cleaning:
for _, file := range selected {