now-task-manager 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +66 -0
  3. data/bin/git-commit-pomodoro +4 -0
  4. data/bin/pomodoro +246 -0
  5. data/doc/benefits.md +91 -0
  6. data/doc/bitbar.md +2 -0
  7. data/doc/curses.md +5 -0
  8. data/doc/example/rules.rb +7 -0
  9. data/doc/formats/scheduled.md +32 -0
  10. data/doc/formats/today.md +115 -0
  11. data/doc/getting-started.md +41 -0
  12. data/doc/integrations.md +68 -0
  13. data/doc/rules.md +0 -0
  14. data/doc/schedules.md +0 -0
  15. data/doc/terms.md +32 -0
  16. data/doc/workflow.md +60 -0
  17. data/lib/pomodoro.rb +6 -0
  18. data/lib/pomodoro/commands/bitbar.rb +87 -0
  19. data/lib/pomodoro/config.rb +30 -0
  20. data/lib/pomodoro/exts/hour.rb +63 -0
  21. data/lib/pomodoro/formats/scheduled.rb +37 -0
  22. data/lib/pomodoro/formats/scheduled/parser/parser.rb +26 -0
  23. data/lib/pomodoro/formats/scheduled/parser/transformer.rb +21 -0
  24. data/lib/pomodoro/formats/scheduled/task_group.rb +40 -0
  25. data/lib/pomodoro/formats/scheduled/task_list.rb +90 -0
  26. data/lib/pomodoro/formats/today.rb +12 -0
  27. data/lib/pomodoro/formats/today/formatter.rb +26 -0
  28. data/lib/pomodoro/formats/today/parser/parser.rb +73 -0
  29. data/lib/pomodoro/formats/today/parser/transformer.rb +65 -0
  30. data/lib/pomodoro/formats/today/task.rb +92 -0
  31. data/lib/pomodoro/formats/today/task/dynamic_additions.rb +5 -0
  32. data/lib/pomodoro/formats/today/task/metadata.rb +37 -0
  33. data/lib/pomodoro/formats/today/task/statuses.rb +63 -0
  34. data/lib/pomodoro/formats/today/task_list.rb +50 -0
  35. data/lib/pomodoro/formats/today/time_frame.rb +113 -0
  36. data/lib/pomodoro/schedule/dsl.rb +68 -0
  37. data/lib/pomodoro/scheduler.rb +46 -0
  38. metadata +124 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 70c0874cdf93fd43ed8551927de6df1108063489
4
+ data.tar.gz: 44a53cdf68384fac811045ff7f014bf17cfb5b22
5
+ SHA512:
6
+ metadata.gz: 0c1a7b2f7d86729e72459bde2c0de679e742af5a96e7f861c7a86d799cde99ab0cb417ed34f3e95867b2ff92ec06736bc91f2e43fefd8369f3b73ad1c1044be1
7
+ data.tar.gz: d4d178e9a047999f5ec680eda76f43959e1a67ace46e57a2f6bb46005443feaf1b953007c5ceacd1d5be66f92f3ad1923a4e9ab9a6480eb4183ef4d14ef5c60a
data/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # About
2
+
3
+ [![Gem version][GV img]][Gem version]
4
+ [![Build status][BS img]][Build status]
5
+ [![Coverage status][CS img]][Coverage status]
6
+ [![YARD documentation][YD img]][YARD documentation]
7
+
8
+ **Now Task Manager** is a daily planner & focus app *for programmers*. It helps
9
+ you plan your day, stay focused and track your time.
10
+
11
+ It doesn't replace either GTD or the pomodoro technique, it complements them.
12
+ (In fact there will be a [Pomodoro plugin #18](https://github.com/botanicus/now-task-manager/issues/18) at some point.)
13
+
14
+ At some point I must have tried every bloody time management app there is (and let
15
+ me tell you, there's a lot of them) and I was still disorganised and eventually
16
+ went back to tracking my tasks in a plain text file.
17
+
18
+ And that's what <abbrev title="Now Task Manager">NTM</abbrev> is using: just plain
19
+ text files. But plain text files by themselves didn't help me: after all, that was
20
+ what I begun with.
21
+
22
+ The problem I was always facing was what to do when. As a freelancer, I can do
23
+ generally do anything anytime. That's great on one hand, on the other hand it
24
+ takes much more discipline. Typical problems:
25
+
26
+ - Work too much time on one project and too little time on another one.
27
+ - Starting a day with a great idea, coding half a day and then working on clients
28
+ projects late at night.
29
+ - Missing incremental steps to my long-term goals, like doing every morning Spanish
30
+ revision.
31
+
32
+ Everything started to turn around when I started to adapt what I call **time framing**:
33
+ time framing is about splitting your day into several blocks with clear start time
34
+ and end time and within the block doing only tasks that are related to that block.
35
+
36
+ So <abbrev title="Now Task Manager">NTM</abbrev> is an automation based on my plain
37
+ text task files where you define your schedule and then forces you to stick to it.
38
+
39
+ ![Workflow diagram](https://raw.githubusercontent.com/botanicus/now-task-manager/master/doc/diagram.png)
40
+
41
+ Read about the [benefits](https://github.com/botanicus/now-task-manager/blob/master/doc/benefits.md).
42
+
43
+ ## What it's not
44
+
45
+ Firstly, this is **not a project management** or **GTD system**: there is no
46
+ concept of a project. Here it's all about chunks of time (days and time frames)
47
+ and populating them with tasks from do-it-later lists as well as automatically.
48
+
49
+ You might very well need such system and that's fine: I use GH issues just for that,
50
+ in addition to using Pomodoro. But Pomodoro is the corner stone of my day organisation,
51
+ GH issues are place to dump to tasks, then link them from Pomodoro.
52
+
53
+ For the same reason it doesn't deal with **priorities**. If it's not a priority,
54
+ why would you put it on today's todo list?
55
+
56
+ _**Read next**: the [workflow](https://github.com/botanicus/now-task-manager/blob/master/doc/workflow.md)_
57
+
58
+ [Gem version]: https://rubygems.org/gems/now-task-manager
59
+ [Build status]: https://travis-ci.org/botanicus/now-task-manager
60
+ [Coverage status]: https://coveralls.io/github/botanicus/now-task-manager
61
+ [YARD documentation]: http://www.rubydoc.info/github/botanicus/now-task-manager/master
62
+
63
+ [GV img]: https://badge.fury.io/rb/pomodoro.svg
64
+ [BS img]: https://travis-ci.org/botanicus/now-task-manager.svg?branch=master
65
+ [CS img]: https://img.shields.io/coveralls/botanicus/now-task-manager.svg
66
+ [YD img]: http://img.shields.io/badge/yard-docs-blue.svg
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+
3
+ message=$(pomodoro active git)
4
+ git commit -m "$message"
data/bin/pomodoro ADDED
@@ -0,0 +1,246 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pomodoro'
4
+ require 'refined-refinements/colours'
5
+
6
+ using RR::ColourExts
7
+
8
+ def parse(parser_class, transformer_class, result_class, file_path)
9
+ input = File.read(file_path, encoding: 'utf-8')
10
+ tree = parser_class.new.parse(input)
11
+ # .parse(input, reporter: Parslet::ErrorReporter::Deepest.new)
12
+ nodes = transformer_class.new.apply(tree)
13
+ result_class.new(nodes) unless nodes.empty?
14
+ rescue Errno::ENOENT
15
+ abort "<red>File #{file_path} doesn't exist.</red>".colourise
16
+ end
17
+
18
+ def parse_today_list(config)
19
+ parse(Pomodoro::TodayParser, Pomodoro::TodayTransformer, Pomodoro::TaskList, config.today_path)
20
+ end
21
+
22
+ def parse_task_list(config)
23
+ parse(Pomodoro::TaskListParser, Pomodoro::SimpleFormat::TaskListTransformer, Pomodoro::SimpleFormat::TaskList, config.task_list_path)
24
+ end
25
+
26
+ def time_frame(config, &block)
27
+ today_list = parse_today_list(config)
28
+
29
+ unless current_time_frame = today_list.get_current_time_frame
30
+ abort "<red>There is no active time frame.</red>".colourise
31
+ end
32
+
33
+ block.call(today_list, current_time_frame)
34
+ end
35
+
36
+ # TODO: change this to find the first active task, ignoring the time frame.
37
+ # Only then complain about the time frame.
38
+ def with_active_task(config, &block)
39
+ time_frame(config) do |today_list, current_time_frame|
40
+ if active_task = current_time_frame.active_task
41
+ block.call(active_task)
42
+ today_list.save(config.today_path)
43
+ else
44
+ abort "<red>No more tasks in #{current_time_frame.desc}</red>".colourise
45
+ end
46
+ end
47
+ end
48
+
49
+ def edit_next_task_when_no_task_active(config, &block)
50
+ time_frame(config) do |today_list, current_time_frame|
51
+ if active_task = current_time_frame.active_task
52
+ abort "<red>There is an active task already:</red>\n#{active_task}".colourise
53
+ end
54
+
55
+ if next_task = current_time_frame.first_unstarted_task
56
+ block.call(next_task)
57
+ today_list.save(config.today_path)
58
+ else
59
+ abort "<red>No more tasks in #{current_time_frame.desc}</red>".colourise
60
+ end
61
+ end
62
+ end
63
+
64
+ def generate_todays_tasks(date, config)
65
+ require 'pomodoro/scheduler'
66
+
67
+ date_path = config.today_path(date)
68
+
69
+ return date_path if File.exist?(config.today_path)
70
+
71
+ scheduler = Pomodoro::Scheduler.load([config.schedule_path, config.routine_path], date)
72
+
73
+ schedule = scheduler.schedule_for_date(date)
74
+ task_list = schedule.call
75
+ scheduler.populate_from_rules(task_list)
76
+
77
+ main_task_list = parse_task_list(config)
78
+ labels = ['Tomorrow', date.strftime('%A'), date.strftime('%-d/%m'), date.strftime('%-d/%m/%Y')]
79
+
80
+ labels.each do |label|
81
+ if main_task_list[label]
82
+ main_task_list[label].tasks.each do |task|
83
+ puts "~ #{task}"
84
+ task_list.morning_ritual.create_task(task)
85
+ main_task_list.delete(main_task_list[label])
86
+ end
87
+ end
88
+ end
89
+
90
+ File.open(date_path, 'w') do |file|
91
+ file.puts(task_list.to_s)
92
+ end
93
+
94
+ main_task_list.save(config.task_list_path)
95
+
96
+ return date_path
97
+ end
98
+
99
+ # Main.
100
+ config = Pomodoro::Config.new
101
+
102
+ case ARGV.shift
103
+ when 'edit', 'e'
104
+ if ARGV.empty?
105
+ date_path = generate_todays_tasks(Date.today, config)
106
+ exec("vim #{date_path}")
107
+ elsif ARGV.first.to_i == 2
108
+ date_path = generate_todays_tasks(Date.today, config)
109
+ exec("vim -O2 #{date_path} #{config.task_list_path}")
110
+ elsif ARGV.first == 'tomorrow'
111
+ date_path = generate_todays_tasks(Date.today + 1, config)
112
+ exec("vim -O2 #{date_path} #{config.task_list_path}")
113
+ elsif ['tasks', 't'].include?(ARGV.first)
114
+ exec("vim #{config.task_list_path}")
115
+ else
116
+ abort(DATA.read.colourise)
117
+ end
118
+ when 'next'
119
+ time_frame(config) do |today_list, current_time_frame|
120
+ if active_task = current_time_frame.active_task
121
+ abort "<red>There is an active task already:</red>\n#{active_task}".colourise
122
+ end
123
+
124
+ if task = current_time_frame.first_unstarted_task
125
+ task.start
126
+ today_list.save(config.today_path)
127
+ else
128
+ abort "<red>No more tasks in #{current_time_frame.desc}</red>".colourise
129
+ end
130
+ end
131
+ when 'next?'
132
+ time_frame(config) do |today_list, current_time_frame|
133
+ if active_task = current_time_frame.active_task
134
+ abort "<red>There is an active task already:</red>\n#{active_task}".colourise
135
+ end
136
+
137
+ if task = current_time_frame.first_unstarted_task
138
+ puts task
139
+ else
140
+ abort "<red>No more tasks in #{current_time_frame.desc}</red>".colourise
141
+ end
142
+ end
143
+ when 'complete'
144
+ with_active_task(config) do |active_task|
145
+ require 'pry'; binding.pry ###
146
+ active_task.complete
147
+ puts active_task
148
+ end
149
+ when 'postpone'
150
+ # Ask for metadata and comments.
151
+ with_active_task(config) do |active_task|
152
+ active_task.postpone
153
+ puts active_task
154
+ end
155
+ when 'move_on'
156
+ # Ask for metadata and comments.
157
+ with_active_task(config) do |active_task|
158
+ active_task.move_on
159
+ puts active_task
160
+ end
161
+ when 'active'
162
+ with_active_task(config) do |active_task|
163
+ case ARGV.shift
164
+ # git-commit-pomodoro
165
+ # TODO: Subtasks as well.
166
+ when 'git' then puts active_task.text
167
+ when 'prompt' then puts active_task.text
168
+ when nil then puts active_task
169
+ else
170
+ # TODO: Format with %d etc.
171
+ end
172
+ end
173
+ when 'tick-off-next'
174
+ edit_next_task_when_no_task_active(config) do |next_task|
175
+ next_task.complete
176
+ end
177
+ when 'fail-next'
178
+ print "<bold>Why?</bold> ".colourise
179
+ reason = STDIN.readline.chomp
180
+ edit_next_task_when_no_task_active(config) do |next_task|
181
+ next_task.fail(reason)
182
+ end
183
+ when 'postpone-next'
184
+ print "<bold>Why?</bold> ".colourise
185
+ reason = STDIN.readline.chomp
186
+ print "<bold>When do you want to review?</bold> Defaults to tomorrow. ".colourise
187
+ review_at = STDIN.readline.chomp
188
+ edit_next_task_when_no_task_active(config) do |next_task|
189
+ next_task.postpone(reason, review_at.empty? ? 'Tomorrow' : review_at)
190
+ end
191
+ when '+'
192
+ task_list = parse_task_list(config)
193
+ task_list['Later'] ||= Array.new
194
+ task_list['Later'] << ARGV.join(' ')
195
+ task_list.save(config.task_list_path)
196
+ when 'console', 'c'
197
+ today = parse_today_list(config)
198
+ tasks = parse_task_list(config)
199
+ require 'pry'; binding.pry
200
+ when 'tools'
201
+ if ARGV.shift == 'workdays'
202
+ start_date = Date.new(2018, 12, 1)
203
+ end_date = Date.new(2018, 12, 31)
204
+ work_days = (start_date..end_date).reduce(0) do |sum, date|
205
+ sum += 1 unless date.saturday? || date.sunday?; sum
206
+ end
207
+ puts "~ There are #{work_days} (without any bank holidays) in 2018."
208
+ # TODO: Per-month breakdown.
209
+ end
210
+ when 'bitbar'
211
+ require 'pomodoro/commands/bitbar'
212
+ today_list = parse_today_list(config)
213
+ task_list = parse_task_list(config)
214
+ Pomodoro::Commands::BitBar.main(today_list, task_list)
215
+ when 'help', '-h', '--help'
216
+ puts(DATA.read.colourise)
217
+ else
218
+ abort(DATA.read.colourise)
219
+ end
220
+
221
+ __END__
222
+
223
+ <red.bold>:: Pomodoro ::</red.bold>
224
+
225
+ pomodoro <green>edit</green>, pomodoro <green>e</green>
226
+ <bright_black>pomodoro e</bright_black> Edit the today task file, creating it if it doesn't exist.
227
+ <bright_black>pomodoro e <yellow>2</yellow></bright_black> Edit both the today task file and tasks (in a split screen).
228
+ <bright_black>pomodoro e <yellow>tasks</yellow></bright_black> (or just <yellow>t</yellow>) Open the task file.
229
+ <bright_black>pomodoro e <yellow>tomorrow</yellow></bright_black> Plan tomorrow.
230
+
231
+ pomodoro <magenta>next</magenta> <bright_black># Start a new task.</bright_black>
232
+ pomodoro <magenta>complete</magenta> <bright_black># Complete the active task.</bright_black>
233
+ pomodoro <magenta>postpone</magenta> <bright_black># Postpone the active task.</bright_black>
234
+ pomodoro <magenta>move_on</magenta> <bright_black># Move on from the active task. Mark its end time, but don't set it as completed.</bright_black>
235
+
236
+ pomodoro <green>next?</green> <bright_black># Print the next task.</bright_black>
237
+ pomodoro <green>active</green> <bright_black># Print the active task.</bright_black>
238
+
239
+ pomodoro <magenta>tick-off-next</magenta> <bright_black># ...</bright_black>
240
+ pomodoro <magenta>fail-next</magenta> <bright_black># ...</bright_black>
241
+ pomodoro <magenta>postpone-next</magenta> <bright_black># ...</bright_black>
242
+
243
+ pomodoro <red>+</red> [strings]<bright_black> # Add a task for later.</bright_black>
244
+
245
+ pomodoro <yellow>console</yellow>, pomodoro <yellow>c</yellow> <bright_black># Load the tasks and launch IRB.</bright_black>
246
+ pomodoro <yellow>bitbar</yellow> <bright_black># Print output for BitBar.</bright_black>
data/doc/benefits.md ADDED
@@ -0,0 +1,91 @@
1
+ _This document is WIP._
2
+
3
+ - Separating planning from execution.
4
+ - Predictable schedules.
5
+ - Task statuses. Where did you ended, why was it postponed and how long for?
6
+
7
+ don't let your work and errands kill your personal objectives. Learning Spanish etc.
8
+
9
+ plan, review
10
+ scrum uses time framing as well (sprints)
11
+ time framing here is different: it's not about deliverables (you can work on a project ad infinitum), it's about the routines and project scheduling (it's all bottom-up).
12
+
13
+ USE POMODORO WITHIN for durations? This can be available via plugins.
14
+ Example: pomodoros are not useful for everything. Like going to a bank,
15
+ you never know how long it's going to take (esp. if you live in Poland).
16
+ The only thing that is certain is that you have to fit it within a time frame,
17
+ because you have to get your client's work done.
18
+
19
+ I'm not a time management expert, but this is the practical solution that made my life infinitely more organised.
20
+
21
+ - Schedules, task archive.
22
+ - Increase awareness.
23
+ - No skipping.
24
+ - End-of-the day/week reports for clients (incl. how much to charge).
25
+ - Offlining.
26
+ - Make your work easier with `git commit-pomodoro`.
27
+
28
+
29
+ _Time management technique based on time framing and a command-line task management tool._
30
+
31
+ This is something between GTD and the pomodoro technique: it has part of the depth of GTD and part of the immediate action management approach of pomodoro. It is a full-circle task management method.
32
+
33
+ It does also time tracking which can be used to count actual time worked for clients.
34
+
35
+ ## Benefits
36
+
37
+ ### Holistic
38
+
39
+ I tried pomodoro and it's great, but it doesn't see the big picture.
40
+
41
+ The pomodoro technique is great to force you to do the work and not procrastinating.
42
+
43
+ It doesn't help you to keep several client projects in the air while you have your
44
+ personal goals and responsibilities.
45
+
46
+ - Holistic. It's not just for the work or just for home.
47
+ - Defaults. Don't think.
48
+ - Automatically tracking time for clients.
49
+
50
+ ## It doesn't make you think
51
+
52
+ Tasks are sequential. You cannot choose which task to work on next. The next task down the list is the one that's coming next.
53
+
54
+ Schedules are automatic.
55
+
56
+ Will power limited.
57
+
58
+ ## Rich data
59
+
60
+ **Time tracking** (optional): Time tracking is useful if you are paid for your time or if you want to run any useful stats.
61
+
62
+ Task **status** and **metadata**
63
+
64
+ **Journaling**
65
+
66
+ ## Data is yours
67
+
68
+ The data are in simple plain text and you get a Ruby library to parse them and do whatever you want.
69
+
70
+ For instance let's see how much time have I spent on admin in the first quarter of 2017:
71
+
72
+ ```ruby
73
+ require 'pomodoro'
74
+
75
+ Pomodoro.load('2017/{1,2,3}').each do |task_list|
76
+ task_list.reduce(0) do |sum, time_frame|
77
+ if time_frame.tags.include?(:admin)
78
+ sum + time_frame.duration
79
+ else
80
+ sum
81
+ end
82
+ end
83
+ end
84
+ ```
85
+
86
+ Or you can want to know how good your estimates are. You've been adding a custom
87
+ metadata such as `Estimate: 4h` to your tasks. Now you can go and compare the estimate
88
+ with the actual duration of the task.
89
+
90
+ Read the [workflow](https://github.com/botanicus/now-task-manager/blob/master/doc/workflow.md)
91
+ to understand how it works.
data/doc/bitbar.md ADDED
@@ -0,0 +1,2 @@
1
+ - BitBar: show each project TODO.
2
+ - colour of a time frame based on how much time left.
data/doc/curses.md ADDED
@@ -0,0 +1,5 @@
1
+ https://github.com/thibaudgg/rb-fsevent
2
+
3
+ - Keep an eye on time frames changing.
4
+ - Keep an eye on tasks scheduled for specific time.
5
+ - Run the timer for tasks with given duration.
@@ -0,0 +1,7 @@
1
+ time_frame(/morning routine/i) do |time_frame|
2
+ time_frame.create_task('Headspace.')
3
+ end
4
+
5
+ time_frame(/admin/i) do |time_frame|
6
+ time_frame.create_task('Inbox 0.')
7
+ end
@@ -0,0 +1,32 @@
1
+ This format is used to store **scheduled tasks**: tasks that will be done later
2
+ or in a certain context.
3
+
4
+ ```
5
+ Tomorrow
6
+ - Buy milk. #errands
7
+ - [9:20] Call with Mike.
8
+
9
+ Prague
10
+ - Pick up my shoes. #errands
11
+ ```
12
+
13
+ # Currently unsupported
14
+
15
+ - **Labels**. Labels allow us to match tasks with _named_ time frames.
16
+ See [#8](https://github.com/botanicus/now-task-manager/issues/8).
17
+
18
+ ```
19
+ - ADM: Catch up with Eva.
20
+ ```
21
+
22
+ # Intentionally unsupported
23
+
24
+ - **Comments**. I want to keep the format simple and the task file small.
25
+ Every time there was something like comments, the file bloated uncontrollably.
26
+ - **Task formatting**. Task is a string, it doesn't recognise any structures within.
27
+ Therefore, anything you can fit in to a line will be the task body. So you can
28
+ put anything that {Pomodoro::Formats::Today} supports such as scheduled times
29
+ and tags.
30
+
31
+ _For more details about the format see
32
+ {https://github.com/botanicus/now-task-manager/blob/master/spec/pomodoro/formats/scheduled/parser/parser_spec.rb parser_spec.rb}._