// Package main has a comment package main import ( "flag" "fmt" "time" "github.com/eiannone/keyboard" ) 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(remains time.Duration, target time.Duration, delim *rune, reverse bool) { sec := remains.Seconds() hrs := int(sec / 60.0) seconds := int(sec) % 60 if *delim == ':' { *delim = ' ' } else { *delim = ':' } if reverse { remains := target - remains rHrs := int(remains.Seconds() / 60.0) rSec := int(remains.Seconds()) % 60 fmt.Printf("\rAt: %d%c%02d\tRemaining: %d%c%02d", hrs, byte(*delim), seconds, rHrs, byte(*delim), rSec) } else { fmt.Printf("\rRemaining: %d%c%02d", hrs, byte(*delim), seconds) } }