thyme 0.0.14 → 0.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0a34024e5c3c57ea62c834ea83adf0c118b3fad2
4
- data.tar.gz: b0e6459d5fb05917846384d5296c7b4da76d0ce1
3
+ metadata.gz: 2bd7f6b22e1eb3fb5b2cc353f25948207113f722
4
+ data.tar.gz: 9de5a45b3b793806536927db3e4464d157e5ab95
5
5
  SHA512:
6
- metadata.gz: bfd282a9ff8df019c9c58b4add8c98bdc7e08e37a71cf4ea980bdacd366cbc9142450fcd9b062e783a4d4e5c0735c3a3ceb35a2c6b6a0c05c0f1d913a2d8b5b9
7
- data.tar.gz: 82391d021bf3735a7e34be5a354de37cd62e104664886ead5e03af649a5b2849cac58c16226f9ab6d6472a1aea4ecd458a45929c29dc2d790717abe58f23d53c
6
+ metadata.gz: 3d1a24078f5c3d2ce251ef8c2b04010e32140a1206548dfec3d4771179ae2a7bf6c8eb890b1106a0db7c855929afb5e4c1057e4ea4e7fc7c6c9b67bb8fc89bb9
7
+ data.tar.gz: 7167e5a067fc49605767fd18a9d13b05a6d430b56a1b809f6c270894897d300ad216441939bfb66a42300354ad8cfed78e4e5bb5cd6bee5a2a99dadf3c7889ae
data/README.md CHANGED
@@ -1,80 +1,76 @@
1
- Description
2
- ===========
1
+ # Description
3
2
 
4
3
  Thyme is a console pomodoro timer.
5
4
 
6
- Installation
7
- ============
5
+ # Installation
8
6
 
9
7
  $ gem install thyme
10
8
 
11
- Usage
12
- =====
9
+ # Usage
13
10
 
14
11
  Start thyme with:
15
12
 
16
13
  $ thyme
17
14
  [= ] 24:59
18
15
 
19
- You'll have 25 minutes by default. `Ctrl-C` to interrupt. You can also start
16
+ You'll have 25 minutes by default. `Ctrl-C` to interrupt. You can also start
20
17
  it in daemon mode, which is only useful if you've got tmux integration to notify
21
18
  you of the timer:
22
19
 
23
20
  $ thyme -d
24
21
 
25
- To interrupt the timer in daemon mode, run `thyme` again. Or wait 25 minutes
26
- for it to kill itself.
22
+ Some other useful commands:
27
23
 
28
- Configure
29
- =========
24
+ $ thyme # run again to pause/unpause
25
+ $ thyme -s # stops daemon
26
+ $ thyme -d -r # repeats timer until you manually stop it
27
+ $ thyme -d -r 10 # repeats timer exactly 10 times
30
28
 
31
- Thyme is configurable and extensible. All configurations live in the
32
- `~/.thymerc` file:
29
+ # Configure
33
30
 
34
- set :timer, 25*60
35
- set :timer_break, 5*60
36
- set :warning, 5*60
37
- set :warning_color, "red,bold"
38
- set :interval, 1
39
- set :tmux, true
31
+ Configurations live in the `~/.thymerc` file:
32
+
33
+ set :timer, 25*60 # 25 minute pomodoros
34
+ set :timer_break, 5*60 # 5 minute breaks
35
+ set :warning, 5*60 # show warning color in tmux at <5 minutes, 0 to disable
36
+ set :warning_color, 'red,bold' # warning color for tmux is red/bold
37
+ set :break_color, 'blue' # break color is blue
38
+ set :interval, 1 # refresh timer every 1 second
39
+ set :tmux, true # turn on tmux integration
40
40
  set :tmux_theme, "#[fg=mycolor,bg=mycolor]#[fg=%s]%s#[fg=mycolor,bg=mycolor]"
41
41
 
42
+ # adds `-t --today` option, which opens a text file in vim
42
43
  option :t, :today, 'open today sheet' do
43
44
  `vim -O ~/.thyme-today.md ~/.thyme-records.md < \`tty\` > \`tty\``
44
45
  end
45
46
 
47
+ # adds `-s --seconds num` option, which allows on the fly timer
46
48
  option :s, 'seconds num', 'run with custom seconds' do |num|
47
- @timer = num.to_i
49
+ set :timer, num.to_i
48
50
  run
49
51
  end
50
52
 
