Printing an ASCII spinning “cursor” in the console

前端 未结 3 537
抹茶落季
抹茶落季 2020-12-14 11:18

I have a Ruby script that does some long taking jobs. It is command-line only and I would like to show that the script is still running and not halted. I used to like the so

相关标签:
3条回答
  • 2020-12-14 11:31
    # First define your chars
    pinwheel = %w{| / - \\}
    
    # Rotate and print as often as needed to "spin"
    def spin_it
      print "\b" + pinwheel.rotate!.first
    end
    

    EDIT from peter: here a working version

    def spin_it(times)
      pinwheel = %w{| / - \\}
      times.times do
        print "\b" + pinwheel.rotate!.first
        sleep(0.1)
      end
    end
    
    spin_it 10
    
    0 讨论(0)
  • 2020-12-14 11:36

    I wrote a gem spin_to_win that displays a spinner while yielding a block. For example:

    SpinToWin.with_spinner('Zzzz') do |spinner| 
      spinner.banner('sleepy')
      sleep 1 
    end
    
    Zzzz \ [sleepy]
    

    It can also track work pending vs. work completed:

    SpinToWin.with_spinner('Zzzz') do |spinner|
        spinner.increment_todo!(3)
    
        spinner.banner('snore')
        sleep 1
        spinner.increment_done!
    
        spinner.banner('dream')
        sleep 1
        spinner.increment_done!
    
        spinner.banner('wake up!')
        sleep 1
        spinner.increment_done!
    end
    
    Zzzz \ 3 of 3 [wake up!]
    
    0 讨论(0)
  • 2020-12-14 11:39

    Yes, this works on Windows, OS X, and Linux. Improving on Niklas' suggestion, you can make this more general like so:

    def show_wait_cursor(seconds,fps=10)
      chars = %w[| / - \\]
      delay = 1.0/fps
      (seconds*fps).round.times{ |i|
        print chars[i % chars.length]
        sleep delay
        print "\b"
      }
    end
    
    show_wait_cursor(3)
    

    If you don't know how long the process will take, you can do this in another thread:

    def show_wait_spinner(fps=10)
      chars = %w[| / - \\]
      delay = 1.0/fps
      iter = 0
      spinner = Thread.new do
        while iter do  # Keep spinning until told otherwise
          print chars[(iter+=1) % chars.length]
          sleep delay
          print "\b"
        end
      end
      yield.tap{       # After yielding to the block, save the return value
        iter = false   # Tell the thread to exit, cleaning up after itself…
        spinner.join   # …and wait for it to do so.
      }                # Use the block's return value as the method's
    end
    
    print "Doing something tricky..."
    show_wait_spinner{
      sleep rand(4)+2 # Simulate a task taking an unknown amount of time
    }
    puts "Done!"
    

    This one outputs:

    Doing something tricky...|
    Doing something tricky.../
    Doing something tricky...-
    Doing something tricky...\ 
    (et cetera)
    Doing something tricky...done!
    
    0 讨论(0)
提交回复
热议问题