aboutsummaryrefslogtreecommitdiff
path: root/main.go
blob: 31d2043e8a5b16a912aa417e9ad26be4abcfa0ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package main

import (
	"context"
	"flag"
	"fmt"
	"os"
	"os/signal"
	"time"
)

type Opt struct {
	Work  time.Duration
	Short time.Duration
	Long  time.Duration
	Day   time.Duration
	Runs  int
	run   int
}

type stateFn func(context.Context) stateFn

func display(ctx context.Context, s string) {
	dl, ok := ctx.Deadline()
	if !ok {
		return
	}
	ticker := time.NewTicker(time.Second)
	defer ticker.Stop()
	defer fmt.Printf("\r%s done\x1b[K\n", s)
	for range ticker.C {
		select {
		case <-ctx.Done():
			return
		default:
			left := time.Until(dl)
			left -= left % time.Second
			if left < 0 {
				left = 0
			}
			fmt.Printf("\r%s %s left\x1b[K", s, left)
		}
	}
}

func (o *Opt) doWork(ctx context.Context) stateFn {
	select {
	case <-ctx.Done():
		return nil
	default:
		ctx, cancel := context.WithTimeout(ctx, o.Work)
		defer cancel()
		display(ctx, "do work")
	}
	if o.run++; o.run%o.Runs == 0 {
		return o.longBreak
	}
	return o.shortBreak
}

func (o *Opt) shortBreak(ctx context.Context) stateFn {
	select {
	case <-ctx.Done():
		return nil
	default:
		ctx, cancel := context.WithTimeout(ctx, o.Short)
		defer cancel()
		display(ctx, "short break")
	}
	return o.doWork
}

func (o *Opt) longBreak(ctx context.Context) stateFn {
	select {
	case <-ctx.Done():
		return nil
	default:
		ctx, cancel := context.WithTimeout(ctx, o.Long)
		defer cancel()
		display(ctx, "long break")
	}
	return o.doWork
}

func main() {
	var o Opt
	flag.DurationVar(&o.Work, "work", 25*time.Minute, "work time")
	flag.DurationVar(&o.Short, "short", 5*time.Minute, "short break")
	flag.DurationVar(&o.Long, "long", 15*time.Minute, "long break")
	flag.DurationVar(&o.Day, "day", 12*time.Hour, "work day")
	flag.IntVar(&o.Runs, "runs", 4, "work runs")
	flag.Parse()

	ctx, cancel := context.WithTimeout(context.Background(), o.Day)

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt)
	go func() {
		<-sig
		cancel()
	}()

	defer func(t time.Time) {
		total := time.Since(t)
		total -= total % time.Second
		fmt.Printf("total %v\n", total)
	}(time.Now())

	for s := o.doWork; s != nil; s = s(ctx) {
	}
}