// Package main has a comment package main import ( "flag" "fmt" "time" "github.com/eiannone/keyboard" "github.com/everdev/mack" ) var notified = false func main() { var duration string var offset string var interval string var repeat bool var invert bool flag.BoolVar(&repeat, "repeat", true, "Whether to repeat the timer on complete") flag.BoolVar(&invert, "stopwatch", false, "Use as a stopwatch") flag.StringVar(&duration, "duration", "30m", "How long the timer should be") flag.StringVar(&offset, "offset", "0m", "How much time the initial time should skip") flag.StringVar(&interval, "interval", "500ms", "Interval duration") flag.Parse() tickerInterval, err := time.ParseDuration(interval) if err != nil { panic(err) } monitor := time.NewTicker(tickerInterval) defer monitor.Stop() base, err := time.ParseDuration(duration) if err != nil { panic(err) } var cur time.Duration if invert { cur = time.Duration(0) } else { cur = base } skip, err := time.ParseDuration(offset) if err != nil { panic(err) } if invert { cur += skip } else { cur -= skip } stop := make(chan bool) pause := make(chan bool) confirm := make(chan bool) paused := false delim := ':' fmt.Println("Quit with 'q', Pause with 'p'") go func() { last := time.Now() printTime(&cur, base, &delim, invert) for { select { case <-monitor.C: if invert { cur += time.Now().Sub(last) } else { cur -= time.Now().Sub(last) } case state := <-pause: if !state { monitor = time.NewTicker(tickerInterval) } else { monitor.Stop() } case <-stop: fmt.Println("") confirm <- true return } last = time.Now() printTime(&cur, base, &delim, invert) } }() if err := keyboard.Open(); err != nil { panic(err) } defer keyboard.Close() for { b, _, err := keyboard.GetKey() if err != nil { panic(err) } switch b { case 'q': stop <- true <-confirm return case 'p': paused = !paused pause <- paused } } } func printTime(pRemains *time.Duration, target time.Duration, delim *rune, reverse bool) { remains := *pRemains sec := remains.Seconds() min := int(sec / 60.0) seconds := int(sec) % 60 hrs := min / 60 min = min % 60 if *delim == ':' { *delim = ' ' } else { *delim = ':' } if reverse { remains := target - remains rMin := int(remains.Seconds() / 60.0) rSec := int(remains.Seconds()) % 60 rHrs := rMin / 60 rMin = rMin % 60 tdelim := byte(*delim) if remains < 0 { rMin = 0 rSec = 0 rHrs = 0 tdelim = ':' go alertTime(pRemains, target, reverse) } fmt.Printf("\rAt: %2d%c%02d%c%02d\tRemaining: %2d%c%02d%c%02d", hrs, byte(*delim), min, byte(*delim), seconds, rHrs, tdelim, rMin, tdelim, rSec) } else { fmt.Printf("\rRemaining: %2d%c%02d%c%02d", hrs, byte(*delim), min, byte(*delim), seconds) if remains < 0 { go alertTime(pRemains, target, reverse) } } } func alertTime(pRemains *time.Duration, target time.Duration, reverse bool) { if !notified { notified = true _, err := mack.Alert("Alert") if err != nil { panic(err) } if reverse { *pRemains -= target } else { *pRemains += target } notified = false } }