diff options
Diffstat (limited to 'gui/internal/model/plan.go')
| -rw-r--r-- | gui/internal/model/plan.go | 37 |
1 files changed, 35 insertions, 2 deletions
diff --git a/gui/internal/model/plan.go b/gui/internal/model/plan.go index 6d3e857..51a86d8 100644 --- a/gui/internal/model/plan.go +++ b/gui/internal/model/plan.go @@ -9,16 +9,20 @@ import ( "context" "fmt" "sort" + "time" "krino/internal/engine" "krino/internal/lock" "krino/internal/plan" + "krino/internal/scan" ) // Row is one line of the Plan tab: a file krino would act on, or one it // could not decide about. type Row struct { Rel string // the file, relative to the directory's root + Size int64 + ModTime time.Time Steps []plan.Step Rule string // the rule that matched first, for the Rule column Warnings []string @@ -104,8 +108,10 @@ func (t *PlanTab) fill() { r := t.dp.Result t.Warnings = append([]string(nil), r.Warnings...) warnings := map[string][]string{} + files := map[string]scan.File{} for _, fms := range [][]engine.FileMatch{r.Matched, r.Unmatched} { for _, fm := range fms { + files[fm.File.Rel] = fm.File if len(fm.Warnings) > 0 { warnings[fm.File.Rel] = fm.Warnings } @@ -119,7 +125,8 @@ func (t *PlanTab) fill() { } t.Rows = nil for _, c := range t.dp.Chains { - row := Row{Rel: c.File.Rel, Steps: c.Steps, Warnings: warnings[c.File.Rel]} + row := Row{Rel: c.File.Rel, Size: c.File.Size, ModTime: c.File.ModTime, + Steps: c.Steps, Warnings: warnings[c.File.Rel]} for _, s := range c.Steps { if s.Skip == "" { row.Actable = true @@ -142,7 +149,9 @@ func (t *PlanTab) fill() { } sort.Strings(rest) for _, rel := range rest { - t.Rows = append(t.Rows, Row{Rel: rel, Warnings: warnings[rel]}) + f := files[rel] + t.Rows = append(t.Rows, Row{Rel: rel, Size: f.Size, ModTime: f.ModTime, + Warnings: warnings[rel]}) } t.Counts = Counts{ Scanned: len(r.Matched) + len(r.Unmatched) + len(r.Skipped), @@ -280,3 +289,27 @@ func (t *PlanTab) record(res *engine.ApplyResult) { } } } + +// AgeText is how long ago a file was last written, in the units krino's own +// (age ...) test uses: minutes, hours, days and weeks, and years past that, +// so a plan can be read at a glance (his request, 2026-09-17). +func AgeText(mod time.Time, now time.Time) string { + if mod.IsZero() { + return "" + } + d := now.Sub(mod) + if d < 0 { + return "0m" // a file dated in the future is not aged + } + switch { + case d < time.Hour: + return fmt.Sprintf("%dm", int(d.Minutes())) + case d < 24*time.Hour: + return fmt.Sprintf("%dh", int(d.Hours())) + case d < 7*24*time.Hour: + return fmt.Sprintf("%dd", int(d.Hours()/24)) + case d < 52*7*24*time.Hour: + return fmt.Sprintf("%dw", int(d.Hours()/(24*7))) + } + return fmt.Sprintf("%dy", int(d.Hours()/(24*365))) +} |
