class Fasten::UI::Curses
Constants
- MOON_LEN
- MOON_STR
- PROGRESSBAR_LEN
- PROGRESSBAR_STR
- SPINNER_LEN
- SPINNER_STR
Attributes
clear_needed[RW]
message[RW]
n_cols[RW]
n_rows[RW]
runner[RW]
sel_index[RW]
selected[RW]
Public Class Methods
new(runner:)
click to toggle source
# File lib/fasten/ui/curses.rb, line 24 def initialize(runner:) @runner = runner end
Public Instance Methods
cleanup()
click to toggle source
# File lib/fasten/ui/curses.rb, line 46 def cleanup close_screen @setup_done = nil end
draw_title()
click to toggle source
# File lib/fasten/ui/curses.rb, line 40 def draw_title ui_text_aligned(0, :left, 'Fasten your seatbelts!') ui_text_aligned(0, :center, "#{name} #{$PID}") ui_text_aligned(0, :right, Time.new.to_s) end
force_clear()
click to toggle source
# File lib/fasten/ui/curses.rb, line 91 def force_clear self.clear_needed = true end
setup()
click to toggle source
# File lib/fasten/ui/curses.rb, line 51 def setup init_screen self.n_rows = lines self.n_cols = cols stdscr.keypad = true stdscr.nodelay = true setup_color noecho cbreak nonl curs_set 0 @setup_done = true end
setup_color()
click to toggle source
# File lib/fasten/ui/curses.rb, line 65 def setup_color start_color use_default_colors init_pair 1, Curses::COLOR_YELLOW, -1 init_pair 2, Curses::COLOR_GREEN, -1 init_pair 3, Curses::COLOR_RED, -1 init_pair 4, Curses::COLOR_WHITE, -1 end
ui_jobs()
click to toggle source
# File lib/fasten/ui/curses.rb, line 138 def ui_jobs l = ui_text_aligned(1, :left, ui_jobs_summary) + 1 workers.each_with_index do |worker, index| setpos 1, l + index attrs = worker.running? ? A_STANDOUT : color_pair(4) | A_DIM attrset attrs addstr worker.running? ? 'R' : '_' attroff attrs end ui_state end
ui_jobs_summary()
click to toggle source
# File lib/fasten/ui/curses.rb, line 129 def ui_jobs_summary running = tasks.running.count waiting = tasks.waiting.count working = workers.count idle = working - running "Procs running: #{running} idle: #{idle} waiting: #{waiting} #{runner.use_threads ? 'threads' : 'processes'}: #{jobs}" end
ui_keyboard()
click to toggle source
# File lib/fasten/ui/curses.rb, line 95 def ui_keyboard return unless (key = stdscr.getch) self.message = nil if key == Curses::Key::LEFT if jobs <= 1 self.message = "Can't remove 1 worker left, press [P] to pause" else self.jobs -= 1 self.message = "Decreasing jobs to #{jobs}" end elsif key == Curses::Key::RIGHT self.jobs += 1 self.message = "Increasing jobs to #{jobs}" elsif key == Curses::Key::DOWN self.sel_index = sel_index ? [sel_index + 1, tasks.count - 1].min : 0 self.selected = tasks[sel_index] elsif key == Curses::Key::UP self.sel_index = sel_index ? [sel_index - 1, 0].max : tasks.count - 1 self.selected = tasks[sel_index] elsif key == 'q' self.message = 'Will quit when running tasks end' self.state = :QUITTING elsif key == 'p' self.message = 'Will pause when running tasks end' self.state = :PAUSING elsif key == 'r' self.state = :RUNNING end force_clear end
ui_progressbar(row, col_ini, col_fin, count, total)
click to toggle source
# File lib/fasten/ui/curses.rb, line 170 def ui_progressbar(row, col_ini, col_fin, count, total) slice = total.to_f / (col_fin - col_ini + 1) col_ini.upto col_fin do |col| setpos row, col count -= slice if count >= 0 addstr PROGRESSBAR_STR[-1] elsif count > -slice addstr PROGRESSBAR_STR[(count * PROGRESSBAR_LEN / slice) % PROGRESSBAR_LEN] else addstr '.' end end end
ui_state()
click to toggle source
# File lib/fasten/ui/curses.rb, line 152 def ui_state if runner.running? attrs = color_pair(2) elsif runner.pausing? attrs = color_pair(1) | A_BLINK | A_STANDOUT elsif runner.paused? attrs = color_pair(1) | A_STANDOUT elsif runner.quitting? attrs = color_pair(3) | A_BLINK | A_STANDOUT end l = ui_text_aligned(1, :right, state.to_s, attrs) return unless message setpos 1, n_cols - l - message.length - 1 addstr message end
ui_task_clock(task, cur, avg)
click to toggle source
# File lib/fasten/ui/curses.rb, line 200 def ui_task_clock(task, cur, avg) return unless task.ini dif = cur - task.ini avg = avg.to_f if task.ini && avg.positive? percent = dif / avg index = (percent * MOON_LEN).to_i index = MOON_LEN - 1 if index > MOON_LEN - 1 format ' %.2f s %s ', dif, MOON_STR[index] else format ' %.2f s ', dif end end
ui_task_color(task)
click to toggle source
# File lib/fasten/ui/curses.rb, line 216 def ui_task_color(task) rev = task == selected ? A_REVERSE : 0 case task.state when :RUNNING color_pair(1) | A_TOP | rev when :DONE color_pair(2) | A_TOP | rev when :FAIL color_pair(3) | A_TOP | rev when :WAIT A_TOP | rev else color_pair(4) | A_DIM | rev end end
ui_task_icon(task)
click to toggle source
# File lib/fasten/ui/curses.rb, line 185 def ui_task_icon(task) case task.state when :RUNNING SPINNER_STR[task.worker&.spinner] when :FAIL '✘' when :DONE '✔' when :WAIT '…' else ' ' end end
ui_task_string(task, y, x, icon: nil, str: nil)
click to toggle source
# File lib/fasten/ui/curses.rb, line 233 def ui_task_string(task, y, x, icon: nil, str: nil) setpos y, x attrs = ui_task_color(task) icon = ui_task_icon(task) if icon str ||= icon ? "#{icon} #{task}" : task.to_s delta = x + str.length - n_cols str = str[0...-delta] if delta.positive? attrset attrs if attrs addstr str attroff attrs if attrs x + str.length end
ui_tasks()
click to toggle source
# File lib/fasten/ui/curses.rb, line 251 def ui_tasks workers.each do |worker| worker.spinner = (worker.spinner + 1) % SPINNER_LEN if worker.running? end cur = Time.new count_done = tasks.done.count count_total = tasks.count tl = count_total.to_s.length percentstr = count_total.positive? && " #{(count_done * 100 / count_total).to_i}%" elapsed_str = format ' %.2f s', (dif = cur - runner.ini) if runner.ini @stat_str ||= begin @runner_last_avg = runner.last_avg if runner.last_avg && runner.last_err format '≈ %.2f s ± %.2f', runner.last_avg, runner.last_err elsif runner.last_avg format '≈ %.2f s', runner.last_avg end end end_str = [elapsed_str, @stat_str].compact.join(' ') if @runner_last_avg a = dif b = @runner_last_avg else a = count_done b = count_total end col_ini = ui_text_aligned(2, :left, format("Tasks %#{tl}d/%d%s", count_done, count_total, percentstr)) + 1 col_fin = n_cols - 1 - end_str.length ui_text_aligned(2, :right, end_str) ui_progressbar(2, col_ini, col_fin, a, b) max = 2 list = tasks.sort_by.with_index { |x, index| [x.run_score, index] } list.each_with_index do |task, index| next if 3 + index >= n_rows x = ui_task_string(task, 3 + index, 2, icon: true) max = x if x > max end list.each_with_index do |task, index| next if 3 + index >= n_rows if task.depends && !task.depends.empty? x = max x = ui_task_string(task, 3 + index, x, str: ':') + 1 task.depends.each do |dependant_task| x = ui_task_string(dependant_task, 3 + index, x) + 1 end else x = max + 1 last_avg = task.last_avg last_err = task.last_err if task.dif str = format ' %.2f s', task.dif elsif last_avg && last_err str = format '%s ≈ %.2f s ± %.2f %s', ui_task_clock(task, cur, last_avg), last_avg, last_err, task.worker&.name elsif last_avg str = format '%s ≈ %.2f s %s', ui_task_clock(task, cur, last_avg), last_avg, task.worker&.name else str = ui_task_clock(task, cur, 0) end ui_task_string(task, 3 + index, x, str: str) if str end end end
ui_text_aligned(row, align, str, attrs = nil)
click to toggle source
# File lib/fasten/ui/curses.rb, line 75 def ui_text_aligned(row, align, str, attrs = nil) if align == :center setpos row, (n_cols - str.length) / 2 elsif align == :right setpos row, n_cols - str.length else setpos row, 0 end attrset attrs if attrs addstr str attroff attrs if attrs str.length end
update()
click to toggle source
# File lib/fasten/ui/curses.rb, line 28 def update setup unless @setup_done ui_keyboard clear if clear_needed draw_title ui_jobs ui_tasks refresh self.clear_needed = false end