Created
July 2, 2023 16:55
-
-
Save mthadley/134ff60cbedc469e40fbaba52009e89a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require "io/console" | |
class Keyboard | |
def initialize(queue) = @queue = queue | |
def monitor | |
return if @thread | |
@thread = Thread.new do | |
STDIN.raw do |io| | |
loop { @queue << [:key, io.getc] } | |
end | |
end | |
end | |
end | |
class Timer | |
def self.get_time = | |
Process.clock_gettime(Process::CLOCK_MONOTONIC, :second) | |
attr_accessor :length_in_s | |
def initialize(length_in_s:, queue:) | |
@length_in_s = length_in_s | |
@queue = queue | |
end | |
def start | |
return if @thread | |
@start_time = Timer.get_time | |
@thread = Thread.new do | |
until done? | |
@queue << [:tick] | |
sleep 1 | |
end | |
@queue << [:ding] | |
end | |
end | |
def done? = seconds_left.zero? | |
def seconds_left = | |
[@length_in_s - (Timer.get_time - @start_time), 0].max | |
def reset | |
@thread.kill | |
@thread = nil | |
start | |
end | |
end | |
class Pomodoro | |
SESSION_LENGTH_IN_S = 1500 | |
BREAK_LENGTH_IN_S = 300 | |
def self.start = new.start | |
def initialize | |
@queue = Queue.new | |
@timer = Timer.new( | |
length_in_s: SESSION_LENGTH_IN_S, | |
queue: @queue, | |
) | |
@keyboard = Keyboard.new(@queue) | |
@state = :session | |
end | |
def start | |
@timer.start | |
@keyboard.monitor | |
loop do | |
case @queue.deq | |
in [:tick] then draw | |
in [:ding] then switch | |
in [:key, "q"] then break | |
in [:key, "r"] then reset | |
in [:key, "b"] then start_break | |
in [:key, "s"] then start_session | |
in [:key, key] then next | |
end | |
end | |
end | |
private | |
def draw | |
label = | |
case @state | |
in :session then "Session time left:" | |
in :break then "Break time left: " | |
end | |
print "#{label} #{formatted_time_left}\r" | |
end | |
def formatted_time_left | |
fmt = "%02d" | |
seconds_left = @timer.seconds_left | |
"#{fmt % (seconds_left / 60)}:#{fmt % (seconds_left % 60)}" | |
end | |
def switch | |
case @state | |
in :session then start_break | |
in :break then start_session | |
end | |
end | |
def start_break | |
@state = :break | |
@timer.length_in_s = BREAK_LENGTH_IN_S | |
reset | |
end | |
def start_session | |
@state = :session | |
@timer.length_in_s = SESSION_LENGTH_IN_S | |
reset | |
end | |
def reset | |
@queue.clear | |
@timer.reset | |
end | |
end | |
Pomodoro.start |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment