Last active
December 29, 2016 04:07
-
-
Save fgimian/d18bb491c50f448c0a80e8effb2593b1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import math | |
import sys | |
import time | |
# Colours | |
BOLD = '\033[1m' | |
RED = '\033[91m' | |
GREEN = '\033[92m' | |
YELLOW = '\033[93m' | |
BLUE = '\033[94m' | |
ENDC = '\033[0m' | |
# Other Escape Sequences | |
MOVE_UP_TWO = '\033[2A' | |
CLEAR_LINE = '\033[0K' | |
HIDE_CURSOR = '\033[?25l' | |
SHOW_CURSOR = '\033[?25h' | |
def print_overlap(text, first=False, file=sys.stdout): | |
""" | |
Prints a block of overlapping text ensuring that previous output is cleared. | |
:param text: The text to display as a multiline string or list (where each item is one line). | |
:param first: Whether or not this is the first run of the function. | |
:param file: The stream to display the output to. | |
""" | |
# Obtain the lines that we will print | |
lines = text.split('\n') if isinstance(text, str) else text | |
# Determine how many times we need to move up two lines | |
num_moves_up_two = math.ceil(len(lines) / 2) | |
if not first: | |
print(MOVE_UP_TWO * num_moves_up_two, end='', file=file, flush=True) | |
# If an odd number of lines is found, we need to move the cursor down one line with a \n | |
if len(lines) % 2 == 1: | |
print(file=file, flush=True) | |
for line in lines: | |
print(f'{CLEAR_LINE}{line}', file=file, flush=True) | |
def progress_bar( | |
percent, width=40, boundary_symbol_left='|', boundary_symbol_right='|', | |
progress_symbols=['▏', '▎', '▍', '▌', '▋', '▊', '▉', '█'] | |
): | |
""" | |
Builds a progress bar based on the required appearance. | |
:param percent: The current percentage to display (as a number between 0 and 100). | |
:param width: The total width of the progress bar (includes the boundaries). | |
:param boundary_symbol_left: The left boundary symbol to display. | |
:param boundary_symbol_right: The right boundary symbol to display. | |
:param progress_symbols: A list containing gradual progress indicators. | |
:return: a unicode string which may be printed to display the progress bar | |
""" | |
# Remove the two boundary items to determine the width of the progress bar | |
progress_width = width - 2 | |
# Calculate how far we've progressed based on the width requested | |
complete_width = progress_width * percent / 100 | |
# Calculate how many full blocks we will display for completeed progress | |
complete_blocks = int(complete_width) | |
# Determine which progress symbol to use for the last block | |
partial_block_width = complete_width - complete_blocks | |
partial_block_symbol_index = int(partial_block_width * len(progress_symbols)) | |
# If progress is less than 100%, we need to show the partial block | |
partial_block_show = complete_blocks < progress_width | |
# Calculate how many full blocks we will display for incomplete progress | |
incomplete_blocks = progress_width - complete_blocks - (1 if partial_block_show else 1) | |
return ( | |
# left boundary | |
f'{boundary_symbol_left}' | |
# completed blocks | |
f'{progress_symbols[-1] * (complete_blocks)}' | |
# partial block | |
f'{progress_symbols[partial_block_symbol_index] if partial_block_show else ""}' | |
# incomplete blocks | |
f'{" " * incomplete_blocks}' | |
# right boundary | |
f'{boundary_symbol_right}' | |
) | |
def main(): | |
# Progress bar example | |
try: | |
print(HIDE_CURSOR, end='', flush=True) | |
progress = 0 | |
while progress <= 100: | |
print_overlap([ | |
'', | |
f'{BOLD}Installing Something Awesome{ENDC}', | |
'', | |
f'{BLUE}Extracting the_awesome_thing.zip...{ENDC}', | |
'', | |
f'{progress:8.1f} % {progress_bar(progress, width=50)} file_{int(progress)}.txt', | |
], first=True if progress == 0 else False) | |
progress += 0.01 | |
time.sleep(0.001) | |
finally: | |
print() | |
print(SHOW_CURSOR, end='', flush=True) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment