Skip to content

Instantly share code, notes, and snippets.

@mthadley
Created July 2, 2023 16:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mthadley/134ff60cbedc469e40fbaba52009e89a to your computer and use it in GitHub Desktop.
Save mthadley/134ff60cbedc469e40fbaba52009e89a to your computer and use it in GitHub Desktop.
#!/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