-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprogram.go
More file actions
113 lines (102 loc) · 2.56 KB
/
Copy pathprogram.go
File metadata and controls
113 lines (102 loc) · 2.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package main
import (
"fmt"
tea "github.com/charmbracelet/bubbletea"
"github.com/gor3a/disk-scan/internal/rules"
"github.com/gor3a/disk-scan/internal/tui"
)
// stage is which screen the TUI is showing.
type stage int
const (
stageList stage = iota // browse + toggle items
stageConfirm // confirm before cleaning
)
type programModel struct {
model *tui.Model
cursor int
stage stage
confirmed bool
}
func newProgram(items []rules.Item) *programModel {
return &programModel{model: tui.New(items)}
}
func (m *programModel) Init() tea.Cmd { return nil }
func (m *programModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
key, ok := msg.(tea.KeyMsg)
if !ok {
return m, nil
}
if key.String() == "ctrl+c" {
return m, tea.Quit // always cancel, never confirm
}
if m.stage == stageConfirm {
switch key.String() {
case "enter", "y":
m.confirmed = true
return m, tea.Quit
case "q", "esc", "n":
m.stage = stageList // back to the list, nothing cleaned
}
return m, nil
}
// stageList
switch key.String() {
case "q":
return m, tea.Quit
case "up", "k":
if m.cursor > 0 {
m.cursor--
}
case "down", "j":
if m.cursor < len(m.model.Items())-1 {
m.cursor++
}
case " ":
m.model.Toggle(m.cursor)
case "enter":
m.stage = stageConfirm // gate: confirm before cleaning
}
return m, nil
}
func (m *programModel) View() string {
if m.stage == stageConfirm {
return m.confirmView()
}
out := fmt.Sprintf("dscan — space to toggle, enter to review, q to quit\nSELECTED: %s\n\n", humized(m.model.SelectedBytes()))
for i, it := range m.model.Items() {
cursor := " "
if i == m.cursor {
cursor = "> "
}
check := "[ ]"
switch {
case !it.Selectable():
check = "[-]"
case m.model.IsSelected(i):
check = "[x]"
}
out += fmt.Sprintf("%s%s %-32s %10s %s\n", cursor, check, it.Label, humized(it.Bytes), it.Tier)
}
return out
}
// confirmView summarizes what will happen before any deletion.
func (m *programModel) confirmView() string {
sel := m.model.Selected()
var rm, tr, run int
for _, it := range sel {
switch it.EffectiveMethod() {
case rules.Trash:
tr++
case rules.Command:
run++
default:
rm++
}
}
out := fmt.Sprintf("Clean %d item(s), freeing %s?\n\n", len(sel), humized(m.model.SelectedBytes()))
out += fmt.Sprintf(" %d delete (caches/build — removed directly)\n", rm)
out += fmt.Sprintf(" %d trash (user data — recoverable from Trash)\n", tr)
out += fmt.Sprintf(" %d tool (run a cleanup command)\n\n", run)
out += "press enter/y to clean · n/q to go back\n"
return out
}