Class: Fasten::UI::Curses
- Inherits:
-
Object
- Object
- Fasten::UI::Curses
- Extended by:
- Forwardable
- Includes:
- Curses
- Defined in:
- lib/fasten/ui/curses.rb
Constant Summary collapse
- SPINNER_STR =
'⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
- SPINNER_LEN =
SPINNER_STR.length
- MOON_STR =
'🌑🌒🌓🌔🌕'
- MOON_LEN =
MOON_STR.length
- PROGRESSBAR_STR =
' ▏▎▍▌▋▊▉'
- PROGRESSBAR_LEN =
PROGRESSBAR_STR.length
Instance Attribute Summary collapse
-
#clear_needed ⇒ Object
Returns the value of attribute clear_needed.
-
#message ⇒ Object
Returns the value of attribute message.
-
#n_cols ⇒ Object
Returns the value of attribute n_cols.
-
#n_rows ⇒ Object
Returns the value of attribute n_rows.
-
#runner ⇒ Object
Returns the value of attribute runner.
-
#sel_index ⇒ Object
Returns the value of attribute sel_index.
-
#selected ⇒ Object
Returns the value of attribute selected.
Instance Method Summary collapse
- #cleanup ⇒ Object
- #draw_title ⇒ Object
- #force_clear ⇒ Object
-
#initialize(runner:) ⇒ Curses
constructor
A new instance of Curses.
- #setup ⇒ Object
- #setup_color ⇒ Object
- #ui_jobs ⇒ Object
- #ui_jobs_summary ⇒ Object
- #ui_keyboard ⇒ Object
- #ui_progressbar(row, col_ini, col_fin, count, total) ⇒ Object
- #ui_state ⇒ Object
- #ui_task_clock(task, cur, avg) ⇒ Object
- #ui_task_color(task) ⇒ Object
- #ui_task_icon(task) ⇒ Object
- #ui_task_string(task, y, x, icon: nil, str: nil) ⇒ Object
- #ui_tasks ⇒ Object
- #ui_text_aligned(row, align, str, attrs = nil) ⇒ Object
- #update ⇒ Object
Constructor Details
#initialize(runner:) ⇒ Curses
Returns a new instance of Curses.
24 25 26 |
# File 'lib/fasten/ui/curses.rb', line 24 def initialize(runner:) @runner = runner end |
Instance Attribute Details
#clear_needed ⇒ Object
Returns the value of attribute clear_needed.
15 16 17 |
# File 'lib/fasten/ui/curses.rb', line 15 def clear_needed @clear_needed end |
#message ⇒ Object
Returns the value of attribute message.
15 16 17 |
# File 'lib/fasten/ui/curses.rb', line 15 def end |
#n_cols ⇒ Object
Returns the value of attribute n_cols.
15 16 17 |
# File 'lib/fasten/ui/curses.rb', line 15 def n_cols @n_cols end |
#n_rows ⇒ Object
Returns the value of attribute n_rows.
15 16 17 |
# File 'lib/fasten/ui/curses.rb', line 15 def n_rows @n_rows end |
#runner ⇒ Object
Returns the value of attribute runner.
15 16 17 |
# File 'lib/fasten/ui/curses.rb', line 15 def runner @runner end |
#sel_index ⇒ Object
Returns the value of attribute sel_index.
15 16 17 |
# File 'lib/fasten/ui/curses.rb', line 15 def sel_index @sel_index end |
#selected ⇒ Object
Returns the value of attribute selected.
15 16 17 |
# File 'lib/fasten/ui/curses.rb', line 15 def selected @selected end |
Instance Method Details
#cleanup ⇒ Object
46 47 48 49 |
# File 'lib/fasten/ui/curses.rb', line 46 def cleanup close_screen @setup_done = nil end |
#draw_title ⇒ Object
40 41 42 43 44 |
# 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 ⇒ Object
91 92 93 |
# File 'lib/fasten/ui/curses.rb', line 91 def force_clear self.clear_needed = true end |
#setup ⇒ Object
51 52 53 54 55 56 57 58 59 60 61 62 63 |
# 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 ⇒ Object
65 66 67 68 69 70 71 72 73 |
# 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 ⇒ Object
138 139 140 141 142 143 144 145 146 147 148 149 150 |
# 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 ⇒ Object
129 130 131 132 133 134 135 136 |
# 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 ⇒ Object
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/fasten/ui/curses.rb', line 95 def ui_keyboard return unless (key = stdscr.getch) self. = nil if key == Curses::Key::LEFT if jobs <= 1 self. = "Can't remove 1 worker left, press [P] to pause" else self.jobs -= 1 self. = "Decreasing jobs to #{jobs}" end elsif key == Curses::Key::RIGHT self.jobs += 1 self. = "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. = 'Will quit when running tasks end' self.state = :QUITTING elsif key == 'p' self. = '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) ⇒ Object
170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/fasten/ui/curses.rb', line 170 def (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 ⇒ Object
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# 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 setpos 1, n_cols - l - .length - 1 addstr end |
#ui_task_clock(task, cur, avg) ⇒ Object
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
# 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) ⇒ Object
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
# 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) ⇒ Object
185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# 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) ⇒ Object
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# 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 ⇒ Object
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
# 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) (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) ⇒ Object
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# 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 ⇒ Object
28 29 30 31 32 33 34 35 36 37 38 |
# 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 |