Skip to content

Commit 708a676

Browse files
committed
chore(release): prepare v1.0.1
- Update README with improved documentation - Enhance diagnose functionality - Improve scanner modules (app, browser, enhanced_junk, history, system_data) - Update UI components (styles, main_menu, disk_trend, system_junk_enhanced, etc.) - Add theme support (new theme.go and custom_theme_example.json) - Fix cleaner and various UI improvements - Update install.sh
1 parent 7edc127 commit 708a676

22 files changed

Lines changed: 1241 additions & 179 deletions

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,50 @@ lume -help # Show help
173173
| `p` | Preview files |
174174
| `d` `c` | Clean selected (→ Trash) |
175175
| `r` | Refresh scan |
176+
| `t` | Toggle theme |
176177
| `Esc` | Back |
177178
| `q` | Quit |
178179

180+
### Themes
181+
182+
Lume supports multiple color themes. Press `t` to cycle through themes.
183+
184+
**Built-in themes:**
185+
- `modern` (default) — Neon cyberpunk style
186+
- `retro` — Matrix green terminal
187+
- `amber` — Vintage amber monitor
188+
- `ocean` — Deep blue ocean
189+
- `highcontrast` — Accessibility friendly
190+
- `dracula` — Classic Dracula colors
191+
- `solarized` — Solarized Dark
192+
- `monokai` — Code editor style
193+
194+
**Custom theme:**
195+
196+
Create `~/.config/lume/themes/mytheme.json`:
197+
198+
```json
199+
{
200+
"name": "mytheme",
201+
"description": "My custom theme",
202+
"primary": "#ff6b6b",
203+
"secondary": "#4ecdc4",
204+
"accent": "#ffe66d",
205+
"danger": "#ff4757",
206+
"warning": "#ffa502",
207+
"success": "#2ed573",
208+
"foreground": "#f1f2f6",
209+
"gray": "#747d8c",
210+
"light_gray": "#a4b0be",
211+
"dim": "#57606f",
212+
"selected_bg": "#3742fa",
213+
"selected_fg": "#ffffff",
214+
"border": "#70a1ff"
215+
}
216+
```
217+
218+
See [assets/custom_theme_example.json](assets/custom_theme_example.json) for a complete example.
219+
179220
---
180221

181222
## Tech Stack

assets/custom_theme_example.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "mytheme",
3+
"description": "My Custom Theme - 我的自定义主题",
4+
"primary": "#ff6b6b",
5+
"secondary": "#4ecdc4",
6+
"accent": "#ffe66d",
7+
"danger": "#ff4757",
8+
"warning": "#ffa502",
9+
"success": "#2ed573",
10+
"foreground": "#f1f2f6",
11+
"gray": "#747d8c",
12+
"light_gray": "#a4b0be",
13+
"dim": "#57606f",
14+
"selected_bg": "#3742fa",
15+
"selected_fg": "#ffffff",
16+
"border": "#70a1ff"
17+
}

cmd/lume/diagnose.go

Lines changed: 56 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,41 @@ import (
1313
"github.com/Tyooughtul/lume/pkg/scanner"
1414
)
1515

