1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-04 13:16:47 +00:00

feat(status): persist cat visibility preference

- Add loadCatHidden/saveCatHidden functions
- Save preference to ~/.config/mole/status_prefs
- Load preference on startup
This commit is contained in:
Tw93
2026-01-08 15:58:50 +08:00
parent b1bb91be1f
commit 180037c22b
7 changed files with 68 additions and 24 deletions

View File

@@ -9,15 +9,13 @@ run:
modules-download-mode: readonly
linters:
disable-all: true
enable:
# Default linters
- govet
- staticcheck
- errcheck
- ineffassign
- unused
# Additional useful linters
- errcheck
linters-settings:
govet:

View File

@@ -74,6 +74,7 @@ mo purge --paths # Configure project scan directories
- **Safety**: Built with strict protections. See [Security Audit](SECURITY_AUDIT.md). Preview changes with `mo clean --dry-run`.
- **Debug Mode**: Use `--debug` for detailed logs (e.g., `mo clean --debug`). Combine with `--dry-run` for comprehensive preview including risk levels and file details.
- **Navigation**: Supports arrow keys and Vim bindings (`h/j/k/l`).
- **Status Shortcuts**: In `mo status`, press `k` to toggle cat visibility and save preference, `q` to quit.
- **Configuration**: Run `mo touchid` for Touch ID sudo, `mo completion` for shell tab completion, `mo clean --whitelist` to manage protected paths.
## Features in Detail
@@ -185,7 +186,7 @@ Up ▮▯▯▯▯ 0.8 MB/s Chrome ▮▮▮▯▯ 2
Proxy HTTP · 192.168.1.100 Terminal ▮▯▯▯▯ 12.5%
```
Health score based on CPU, memory, disk, temperature, and I/O load. Color-coded by range. Press `k` to hide/show cat, `q` to quit.
Health score based on CPU, memory, disk, temperature, and I/O load. Color-coded by range.
### Project Artifact Purge

View File

@@ -1,8 +1,11 @@
// Package main provides the mo status command for real-time system monitoring.
package main
import (
"fmt"
"os"
"path/filepath"
"strings"
"time"
tea "github.com/charmbracelet/bubbletea"
@@ -37,10 +40,50 @@ type model struct {
catHidden bool // true = hidden, false = visible
}
// getConfigPath returns the path to the status preferences file.
func getConfigPath() string {
home, err := os.UserHomeDir()
if err != nil {
return ""
}
return filepath.Join(home, ".config", "mole", "status_prefs")
}
// loadCatHidden loads the cat hidden preference from config file.
func loadCatHidden() bool {
path := getConfigPath()
if path == "" {
return false
}
data, err := os.ReadFile(path)
if err != nil {
return false
}
return strings.TrimSpace(string(data)) == "cat_hidden=true"
}
// saveCatHidden saves the cat hidden preference to config file.
func saveCatHidden(hidden bool) {
path := getConfigPath()
if path == "" {
return
}
// Ensure directory exists
dir := filepath.Dir(path)
if err := os.MkdirAll(dir, 0755); err != nil {
return
}
value := "cat_hidden=false"
if hidden {
value = "cat_hidden=true"
}
_ = os.WriteFile(path, []byte(value+"\n"), 0644)
}
func newModel() model {
return model{
collector: NewCollector(),
catHidden: false,
catHidden: loadCatHidden(),
}
}
@@ -55,8 +98,9 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case "q", "esc", "ctrl+c":
return m, tea.Quit
case "k":
// Toggle cat visibility
// Toggle cat visibility and persist preference
m.catHidden = !m.catHidden
saveCatHidden(m.catHidden)
return m, nil
}
case tea.WindowSizeMsg:

View File

@@ -286,9 +286,8 @@ func commandExists(name string) bool {
return false
}
defer func() {
if r := recover(); r != nil { //nolint:staticcheck
// Treat LookPath panics as "missing".
}
_ = recover()
}()
_, err := exec.LookPath(name)
return err == nil

View File

@@ -32,7 +32,7 @@ func collectCPU() (CPUStatus, error) {
}
// Two-call pattern for more reliable CPU usage.
warmUpCpu()
warmUpCPU()
time.Sleep(cpuSampleInterval)
percents, err := cpu.Percent(0, true)
var totalPercent float64
@@ -256,6 +256,6 @@ func fallbackCPUUtilization(logical int) (float64, []float64, error) {
return avg, perCore, nil
}
func warmUpCpu() {
func warmUpCPU() {
cpu.Percent(0, true) //nolint:errcheck
}

View File

@@ -134,15 +134,16 @@ func calculateHealthScore(cpu CPUStatus, mem MemoryStatus, disks []DiskStatus, d
// Build message.
var msg string
if score >= 90 {
switch {
case score >= 90:
msg = "Excellent"
} else if score >= 75 {
case score >= 75:
msg = "Good"
} else if score >= 60 {
case score >= 60:
msg = "Fair"
} else if score >= 40 {
case score >= 40:
msg = "Poor"
} else {
default:
msg = "Critical"
}

View File

@@ -187,15 +187,16 @@ func renderHeader(m MetricsSnapshot, errMsg string, animFrame int, termWidth int
}
func getScoreStyle(score int) lipgloss.Style {
if score >= 90 {
switch {
case score >= 90:
return lipgloss.NewStyle().Foreground(lipgloss.Color("#87FF87")).Bold(true)
} else if score >= 75 {
case score >= 75:
return lipgloss.NewStyle().Foreground(lipgloss.Color("#87D787")).Bold(true)
} else if score >= 60 {
case score >= 60:
return lipgloss.NewStyle().Foreground(lipgloss.Color("#FFD75F")).Bold(true)
} else if score >= 40 {
case score >= 40:
return lipgloss.NewStyle().Foreground(lipgloss.Color("#FFAF5F")).Bold(true)
} else {
default:
return lipgloss.NewStyle().Foreground(lipgloss.Color("#FF6B6B")).Bold(true)
}
}
@@ -707,11 +708,11 @@ func humanBytesCompact(v uint64) string {
}
}
func shorten(s string, max int) string {
if len(s) <= max {
func shorten(s string, maxLen int) string {
if len(s) <= maxLen {
return s
}
return s[:max-1] + "…"
return s[:maxLen-1] + "…"
}
func renderTwoColumns(cards []cardData, width int) string {