51
- before do
53
+ # execute hook before thyme program starts
54
+ before(:all) do
52
55
  `mplayer ~/music/flight-of-the-bumble-bee.mp3 &`
53
56
  end
54
57
 
55
- after do |seconds_left|
56
- `notify-send -u critical "Thyme's Up!"` if seconds_left == 0
58
+ # execute hook before each pomodoro
59
+ before do
60
+ `terminal-notifier -message "Let's get started!"`
57
61
  end
58
62
 
59
- The `set` method sets different configurations.
60
-
61
- * `:timer` seconds to countdown from
62
- * `:timer_break` seconds to countdown from in break mode
63
- * `:warning` seconds threshold before tmux timer turns red (use 0 to disable)
64
- * `:warning_color` color of the tmux timer during the warning period
65
- * `:interval` refresh rate of the progress bar and tmux status in seconds
66
- * `:tmux` whether or not you want tmux integration on (false by default)
67
- * `:tmux_theme` optionally lets you format the tmux status
68
-
69
- The `option` method adds new options to the `thyme` command. In the above
70
- example, we can now execute `thyme -b` or `thyme -t`. Use `thyme -h` to see
71
- available options.
63
+ # execute hook after each pomodoro
64
+ after do |seconds_left|
65
+ `terminal-notifier -message "Thyme's Up!"` if seconds_left == 0
66
+ end
72
67
 
73
- The `before` and `after` adds hooks to our timer. Now before the timer starts,
74
- an mp3 will play. After the timer ends, a notification will be sent.
68
+ # execute hook after thyme program quits
69
+ after(:all) do
70
+ `mplayer ~/music/victory.mp3 &`
71
+ end
75
72
 
76
- Integration
77
- ===========
73
+ # Tmux
78
74
 
79
75
  For tmux integration, make sure to set the `:tmux` option in `~/.thymerc`:
80
76
 
@@ -85,25 +81,28 @@ Then in your `.tmux.conf` file:
85
81
  set-option -g status-right '#(cat ~/.thyme-tmux)'
86
82
  set-option -g status-interval 1
87
83
 
88
- For vim integration, I like to execute `thyme -d` to toggle the timer. This only
84
+ For vim integration, I like to execute `thyme -d` to toggle the timer. This only
89
85
  works if you have tmux integration setup for the countdown:
90
86
 
91
87
  nmap <leader>t :!thyme -d<cr>
92
88
 
93
- Plugins
94
- =======
89
+ # Plugins
95
90
 
96
- Thyme's functionality can also be extended with plugins. They'll usually follow this
97
- format:
91
+ Thyme's functionality can also be extended with plugins. They'll usually be installed
92
+ in `~/.thymerc` like this:
98
93
 
99
- require "thyme_growl"
100
- use ThymeGrowl, text: "Go take a break!"
94
+ require 'thyme_growl'
95
+ use ThymeGrowl, text: 'Go take a break!'
101
96
 
102
- You can create your own plugins. They implement these methods:
97
+ You can create your own plugins. They implement these methods:
103
98
 
104
99
  class MyThymePlugin
105
100
  def initialize(thyme, options={})
106
- # `thyme` is an instance of Thyme (see lib/thyme.rb)
101
+ # `thyme` is an instance of Thyme::Config (see lib/thyme/config.rb)
102
+ end
103
+
104
+ def before_all
105
+ # code to run when thyme starts up
107
106
  end
108
107
 
109
108
  def before
@@ -117,12 +116,15 @@ You can create your own plugins. They implement these methods:
117
116
  def after(seconds_left)
118
117
  # code to run when timer stops
119
118
  end
119
+
120
+ def after_all
121
+ # code to run when thyme program ends
122
+ end
120
123
  end
121
124
 
122
- The `before`, `tick`, and `after` methods are all optional.
125
+ The `before_all`, `before`, `tick`, `after`, and `after_all` methods are all optional.
123
126
 
124
- License
125
- =======
127
+ # License
126
128
 
127
129
  Copyright Hugh Bien - http://hughbien.com.
128
130
  Released under BSD License, see LICENSE.md for more info.
