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
@@ -0,0 +1,115 @@
1
+ # `Today` format
2
+
3
+ This format is used for tasks that are being worked on today.
4
+
5
+ ```
6
+ Morning routine (7:50 – 9:20)
7
+ ✔ Headspace. #meditation
8
+ ✘ Go swimming. #exercise
9
+ Reason: Some clever excuse.
10
+ ✔ Eat breakfast.
11
+ ✔ [20] Spanish flashcards. #learning
12
+
13
+ Admin (9:20 – 12)
14
+ ✔ [9:20-10:00] Inbox 0.
15
+ I should allocate more time to it from now on.
16
+
17
+ Some more comment line 1
18
+ Some more comment line 2
19
+ - [started at 10:00] Print out invoices.
20
+ - Review GitHub issues.
21
+ - [11:40] Call with Sonia.
22
+
23
+ Lunch break (12 – 13)
24
+
25
+ Work for client 1 (13 – 17)
26
+ - Issue#87.
27
+
28
+ Evening (after 17)
29
+ - Free style meditation. #meditation
30
+ ```
31
+
32
+ ## Metadata
33
+
34
+ Metadata are indented lines following a task.
35
+
36
+ There can be either lines, subtasks or key value pairs or a combination of either.
37
+
38
+ ### Lines
39
+
40
+ ```
41
+ I should allocate more time to it from now on.
42
+
43
+ Some more comment line 1.
44
+ Some more comment line 2.
45
+ ```
46
+
47
+ This will turn into:
48
+
49
+ ```ruby
50
+ [
51
+ "I should allocate more time to it from now on.",
52
+ "Some more comment line 1. Some more comment line 2."
53
+ ]
54
+ ```
55
+
56
+ ### Key-value pairs
57
+
58
+ ```
59
+ - [8:25-8:41] Research EU residency permit:
60
+ Link: http://www.migrant.info.pl/temporary-residence-permit.html, http://www.migrant.info.pl/residence-card.html
61
+ Outcome: This is what I need.
62
+ Next: Apply for http://www.migrant.info.pl/temporary-residence-permit.html # -> This makes the task.
63
+ Review: Upon my return from CZ/ES. # -> This makes a headline.
64
+
65
+ - [10:09-10:20] Push the code from Cloud9 to GH and clone it from my mac.
66
+ Skipped: SSH keys issues, I requested it to be researched.
67
+
68
+ - [11:42-12:20] Clean up the flat, find my MasterCard.
69
+ Comment: It took me a good while to find the card. # VNORENY.
70
+ I have to clean up the mess and keep it clean!
71
+
72
+ - Headspace.
73
+ Skipped: Instead of meditating, I wrote a command to play the next HS episode and, to remember them. I tend to forget which episode I'm on.
74
+
75
+ - Millennium: pick up EUR.
76
+ Postponed: Queue too long.
77
+
78
+ - [11:31-11:41] Review my moleskine to see whether I need to take it with me.
79
+ Outcome: I don't need to take it.
80
+
81
+ ✔ Inquire about why the payment failed.
82
+ Waiting for: Response.
83
+ Review: Tomorrow.
84
+
85
+ - [9:51-9:59] Inquire about why the payment failed.
86
+ Review: tomorrow.
87
+ ```
88
+
89
+ ### Subtasks
90
+
91
+ ```
92
+ - [9:37-9:51] Plan the CZ/ES trip and make the reservations for PRG.
93
+ ✔ Book accommodation in PRG.
94
+ - Ping Macarena.
95
+ ```
96
+
97
+ ## Considered features
98
+
99
+ #### Nested time frames
100
+
101
+ Very often an action is interrupted by an other. If it takes 5 minutes, it's irrelevant to log it, but what if it took half of the afternoon?
102
+
103
+ NOTE: http://kschiess.github.io/parslet/parser.html last to chapters explain how to create the recursion.
104
+
105
+ ```
106
+ Work for client 1 (13 – 17)
107
+ - Issue#87.
108
+
109
+ Emergency (2 – 3:30)
110
+ ✔ Extinguish fire in the living room.
111
+
112
+ - Task
113
+ ```
114
+
115
+ _There are detailed [unit specs](spec/pomodoro/parser) for the format._
@@ -0,0 +1,41 @@
1
+ _This document is WIP._
2
+
3
+ # Getting started
4
+
5
+ _If you don't understand any term, read [terms](https://github.com/botanicus/now-task-manager/blob/master/doc/terms.md)_
6
+
7
+ 1. Define your schedules.
8
+
9
+ There are two types of tasks: tasks to be done **today** and **scheduled tasks**.
10
+
11
+
12
+ ## Schedules
13
+
14
+ The real fun starts with using schedules.
15
+
16
+ ```ruby
17
+ # ~/.config/pomodoro/schedules/base.rb
18
+ rule(:weekday, -> { today.weekday? }) do |tasks|
19
+ tasks.push(*morning_ritual_tasks)
20
+ tasks << Pomodoro::Task.new('TopTal.', 20, [:online, :work])
21
+ tasks << work_tasks[rand(work_tasks.length)]
22
+ tasks.push(*lunch_break_tasks)
23
+ tasks << Pomodoro::Task.new(project_of_the_week, 90, [:project_of_the_week, :online])
24
+ tasks << cleanup_tasks[rand(cleanup_tasks.length)]
25
+ tasks.push(*evening_tasks)
26
+ end
27
+ ```
28
+
29
+ # Configuration
30
+
31
+ ```yaml
32
+ # ~/.config/pomodoro.yml
33
+ ---
34
+ schedule: ~/Dropbox/Data/Data/Pomodoro/Schedules/schedules.rb
35
+ routine: ~/Dropbox/Data/Data/Pomodoro/Schedules/base.rb
36
+ today: ~/Dropbox/Data/Data/Pomodoro/Tasks/%Y-%m-%d.today
37
+ task_list: ~/Dropbox/Data/WIP/tasks.todo
38
+ ```
39
+
40
+ - [today format](https://github.com/botanicus/now-task-manager/blob/master/doc/formats/today.md)
41
+ - [schedule task list format](https://github.com/botanicus/now-task-manager/blob/master/doc/formats/scheduled.md)
@@ -0,0 +1,68 @@
1
+ _This document is WIP._
2
+
3
+ https://github.com/blog/2231-building-your-first-atom-plugin
4
+
5
+ - Writing Vim plugins http://stevelosh.com/blog/2011/09/writing-vim-plugins/
6
+ - Vim plugin documentation http://learnvimscriptthehardway.stevelosh.com/chapters/54.html
7
+
8
+ ## BitBar plugin
9
+
10
+ [BitBar](https://getbitbar.com/)
11
+
12
+ ```shell
13
+ tee ~/.bitbar/pomodoro.1s.sh <<EOF
14
+ #!/bin/sh
15
+
16
+ log-time --bitbar
17
+ EOF
18
+ ```
19
+
20
+ ![](https://raw.githubusercontent.com/botanicus/now-task-manager/master/doc/more-than-5m.png)
21
+ ![](https://raw.githubusercontent.com/botanicus/now-task-manager/master/doc/less-than-5m.png)
22
+
23
+ ## ZSH prompt.
24
+
25
+ ![](https://raw.githubusercontent.com/botanicus/now-task-manager/master/doc/prompt.png)
26
+
27
+ ## Limiting online access
28
+
29
+ _TODO_
30
+ This is why I wrote it in the first place.
31
+
32
+ ## OS X notifications
33
+
34
+ `~/Library/LaunchAgents/botanicus.pomodoro_notification.plist`
35
+
36
+ ```xml
37
+ <?xml version="1.0" encoding="UTF-8"?>
38
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
39
+ <plist version="1.0">
40
+ <dict>
41
+ <key>Label</key>
42
+ <string>botanicus.pomodoro_notification</string>
43
+
44
+ <key>ProgramArguments</key>
45
+ <array>
46
+ <string>zsh</string>
47
+ <string>-c</string>
48
+ <string>pomodoro-loop</string>
49
+ </array>
50
+
51
+ <key>RunAtLoad</key>
52
+ <true />
53
+
54
+ <key>KeepAlive</key>
55
+ <true />
56
+
57
+ <!-- I don't have permissions to write into /var/log. -->
58
+ <key>StandardOutPath</key>
59
+ <string>/tmp/botanicus.pomodoro_notification.stdout</string>
60
+ <key>StandardErrorPath</key>
61
+ <string>/tmp/botanicus.pomodoro_notification.stderr</string>
62
+ </dict>
63
+ </plist>
64
+ ```
65
+
66
+ ```shell
67
+ launchctl load -w ~/Library/LaunchAgents/botanicus.pomodoro_notification.plist
68
+ ```
data/doc/rules.md ADDED
File without changes
data/doc/schedules.md ADDED
File without changes
data/doc/terms.md ADDED
@@ -0,0 +1,32 @@
1
+ ### Time frames (not the same as time boxes for tasks)
2
+
3
+ I always had some kind of semi-functional task list in place, but my work organisation
4
+ was still hardly existent at all. It wasn't until I started to use time framing that this changed.
5
+
6
+ Time frame is a block of time you give to a project. Your schedule is then time frames of a day
7
+
8
+ ```
9
+ Morning routine (from 7:50)
10
+ Admin (from 9:20)
11
+ Work for client 1 (10:00 – 12:00)
12
+ Lunch break (12:00 – 13)
13
+ Work for client 2 (13 – 18)
14
+ ```
15
+
16
+ ### Schedules
17
+
18
+ You are likely to have more schedules than one. I have one for Tuesday when I have
19
+ a class from 6 and therefore I have to move my work session earlier, one for Wednesday
20
+ when I have my Spanish class in the morning, one for the other work days,
21
+ one for Saturday and one for Sunday.
22
+
23
+ Using the [holidays gem](https://github.com/holidays/holidays) you can easily
24
+ chose your Sunday schedule for a bank holiday.
25
+
26
+ I have a different morning routine on Mondays and Thursdays, I go swimming, but
27
+ since it fits into the given time frame, I do this in automatically scheduled tasks
28
+ while keeping the schedule the same.
29
+
30
+ ### Automatically scheduled tasks
31
+
32
+ ### Scheduled tasks
data/doc/workflow.md ADDED
@@ -0,0 +1,60 @@
1
+ _This document is WIP._
2
+
3
+ ## The workflow
4
+
5
+ _If you don't understand any term, read [terms](https://github.com/botanicus/now-task-manager/blob/master/doc/terms.md)_
6
+
7
+ ![Workflow diagram](https://raw.githubusercontent.com/botanicus/now-task-manager/master/doc/diagram.png)
8
+
9
+ ### Planning
10
+
11
+ In the evening you'll do `pomodoro edit tomorrow`. This will check your schedules and picks one to use. Schedule is a list of time frames, for instance for a work day we could have something like this:
12
+
13
+ ```
14
+ Morning routine (from 7:50)
15
+ Work for client 1 (9:20 – 12:00)
16
+ Lunch break (12:00 – 13)
17
+ Work for client 2 (13 – 18)
18
+ ```
19
+
20
+ Then it will try to prepopulate the schedule with tasks. There will be various sources:
21
+
22
+ - The scheduled lists.
23
+ - Automatically scheduled tasks.
24
+ - Unfinished tasks from today and postponed tasks.
25
+
26
+ ## Doing
27
+
28
+ 3. Next day you simply start getting through your list using `pomodoro next` and `pomodoro complete` (as well as `pomodoro postpone` and `pomodoro move_on`).
29
+
30
+ The tasks will be looked for in the current time frame. That is even if you have unfinished tasks, if a new time frame started, the tool will pick a task from the newly started one.
31
+
32
+ ### Today tasks
33
+
34
+ ![](https://raw.githubusercontent.com/botanicus/now-task-manager/master/doc/img/today-annotated.png)
35
+
36
+ - Tasks are stored in readable plain text format.
37
+ - Command-line interface.
38
+ - [Vim plugin](https://github.com/botanicus/now-task-manager/tree/master/support/vim).
39
+ - BitBar plugin.
40
+
41
+ ### Scheduled tasks
42
+
43
+ Scheduled tasks are either scheduled for a certain **date** (tomorrow, next Friday etc), for a ceratin **context** (next time I'm in Prague etc) or just generally for **later**.
44
+
45
+ ```
46
+ Tomorrow
47
+ - Buy milk.
48
+
49
+ Prague
50
+ - Pick up my shoes.
51
+
52
+ Later
53
+ - Fix the expense gem.
54
+ ```
55
+
56
+ That's all there is to it. It's a simple text file and you can edit it to your liking.
57
+
58
+ The only shortcut you get is `pomodoro + Another task.` which will add a task to the list for later.
59
+
60
+ _**Read next**: [getting started](https://github.com/botanicus/now-task-manager/blob/master/doc/getting-started.md)_
data/lib/pomodoro.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'pomodoro/config'
2
+ require 'pomodoro/parser/today_parser'
3
+ require 'pomodoro/parser/today_transformer'
4
+ require 'pomodoro/parser/task_list_parser'
5
+ require 'pomodoro/parser/task_list_transformer'
6
+ require 'pomodoro/task_list'
@@ -0,0 +1,87 @@
1
+ require 'pomodoro/exts/hour'
2
+
3
+ module Pomodoro
4
+ module Commands
5
+ class BitBar
6
+ def self.heading(current_time_frame)
7
+ if current_time_frame
8
+ self.heading_work_in_progress(current_time_frame)
9
+ else
10
+ ['black', self.heading_default_icon]
11
+ end
12
+ end
13
+
14
+ def self.heading_default_icon
15
+ "| image=iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAACx1BMVEUAAAAhZ5QmerEmgLkmgLomgLomgLomgLomgLomgLkme7EhZ5QAAAAeYYwlerIcWogZTHkaTn0aTn0aTn0aTn0aTn0aTXocW4klerIfYYwicaUaZJtRXGurrLCur7NWYW4aZZoicaUhcacUWpN7hZWCi5gWXJQhcKcebqUTWZN9h5eDjJsUW5UebqUca6QRV5N8h5eDjJoSWZQca6QaaKMPVZJ8h5eDjJoQV5QaaKMXZqINU5F8h5eDjJoPVZMXZqIVY6AMUZB8h5eDjJoNU5IVY6ETX58LTo98h5eDjJoMUJATX58SXJwKTI18h5eDjJoLTo8SXJwRWJoJSYx9h5eDjJoKS40RWJsQVJcKSYx/iJeBipcKSY0QVJcORHwNU50yUnlVaYZTaIVTaIVTaIVTaIVTaIVUaIUwUXcNU50ORH0GGzENRH8LUZ0JUKAJUaEJUaEJUaEJUaEJUaEJUKALUZ4NRH8GHDIAAAADDBcIJUYILFQILFQILFQILFQILFQILFQILFQIJUYDDRgAAACxs7ewsrewsrewsrexs7f29fT19PT09PT09PT09PT09PT29fX39vb39vX19PPy8vLy8vLy8vLy8vL09PTf39/Jycny8fD19PPy8vLz8/Py8vLy8vLy8vK1tbVeXl6wsLD19fT19PPq6ura2trz8/Py8vKlpaVISEisrKzy8vL19fT29vXS0tJeXl60tLS0tLRFRUWlpaX09PTy8vL19PT19PPx8fGfn59JSUlISEiGhobv7+/z8/Py8vL19PT19PPz8/Pu7u6Pj49lZWXd3d309PTy8vLy8vL19PT19PPy8vLz8/Pl5eXMzMzy8vLy8vLy8vLy8vL19PT19PPy8vLy8vLz8/P09PTy8vLy8vLy8vLy8vL19fTz8e/v7u3v7u3v7u3v7u3v7u3v7u3v7u3v7u3y8e////+EY5Z8AAAAhXRSTlMDW8nf3t7e3t7fylwESeT////////////lS5b///////+YpP////+kpP////+kpP////+kpP////+kpP////+kpP////+kpP////+kpP////+kpP////+ko/////+jhf7////////////+hi3A+/7+/v7+/v77wi8AMomjpKSkpKSjiTMB0B5+TQAAAAFiS0dE7CG5sxsAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfhAhQRBSmWVlRBAAABG0lEQVQY0wEQAe/+AAABAgMEBQYGBgYHCAkKCwwADQ4PEBESExMTExQVFhcYGQAaGxwdhYaHh4eHiIkeHyAhACIjJIqLjI2Njo+QkZIlJicAKCkqk5SVlZaXmJmamyssLQAuLzCcnZ6foKGio6SlMTIzADQ1NqanqKmqq6ytrq83ODkAOjs8sLGys7S1tre4uT0+PwBAQUK6u7y9vr/AwcLDQ0RFAEZHSMTFxsfIycrLzM1JSksATE1Ozs/Q0dLT1NXW109QUQBSU1TY2drb3N3e3+DhVVZXAFhZWuLj5OXm5+jp6utbXF0AXl9gYWJjZGRkZGVmZ2hpagBrbG1ub3BxcXFxcnN0dXZ3AHh5ent8fX5+fn5/gIGCg4Sov3NOEAy3KQAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNy0wMi0yMFQxNzowNTo0MS0wNTowMHrHzbIAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTctMDItMjBUMTc6MDU6NDEtMDU6MDALmnUOAAAAAElFTkSuQmCC"
16
+ end
17
+
18
+ def self.heading_work_in_progress(current_time_frame)
19
+ colour = self.colour_based_on_remaining_duration(current_time_frame)
20
+ [colour, "#{current_time_frame.name} | color=#{colour}"]
21
+ end
22
+
23
+ def self.colour_based_on_remaining_duration(current_time_frame)
24
+ if current_time_frame.remaining_duration.nil?
25
+ 'gray'
26
+ elsif current_time_frame.remaining_duration < Hour.new(0, 10)
27
+ 'red'
28
+ elsif current_time_frame.remaining_duration < Hour.new(0, 30)
29
+ 'blue'
30
+ else
31
+ 'green'
32
+ end
33
+ end
34
+
35
+ def self.with_active_time_frame(current_time_frame)
36
+ if current_time_frame
37
+ if current_time_frame.interval[1]
38
+ puts "#{current_time_frame.interval[0]}-#{current_time_frame.interval[1]} (#{current_time_frame.remaining_duration}h remaining) | color=#{colour}"
39
+ else
40
+ puts "After #{current_time_frame.interval[0]} | color=gray"
41
+ end
42
+ current_time_frame.tasks.each do |task|
43
+ colour = {unstarted: 'blue', in_progress: 'red', finished: 'gray', postponed: 'gray'}[task.status]
44
+ puts "#{task} | color=#{colour}"
45
+ end
46
+ elsif Time.now.hour < 14
47
+ today_tasks.each do |time_frame|
48
+ task_lines = time_frame.to_s.split("\n")[1..-1]
49
+ puts "#{time_frame.header} | color=#{task_lines.empty? ? 'gray' : 'green'}"
50
+ puts task_lines.map { |line| "#{line} | color=black" }.join("\n").gsub(/^- /, '-- ')
51
+ end
52
+ puts "Total: XYZ | colour=gray"
53
+ else
54
+ puts "Hours worked: #{Hour.new(0, today_tasks.duration)}"
55
+ end
56
+ end
57
+
58
+ def self.main(today_tasks, task_list)
59
+ if today_tasks && current_time_frame = today_tasks.get_current_time_frame
60
+ colour, icon = self.heading(current_time_frame)
61
+ puts icon, '---'
62
+ self.with_active_time_frame(current_time_frame)
63
+ elsif today_tasks
64
+ colour, icon = self.heading(nil)
65
+ puts icon, '---'
66
+ puts 'TODO: Some day summary and possibly show tomorrow.'
67
+ else
68
+ colour, icon = self.heading(nil)
69
+ puts icon, '---'
70
+ puts "Run 'pomodoro e' to add some tasks. | color=green"
71
+ end
72
+
73
+ if task_list && task_list.any? { |task_group| ! task_group.tasks.empty? }
74
+ puts "Scheduled tasks"
75
+ task_list.each do |task_group|
76
+ unless task_group.tasks.empty?
77
+ puts "-- #{task_group.name}"
78
+ task_group.tasks.each do |task|
79
+ puts "---- #{task} | color=black"
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,30 @@
1
+ require 'yaml'
2
+
3
+ module Pomodoro
4
+ class Config
5
+ CONFIG_PATH ||= File.expand_path('~/.config/pomodoro.yml')
6
+
7
+ def initialize
8
+ @data ||= YAML.load_file(CONFIG_PATH)
9
+ rescue
10
+ @data ||= Hash.new
11
+ end
12
+
13
+ {
14
+ task_list_path: '~/pomodoro/tasks.todo',
15
+ today_path: '~/pomodoro/%Y-%m-%d.today',
16
+ schedule_path: '~/pomodoro/schedule.rb',
17
+ routine_path: '~/pomodoro/routine.rb'
18
+ }.each do |key, default_value|
19
+ define_method(key) do |time = Time.now|
20
+ path = @data[key.to_s] || default_value
21
+ path = File.expand_path(time.strftime(path))
22
+ if File.exist?(File.expand_path("#{path}/.."))
23
+ path
24
+ else
25
+ raise "No #{key} found. Either create #{default_value} or add #{key} into #{CONFIG_PATH} pointing the the actual path."
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end