Skip to content

Commit 8e0b55f

Browse files
committed
feat: Add Bubble Tea TUI for interactive selection
- Add internal/tui/tui.go with full-screen interactive UI - Arrow key navigation, spacebar toggle, enter to clean - Styled with lipgloss - colored type badges, progress indicators - TUI mode enabled by default, --no-tui for simple mode - Add --tui and --no-tui flags to clean command
1 parent 66ff969 commit 8e0b55f

5 files changed

Lines changed: 418 additions & 12 deletions

File tree

cmd/root/clean.go

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/spf13/cobra"
1111
"github.com/thanhdevapp/dev-cleaner/internal/cleaner"
1212
"github.com/thanhdevapp/dev-cleaner/internal/scanner"
13+
"github.com/thanhdevapp/dev-cleaner/internal/tui"
1314
"github.com/thanhdevapp/dev-cleaner/internal/ui"
1415
"github.com/thanhdevapp/dev-cleaner/pkg/types"
1516
)
@@ -20,6 +21,7 @@ var (
2021
cleanIOS bool
2122
cleanAndroid bool
2223
cleanNode bool
24+
useTUI bool
2325
)
2426

2527
// cleanCmd represents the clean command
@@ -28,14 +30,14 @@ var cleanCmd = &cobra.Command{
2830
Short: "Clean development artifacts",
2931
Long: `Interactively select and clean development artifacts.
3032
31-
By default, runs in dry-run mode (preview only).
32-
Use --confirm to actually delete files.
33+
By default, runs in TUI mode with interactive selection.
34+
Use --confirm to actually delete files (default is dry-run).
3335
3436
Examples:
35-
dev-cleaner clean # Interactive selection (dry-run)
36-
dev-cleaner clean --confirm # Actually delete selected items
37-
dev-cleaner clean --ios # Clean iOS artifacts only
38-
dev-cleaner clean --dry-run # Preview what would be deleted`,
37+
dev-cleaner clean # Interactive TUI (dry-run)
38+
dev-cleaner clean --confirm # Interactive TUI (actually delete)
39+
dev-cleaner clean --no-tui # Simple text mode
40+
dev-cleaner clean --ios # Clean iOS artifacts only`,
3941
Run: runClean,
4042
}
4143

@@ -47,6 +49,8 @@ func init() {
4749
cleanCmd.Flags().BoolVar(&cleanIOS, "ios", false, "Clean iOS/Xcode artifacts only")
4850
cleanCmd.Flags().BoolVar(&cleanAndroid, "android", false, "Clean Android/Gradle artifacts only")
4951
cleanCmd.Flags().BoolVar(&cleanNode, "node", false, "Clean Node.js artifacts only")
52+
cleanCmd.Flags().BoolVar(&useTUI, "tui", true, "Use interactive TUI mode (default)")
53+
cleanCmd.Flags().BoolP("no-tui", "T", false, "Disable TUI, use simple text mode")
5054
}
5155

5256
func runClean(cmd *cobra.Command, args []string) {
@@ -55,6 +59,12 @@ func runClean(cmd *cobra.Command, args []string) {
5559
dryRun = false
5660
}
5761

62+
// Check for --no-tui flag
63+
noTUI, _ := cmd.Flags().GetBool("no-tui")
64+
if noTUI {
65+
useTUI = false
66+
}
67+
5868
s, err := scanner.New()
5969
if err != nil {
6070
fmt.Fprintf(os.Stderr, "Error initializing scanner: %v\n", err)
@@ -92,6 +102,18 @@ func runClean(cmd *cobra.Command, args []string) {
92102
// Sort by size
93103
sortBySize(results)
94104

105+
// Use TUI or simple mode
106+
if useTUI {
107+
if err := tui.Run(results, dryRun); err != nil {
108+
fmt.Fprintf(os.Stderr, "TUI error: %v\n", err)
109+
os.Exit(1)
110+
}
111+
} else {
112+
runSimpleMode(results)
113+
}
114+
}
115+
116+
func runSimpleMode(results []types.ScanResult) {
95117
// Print results with enhanced UI
96118
ui.PrintResults(results)
97119
ui.PrintSummary(results)

dev-cleaner

250 KB
Binary file not shown.

go.mod

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,30 @@ module github.com/thanhdevapp/dev-cleaner
33
go 1.25.5
44

55
require (
6+
github.com/charmbracelet/bubbles v0.21.0
7+
github.com/charmbracelet/bubbletea v1.3.10
68
github.com/charmbracelet/lipgloss v1.1.0
79
github.com/spf13/cobra v1.10.2
810
)
911

1012
require (
1113
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
1214
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
13-
github.com/charmbracelet/x/ansi v0.8.0 // indirect
15+
github.com/charmbracelet/x/ansi v0.10.1 // indirect
1416
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
1517
github.com/charmbracelet/x/term v0.2.1 // indirect
18+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
1619
github.com/inconshreveable/mousetrap v1.1.0 // indirect
1720
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
1821
github.com/mattn/go-isatty v0.0.20 // indirect
22+
github.com/mattn/go-localereader v0.0.1 // indirect
1923
github.com/mattn/go-runewidth v0.0.16 // indirect
24+
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
25+
github.com/muesli/cancelreader v0.2.2 // indirect
2026
github.com/muesli/termenv v0.16.0 // indirect
2127
github.com/rivo/uniseg v0.4.7 // indirect
2228
github.com/spf13/pflag v1.0.9 // indirect
2329
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
24-
golang.org/x/sys v0.30.0 // indirect
30+
golang.org/x/sys v0.36.0 // indirect
31+
golang.org/x/text v0.3.8 // indirect
2532
)

go.sum

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,36 @@
11
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
22
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
3+
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
4+
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
5+
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
6+
github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
37
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
48
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
59
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
610
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
7-
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
8-
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
11+
github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ=
12+
github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
913
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
1014
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
1115
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
1216
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
1317
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
18+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
19+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
1420
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
1521
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
1622
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
1723
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
1824
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
1925
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
26+
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
27+
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
2028
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
2129
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
30+
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
31+
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
32+
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
33+
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
2234
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
2335
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
2436
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
@@ -34,7 +46,10 @@ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJu
3446
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
3547
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
3648
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
49+
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
3750
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
38-
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
39-
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
51+
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
52+
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
53+
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
54+
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
4055
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

0 commit comments

Comments
 (0)