■ ■ ■ ■ ■ ■
stackexplain/utilities/printers.py
| 1 | + | # Standard library |
1 | 2 | | import sys |
2 | 3 | | from itertools import cycle |
3 | 4 | | from shutil import get_terminal_size |
| skipped 1 lines |
5 | 6 | | from time import sleep |
6 | 7 | | from random import random |
7 | 8 | | |
| 9 | + | # Third party |
| 10 | + | from pygments import highlight |
| 11 | + | from pygments.lexers import get_lexer_by_name |
| 12 | + | from pygments.formatters import Terminal256Formatter |
| 13 | + | |
| 14 | + | CODE_IDENTIFIER = "```" |
| 15 | + | CODE_INDENT = " " |
| 16 | + | |
8 | 17 | | # ASCII color codes |
9 | | - | GREEN = '\033[92m' |
10 | | - | GRAY = '\033[90m' |
11 | | - | CYAN = '\033[36m' |
12 | | - | RED = '\033[31m' |
13 | | - | YELLOW = '\033[33m' |
14 | | - | END = '\033[0m' |
15 | | - | UNDERLINE = '\033[4m' |
16 | | - | BOLD = '\033[1m' |
| 18 | + | GREEN = "\033[92m" |
| 19 | + | GRAY = "\033[90m" |
| 20 | + | CYAN = "\033[36m" |
| 21 | + | RED = "\033[31m" |
| 22 | + | YELLOW = "\033[33m" |
| 23 | + | END = "\033[0m" |
| 24 | + | UNDERLINE = "\033[4m" |
| 25 | + | BOLD = "\033[1m" |
| 26 | + | |
| 27 | + | |
| 28 | + | ######### |
| 29 | + | # HELPERS |
| 30 | + | ######### |
| 31 | + | |
| 32 | + | |
| 33 | + | def slow_print(text, delay=0.01): |
| 34 | + | for word in text: |
| 35 | + | sys.stdout.write(word) |
| 36 | + | sys.stdout.flush() # Defeat buffering |
| 37 | + | |
| 38 | + | sleep(delay) |
17 | 39 | | |
18 | 40 | | |
19 | 41 | | ###### |
| skipped 1 lines |
21 | 43 | | ###### |
22 | 44 | | |
23 | 45 | | |
24 | | - | def register_openai_credentials(): |
25 | | - | pass # TODO |
26 | | - | |
27 | | - | |
28 | 46 | | def print_help_message(): |
29 | 47 | | pass # TODO |
30 | 48 | | |
| skipped 3 lines |
34 | 52 | | print(f"\n{RED}Sorry, stackexplain doesn't support this file type.\n{END}") |
35 | 53 | | |
36 | 54 | | |
| 55 | + | def prompt_user_for_credentials(): |
| 56 | + | print(f"{BOLD}Please enter your OpenAI credentials.{END}\n") |
| 57 | + | email = input("Email address: ") |
| 58 | + | password = input("Password: ") |
| 59 | + | |
| 60 | + | return email, password |
| 61 | + | |
| 62 | + | |
37 | 63 | | class LoadingMessage: |
38 | 64 | | def __init__(self, timeout=0.1): |
39 | 65 | | """ |
| skipped 6 lines |
46 | 72 | | """ |
47 | 73 | | |
48 | 74 | | self.steps = ["⢿", "⣻", "⣽", "⣾", "⣷", "⣯", "⣟", "⡿"] |
49 | | - | self.message = "Asking ChatGPT to explain your error" |
50 | | - | # self.end = "" |
| 75 | + | self.message = f"{BOLD}{CYAN}Asking ChatGPT to explain your error{END}" |
| 76 | + | self.end = f"{BOLD}{CYAN}🤖 ChatGPT's Explanation:{END}" |
51 | 77 | | self.timeout = timeout |
52 | 78 | | |
53 | 79 | | self._thread = Thread(target=self._animate, daemon=True) |
| skipped 7 lines |
61 | 87 | | self.done = True |
62 | 88 | | cols = get_terminal_size((80, 20)).columns |
63 | 89 | | |
64 | | - | print("\r" + " " * cols, end="", flush=True) |
65 | | - | # print(f"\r{self.end}", flush=True) |
| 90 | + | print(f"\r{' ' * cols}", end="", flush=True) |
| 91 | + | print(f"\r{self.end}\n", flush=True) |
66 | 92 | | |
67 | 93 | | def _animate(self): |
68 | 94 | | for step in cycle(self.steps): |
69 | 95 | | if self.done: |
70 | 96 | | break |
71 | 97 | | |
72 | | - | print(f"\r{step} {self.message}", flush=True, end="") |
| 98 | + | print(f"\r{CYAN}{step}{END} {self.message}", flush=True, end="") |
73 | 99 | | |
74 | 100 | | sleep(self.timeout) |
75 | 101 | | |
| skipped 1 lines |
77 | 103 | | self.start() |
78 | 104 | | |
79 | 105 | | def __exit__(self, exc_type, exc_value, tb): |
80 | | - | # handle exceptions with those variables ^ |
81 | 106 | | self.stop() |
82 | 107 | | |
83 | 108 | | |
84 | 109 | | def print_error_explanation(explanation): |
85 | | - | for word in f"{explanation}\n": |
86 | | - | sys.stdout.write(word) |
87 | | - | sys.stdout.flush() # Defeat buffering |
88 | | - | sleep(0.01) |
| 110 | + | for i, text in enumerate(explanation.split(CODE_IDENTIFIER)): |
| 111 | + | if not i % 2: |
| 112 | + | # TODO: Handle bolds |
| 113 | + | slow_print(text) |
| 114 | + | |
| 115 | + | continue |
| 116 | + | |
| 117 | + | code = highlight( |
| 118 | + | text, |
| 119 | + | lexer=get_lexer_by_name("python"), |
| 120 | + | formatter=Terminal256Formatter(style="solarized-dark") |
| 121 | + | ) |
| 122 | + | for line in code.strip().split("\n"): |
| 123 | + | slow_print(f"{CODE_INDENT}{line}", delay=0.001) |
| 124 | + | print() |
| 125 | + | |
| 126 | + | print("\n") |
89 | 127 | | |