Class: Clack::Prompts::Spinner
- Inherits:
-
Object
- Object
- Clack::Prompts::Spinner
- Defined in:
- lib/clack/prompts/spinner.rb
Overview
Animated spinner for async operations.
Runs animation in a background thread. Call #start to begin, #stop/#error/#cancel to finish. Thread-safe message updates.
Indicator modes:
:dots- animating dots after message (default):timer- elapsed time display [Xs] or [Xm Ys]
Exit safety: a spinner still running when the process exits, whether by
exit (including exit 0), Ctrl+C, or an uncaught exception, prints its
cancel or error line first and stops the animation thread, instead of
leaving a half-drawn frame. Clack.spin does the same when its block
exits early. Exit and signals count as cancelled; any other exception
counts as an error.
Defined Under Namespace
Modules: Registry
Instance Method Summary collapse
-
#abandon(exception = nil) ⇒ void
private
Finish a spinner whose caller is not coming back.
-
#cancel(message = nil) ⇒ Object
Stop with cancelled state and run
on_cancel. -
#cancelled? ⇒ Boolean
True once #cancel has finished the spinner.
-
#clear ⇒ Object
Clear the spinner without showing a final message.
-
#error(message = nil) ⇒ Object
Stop with error state.
-
#initialize(indicator: :dots, frames: nil, delay: nil, style_frame: nil, cancel_message: nil, error_message: nil, on_cancel: nil, with_guide: nil, output: $stdout) ⇒ Spinner
constructor
A new instance of Spinner.
-
#message(msg) ⇒ Object
Update the spinner message while running.
-
#running? ⇒ Boolean
True between start and the first of stop/error/cancel/clear.
-
#start(message = nil) ⇒ self
Start the spinner animation.
-
#stop(message = nil) ⇒ Object
Stop with success state.
Constructor Details
#initialize(indicator: :dots, frames: nil, delay: nil, style_frame: nil, cancel_message: nil, error_message: nil, on_cancel: nil, with_guide: nil, output: $stdout) ⇒ Spinner
Returns a new instance of Spinner.
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/clack/prompts/spinner.rb', line 152 def initialize( indicator: :dots, frames: nil, delay: nil, style_frame: nil, cancel_message: nil, error_message: nil, on_cancel: nil, with_guide: nil, output: $stdout ) (, , on_cancel) @messages = {cancel: , error: }.freeze @on_cancel = on_cancel @with_guide = with_guide @output = output @indicator = indicator @frames = frames || Symbols::SPINNER_FRAMES @delay = delay || Symbols::SPINNER_DELAY @style_frame = style_frame || ->(frame) { Colors.magenta(frame) } @state = :idle @message = "" @thread = nil @frame_idx = 0 @prev_frame = nil # The pid that started the spinner and the monotonic start time; nil # while idle. One hash so the class stays within reek's ivar limit. @run = nil @mutex = Mutex.new end |
Instance Method Details
#abandon(exception = nil) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Finish a spinner whose caller is not coming back. Exit and signals end cancelled, any other exception ends in the error state, nil (break, throw, or a forgotten stop at process exit) ends cancelled. No-op unless running.
263 264 265 266 267 |
# File 'lib/clack/prompts/spinner.rb', line 263 def abandon(exception = nil) return unless running? crash?(exception) ? error : cancel end |
#cancel(message = nil) ⇒ Object
Stop with cancelled state and run on_cancel.
227 228 229 |
# File 'lib/clack/prompts/spinner.rb', line 227 def cancel( = nil) finish(:cancelled, ) end |
#cancelled? ⇒ Boolean
Returns true once #cancel has finished the spinner.
252 |
# File 'lib/clack/prompts/spinner.rb', line 252 def cancelled? = @mutex.synchronize { @state == :cancelled } |
#clear ⇒ Object
Clear the spinner without showing a final message.
240 241 242 243 244 245 246 247 248 249 |
# File 'lib/clack/prompts/spinner.rb', line 240 def clear @mutex.synchronize do @state = :idle Registry.unregister(self) end @thread&.join restore_cursor @output.print Core::Cursor.clear_down @output.print Core::Cursor.show end |
#error(message = nil) ⇒ Object
Stop with error state.
219 220 221 |
# File 'lib/clack/prompts/spinner.rb', line 219 def error( = nil) finish(:error, ) end |
#message(msg) ⇒ Object
Update the spinner message while running.
234 235 236 237 |
# File 'lib/clack/prompts/spinner.rb', line 234 def (msg) @mutex.synchronize { @message = remove_trailing_dots(msg) } self end |
#running? ⇒ Boolean
Returns true between start and the first of stop/error/cancel/clear.
255 |
# File 'lib/clack/prompts/spinner.rb', line 255 def running? = @mutex.synchronize { @state == :running } |
#start(message = nil) ⇒ self
Start the spinner animation.
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/clack/prompts/spinner.rb', line 187 def start( = nil) @mutex.synchronize do return unless @state == :idle @message = remove_trailing_dots( || "") @state = :running @prev_frame = nil @frame_idx = 0 @run = {pid: Process.pid, started_at: Process.clock_gettime(Process::CLOCK_MONOTONIC)}.freeze # Under the mutex so a concurrent finish cannot slip between the # state flip and registration and leave a finished spinner tracked. Registry.register(self) end @output.print Core::Cursor.hide @output.print "#{Colors.gray(Symbols::S_BAR)}\n" if Core::Settings.with_guide?(@with_guide) @thread = Thread.new { spin_loop } self end |
#stop(message = nil) ⇒ Object
Stop with success state.
211 212 213 |
# File 'lib/clack/prompts/spinner.rb', line 211 def stop( = nil) finish(:success, ) end |