16+
// ANSI color helpers for diagnose output
17+
const (
18+
colorReset = "\033[0m"
19+
colorRed = "\033[31m"
20+
colorGreen = "\033[32m"
21+
colorYellow = "\033[33m"
22+
colorCyan = "\033[36m"
23+
colorDim = "\033[2m"
24+
colorBold = "\033[1m"
25+
)
26+
27+
// sizeTag returns a colored severity indicator for a given size
28+
func sizeTag(size int64, canClean bool) string {
29+
if !canClean {
30+
return colorDim + "[L]" + colorReset
31+
}
32+
if size > 1024*1024*1024 {
33+
return colorRed + colorBold + "[!]" + colorReset
34+
}
35+
if size > 100*1024*1024 {
36+
return colorYellow + "[~]" + colorReset
37+
}
38+
return colorGreen + "[+]" + colorReset
39+
}
40+
1641
func diagnose() {
1742
fmt.Println("╔════════════════════════════════════════════════════════════╗")
1843
fmt.Println("║ Lume - Disk Space Diagnostic Tool ║")
1944
fmt.Println("╚════════════════════════════════════════════════════════════╝")
2045
fmt.Println()
2146

22-
homeDir, _ := os.UserHomeDir()
47+
homeDir := scanner.GetRealHomeDir()
2348

2449
// 1. Quick analysis of main directories
25-
fmt.Println("📊 Analyzing main directories...")
50+
fmt.Println("[*] Analyzing main directories...")
2651
fmt.Println()
2752

2853
keyDirs := []struct {
@@ -71,22 +96,23 @@ func diagnose() {
7196
})
7297

7398
for _, r := range results {
99+
tag := sizeTag(r.size, true)
74100
sizeStr := humanize.Bytes(uint64(r.size))
75-
if r.size > 1024*1024*1024 {
76-
sizeStr = "🔴 " + sizeStr
77-
} else if r.size > 100*1024*1024 {
78-
sizeStr = "🟡 " + sizeStr
79-
} else {
80-
sizeStr = "🟢 " + sizeStr
101+
// pad manually: tag has ANSI codes, so use fixed field for the visible part
102+
visible := fmt.Sprintf("%s %s", tag, sizeStr)
103+
// ANSI codes don't take visual space; right-align within 17 char column
104+
pad := 17 - (3 + 1 + len(sizeStr)) // [!] + space + size
105+
if pad < 0 {
106+
pad = 0
81107
}
82-
fmt.Printf("│ %-39s │ %17s\n", r.name, sizeStr)
108+
fmt.Printf("│ %-39s │ %s%s\n", r.name, strings.Repeat(" ", pad), visible)
83109
}
84110

85111
fmt.Println("└─────────────────────────────────────────┴───────────────────┘")
86112
fmt.Println()
87113

88114
// 2. Detailed scan of junk directories
89-
fmt.Println("🗑 Scanning junk file directories...")
115+
fmt.Println("[*] Scanning junk file directories...")
90116
fmt.Println()
91117

92118
junkScanner := scanner.NewEnhancedJunkScanner()
@@ -134,14 +160,14 @@ func diagnose() {
134160
name = name[:36] + "..."
135161
}
136162

163+
tag := sizeTag(target.Size, true)
137164
sizeStr := humanize.Bytes(uint64(target.Size))
138-
if target.Size > 1024*1024*1024 {
139-
sizeStr = "🔴 " + sizeStr
140-
} else if target.Size > 100*1024*1024 {
141-
sizeStr = "🟡 " + sizeStr
165+
pad := 17 - (3 + 1 + len(sizeStr))
166+
if pad < 0 {
167+
pad = 0
142168
}
143-
144-
fmt.Printf("│ %-39s │ %17s\n", name, sizeStr)
169+
visible := fmt.Sprintf("%s %s", tag, sizeStr)
170+
fmt.Printf("│ %-39s │ %s%s\n", name, strings.Repeat(" ", pad), visible)
145171
}
146172

147173
fmt.Println("└─────────────────────────────────────────┴───────────────────┘")
@@ -154,12 +180,12 @@ func diagnose() {
154180
}
155181

156182
fmt.Println("═════════════════════════════════════════════════════════════")
157-
fmt.Printf("💾 Total reclaimable space: %s\n", humanize.Bytes(uint64(totalJunk)))
183+
fmt.Printf("[Total] Reclaimable space: %s\n", humanize.Bytes(uint64(totalJunk)))
158184
fmt.Println("═════════════════════════════════════════════════════════════")
159185
fmt.Println()
160186

161187
// 4. System Data Analysis
162-
fmt.Println("🔍 Analyzing System Data (hidden space usage)...")
188+
fmt.Println("[*] Analyzing System Data (hidden space usage)...")
163189
fmt.Println()
164190

165191
systemScanner := scanner.NewSystemDataScanner()
@@ -182,31 +208,29 @@ func diagnose() {
182208
name = name[:36] + "..."
183209
}
184210

211+
tag := sizeTag(item.Size, item.CanClean)
185212
sizeStr := humanize.Bytes(uint64(item.Size))
186-
if !item.CanClean {
187-
sizeStr = "🔒 " + sizeStr
188-
} else if item.Size > 1024*1024*1024 {
189-
sizeStr = "🔴 " + sizeStr
190-
} else if item.Size > 100*1024*1024 {
191-
sizeStr = "🟡 " + sizeStr
213+
pad := 17 - (3 + 1 + len(sizeStr))
214+
if pad < 0 {
215+
pad = 0
192216
}
193-
194-
fmt.Printf("│ %-39s │ %17s\n", name, sizeStr)
217+
visible := fmt.Sprintf("%s %s", tag, sizeStr)
218+
fmt.Printf("│ %-39s │ %s%s\n", name, strings.Repeat(" ", pad), visible)
195219
}
196220

197221
fmt.Println("└─────────────────────────────────────────┴───────────────────┘")
198222
fmt.Println()
199223

200224
totalSystem := systemScanner.GetTotalSize()
201225
cleanableSystem := systemScanner.GetCleanableSize()
202-
fmt.Printf("💾 Total System Data: %s\n", humanize.Bytes(uint64(totalSystem)))
203-
fmt.Printf(" Cleanable System Data: %s\n", humanize.Bytes(uint64(cleanableSystem)))
226+
fmt.Printf("[Total] System Data: %s\n", humanize.Bytes(uint64(totalSystem)))
227+
fmt.Printf("[OK] Cleanable System Data: %s\n", humanize.Bytes(uint64(cleanableSystem)))
204228
fmt.Println()
205229
}
206230

207231
// 5. Show scan errors if any
208232
if errs := junkScanner.GetErrors(); len(errs) > 0 {
209-
fmt.Printf("⚠️ %d warnings during scan (usually permission issues):\n", len(errs))
233+
fmt.Printf("[!] %d warnings during scan (usually permission issues):\n", len(errs))
210234
for i, err := range errs {
211235
if i >= 5 {
212236
fmt.Printf(" ... and %d more\n", len(errs)-5)
@@ -218,12 +242,12 @@ func diagnose() {
218242
}
219243

220244
// 6. Tips
221-
fmt.Println("💡 Tips:")
245+
fmt.Println("[Tips]:")
222246
fmt.Println(" 1. If some directories show 'No access', try running with sudo")
223-
fmt.Println(" 2. For 🔴 large directories, use TUI mode to view details")
247+
fmt.Printf(" 2. For %s%s[!]%s large directories, use TUI mode to view details\n", colorRed, colorBold, colorReset)
224248
fmt.Println(" 3. Docker data is usually in ~/Library/Containers/com.docker.docker")
225249
fmt.Println(" 4. Xcode cache can be very large, DerivedData is safe to clean")
226-
fmt.Println(" 5. 🔒 items are system data that cannot be safely cleaned")
250+
fmt.Printf(" 5. %s[L]%s items are system data that cannot be safely cleaned\n", colorDim, colorReset)
227251
fmt.Println(" 6. Time Machine snapshots are automatically managed by macOS")
228252
fmt.Println(" 7. System swap files are automatically managed by the OS")
229253
fmt.Println()

cmd/lume/main.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,24 @@ import (
66
"os"
77

88
"github.com/charmbracelet/bubbletea"
9+
"github.com/mattn/go-runewidth"
10+
911
"github.com/Tyooughtul/lume/pkg/ui"
1012
)
1113

14+
func init() {
15+
// Force EastAsianWidth=false so that ambiguous-width Unicode characters
16+
// (●, ○, █, ─, │, etc.) are always treated as single-width.
17+
// macOS Terminal.app renders these as 1 cell even under CJK locales,
18+
// while go-runewidth auto-detects zh_CN → EAW=true → width=2, causing
19+
// column misalignment. This makes behaviour consistent across terminals.
20+
runewidth.DefaultCondition.EastAsianWidth = false
21+
}
22+
1223
func main() {
24+
// Initialize theme manager
25+
ui.InitThemeManager()
26+
1327
diagnoseMode := flag.Bool("diagnose", false, "Run diagnostic mode (no TUI)")
1428
helpMode := flag.Bool("help", false, "Show help information")
1529
flag.Parse()

install.sh

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,26 +39,26 @@ get_latest_version() {
3939

4040
main() {
4141
echo ""
42-
echo "🧹 Installing Lume..."
42+
echo "[*] Installing Lume..."
4343
echo ""
4444

4545
# 检测操作系统
4646
if [ "$(uname -s)" != "Darwin" ]; then
47-
echo -e "${RED} Lume only supports macOS${NC}"
47+
echo -e "${RED}[X] Lume only supports macOS${NC}"
4848
exit 1
4949
fi
5050

5151
ARCH=$(detect_arch)
5252
if [ "$ARCH" = "unknown" ]; then
53-
echo -e "${RED} Unsupported architecture: $(uname -m)${NC}"
53+
echo -e "${RED}[X] Unsupported architecture: $(uname -m)${NC}"
5454
exit 1
5555
fi
5656

5757
echo "→ Detected: macOS $ARCH"
5858

5959
VERSION=$(get_latest_version)
6060
if [ -z "$VERSION" ]; then
61-
echo -e "${RED} Failed to fetch latest version${NC}"
61+
echo -e "${RED}[X] Failed to fetch latest version${NC}"
6262
echo " Please check your internet connection"
6363
exit 1
6464
fi
@@ -70,7 +70,7 @@ main() {
7070

7171
echo "→ Downloading..."
7272
if ! curl -fsSL "$DOWNLOAD_URL" -o "$TMP_FILE" 2>/dev/null; then
73-
echo -e "${RED} Download failed${NC}"
73+
echo -e "${RED}[X] Download failed${NC}"
7474
echo " URL: $DOWNLOAD_URL"
7575
exit 1
7676
fi
@@ -86,7 +86,7 @@ main() {
8686
fi
8787

8888
echo ""
89-
echo -e "${GREEN} Lume installed successfully!${NC}"
89+
echo -e "${GREEN}[OK] Lume installed successfully!${NC}"
9090
echo ""
9191
echo " Run 'lume' to start cleaning"
9292
echo " Run 'lume -help' for more options"

pkg/cleaner/cleaner.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ type Cleaner struct {
2020

2121
// NewCleaner creates a new Cleaner instance
2222
func NewCleaner() *Cleaner {
23-
homeDir, _ := os.UserHomeDir()
23+
homeDir := scanner.GetRealHomeDir()
2424
return &Cleaner{
2525
trashPath: filepath.Join(homeDir, ".Trash"),
2626
}

pkg/scanner/app.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ func (s *AppScanner) getAppVersion(appPath string) string {
106106
// findResiduals finds residual files for an app
107107
func (s *AppScanner) findResiduals(appName string) []ResidualInfo {
108108
var residuals []ResidualInfo
109-
homeDir, _ := os.UserHomeDir()
109+
homeDir := GetRealHomeDir()
110110

111111
// Possible residual locations (comprehensive list)
112112
locations := []string{

pkg/scanner/browser.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,12 @@ func (s *BrowserScanner) Scan(progressCh chan<- string) ([]BrowserDataInfo, erro
7474

7575
// scanSafari scans Safari data.
7676
func (s *BrowserScanner) scanSafari() *BrowserDataInfo {
77-
homeDir, _ := os.UserHomeDir()
77+
homeDir := GetRealHomeDir()
7878

7979
info := &BrowserDataInfo{
8080
Name: "Safari",
8181
Type: Safari,
82-
Icon: "🧭",
82+
Icon: "[SF]",
8383
}
8484

8585
// Safari cache
@@ -127,12 +127,12 @@ func (s *BrowserScanner) scanSafari() *BrowserDataInfo {
127127

128128
// scanChrome scans Chrome data.
129129
func (s *BrowserScanner) scanChrome() *BrowserDataInfo {
130-
homeDir, _ := os.UserHomeDir()
130+
homeDir := GetRealHomeDir()
131131

132132
info := &BrowserDataInfo{
133133
Name: "Google Chrome",
134134
Type: Chrome,
135-
Icon: "🌐",
135+
Icon: "[CH]",
136136
}
137137

138138
basePath := filepath.Join(homeDir, "Library", "Application Support", "Google", "Chrome")
@@ -195,12 +195,12 @@ func (s *BrowserScanner) scanChrome() *BrowserDataInfo {
195195

196196
// scanFirefox scans Firefox data.
197197
func (s *BrowserScanner) scanFirefox() *BrowserDataInfo {
198-
homeDir, _ := os.UserHomeDir()
198+
homeDir := GetRealHomeDir()
199199

200200
info := &BrowserDataInfo{
201201
Name: "Firefox",
202202
Type: Firefox,
203-
Icon: "🦊",
203+
Icon: "[FF]",
204204
}
205205

206206
basePath := filepath.Join(homeDir, "Library", "Application Support", "Firefox", "Profiles")
@@ -252,12 +252,12 @@ func (s *BrowserScanner) scanFirefox() *BrowserDataInfo {
252252

253253
// scanEdge scans Edge data.
254254
func (s *BrowserScanner) scanEdge() *BrowserDataInfo {
255-
homeDir, _ := os.UserHomeDir()
255+
homeDir := GetRealHomeDir()
256256

257257
info := &BrowserDataInfo{
258258
Name: "Microsoft Edge",
259259
Type: Edge,
260-
Icon: "🌊",
260+
Icon: "[ED]",
261261
}
262262

263263
basePath := filepath.Join(homeDir, "Library", "Application Support", "Microsoft Edge")

0 commit comments

Comments
 (0)