mirror of
https://github.com/tw93/Mole.git
synced 2026-02-14 17:02:26 +00:00
refactor: modernize Go code
This commit is contained in:
@@ -93,15 +93,12 @@ func humanizeBytes(size int64) string {
|
|||||||
return fmt.Sprintf("%.1f %cB", value, "KMGTPE"[exp])
|
return fmt.Sprintf("%.1f %cB", value, "KMGTPE"[exp])
|
||||||
}
|
}
|
||||||
|
|
||||||
func coloredProgressBar(value, max int64, percent float64) string {
|
func coloredProgressBar(value, maxValue int64, percent float64) string {
|
||||||
if max <= 0 {
|
if maxValue <= 0 {
|
||||||
return colorGray + strings.Repeat("░", barWidth) + colorReset
|
return colorGray + strings.Repeat("░", barWidth) + colorReset
|
||||||
}
|
}
|
||||||
|
|
||||||
filled := int((value * int64(barWidth)) / max)
|
filled := min(int((value*int64(barWidth))/maxValue), barWidth)
|
||||||
if filled > barWidth {
|
|
||||||
filled = barWidth
|
|
||||||
}
|
|
||||||
|
|
||||||
var barColor string
|
var barColor string
|
||||||
if percent >= 50 {
|
if percent >= 50 {
|
||||||
@@ -114,26 +111,27 @@ func coloredProgressBar(value, max int64, percent float64) string {
|
|||||||
barColor = colorGreen
|
barColor = colorGreen
|
||||||
}
|
}
|
||||||
|
|
||||||
bar := barColor
|
var bar strings.Builder
|
||||||
for i := 0; i < barWidth; i++ {
|
bar.WriteString(barColor)
|
||||||
|
for i := range barWidth {
|
||||||
if i < filled {
|
if i < filled {
|
||||||
if i < filled-1 {
|
if i < filled-1 {
|
||||||
bar += "█"
|
bar.WriteString("█")
|
||||||
} else {
|
} else {
|
||||||
remainder := (value * int64(barWidth)) % max
|
remainder := (value * int64(barWidth)) % maxValue
|
||||||
if remainder > max/2 {
|
if remainder > maxValue/2 {
|
||||||
bar += "█"
|
bar.WriteString("█")
|
||||||
} else if remainder > max/4 {
|
} else if remainder > maxValue/4 {
|
||||||
bar += "▓"
|
bar.WriteString("▓")
|
||||||
} else {
|
} else {
|
||||||
bar += "▒"
|
bar.WriteString("▒")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bar += colorGray + "░" + barColor
|
bar.WriteString(colorGray + "░" + barColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bar + colorReset
|
return bar.String() + colorReset
|
||||||
}
|
}
|
||||||
|
|
||||||
// runeWidth returns display width for wide characters and emoji.
|
// runeWidth returns display width for wide characters and emoji.
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ func (h entryHeap) Len() int { return len(h) }
|
|||||||
func (h entryHeap) Less(i, j int) bool { return h[i].Size < h[j].Size }
|
func (h entryHeap) Less(i, j int) bool { return h[i].Size < h[j].Size }
|
||||||
func (h entryHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
|
func (h entryHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
|
||||||
|
|
||||||
func (h *entryHeap) Push(x interface{}) {
|
func (h *entryHeap) Push(x any) {
|
||||||
*h = append(*h, x.(dirEntry))
|
*h = append(*h, x.(dirEntry))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *entryHeap) Pop() interface{} {
|
func (h *entryHeap) Pop() any {
|
||||||
old := *h
|
old := *h
|
||||||
n := len(old)
|
n := len(old)
|
||||||
x := old[n-1]
|
x := old[n-1]
|
||||||
@@ -26,11 +26,11 @@ func (h largeFileHeap) Len() int { return len(h) }
|
|||||||
func (h largeFileHeap) Less(i, j int) bool { return h[i].Size < h[j].Size }
|
func (h largeFileHeap) Less(i, j int) bool { return h[i].Size < h[j].Size }
|
||||||
func (h largeFileHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
|
func (h largeFileHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
|
||||||
|
|
||||||
func (h *largeFileHeap) Push(x interface{}) {
|
func (h *largeFileHeap) Push(x any) {
|
||||||
*h = append(*h, x.(fileEntry))
|
*h = append(*h, x.(fileEntry))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *largeFileHeap) Pop() interface{} {
|
func (h *largeFileHeap) Pop() any {
|
||||||
old := *h
|
old := *h
|
||||||
n := len(old)
|
n := len(old)
|
||||||
x := old[n-1]
|
x := old[n-1]
|
||||||
|
|||||||
@@ -359,7 +359,7 @@ func (m model) scanCmd(path string) tea.Cmd {
|
|||||||
return scanResultMsg{result: result, err: nil}
|
return scanResultMsg{result: result, err: nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err, _ := scanGroup.Do(path, func() (interface{}, error) {
|
v, err, _ := scanGroup.Do(path, func() (any, error) {
|
||||||
return scanPathConcurrent(path, m.filesScanned, m.dirsScanned, m.bytesScanned, m.currentPath)
|
return scanPathConcurrent(path, m.filesScanned, m.dirsScanned, m.bytesScanned, m.currentPath)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -997,10 +997,7 @@ func (m *model) clampEntrySelection() {
|
|||||||
m.selected = 0
|
m.selected = 0
|
||||||
}
|
}
|
||||||
viewport := calculateViewport(m.height, false)
|
viewport := calculateViewport(m.height, false)
|
||||||
maxOffset := len(m.entries) - viewport
|
maxOffset := max(len(m.entries)-viewport, 0)
|
||||||
if maxOffset < 0 {
|
|
||||||
maxOffset = 0
|
|
||||||
}
|
|
||||||
if m.offset > maxOffset {
|
if m.offset > maxOffset {
|
||||||
m.offset = maxOffset
|
m.offset = maxOffset
|
||||||
}
|
}
|
||||||
@@ -1025,10 +1022,7 @@ func (m *model) clampLargeSelection() {
|
|||||||
m.largeSelected = 0
|
m.largeSelected = 0
|
||||||
}
|
}
|
||||||
viewport := calculateViewport(m.height, true)
|
viewport := calculateViewport(m.height, true)
|
||||||
maxOffset := len(m.largeFiles) - viewport
|
maxOffset := max(len(m.largeFiles)-viewport, 0)
|
||||||
if maxOffset < 0 {
|
|
||||||
maxOffset = 0
|
|
||||||
}
|
|
||||||
if m.largeOffset > maxOffset {
|
if m.largeOffset > maxOffset {
|
||||||
m.largeOffset = maxOffset
|
m.largeOffset = maxOffset
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,7 @@ func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *in
|
|||||||
heap.Init(largeFilesHeap)
|
heap.Init(largeFilesHeap)
|
||||||
|
|
||||||
// Worker pool sized for I/O-bound scanning.
|
// Worker pool sized for I/O-bound scanning.
|
||||||
numWorkers := runtime.NumCPU() * cpuMultiplier
|
numWorkers := max(runtime.NumCPU()*cpuMultiplier, minWorkers)
|
||||||
if numWorkers < minWorkers {
|
|
||||||
numWorkers = minWorkers
|
|
||||||
}
|
|
||||||
if numWorkers > maxWorkers {
|
if numWorkers > maxWorkers {
|
||||||
numWorkers = maxWorkers
|
numWorkers = maxWorkers
|
||||||
}
|
}
|
||||||
@@ -289,10 +286,7 @@ func calculateDirSizeFast(root string, filesScanned, dirsScanned, bytesScanned *
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
concurrency := runtime.NumCPU() * 4
|
concurrency := min(runtime.NumCPU()*4, 64)
|
||||||
if concurrency > 64 {
|
|
||||||
concurrency = 64
|
|
||||||
}
|
|
||||||
sem := make(chan struct{}, concurrency)
|
sem := make(chan struct{}, concurrency)
|
||||||
|
|
||||||
var walk func(string)
|
var walk func(string)
|
||||||
@@ -363,10 +357,9 @@ func findLargeFilesWithSpotlight(root string, minSize int64) []fileEntry {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
lines := strings.Split(strings.TrimSpace(string(output)), "\n")
|
|
||||||
var files []fileEntry
|
var files []fileEntry
|
||||||
|
|
||||||
for _, line := range lines {
|
for line := range strings.Lines(strings.TrimSpace(string(output))) {
|
||||||
if line == "" {
|
if line == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -413,8 +406,8 @@ func findLargeFilesWithSpotlight(root string, minSize int64) []fileEntry {
|
|||||||
|
|
||||||
// isInFoldedDir checks if a path is inside a folded directory.
|
// isInFoldedDir checks if a path is inside a folded directory.
|
||||||
func isInFoldedDir(path string) bool {
|
func isInFoldedDir(path string) bool {
|
||||||
parts := strings.Split(path, string(os.PathSeparator))
|
parts := strings.SplitSeq(path, string(os.PathSeparator))
|
||||||
for _, part := range parts {
|
for part := range parts {
|
||||||
if foldDirs[part] {
|
if foldDirs[part] {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -432,10 +425,7 @@ func calculateDirSizeConcurrent(root string, largeFileChan chan<- fileEntry, fil
|
|||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
// Limit concurrent subdirectory scans.
|
// Limit concurrent subdirectory scans.
|
||||||
maxConcurrent := runtime.NumCPU() * 2
|
maxConcurrent := min(runtime.NumCPU()*2, maxDirWorkers)
|
||||||
if maxConcurrent > maxDirWorkers {
|
|
||||||
maxConcurrent = maxDirWorkers
|
|
||||||
}
|
|
||||||
sem := make(chan struct{}, maxConcurrent)
|
sem := make(chan struct{}, maxConcurrent)
|
||||||
|
|
||||||
for _, child := range children {
|
for _, child := range children {
|
||||||
|
|||||||
@@ -100,14 +100,8 @@ func (m model) View() string {
|
|||||||
fmt.Fprintln(&b, " No large files found (>=100MB)")
|
fmt.Fprintln(&b, " No large files found (>=100MB)")
|
||||||
} else {
|
} else {
|
||||||
viewport := calculateViewport(m.height, true)
|
viewport := calculateViewport(m.height, true)
|
||||||
start := m.largeOffset
|
start := max(m.largeOffset, 0)
|
||||||
if start < 0 {
|
end := min(start+viewport, len(m.largeFiles))
|
||||||
start = 0
|
|
||||||
}
|
|
||||||
end := start + viewport
|
|
||||||
if end > len(m.largeFiles) {
|
|
||||||
end = len(m.largeFiles)
|
|
||||||
}
|
|
||||||
maxLargeSize := int64(1)
|
maxLargeSize := int64(1)
|
||||||
for _, file := range m.largeFiles {
|
for _, file := range m.largeFiles {
|
||||||
if file.Size > maxLargeSize {
|
if file.Size > maxLargeSize {
|
||||||
@@ -163,10 +157,7 @@ func (m model) View() string {
|
|||||||
for idx, entry := range m.entries {
|
for idx, entry := range m.entries {
|
||||||
icon := "📁"
|
icon := "📁"
|
||||||
sizeVal := entry.Size
|
sizeVal := entry.Size
|
||||||
barValue := sizeVal
|
barValue := max(sizeVal, 0)
|
||||||
if barValue < 0 {
|
|
||||||
barValue = 0
|
|
||||||
}
|
|
||||||
var percent float64
|
var percent float64
|
||||||
if totalSize > 0 && sizeVal >= 0 {
|
if totalSize > 0 && sizeVal >= 0 {
|
||||||
percent = float64(sizeVal) / float64(totalSize) * 100
|
percent = float64(sizeVal) / float64(totalSize) * 100
|
||||||
@@ -243,14 +234,8 @@ func (m model) View() string {
|
|||||||
|
|
||||||
viewport := calculateViewport(m.height, false)
|
viewport := calculateViewport(m.height, false)
|
||||||
nameWidth := calculateNameWidth(m.width)
|
nameWidth := calculateNameWidth(m.width)
|
||||||
start := m.offset
|
start := max(m.offset, 0)
|
||||||
if start < 0 {
|
end := min(start+viewport, len(m.entries))
|
||||||
start = 0
|
|
||||||
}
|
|
||||||
end := start + viewport
|
|
||||||
if end > len(m.entries) {
|
|
||||||
end = len(m.entries)
|
|
||||||
}
|
|
||||||
|
|
||||||
for idx := start; idx < end; idx++ {
|
for idx := start; idx < end; idx++ {
|
||||||
entry := m.entries[idx]
|
entry := m.entries[idx]
|
||||||
|
|||||||
@@ -127,10 +127,7 @@ func animTick() tea.Cmd {
|
|||||||
|
|
||||||
func animTickWithSpeed(cpuUsage float64) tea.Cmd {
|
func animTickWithSpeed(cpuUsage float64) tea.Cmd {
|
||||||
// Higher CPU = faster animation.
|
// Higher CPU = faster animation.
|
||||||
interval := 300 - int(cpuUsage*2.5)
|
interval := max(300-int(cpuUsage*2.5), 50)
|
||||||
if interval < 50 {
|
|
||||||
interval = 50
|
|
||||||
}
|
|
||||||
return tea.Tick(time.Duration(interval)*time.Millisecond, func(time.Time) tea.Msg { return animTickMsg{} })
|
return tea.Tick(time.Duration(interval)*time.Millisecond, func(time.Time) tea.Msg { return animTickMsg{} })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,11 +68,10 @@ func collectBatteries() (batts []BatteryStatus, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parsePMSet(raw string, health string, cycles int, capacity int) []BatteryStatus {
|
func parsePMSet(raw string, health string, cycles int, capacity int) []BatteryStatus {
|
||||||
lines := strings.Split(raw, "\n")
|
|
||||||
var out []BatteryStatus
|
var out []BatteryStatus
|
||||||
var timeLeft string
|
var timeLeft string
|
||||||
|
|
||||||
for _, line := range lines {
|
for line := range strings.Lines(raw) {
|
||||||
// Time remaining.
|
// Time remaining.
|
||||||
if strings.Contains(line, "remaining") {
|
if strings.Contains(line, "remaining") {
|
||||||
parts := strings.Fields(line)
|
parts := strings.Fields(line)
|
||||||
@@ -128,8 +127,7 @@ func getCachedPowerData() (health string, cycles int, capacity int) {
|
|||||||
return "", 0, 0
|
return "", 0, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
lines := strings.Split(out, "\n")
|
for line := range strings.Lines(out) {
|
||||||
for _, line := range lines {
|
|
||||||
lower := strings.ToLower(line)
|
lower := strings.ToLower(line)
|
||||||
if strings.Contains(lower, "cycle count") {
|
if strings.Contains(lower, "cycle count") {
|
||||||
if _, after, found := strings.Cut(line, ":"); found {
|
if _, after, found := strings.Cut(line, ":"); found {
|
||||||
@@ -183,8 +181,7 @@ func collectThermal() ThermalStatus {
|
|||||||
// Fan info from cached system_profiler.
|
// Fan info from cached system_profiler.
|
||||||
out := getSystemPowerOutput()
|
out := getSystemPowerOutput()
|
||||||
if out != "" {
|
if out != "" {
|
||||||
lines := strings.Split(out, "\n")
|
for line := range strings.Lines(out) {
|
||||||
for _, line := range lines {
|
|
||||||
lower := strings.ToLower(line)
|
lower := strings.ToLower(line)
|
||||||
if strings.Contains(lower, "fan") && strings.Contains(lower, "speed") {
|
if strings.Contains(lower, "fan") && strings.Contains(lower, "speed") {
|
||||||
if _, after, found := strings.Cut(line, ":"); found {
|
if _, after, found := strings.Cut(line, ":"); found {
|
||||||
@@ -200,8 +197,7 @@ func collectThermal() ThermalStatus {
|
|||||||
ctxPower, cancelPower := context.WithTimeout(context.Background(), 500*time.Millisecond)
|
ctxPower, cancelPower := context.WithTimeout(context.Background(), 500*time.Millisecond)
|
||||||
defer cancelPower()
|
defer cancelPower()
|
||||||
if out, err := runCmd(ctxPower, "ioreg", "-rn", "AppleSmartBattery"); err == nil {
|
if out, err := runCmd(ctxPower, "ioreg", "-rn", "AppleSmartBattery"); err == nil {
|
||||||
lines := strings.Split(out, "\n")
|
for line := range strings.Lines(out) {
|
||||||
for _, line := range lines {
|
|
||||||
line = strings.TrimSpace(line)
|
line = strings.TrimSpace(line)
|
||||||
|
|
||||||
// Battery temperature ("Temperature" = 3055).
|
// Battery temperature ("Temperature" = 3055).
|
||||||
|
|||||||
@@ -68,13 +68,12 @@ func readBluetoothCTLDevices() ([]BluetoothDevice, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parseSPBluetooth(raw string) []BluetoothDevice {
|
func parseSPBluetooth(raw string) []BluetoothDevice {
|
||||||
lines := strings.Split(raw, "\n")
|
|
||||||
var devices []BluetoothDevice
|
var devices []BluetoothDevice
|
||||||
var currentName string
|
var currentName string
|
||||||
var connected bool
|
var connected bool
|
||||||
var battery string
|
var battery string
|
||||||
|
|
||||||
for _, line := range lines {
|
for line := range strings.Lines(raw) {
|
||||||
trim := strings.TrimSpace(line)
|
trim := strings.TrimSpace(line)
|
||||||
if len(trim) == 0 {
|
if len(trim) == 0 {
|
||||||
continue
|
continue
|
||||||
@@ -112,10 +111,9 @@ func parseSPBluetooth(raw string) []BluetoothDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parseBluetoothctl(raw string) []BluetoothDevice {
|
func parseBluetoothctl(raw string) []BluetoothDevice {
|
||||||
lines := strings.Split(raw, "\n")
|
|
||||||
var devices []BluetoothDevice
|
var devices []BluetoothDevice
|
||||||
current := BluetoothDevice{}
|
current := BluetoothDevice{}
|
||||||
for _, line := range lines {
|
for line := range strings.Lines(raw) {
|
||||||
trim := strings.TrimSpace(line)
|
trim := strings.TrimSpace(line)
|
||||||
if strings.HasPrefix(trim, "Device ") {
|
if strings.HasPrefix(trim, "Device ") {
|
||||||
if current.Name != "" {
|
if current.Name != "" {
|
||||||
@@ -123,8 +121,8 @@ func parseBluetoothctl(raw string) []BluetoothDevice {
|
|||||||
}
|
}
|
||||||
current = BluetoothDevice{Name: strings.TrimPrefix(trim, "Device "), Connected: false}
|
current = BluetoothDevice{Name: strings.TrimPrefix(trim, "Device "), Connected: false}
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(trim, "Name:") {
|
if after, ok := strings.CutPrefix(trim, "Name:"); ok {
|
||||||
current.Name = strings.TrimSpace(strings.TrimPrefix(trim, "Name:"))
|
current.Name = strings.TrimSpace(after)
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(trim, "Connected:") {
|
if strings.HasPrefix(trim, "Connected:") {
|
||||||
current.Connected = strings.Contains(trim, "yes")
|
current.Connected = strings.Contains(trim, "yes")
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ func isExternalDisk(device string) (bool, error) {
|
|||||||
found bool
|
found bool
|
||||||
external bool
|
external bool
|
||||||
)
|
)
|
||||||
for _, line := range strings.Split(out, "\n") {
|
for line := range strings.Lines(out) {
|
||||||
trim := strings.TrimSpace(line)
|
trim := strings.TrimSpace(line)
|
||||||
if strings.HasPrefix(trim, "Internal:") {
|
if strings.HasPrefix(trim, "Internal:") {
|
||||||
found = true
|
found = true
|
||||||
|
|||||||
@@ -61,9 +61,8 @@ func (c *Collector) collectGPU(now time.Time) ([]GPUStatus, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
lines := strings.Split(strings.TrimSpace(out), "\n")
|
|
||||||
var gpus []GPUStatus
|
var gpus []GPUStatus
|
||||||
for _, line := range lines {
|
for line := range strings.Lines(strings.TrimSpace(out)) {
|
||||||
fields := strings.Split(line, ",")
|
fields := strings.Split(line, ",")
|
||||||
if len(fields) < 4 {
|
if len(fields) < 4 {
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -28,8 +28,7 @@ func collectHardware(totalRAM uint64, disks []DiskStatus) HardwareInfo {
|
|||||||
|
|
||||||
out, err := runCmd(ctx, "system_profiler", "SPHardwareDataType")
|
out, err := runCmd(ctx, "system_profiler", "SPHardwareDataType")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
lines := strings.Split(out, "\n")
|
for line := range strings.Lines(out) {
|
||||||
for _, line := range lines {
|
|
||||||
lower := strings.ToLower(strings.TrimSpace(line))
|
lower := strings.ToLower(strings.TrimSpace(line))
|
||||||
// Prefer "Model Name" over "Model Identifier".
|
// Prefer "Model Name" over "Model Identifier".
|
||||||
if strings.Contains(lower, "model name:") {
|
if strings.Contains(lower, "model name:") {
|
||||||
@@ -85,10 +84,9 @@ func collectHardware(totalRAM uint64, disks []DiskStatus) HardwareInfo {
|
|||||||
|
|
||||||
// parseRefreshRate extracts the highest refresh rate from system_profiler display output.
|
// parseRefreshRate extracts the highest refresh rate from system_profiler display output.
|
||||||
func parseRefreshRate(output string) string {
|
func parseRefreshRate(output string) string {
|
||||||
lines := strings.Split(output, "\n")
|
|
||||||
maxHz := 0
|
maxHz := 0
|
||||||
|
|
||||||
for _, line := range lines {
|
for line := range strings.Lines(output) {
|
||||||
lower := strings.ToLower(line)
|
lower := strings.ToLower(line)
|
||||||
// Look for patterns like "@ 60Hz", "@ 60.00Hz", or "Refresh Rate: 120 Hz".
|
// Look for patterns like "@ 60Hz", "@ 60.00Hz", or "Refresh Rate: 120 Hz".
|
||||||
if strings.Contains(lower, "hz") {
|
if strings.Contains(lower, "hz") {
|
||||||
@@ -100,8 +98,7 @@ func parseRefreshRate(output string) string {
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(field, "hz") {
|
if numStr, ok := strings.CutSuffix(field, "hz"); ok {
|
||||||
numStr := strings.TrimSuffix(field, "hz")
|
|
||||||
if numStr == "" && i > 0 {
|
if numStr == "" && i > 0 {
|
||||||
numStr = fields[i-1]
|
numStr = fields[i-1]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,10 +66,7 @@ func getMoleFrame(animFrame int, termWidth int) string {
|
|||||||
body := moleBody[bodyIdx]
|
body := moleBody[bodyIdx]
|
||||||
|
|
||||||
moleWidth := 15
|
moleWidth := 15
|
||||||
maxPos := termWidth - moleWidth
|
maxPos := max(termWidth-moleWidth, 0)
|
||||||
if maxPos < 0 {
|
|
||||||
maxPos = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
cycleLength := maxPos * 2
|
cycleLength := maxPos * 2
|
||||||
if cycleLength == 0 {
|
if cycleLength == 0 {
|
||||||
@@ -197,10 +194,7 @@ func renderCPUCard(cpu CPUStatus) cardData {
|
|||||||
}
|
}
|
||||||
sort.Slice(cores, func(i, j int) bool { return cores[i].val > cores[j].val })
|
sort.Slice(cores, func(i, j int) bool { return cores[i].val > cores[j].val })
|
||||||
|
|
||||||
maxCores := 3
|
maxCores := min(len(cores), 3)
|
||||||
if len(cores) < maxCores {
|
|
||||||
maxCores = len(cores)
|
|
||||||
}
|
|
||||||
for i := 0; i < maxCores; i++ {
|
for i := 0; i < maxCores; i++ {
|
||||||
c := cores[i]
|
c := cores[i]
|
||||||
lines = append(lines, fmt.Sprintf("Core%-2d %s %5.1f%%", c.idx+1, progressBar(c.val), c.val))
|
lines = append(lines, fmt.Sprintf("Core%-2d %s %5.1f%%", c.idx+1, progressBar(c.val), c.val))
|
||||||
@@ -356,10 +350,7 @@ func formatDiskLine(label string, d DiskStatus) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ioBar(rate float64) string {
|
func ioBar(rate float64) string {
|
||||||
filled := int(rate / 10.0)
|
filled := min(int(rate/10.0), 5)
|
||||||
if filled > 5 {
|
|
||||||
filled = 5
|
|
||||||
}
|
|
||||||
if filled < 0 {
|
if filled < 0 {
|
||||||
filled = 0
|
filled = 0
|
||||||
}
|
}
|
||||||
@@ -391,10 +382,7 @@ func renderProcessCard(procs []ProcessInfo) cardData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func miniBar(percent float64) string {
|
func miniBar(percent float64) string {
|
||||||
filled := int(percent / 20)
|
filled := min(int(percent/20), 5)
|
||||||
if filled > 5 {
|
|
||||||
filled = 5
|
|
||||||
}
|
|
||||||
if filled < 0 {
|
if filled < 0 {
|
||||||
filled = 0
|
filled = 0
|
||||||
}
|
}
|
||||||
@@ -437,10 +425,7 @@ func renderNetworkCard(netStats []NetworkStatus, proxy ProxyStatus) cardData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func netBar(rate float64) string {
|
func netBar(rate float64) string {
|
||||||
filled := int(rate / 2.0)
|
filled := min(int(rate/2.0), 5)
|
||||||
if filled > 5 {
|
|
||||||
filled = 5
|
|
||||||
}
|
|
||||||
if filled < 0 {
|
if filled < 0 {
|
||||||
filled = 0
|
filled = 0
|
||||||
}
|
}
|
||||||
@@ -551,10 +536,7 @@ func renderSensorsCard(sensors []SensorReading) cardData {
|
|||||||
|
|
||||||
func renderCard(data cardData, width int, height int) string {
|
func renderCard(data cardData, width int, height int) string {
|
||||||
titleText := data.icon + " " + data.title
|
titleText := data.icon + " " + data.title
|
||||||
lineLen := width - lipgloss.Width(titleText) - 2
|
lineLen := max(width-lipgloss.Width(titleText)-2, 4)
|
||||||
if lineLen < 4 {
|
|
||||||
lineLen = 4
|
|
||||||
}
|
|
||||||
header := titleStyle.Render(titleText) + " " + lineStyle.Render(strings.Repeat("╌", lineLen))
|
header := titleStyle.Render(titleText) + " " + lineStyle.Render(strings.Repeat("╌", lineLen))
|
||||||
content := header + "\n" + strings.Join(data.lines, "\n")
|
content := header + "\n" + strings.Join(data.lines, "\n")
|
||||||
|
|
||||||
@@ -576,7 +558,7 @@ func progressBar(percent float64) string {
|
|||||||
filled := int(percent / 100 * float64(total))
|
filled := int(percent / 100 * float64(total))
|
||||||
|
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
for i := 0; i < total; i++ {
|
for i := range total {
|
||||||
if i < filled {
|
if i < filled {
|
||||||
builder.WriteString("█")
|
builder.WriteString("█")
|
||||||
} else {
|
} else {
|
||||||
@@ -597,7 +579,7 @@ func batteryProgressBar(percent float64) string {
|
|||||||
filled := int(percent / 100 * float64(total))
|
filled := int(percent / 100 * float64(total))
|
||||||
|
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
for i := 0; i < total; i++ {
|
for i := range total {
|
||||||
if i < filled {
|
if i < filled {
|
||||||
builder.WriteString("█")
|
builder.WriteString("█")
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user