all repos

viye @ fa602cd19cb3521c7731a187b6e70f3e1c8cdebf

my shot at reimplementing xiki
5 files changed, 147 insertions(+), 0 deletions(-)
add neofetch
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
        +}

      
A internal/version/version.go
···
        
        1
        +package version

      
        
        2
        +

      
        
        3
        +const Version = "0.0.1-alpha"

      
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)