package main import ( "bufio" "fmt" "os" "time" "golang.org/x/sys/unix" "os/exec" "strconv" "strings" "io/ioutil" ) var ( data, connectedWiFi, memPercentage, cpuTemp, cpuPercentage, volumeLevel string batteryLevel, chargingStatus string text string = "\n" moduleColor0, moduleColor1 string = "#9b1bed", "#ff0aa3" ) func dataLoop() { for { data = getData() time.Sleep(time.Second / 10) } } func stdinLoop() { reader := bufio.NewReader(os.Stdin) for { text, _ = reader.ReadString('\n') } } // to update modules every 5 seconds func fiveSecLoop() { for { memPercentage = getMemUsage() cpuTemp = getCPUTemp() cpuPercentage = getCPUUsage() time.Sleep(time.Second * 5) } } // to update modules every 10 seconds func tenSecLoop() { for { connectedWiFi = getWiFiName() chargingStatus, batteryLevel = getBatteryInfo() time.Sleep(time.Second * 10) } } // very creative name // used to update modules like volume, etc // don't want lag on those modules! func veryFastLoop() { for { volumeLevel = getVolumeLevel() time.Sleep(time.Second / 10) } } func main() { go dataLoop() go stdinLoop() go fiveSecLoop() go tenSecLoop() go veryFastLoop() for { fmt.Print(data + text) time.Sleep(time.Second / 10) } } func getData() string { time := "%{F" + moduleColor0 + "} " + getTime() + "%{F-} " wifiName := "%{F" + moduleColor1 + "} WiFI: " + connectedWiFi + "%{F-} " rootFree := "%{F" + moduleColor0 + "} / " + getDisk("/") + "%%{F-} " homeFree := "%{F" + moduleColor1 + "} /home " + getDisk("/home") + "%%{F-} " hddFree := "%{F" + moduleColor0 + "} /hdd " + getDisk("/hdd") + "%%{F-} " cpuUsage := "%{F" + moduleColor1 + "} CPU: " + cpuPercentage + "%%{F-} " cpuTemp := "%{F" + moduleColor0 + "} TEMP: " + cpuTemp + "%{F-} " memUsage := "%{F" + moduleColor1 + "} MEM: " + memPercentage + "%{F-} " volume := "%{F" + moduleColor0 + "}" if volumeLevel != "muted" { volume = volume + "} VOL: " + volumeLevel + "%{F-} " } else { volume = volume + "} MUTED%{F-} " } // shows battery level in different color // depending on charging status // hidden when full var battery string btlvl, _ := strconv.Atoi(batteryLevel) if btlvl < 100 { col := moduleColor1 if chargingStatus == "Charging" { col = moduleColor0 } battery = fmt.Sprintf("%%{F%s} BATT: %s%%{F-} ", col, batteryLevel) } // TODO add brightness (new) return time + wifiName + rootFree + homeFree + hddFree + cpuUsage + cpuTemp + "%{r}" + memUsage + battery } func getWiFiName() string { // script located in ~/.scripts/ // look at github.com/MikunoNaka/dots cmd := exec.Command("get_wifi_name.sh") name, _ := cmd.Output() return string(name) } func getMemUsage() string { // script located in ~/.scripts/ // look at github.com/MikunoNaka/dots cmd := exec.Command("ram_usage.sh") usage, _ := cmd.Output() return string(usage) } func getCPUTemp() string { // script located in ~/.scripts/ // look at github.com/MikunoNaka/dots cmd := exec.Command("cpu_temp.sh") temp, _ := cmd.Output() return string(temp) } func getVolumeLevel() string { // script located in ~/.scripts/ // look at github.com/MikunoNaka/dots cmd := exec.Command("volume_level.sh") level, _ := cmd.Output() return string(level) } func getBatteryInfo() (string, string) { // scripts located in ~/.scripts/ // look at github.com/MikunoNaka/dots statCmd := exec.Command("charging_status.sh") stat, _ := statCmd.Output() levelCmd := exec.Command("battery_level.sh") level, _ := levelCmd.Output() return string(stat), string(level) } // TODO: maybe add dates on click func getTime() string { now := time.Now() return now.Format(" 3:04 PM") } // TODO: maybe show percentages instead of free space func getDisk(mountPoint string) string { var stat unix.Statfs_t unix.Statfs(mountPoint, &stat) // this is witchcraft. I wrote this but I have -10000 idea how AND IF it works totalSize := float64(stat.Blocks) * float64(stat.Bsize) / 1073741824 usedSpace := float64(stat.Bfree) * float64(stat.Bsize) / 1073741824 return strconv.FormatFloat((100 - (usedSpace / totalSize) * 100), 'f', 0, 64) } func getCPUSample() (idle, total uint64) { contents, err := ioutil.ReadFile("/proc/stat") if err != nil { return } lines := strings.Split(string(contents), "\n") for _, line := range(lines) { fields := strings.Fields(line) if fields[0] == "cpu" { numFields := len(fields) for i := 1; i < numFields; i++ { val, err := strconv.ParseUint(fields[i], 10, 64) if err != nil { fmt.Println("Error: ", i, fields[i], err) } total += val // tally up all the numbers to get total ticks if i == 4 { // idle is the 5th field in the cpu line idle = val } } return } } return } func getCPUUsage() string { idle0, total0 := getCPUSample() time.Sleep(3 * time.Second) idle1, total1 := getCPUSample() idleTicks := float64(idle1 - idle0) totalTicks := float64(total1 - total0) cpuUsage := 100 * (totalTicks - idleTicks) / totalTicks return strconv.Itoa(int(cpuUsage)) }