How to Create a Spinning Command Line Cursor

How to create a spinning command line cursor?

Something like this, assuming your terminal handles \b

import sys
import time

def spinning_cursor():
while True:
for cursor in '|/-\\':
yield cursor

spinner = spinning_cursor()
for _ in range(50):
sys.stdout.write(next(spinner))
sys.stdout.flush()
time.sleep(0.1)
sys.stdout.write('\b')

Making Python text green and using Spinning cursor - Newbies questions

So, about getting the terminal color to be green, there is a neat package called colorama that generally works great for me. To check whether the process is running or not, I would recommend using Popen instead of check_output, since the latter does not allow you to communicate with the process as far as I know. But you need to since you want to know if your subprocess is still running. Here is a little code example that should get you running:

import subprocess
import shlex
import time
import sys
import colorama

def spinning_cursor():

"""Spinner taken from http://stackoverflow.com/questions/4995733/how-to-create-a-spinning-command-line-cursor-using-python/4995896#4995896."""

while True:
for cursor in '|/-\\':
yield cursor

# Create spinner
spinner = spinning_cursor()

# Print and change color to green
print(colorama.Fore.GREEN + 'running network scan')

# Define command we want to run
cmd = 'your command goes here'

# Split args for POpen
args=shlex.split(cmd)

# Create subprocess
p = subprocess.Popen(args,stdout=subprocess.PIPE)

# Check if process is still running
while p.poll()==None:

# Print spinner
sys.stdout.write(spinner.next())
sys.stdout.flush()
sys.stdout.write('\b')

print('Done')

# Grab output
output=p.communicate()[0]

# Reset color (otherwise your terminal is green)
print(colorama.Style.RESET_ALL)

Printing an ASCII spinning cursor in the console

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!

Print spinning cursor in a terminal running application using C

You could use the backspace character (\b) like this:

printf("processing... |");
fflush(stdout);
// do something
printf("\b/");
fflush(stdout);
// do some more
printf("\b-");
fflush(stdout);

etc. You need the fflush(stdout) because normally stdout is buffered until you output a newline.

Is it possible to print a spinning cursor in a terminal using bash scripting?

Spinners are nice, but if you really want a controllable progress meter that is aware of the IO you're dealing with, take a look at pv.

Here's a quick-and-dirty spinner. (Many nonstandard implementations of sleep will let you sleep for fractions of a second.)

Bash

spin() {
local -a marks=( '/' '-' '\' '|' )
while [[ 1 ]]; do
printf '%s\r' "${marks[i++ % ${#marks[@]}]}"
sleep 1
done
}

POSIX Sh

spin() {
i=0
marks='/ - \ |'
while true; do
if [ $# -lt 4 ]; then
set -- "$@" $marks
fi
shift $(( (i+1) % $# ))
printf '%s\r' "$1"
sleep 1
done
}

How to create a spinning command line cursor?

Something like this, assuming your terminal handles \b

import sys
import time

def spinning_cursor():
while True:
for cursor in '|/-\\':
yield cursor

spinner = spinning_cursor()
for _ in range(50):
sys.stdout.write(next(spinner))
sys.stdout.flush()
time.sleep(0.1)
sys.stdout.write('\b')

How to program a spinning cursor in c++ on OSX?

You can use the ncurses library for cross-platform terminal access. You csn make nice text-only UIs using this.

Problem with ASCII Rotating Cursor (TUI) Animation

The output effect is not guaranteed but dividing it into sections might help.

Idea:

#include <algorithm>
#include <chrono>
#include <cstddef>
#include <iostream>
#include <string>
#include <thread>

using namespace std::chrono_literals; // a cumbersome way to be able to write 100ms

// unformatted output of one char, a backspace, flushing and Zzz...
void slow_put(char ch) {
static const auto delay = 100ms;
static const char bs = '\b';
std::cout.write(&ch, 1);
std::cout.write(&bs, 1);
std::cout.flush();
std::this_thread::sleep_for(delay);
}

// newline, but erase the char under it first
void nl() {
std::cout.write(" \n", 2);
}

// proxy ... decorate stuff here (for debugging etc)
void display(char ch) {
slow_put(ch);
}

// enabler to repeat a bunch of sequences
void spinner(const std::string& sequence) {
// execute the display function for one char at a time
std::for_each(sequence.begin(), sequence.end(), display);
}

// example use of the helpers above
void spinningCursorSchema(size_t times) {
static const std::string seq = R"raw(|/-\)raw"; // the pattern to display

while(times--) spinner(seq);
// add more patterns to this schema if wanted
}

int main() {
std::cout << "Spinner: [ ]\b\b";
spinningCursorSchema(100); // run the spinningCursor 100 times
nl(); // erasing newline
}

Edit: A brief explanation:

For every group of functions you called that I felt could be named, "do_this()" or "do_that()" I put them in a function and named them accordingly.

The purpose of this exercice was not primarily for me to find the error in your code but to provide a frame of reference. It's easier to identify/talk about/fix problems when one can say "your do_this() function needs this or that..." or similar. When everything is in one big code block everyone reading it needs to start from zero. A function with a clear name (or a comment to compensate for the poor naming as I did above, "proxy") and only a few lines of code can be reviewed by everyone without much background knowledge about the bigger problem.

In short, I took your code that was specifically created to do one thing and broke it down into a few functions that I used to rebuild something similar to your original idea. By doing that I made it easier to see flaws, talk about design decisions. If a function of 2-4 lines can be reviewed by 10000 people and they don't see a problem, it's very unlikely that that function is the problem (in itself). By building blocks of small functions with a clear purpose, bughunting becomes a lot more available for everyone, not only people deeply involved in the particular problem you're solving.

I now see that I used a function template from <algorithm> that may be unfamiliar: std::for_each. In this case, it could be replaced by:

for(char ch : sequence) display(ch);

Come to think of it, that's even clearer.

If this wasn't the overview you sought, just comment and point out the parts you want to get explained and I'll try again



Related Topics



Leave a reply



Submit