commit 0013cb6d812b556fd6941cbfa962ff2bed915bd4 Author: tijl Date: Fri Sep 27 17:22:11 2024 +0200 updates diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..e8a0616 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git.tijl.dev/tijl/stopwatch + +go 1.22.6 diff --git a/main.go b/main.go new file mode 100644 index 0000000..f3e659b --- /dev/null +++ b/main.go @@ -0,0 +1,133 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + "os/signal" + "os/user" + "path/filepath" + "syscall" + "time" +) + +type Stopwatches map[string]time.Time + +var configPath string + +func main() { + args := os.Args[1:] + + if len(args) == 0 { + // Quick stop watch + stopwatchUI(time.Now()) + } else if len(args) == 1 && (args[0] == "help" || args[0] == "-h" || args[0] == "--help") { + printHelp() + } else if len(args) == 1 { + namedStopwatch(args[0]) + } else if len(args) == 2 && (args[0] == "clear" || args[0] == "-c" || args[0] == "--clear") { + clearStopwatch(args[1]) + } +} + +func namedStopwatch(name string) { + stopwatches, err := loadStopwatches() + if err != nil { + fmt.Println("Error loading stopwatches:", err) + return + } + + startTime, exists := stopwatches[name] + if !exists { + stopwatches[name] = time.Now() + saveStopwatches(stopwatches) + } else { + stopwatchUI(startTime) + } +} + +func clearStopwatch(name string) { + stopwatches, err := loadStopwatches() + if err != nil { + fmt.Println("Error loading stopwatches:", err) + return + } + + if _, exists := stopwatches[name]; exists { + delete(stopwatches, name) + err := saveStopwatches(stopwatches) + if err != nil { + fmt.Println("Error saving stopwatches:", err) + return + } + } else { + fmt.Printf("Stopwatch '%s' does not exist.\n", name) + } +} + +func init() { + usr, err := user.Current() + if err != nil { + fmt.Println("Error getting user home directory:", err) + os.Exit(1) + } + configDir := filepath.Join(usr.HomeDir, ".config") + configPath = filepath.Join(configDir, ".stopwatches") + + if _, err := os.Stat(configDir); os.IsNotExist(err) { + os.MkdirAll(configDir, 0755) + } +} + +func loadStopwatches() (Stopwatches, error) { + stopwatches := Stopwatches{} + + if _, err := os.Stat(configPath); err == nil { + data, err := os.ReadFile(configPath) + if err != nil { + return stopwatches, err + } + err = json.Unmarshal(data, &stopwatches) + if err != nil { + return stopwatches, err + } + } + + return stopwatches, nil +} + +func saveStopwatches(stopwatches Stopwatches) error { + data, err := json.MarshalIndent(stopwatches, "", " ") + if err != nil { + return err + } + return os.WriteFile(configPath, data, 0644) +} + +func stopwatchUI(startTime time.Time) { + stop := make(chan os.Signal, 1) + signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM) + + go func() { + <-stop + os.Exit(0) + }() + + for { + elapsed := time.Since(startTime) + fmt.Printf("\r%02dd %02dh %02dm %02ds %03dms", + elapsed/(24*time.Hour), + (elapsed%(24*time.Hour))/time.Hour, + (elapsed%time.Hour)/time.Minute, + (elapsed%time.Minute)/time.Second, + (elapsed%time.Second)/time.Millisecond) + time.Sleep(10 * time.Millisecond) + } +} + +func printHelp() { + fmt.Println("Usage:") + fmt.Println(" stopwatch - Start a quick stopwatch") + fmt.Println(" stopwatch [name] - Start or view a named stopwatch") + fmt.Println(" stopwatch clear [name] - Remove a named stopwatch") +}