data/bin/thyme CHANGED
@@ -1,17 +1,19 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'optparse'
3
- require File.expand_path('thyme', File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require_relative '../lib/thyme'
4
4
 
5
5
  $0 = 'thyme'
6
6
  ARGV.options do |o|
7
- thyme = Thyme.new
7
+ thyme = Thyme::Console.new
8
8
  o.set_summary_indent(' ')
9
- o.banner = "Usage: #{File.basename($0)} [OPTION]"
9
+ o.banner = "Usage: #{File.basename($0)} [OPTION]"
10
10
  o.define_head "Timer for Pomodoro Technique"
11
11
  o.on('-b', '--break', 'run break timer') { thyme.break! }
12
12
  o.on('-d', '--daemon', 'run in background') { thyme.daemonize! }
13
13
  o.on('-h', '--help', 'show this help message') { puts o; exit }
14
- thyme.load_config(o)
14
+ o.on('-r', '--repeat [COUNT]', 'repeat timer') { |count| thyme.repeat!(count) }
15
+ o.on('-s', '--stop', 'stops running timer') { thyme.stop; exit }
16
+ thyme.load(o)
15
17
  o.parse!
16
- thyme.run(true)
18
+ thyme.run
17
19
  end
@@ -1,205 +1,10 @@
1
- require 'ruby-progressbar'
2
1
  require 'date'
3
-
4
- class Thyme
5
- VERSION = '0.0.14'
6
- CONFIG_FILE = "#{ENV['HOME']}/.thymerc"
7
- PID_FILE = "#{ENV['HOME']}/.thyme-pid"
8
- TMUX_FILE = "#{ENV['HOME']}/.thyme-tmux"
9
- OPTIONS = [:interval, :timer, :timer_break, :tmux, :tmux_theme, :warning, :warning_color]
10
-
11
- def initialize
12
- @break = false
13
- @interval = 1
14
- @timer = 25 * 60
15
- @timer_break = 5 * 60
16
- @tmux = false
17
- @tmux_theme = "#[default]#[fg=%s]%s#[default]"
18
- @warning = 5 * 60
19
- @warning_color = "red,bold"
20
- @plugins = []
21
- end
22
-
23
- def use(plugin_class, *args, &block)
24
- @plugins << plugin_class.new(self, *args, &block)
25
- end
26
-
27
- def run(force=false)
28
- if force
29
- running? ? stop_timer : start_timer
30
- else
31
- @run = true
32
- end
33
- end
34
-
35
- def break!
36
- @break = true
37
- end
38
-
39
- def daemonize!
40
- @daemon = true
41
- Process.daemon
42
- end
43
-
44
- def daemon?
45
- !!@daemon
46
- end
47
-
48
- def set(opt, val)
49
- raise ThymeError.new("Invalid option: #{opt}") if !OPTIONS.include?(opt.to_sym)
50
- self.instance_variable_set("@#{opt}", val)
51
- end
52
-
53
- def before(&block)
54
- hooks_plugin.add(:before, &block)
55
- end
56
-
57
- def after(&block)
58
- hooks_plugin.add(:after, &block)
59
- end
60
-
61
- def tick(&block)
62
- hooks_plugin.add(:tick, &block)
63
- end
64
-
65
- def option(optparse, short, long, desc, &block)
66
- optparse.on("-#{short}", "--#{long}", desc) do |*args|
67
- self.instance_exec(*args, &block)
68
- exit if !@run
69
- end
70
- end
71
-
72
- def load_config(optparse)
73
- return if !File.exists?(CONFIG_FILE)
74
- app = self
75
- environment = Class.new do
76
- define_method(:set) { |opt,val| app.set(opt,val) }
77
- define_method(:use) { |plugin,*args,&b| app.use(plugin,*args,&b) }
78
- define_method(:before) { |&block| app.before(&block) }
79
- define_method(:after) { |&block| app.after(&block) }
80
- define_method(:tick) { |&block| app.tick(&block) }
81
- define_method(:option) { |sh,lo,desc,&b| app.option(optparse,sh,lo,desc,&b) }
82
- end.new
83
- environment.instance_eval(File.read(CONFIG_FILE), CONFIG_FILE)
84
- end
85
-
86
- def running?
87
- File.exists?(PID_FILE)
88
- end
89
-
90
- private
91
-
92
- def start_timer
93
- File.open(PID_FILE, "w") { |f| f.print(Process.pid) }
94
- seconds_start = @break ? @timer_break : @timer
95
- seconds_left = seconds_start + 1
96
- start_time = DateTime.now
97
- min_length = (seconds_left / 60).floor.to_s.length
98
- tmux_file = File.open(TMUX_FILE, "w") if @tmux
99
- started = false
100
- bar = ENV['THYME_TEST'].nil? && !daemon? ?
101
- ProgressBar.create(
102
- title: format(seconds_left-1, min_length),
103
- total: seconds_start,
104
- length: 50,
105
- format: '[%B] %t') : nil
106
- while seconds_left > 0
107
- seconds_passed = seconds_since(start_time)
108
- seconds_left = [seconds_start - seconds_passed, 0].max
109
- title = format(seconds_left, min_length)
110
- fg = color(seconds_left)
111
- if bar
112
- bar.title = title
113
- bar.progress = seconds_passed
114
- end
115
- if @tmux
116
- tmux_file.truncate(0)
117
- tmux_file.rewind
118
- tmux_file.write(@tmux_theme % [fg, title])
119
- tmux_file.flush
120
- end
121
- unless started
122
- started = true
123
- send_to_plugin :before
124
- end
125
- send_to_plugin :tick, seconds_left
126
- sleep(@interval)
127
- end
128
- rescue SignalException => e
129
- puts ""
130
- ensure
131
- tmux_file.close if tmux_file
132
- File.delete(TMUX_FILE) if File.exists?(TMUX_FILE)
133
- File.delete(PID_FILE) if File.exists?(PID_FILE)
134
- seconds_left = [seconds_start - seconds_since(start_time), 0].max
135
- send_to_plugin :after, seconds_left
136
- end
137
-
138
- def stop_timer
139
- pid = File.read(PID_FILE).to_i
140
- Process.kill('TERM', pid) if pid > 1
141
- rescue Errno::ESRCH # process is already dead, cleanup files and restart
142
- File.delete(TMUX_FILE) if File.exists?(TMUX_FILE)
143
- File.delete(PID_FILE) if File.exists?(PID_FILE)
144
- end
145
-
146
- def send_to_plugin(message, *args)
147
- @plugins.each do |plugin|
148
- begin
149
- plugin.public_send(message, *args) if plugin.respond_to?(message)
150
- rescue
151
- $stderr.puts "Exception raised from #{plugin.class}:", $!, $@
152
- end
153
- end
154
- end
155
-
156
- def hooks_plugin
157
- @hooks_plugin ||= begin
158
- use ThymeHooksPlugin
159
- @plugins.last
160
- end
161
- end
162
-
163
- def seconds_since(time)
164
- ((DateTime.now - time) * 24 * 60 * 60).to_i
165
- end
166
-
167
- def format(seconds, min_length)
168
- min = (seconds / 60).floor
169
- lead = ' ' * (min_length - min.to_s.length)
170
- sec = (seconds % 60).floor
171
- sec = "0#{sec}" if sec.to_s.length == 1
172
- @interval < 60 ?
173
- "#{lead}#{min}:#{sec}" :
174
- "#{lead}#{min}m"
175
- end
176
-
177
- def color(seconds)
178
- !@break && seconds < @warning ? @warning_color : 'default'
179
- end
180
- end
181
-
182
- class ThymeError < StandardError; end;
183
-
184
- class ThymeHooksPlugin
185
- def initialize(app)
186
- @app = app
187
- @hooks = {before: [], tick: [], after: []}
188
- end
189
-
190
- def add(type, &block)
191
- @hooks[type] << block
192
- end
193
-
194
- def before
195
- @hooks[:before].each { |b| @app.instance_exec(&b) }
196
- end
197
-
198
- def tick(seconds_left)
199
- @hooks[:tick].each { |t| @app.instance_exec(seconds_left, &t) }
200
- end
201
-
202
- def after(seconds_left)
203
- @hooks[:after].each { |a| @app.instance_exec(seconds_left, &a) }
204
- end
205
- end
2
+ require 'ruby-progressbar'
3
+ require_relative 'thyme/config'
4
+ require_relative 'thyme/console'
5
+ require_relative 'thyme/error'
6
+ require_relative 'thyme/format'
7
+ require_relative 'thyme/hooks_plugin'
8
+ require_relative 'thyme/timer'
9
+ require_relative 'thyme/tmux'
10
+ require_relative 'thyme/version'
@@ -0,0 +1,74 @@
1
+ module Thyme
2
+ class Config
3
+ CONFIG_FILE = "#{ENV['HOME']}/.thymerc"
4
+ PID_FILE = "#{ENV['HOME']}/.thyme-pid"
5
+ TMUX_FILE = "#{ENV['HOME']}/.thyme-tmux"
6
+ OPTIONS = [:break_color, :interval, :timer, :timer_break, :tmux, :tmux_theme, :warning, :warning_color]
7
+ OPTIONS.each { |opt| attr_reader(opt) }
8
+ attr_accessor :break, :daemon, :repeat, :repeat_index
9
+
10
+ def initialize
11
+ # options set via config file
12
+ @break_color = 'default'
13
+ @interval = 1
14
+ @timer = 25 * 60
15
+ @timer_break = 5 * 60
16
+ @tmux = false
17
+ @tmux_theme = "#[default]#[fg=%s]%s#[default]"
18
+ @warning = 5 * 60
19
+ @warning_color = 'red,bold'
20
+
21
+ # plugins set via config file
22
+ @plugins = []
23
+ @hooks_plugin = use(Thyme::HooksPlugin)
24
+
25
+ # settings via command line
26
+ @break = false
27
+ @daemon = false
28
+ @repeat = 1
29
+ @repeat_index = 1
30
+ end
31
+
32
+ def set(opt, val)
33
+ raise Thyme::Error.new("Invalid option: #{opt}") if !OPTIONS.include?(opt.to_sym)
34
+ self.instance_variable_set("@#{opt}", val)
35
+ end
36
+
37
+ def use(plugin_class, *args, &block)
38
+ plugin = plugin_class.new(self, *args, &block)
39
+ @plugins << plugin
40
+ plugin
41
+ end
42
+
43
+ def before(kind = :each, &block)
44
+ type = kind == :all ? :before_all : :before
45
+ @hooks_plugin.add(type, &block)
46
+ end
47
+
48
+ def after(kind = :each, &block)
49
+ type = kind == :all ? :after_all : :after
50
+ @hooks_plugin.add(type, &block)
51
+ end
52
+
53
+ def tick(&block)
54
+ @hooks_plugin.add(:tick, &block)
55
+ end
56
+
57
+ def option(optparse, short, long, desc, &block)
58
+ optparse.on("-#{short}", "--#{long}", desc) do |*args|
59
+ self.instance_exec(*args, &block)
60
+ exit if !@run
61
+ end
62
+ end
63
+
64
+ def send_to_plugin(message, *args)
65
+ @plugins.each do |plugin|
66
+ begin
67
+ plugin.public_send(message, *args) if plugin.respond_to?(message)
68
+ rescue
69
+ $stderr.puts "Exception raised from #{plugin.class}:", $!, $@
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,55 @@
1
+ module Thyme
2
+ class Console
3
+ attr_accessor :config
4
+
5
+ def initialize
6
+ @config = Config.new
7
+ end
8
+
9
+ def break!
10
+ @config.break = true
11
+ end
12
+
13
+ def daemonize!
14
+ @config.daemon = true
15
+ Process.daemon if !ENV['THYME_TEST']
16
+ end
17
+
18
+ def repeat!(count = 0)
19
+ @config.repeat = count.to_i
20
+ end
21
+
22
+ def stop
23
+ timer.stop
24
+ end
25
+
26
+ def run
27
+ timer.run
28
+ end
29
+
30
+ def load(optparse, &block)
31
+ return if block.nil? && !File.exists?(Config::CONFIG_FILE)
32
+ config = @config
33
+ environment = Class.new do
34
+ define_method(:set) { |opt,val| config.set(opt,val) }
35
+ define_method(:use) { |plugin,*args,&b| config.use(plugin,*args,&b) }
36
+ define_method(:before) { |*args,&block| config.before(*args,&block) }
37
+ define_method(:after) { |*args,&block| config.after(*args,&block) }
38
+ define_method(:tick) { |&block| config.tick(&block) }
39
+ define_method(:option) { |sh,lo,desc,&b| config.option(optparse,sh,lo,desc,&b) }
40
+ end.new
41
+
42
+ if block # for test environment
43
+ environment.instance_eval(&block)
44
+ else
45
+ environment.instance_eval(File.read(Config::CONFIG_FILE), Config::CONFIG_FILE)
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def timer
52
+ Timer.new(@config)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,4 @@
1
+ module Thyme
2
+ class Error < StandardError; end
3
+ class StopTimer < StandardError; end
4
+ end
@@ -0,0 +1,41 @@
1
+ module Thyme
2
+ class Format
3
+ def initialize(config)
4
+ @config = config
5
+ end
6
+
7
+ def seconds_since(time)
8
+ ((DateTime.now - time) * 24 * 60 * 60).to_i
9
+ end
10
+
11
+ def time_left(seconds, min_length)
12
+ min = (seconds / 60).floor
13
+ lead = ' ' * [0, min_length - min.to_s.length].max
14
+ sec = (seconds % 60).floor
15
+ sec = "0#{sec}" if sec.to_s.length == 1
16
+ @config.interval < 60 ?
17
+ "#{lead}#{min}:#{sec} #{repeat_subtitle}".sub(/\s*$/, '') :
18
+ "#{lead}#{min}m #{repeat_subtitle}".sub(/\s*$/, '')
19
+ end
20
+
21
+ def repeat_subtitle
22
+ if @config.repeat == 1
23
+ ''
24
+ elsif @config.repeat == 0
25
+ "(#{@config.repeat_index})"
26
+ else
27
+ "(#{@config.repeat_index}/#{@config.repeat})"
28
+ end
29
+ end
30
+
31
+ def tmux_color(seconds)
32
+ if @config.break
33
+ @config.break_color
34
+ elsif seconds < @config.warning
35
+ @config.warning_color
36
+ else
37
+ 'default'
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,32 @@
1
+ module Thyme
2
+ class HooksPlugin
3
+ def initialize(config)
4
+ @config = config
5
+ @hooks = {before_all: [], before: [], tick: [], after: [], after_all: []}
6
+ end
7
+
8
+ def add(type, &block)
9
+ @hooks[type] << block
10
+ end
11
+
12
+ def before_all
13
+ @hooks[:before_all].each { |b| @config.instance_exec(&b) }
14
+ end
15
+
16
+ def before
17
+ @hooks[:before].each { |b| @config.instance_exec(&b) }
18
+ end
19
+
20
+ def tick(seconds_left)
21
+ @hooks[:tick].each { |t| @config.instance_exec(seconds_left, &t) }
22
+ end
23
+
24
+ def after(seconds_left)
25
+ @hooks[:after].each { |a| @config.instance_exec(seconds_left, &a) }
26
+ end
27
+
28
+ def after_all
29
+ @hooks[:after_all].each { |a| @config.instance_exec(&a) }
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,120 @@
1
+ module Thyme
2
+ class Timer
3
+ def initialize(config)
4
+ @config = config
5
+ @format = Format.new(config)
6
+ @tmux = Tmux.new(config)
7
+ end
8
+
9
+ def stop
10
+ send_signal('TERM')
11
+ end
12
+
13
+ def run
14
+ # pause/unpause timer if it's already running
15
+ send_signal('USR1') and return if File.exists?(Config::PID_FILE)
16
+
17
+ begin
18
+ File.open(Config::PID_FILE, "w") { |f| f.print(Process.pid) }
19
+ @tmux.open
20
+ if @config.repeat == 1
21
+ run_single
22
+ else
23
+ while @config.repeat_index <= @config.repeat || @config.repeat == 0
24
+ @config.break = false
25
+ run_single
26
+ if @config.repeat_index < @config.repeat || @config.repeat == 0
27
+ @config.break = true
28
+ run_single
29
+ end
30
+ @config.repeat_index += 1
31
+ end
32
+ end
33
+ rescue Thyme::StopTimer
34
+ # stop signal received
35
+ ensure
36
+ @tmux.close
37
+ File.delete(Config::PID_FILE) if File.exists?(Config::PID_FILE)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def run_single
44
+ seconds_total = @config.break ? @config.timer_break : @config.timer
45
+ seconds_left = seconds_total + 1
46
+ start_time = DateTime.now
47
+ paused_time = nil
48
+ min_length = (seconds_left / 60).floor.to_s.length
49
+ started = false
50
+ @bar ||= ENV['THYME_TEST'].nil? && !@config.daemon ?
51
+ ProgressBar.create(
52
+ title: @format.time_left(seconds_left-1, min_length),
53
+ total: seconds_total,
54
+ length: 50,
55
+ format: '[%B] %t') : nil
56
+ @bar.reset if @bar
57
+ while seconds_left > 0
58
+ begin
59
+ if paused_time
60
+ sleep(@config.interval)
61
+ next
62
+ end
63
+ seconds_passed = @format.seconds_since(start_time)
64
+ seconds_left = [seconds_total - seconds_passed, 0].max
65
+ title = @format.time_left(seconds_left, min_length)
66
+ if @bar
67
+ @bar.title = title
68
+ if seconds_left == 0 && !last?
69
+ @bar.progress = seconds_passed - 0.01 # prevent bar from finishing
70
+ else
71
+ @bar.progress = seconds_passed
72
+ end
73
+ end
74
+ @tmux.tick(@format.tmux_color(seconds_left), title)
75
+ unless started
76
+ started = true
77
+ @config.send_to_plugin(:before_all) if first?
78
+ @config.send_to_plugin(:before)
79
+ end
80
+ @config.send_to_plugin(:tick, seconds_left)
81
+ sleep(@config.interval)
82
+ rescue SignalException => e
83
+ if e.signm == 'SIGUSR1' && paused_time.nil?
84
+ paused_time = DateTime.now
85
+ elsif e.signm == 'SIGUSR1'
86
+ delta = DateTime.now - paused_time
87
+ start_time += delta
88
+ paused_time = nil
89
+ else
90
+ puts ""
91
+ @interrupted = true
92
+ raise Thyme::StopTimer
93
+ end
94
+ end
95
+ end
96
+ ensure
97
+ seconds_left = [seconds_total - @format.seconds_since(start_time), 0].max
98
+ @config.send_to_plugin(:after, seconds_left)
99
+ @config.send_to_plugin(:after_all) if @interrupted || last?
100
+ end
101
+
102
+ def first?
103
+ @config.repeat == 1 || (!@config.break && @config.repeat_index == 1)
104
+ end
105
+
106
+ def last?
107
+ @config.repeat == @config.repeat_index
108
+ end
109
+
110
+ def send_signal(signal)
111
+ pid = File.read(Config::PID_FILE).to_i
112
+ Process.kill(signal, pid) if pid > 1
113
+ rescue Errno::ESRCH, Errno::ENOENT # process is already dead, cleanup files
114
+ File.delete(Config::TMUX_FILE) if File.exists?(Config::TMUX_FILE)
115
+ File.delete(Config::PID_FILE) if File.exists?(Config::PID_FILE)
116
+ ensure
117
+ true
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,29 @@
1
+ module Thyme
2
+ class Tmux
3
+ def initialize(config)
4
+ @config = config
5
+ end
6
+
7
+ def open
8
+ return if !@config.tmux
9
+ @tmux_file = File.open(Config::TMUX_FILE, "w")
10
+ @tmux_file.truncate(0)
11
+ @tmux_file.rewind
12
+ @tmux_file.write('')
13
+ @tmux_file.flush
14
+ end
15
+
16
+ def tick(color, title)
17
+ return if !@tmux_file
18
+ @tmux_file.truncate(0)
19
+ @tmux_file.rewind
20
+ @tmux_file.write(@config.tmux_theme % [color, title])
21
+ @tmux_file.flush
22
+ end
23
+
24
+ def close
25
+ @tmux_file.close if @tmux_file
26
+ File.delete(Config::TMUX_FILE) if File.exists?(Config::TMUX_FILE)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ module Thyme
2
+ VERSION = '0.0.15'
3
+ end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thyme
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.14
4
+ version: 0.0.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hugh Bien
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-19 00:00:00.000000000 Z
11
+ date: 2015-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-progressbar
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '1.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '1.0'
27
27
  description: Extensible and configurable timer for Pomodoro Technique.
28
28
  email:
29
29
  - hugh@hughbien.com
@@ -36,8 +36,17 @@ files:
36
36
  - README.md
37
37
  - bin/thyme
38
38
  - lib/thyme.rb
39
- homepage: http://thymerb.com
40
- licenses: []
39
+ - lib/thyme/config.rb
40
+ - lib/thyme/console.rb
41
+ - lib/thyme/error.rb
42
+ - lib/thyme/format.rb
43
+ - lib/thyme/hooks_plugin.rb
44
+ - lib/thyme/timer.rb
45
+ - lib/thyme/tmux.rb
46
+ - lib/thyme/version.rb
47
+ homepage: http://hughbien.com/thyme/
48
+ licenses:
49
+ - BSD
41
50
  metadata: {}
42
51
  post_install_message:
43
52
  rdoc_options: []
@@ -55,7 +64,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
55
64
  version: 1.3.6
56
65
  requirements: []
57
66
  rubyforge_project:
58
- rubygems_version: 2.2.2
67
+ rubygems_version: 2.4.5
59
68
  signing_key:
60
69
  specification_version: 4
61
70
  summary: Timer for Pomodoro Technique