5 files changed,
147 insertions(+),
0 deletions(-)
Author:
Oleksandr Smirnov
olexsmir@gmail.com
Committed at:
2026-07-25 22:24:29 +0300
Authored at:
2026-07-25 21:44:47 +0300
Change ID:
rxlwqywpnykunnrvsmzylyvopumupltq
Parent:
caaab43
M
internal/osutil/osutil_linux.go
··· 3 3 package osutil 4 4 5 5 import ( 6 + "fmt" 7 + "os" 6 8 "os/exec" 9 + "runtime" 10 + "strconv" 11 + "strings" 7 12 "syscall" 13 + "time" 8 14 ) 9 15 10 16 func Open(path string) error { ··· 13 19 cmd.Start() 14 20 return nil 15 21 } 22 + 23 +func GetKernel() (string, error) { 24 + // or read from: /proc/sys/kernel/osrelease 25 + k, err := exec.Command("uname", "-r").Output() 26 + if err != nil { 27 + return "?", nil 28 + } 29 + return strings.TrimSpace(string(k)), nil 30 +} 31 + 32 +func GetMemory() (string, error) { 33 + f, err := os.ReadFile("/proc/meminfo") 34 + if err != nil { 35 + return "", err 36 + } 37 + var totalKB, availKB int64 38 + for line := range strings.SplitSeq(string(f), "\n") { 39 + switch { 40 + case strings.HasPrefix(line, "MemTotal:"): 41 + p := strings.Fields(line) 42 + if len(p) >= 2 { 43 + totalKB, _ = strconv.ParseInt(p[1], 10, 64) 44 + } 45 + case strings.HasPrefix(line, "MemAvailable:"): 46 + lp := strings.Fields(line) 47 + if len(lp) >= 2 { 48 + availKB, _ = strconv.ParseInt(lp[1], 10, 64) 49 + } 50 + } 51 + } 52 + if totalKB == 0 { 53 + return "", fmt.Errorf("no MemTotal in /proc/meminfo") 54 + } 55 + used := float64(totalKB-availKB) / (1024 * 1024) 56 + total := float64(totalKB) / (1024 * 1024) 57 + return fmt.Sprintf("%.1f/%.1f GiB", used, total), nil 58 +} 59 + 60 +func GetCPU() (string, error) { 61 + f, err := os.ReadFile("/proc/cpuinfo") 62 + if err != nil { 63 + return "", err 64 + } 65 + for line := range strings.SplitSeq(string(f), "\n") { 66 + if !strings.HasPrefix(line, "model name") { 67 + continue 68 + } 69 + _, after, ok := strings.Cut(line, ":") 70 + if !ok { 71 + continue 72 + } 73 + return fmt.Sprintf("%s (%d)", strings.TrimSpace(after), runtime.NumCPU()), nil 74 + } 75 + return "", fmt.Errorf("no model name in /proc/cpuinfo") 76 +} 77 + 78 +func GetUptime() (string, error) { 79 + f, err := os.ReadFile("/proc/uptime") 80 + if err != nil { 81 + return "", err 82 + } 83 + p := strings.Fields(string(f)) 84 + if len(p) == 0 { 85 + return "", fmt.Errorf("empty /proc/uptime") 86 + } 87 + s, err := strconv.ParseFloat(p[0], 64) 88 + if err != nil { 89 + return "", err 90 + } 91 + 92 + d := time.Duration(s) * time.Second 93 + days := int(d.Hours()) / 24 94 + hours := int(d.Hours()) % 24 95 + mins := int(d.Minutes()) % 60 96 + 97 + switch { 98 + case days > 0: 99 + return fmt.Sprintf("%dd %dh", days, hours), nil 100 + case hours > 0: 101 + return fmt.Sprintf("%dh %dm", hours, mins), nil 102 + default: 103 + return fmt.Sprintf("%dm", mins), nil 104 + } 105 +} 106 + 107 +func GetOS() (string, error) { 108 + f, err := os.ReadFile("/etc/os-release") 109 + if err != nil { 110 + return "", err 111 + } 112 + for line := range strings.SplitSeq(string(f), "\n") { 113 + if strings.HasPrefix(line, "PRETTY_NAME=") { 114 + p := strings.Split(line, "=") 115 + if len(p) != 2 { 116 + return "Linux", err 117 + } 118 + return strings.Trim(p[1], `" `), nil 119 + } 120 + } 121 + return "Linux", nil 122 +}
A
internal/plumbing/neofetch/neofetch.go
··· 1 +package neofetch 2 + 3 +import ( 4 + "fmt" 5 + "strings" 6 + 7 + "github.com/olexsmir/viye/internal/osutil" 8 + "github.com/olexsmir/viye/internal/version" 9 + "github.com/olexsmir/viye/internal/viye" 10 +) 11 + 12 +type Tool struct{} 13 + 14 +func (Tool) Name() string { return "neofetch" } 15 +func (Tool) Match(c *viye.Context) bool { return c.Cmd == "neofetch" } 16 +func (Tool) Execute(c *viye.Context) (string, error) { 17 + kernel, _ := osutil.GetKernel() 18 + osname, _ := osutil.GetOS() 19 + cpu, _ := osutil.GetCPU() 20 + mem, _ := osutil.GetMemory() 21 + uptime, _ := osutil.GetUptime() 22 + 23 + var buf strings.Builder 24 + _, _ = fmt.Fprintf(&buf, "| OS: %s (%s)\n", osname, kernel) 25 + _, _ = fmt.Fprintf(&buf, "| SYS: %s · %s\n", cpu, mem) 26 + _, _ = fmt.Fprintf(&buf, "| Uptime: %s\n", uptime) 27 + _, _ = fmt.Fprintf(&buf, "| Viye: %s\n", version.Version) 28 + return buf.String(), nil 29 +}
M
internal/viye/viye.go
··· 5 5 "io" 6 6 "os" 7 7 "strings" 8 + 9 + "github.com/olexsmir/viye/internal/version" 8 10 ) 9 11 10 12 type Context struct { ··· 44 46 } 45 47 if args[1] == "help" { 46 48 return v.showHelp(out) 49 + } 50 + if args[1] == "--version" { 51 + fmt.Fprint(out, "| viye version: "+version.Version) 52 + return nil 47 53 } 48 54 49 55 path, body := splitArgs(args[1:])
M
main.go
··· 9 9 "github.com/olexsmir/viye/internal/plumbing/gobin" 10 10 "github.com/olexsmir/viye/internal/plumbing/ip" 11 11 "github.com/olexsmir/viye/internal/plumbing/json" 12 + "github.com/olexsmir/viye/internal/plumbing/neofetch" 12 13 "github.com/olexsmir/viye/internal/plumbing/shell" 13 14 "github.com/olexsmir/viye/internal/plumbing/url" 14 15 "github.com/olexsmir/viye/internal/viye" ··· 23 24 v.Register(&gobin.Tool{}) 24 25 v.Register(&json.Tool{}) 25 26 v.Register(&config.Tool{}) 27 + v.Register(&neofetch.Tool{}) 26 28 27 29 if err := v.Run(os.Stdout, os.Args); err != nil { 28 30 fmt.Fprintf(os.Stderr, "viye: %v\n", err)