<commit_before>// Simple tool to show battery status from SysFS as GTK icon.
package main

import (
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	"github.com/mattn/go-gtk/gtk"
	"power"
)

var levels = []string{
	"empty",
	"caution",
	"low",
	"good",
	"full",
}

var states = []string{
	"charged",
	"charging",
}

type Icon struct {
	Battery    power.Battery
	StatusIcon *gtk.StatusIcon
}

func getIcons() []Icon {
	bat, err := power.Get()
	if err != nil {
		log.Fatalf("failed to get battery info: %v\n", err)
	}
	result := make([]Icon, len(bat))
	for i, b := range bat {
		icon := Icon{
			Battery: b,
		}
		in := icon.getName()
		icon.StatusIcon = gtk.NewStatusIconFromIconName(in)
		log.Printf("Created status icon %v with icon name %s\n", icon, in)
		result[i] = icon
	}
	return result
}

// getName builds the GTK icon name.
func (i Icon) getName() string {
	state := strings.ToLower(i.Battery.State.String())
	var level string
	if i.Battery.Current < 0.1 { // TODO: Map, or something.
		level = "empty"
	} else if i.Battery.Current < 0.4 {
		level = "caution"
	} else if i.Battery.Current < 0.9 {
		level = "good"
	} else {
		level = "full"
	}
	if state == "discharging" || state == "full" {
		return fmt.Sprintf("battery-%s", level)
	} else {
		return fmt.Sprintf("battery-%s-%s", level, state)
	}
}

// update updates the icon with new battery info.
func (i *Icon) update(battery power.Battery) {
	// TODO: also set / update tooltip.
	oldName := i.getName()
	i.Battery = battery
	newName := i.getName()
	if newName != oldName {
		log.Printf("Changing icon to %q from %q..\n", newName, oldName)
		i.StatusIcon.SetFromIconName(newName)
	}
}

// poll reads battery info and sleeps for specified duration.
func poll(d time.Duration, icon []Icon) {
	for {
		bat, err := power.Get()
		if err != nil {
			log.Fatalf("failed to get battery info: %v\n", err)
		}
		for i, b := range bat {
			log.Printf("[Battery %d]: %+v\n", i, b)
			icon[i].update(b)
		}
		time.Sleep(d)
	}
}

func main() {
	gtk.Init(&os.Args)
	icons := getIcons()
	d, err := time.ParseDuration("20s")
	if err != nil {
		log.Fatalf("bad duration: %v\n", err)
	}
	go poll(d, icons)
	log.Printf("Calling gtk.Main()..")
	gtk.Main()
}
<commit_msg>tweaks icon-picking logic, adds tooltip, TODOs<commit_after>// Simple tool to show battery status from SysFS as GTK icon.
package main

import (
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	"github.com/mattn/go-gtk/gtk"
	"power"
)

var levels = []string{
	"empty",
	"caution",
	"low",
	"good",
	"full",
}

var states = []string{
	"charged",
	"charging",
}

type Icon struct {
	Battery    power.Battery
	StatusIcon *gtk.StatusIcon
}

func getIcons() []Icon {
	bat, err := power.Get()
	if err != nil {
		log.Fatalf("failed to get battery info: %v\n", err)
	}
	result := make([]Icon, len(bat))
	for i, b := range bat {
		icon := Icon{
			Battery: b,
		}
		in := icon.getName()
		icon.StatusIcon = gtk.NewStatusIconFromIconName(in)
		log.Printf("Created status icon %v with icon name %s\n", icon, in)
		result[i] = icon
	}
	return result
}

// getName builds the GTK icon name.
func (i Icon) getName() string {
	state := strings.ToLower(i.Battery.State.String())
	var level string
	if i.Battery.Current < 0.1 { // TODO: Map, or something.
		level = "empty"
	} else if i.Battery.Current < 0.4 {
		level = "caution"
	} else if i.Battery.Current < 0.9 {
		level = "good"
	} else {
		level = "full"
	}
	if state == "unknown" {
		if level == "full" {
			// Full batteries sometimes are reported as "unknown", for some reason.
			state = "full"
		} else {
			state = "missing"
		}
	}
	if state == "missing" {
		return "battery-missing"
	} else if state == "discharging" || state == "full" {
		return fmt.Sprintf("battery-%s", level)
	} else {
		return fmt.Sprintf("battery-%s-%s", level, state)
	}
}

// update updates the icon with new battery info.
func (i *Icon) update(battery power.Battery) {
	oldName := i.getName()
	i.Battery = battery
	newName := i.getName()
	if newName != oldName {
		log.Printf("Changing icon to %q from %q..\n", newName, oldName)
		// TODO: this should check if the icon name to set actually exists, somehow.
		i.StatusIcon.SetFromIconName(newName)
	}
	i.StatusIcon.SetTooltipText(battery.String())
}

// poll reads battery info and sleeps for specified duration.
func poll(d time.Duration, icons []Icon) {
	for {
		// TODO: when a battery disappears (e.g. is disconnected), the
		// icon persists (but the goroutine seems to block, maybe on SysFS
		// read). Repro and address - icon should go away.
		bat, err := power.Get()
		if err != nil {
			log.Fatalf("failed to get battery info: %v\n", err)
		}
		for i, b := range bat {
			log.Printf("[Battery %d]: %+v\n", i, b)
			icons[i].update(b)
		}
		time.Sleep(d)
	}
}

func main() {
	gtk.Init(&os.Args)
	icons := getIcons()
	d, err := time.ParseDuration("20s")
	if err != nil {
		log.Fatalf("bad duration: %v\n", err)
	}
	go poll(d, icons)
	log.Printf("Calling gtk.Main()..")
	gtk.Main()
}

{'fraction_non_alphanumeric': 0.16465135026199113, 'fraction_numerical': 0.0032245062474808546, 'mean_word_length': 3.2600858369098713, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3345111', 'n_tokens_mistral': 1996, 'n_tokens_neox': 1897, 'n_words': 545}