// SPDX-License-Identifier: GPL-3.0-or-later package model import ( "sort" "strings" ) // The orders a plan can be read in. "default" is the order krino planned // the directory in, which is the order the files were scanned; the rest are // what a column is worth sorting by (his request, 2026-09-17). const ( SortDefault = "default" SortName = "name" SortSize = "size" SortAge = "age" SortAction = "action" SortRule = "rule" ) // SortOrders are the choices, in the order they are offered. var SortOrders = []string{SortDefault, SortName, SortSize, SortAge, SortAction, SortRule} // SortLabels say which way each order runs, for the picker and its help. var SortLabels = map[string]string{ SortDefault: "as scanned", SortName: "name, A to Z", SortSize: "size, largest first", SortAge: "age, oldest first", SortAction: "action, A to Z", SortRule: "rule, A to Z", } // IsSortOrder reports whether s names one of them. func IsSortOrder(s string) bool { for _, o := range SortOrders { if o == s { return true } } return false } // Sorted puts the rows named by shown in the order asked for, leaving the // plan itself alone: only the reading order changes. Ties keep the plan's // own order, so the list never shuffles between two files that compare the // same. func (t *PlanTab) Sorted(shown []int, by string) []int { out := append([]int(nil), shown...) if by == SortDefault || by == "" || !IsSortOrder(by) { return out } less := func(a, b int) bool { x, y := t.Rows[a], t.Rows[b] switch by { case SortName: return strings.ToLower(x.Rel) < strings.ToLower(y.Rel) case SortSize: return x.Size > y.Size case SortAge: // Oldest first: the files an (age > ...) rule is about. return x.ModTime.Before(y.ModTime) case SortAction: return firstAction(x) < firstAction(y) case SortRule: return strings.ToLower(x.Rule) < strings.ToLower(y.Rule) } return false } sort.SliceStable(out, func(i, j int) bool { return less(out[i], out[j]) }) return out } // firstAction is what a row does, for sorting; a row that does nothing // sorts after the ones that do. func firstAction(r Row) string { for _, s := range r.Steps { if s.Skip == "" { return s.Kind.String() } } return "~" }