Commit
+155 -0 +/-5 browse
1 | diff --git a/.gitignore b/.gitignore |
2 | new file mode 100644 |
3 | index 0000000..dde85ad |
4 | --- /dev/null |
5 | +++ b/.gitignore |
6 | @@ -0,0 +1,26 @@ |
7 | + # Compiled Object files, Static and Dynamic libs (Shared Objects) |
8 | + *.o |
9 | + *.a |
10 | + *.so |
11 | + |
12 | + # Folders |
13 | + _obj |
14 | + _test |
15 | + |
16 | + # Architecture specific extensions/prefixes |
17 | + *.[568vq] |
18 | + [568vq].out |
19 | + |
20 | + *.cgo1.go |
21 | + *.cgo2.c |
22 | + _cgo_defun.c |
23 | + _cgo_gotypes.go |
24 | + _cgo_export.* |
25 | + |
26 | + _testmain.go |
27 | + |
28 | + *.exe |
29 | + *.test |
30 | + *.prof |
31 | + |
32 | + *.swp |
33 | diff --git a/README.md b/README.md |
34 | new file mode 100644 |
35 | index 0000000..e479334 |
36 | --- /dev/null |
37 | +++ b/README.md |
38 | @@ -0,0 +1,3 @@ |
39 | + # pomo |
40 | + |
41 | + `pomo` is a simple CLI implementation of the [Pomodoro Technique](https://en.wikipedia.org/wiki/Pomodoro_Technique). It integrates with [i3](i3wm.org) and might support other environments later on. |
42 | diff --git a/main.go b/main.go |
43 | new file mode 100644 |
44 | index 0000000..dfdfa46 |
45 | --- /dev/null |
46 | +++ b/main.go |
47 | @@ -0,0 +1,71 @@ |
48 | + package main |
49 | + |
50 | + import ( |
51 | + "fmt" |
52 | + "github.com/jawher/mow.cli" |
53 | + "os" |
54 | + "time" |
55 | + ) |
56 | + |
57 | + func maybe(err error) { |
58 | + if err != nil { |
59 | + fmt.Printf("Error: %s", err) |
60 | + os.Exit(1) |
61 | + } |
62 | + } |
63 | + |
64 | + func startTask(task Task, prompter Prompter, db *Store) { |
65 | + taskID, err := db.AddTask(task) |
66 | + maybe(err) |
67 | + for i := 0; i < task.count; i++ { |
68 | + // Create a new "Pomo" to represent |
69 | + // this particular stent of work |
70 | + pomo := &Pomo{TaskID: taskID} |
71 | + // Prompt the client |
72 | + maybe(prompter.Prompt("Begin Working!")) |
73 | + pomo.Start = time.Now() |
74 | + // Wait the specified interval |
75 | + time.Sleep(task.duration) |
76 | + maybe(prompter.Prompt("Take a Break!")) |
77 | + // Record how long the user waited |
78 | + // until closing the notification |
79 | + pomo.End = time.Now() |
80 | + maybe(db.AddPomo(*pomo)) |
81 | + } |
82 | + |
83 | + } |
84 | + |
85 | + func start(cmd *cli.Cmd) { |
86 | + cmd.Spec = "[OPTIONS] NAME" |
87 | + var ( |
88 | + duration = cmd.StringOpt("d duration", "25m", "duration of each stent") |
89 | + count = cmd.IntOpt("c count", 4, "number of working stents") |
90 | + name = cmd.StringArg("NAME", "", "descriptive name of the given task") |
91 | + path = cmd.StringOpt("d db", "~/.pomo/state.db", "path to the pomo sqlite database") |
92 | + ) |
93 | + cmd.Action = func() { |
94 | + parsed, err := time.ParseDuration(*duration) |
95 | + maybe(err) |
96 | + db, err := NewStore(*path) |
97 | + maybe(err) |
98 | + task := Task{ |
99 | + Name: *name, |
100 | + count: *count, |
101 | + duration: parsed, |
102 | + } |
103 | + startTask(task, &I3{}, db) |
104 | + } |
105 | + } |
106 | + |
107 | + func initialize(cmd *cli.Cmd) {} |
108 | + |
109 | + func list(cmd *cli.Cmd) {} |
110 | + |
111 | + func main() { |
112 | + app := cli.App("pomo", "Pomodoro CLI") |
113 | + app.Spec = "[OPTIONS]" |
114 | + app.Command("start", "start a new task", start) |
115 | + app.Command("init", "initialize the sqlite database", initialize) |
116 | + app.Command("ls", "list historical tasks", list) |
117 | + app.Run(os.Args) |
118 | + } |
119 | diff --git a/store.go b/store.go |
120 | new file mode 100644 |
121 | index 0000000..48c0ae1 |
122 | --- /dev/null |
123 | +++ b/store.go |
124 | @@ -0,0 +1,11 @@ |
125 | + package main |
126 | + |
127 | + type Store struct{} |
128 | + |
129 | + func NewStore(path string) (*Store, error) { |
130 | + return &Store{}, nil |
131 | + } |
132 | + |
133 | + func (s Store) AddTask(task Task) (int, error) { return 0, nil } |
134 | + |
135 | + func (s Store) AddPomo(pomo Pomo) error { return nil } |
136 | diff --git a/types.go b/types.go |
137 | new file mode 100644 |
138 | index 0000000..2054ede |
139 | --- /dev/null |
140 | +++ b/types.go |
141 | @@ -0,0 +1,44 @@ |
142 | + package main |
143 | + |
144 | + import ( |
145 | + "fmt" |
146 | + "os/exec" |
147 | + "time" |
148 | + ) |
149 | + |
150 | + // Task describes some activity |
151 | + type Task struct { |
152 | + ID int `json:"id"` |
153 | + Name string `json:"name"` |
154 | + count int |
155 | + duration time.Duration |
156 | + } |
157 | + |
158 | + // Pomo is a stetch of work performed on a |
159 | + // specific task. |
160 | + type Pomo struct { |
161 | + TaskID int `json:"task_id"` |
162 | + Start time.Time `json:"start"` |
163 | + End time.Time `json:"end"` |
164 | + } |
165 | + |
166 | + // Prompter prompts a user with a message. |
167 | + type Prompter interface { |
168 | + Prompt(string) error |
169 | + } |
170 | + |
171 | + // I3 implements a prompter for i3 |
172 | + type I3 struct{} |
173 | + |
174 | + func (i *I3) Prompt(message string) error { |
175 | + raw, err := exec.Command( |
176 | + "/bin/i3-nagbar", |
177 | + "-m", |
178 | + message, |
179 | + ).Output() |
180 | + if err != nil { |
181 | + return err |
182 | + } |
183 | + fmt.Println(string(raw)) |
184 | + return nil |
185 | + } |