summaryrefslogtreecommitdiff
path: root/cmd2/cmd2.py
diff options
context:
space:
mode:
Diffstat (limited to 'cmd2/cmd2.py')
-rw-r--r--cmd2/cmd2.py78
1 files changed, 75 insertions, 3 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index d817e461..baf511f3 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -50,7 +50,7 @@ from .clipboard import can_clip, get_paste_buffer, write_to_paste_buffer
from .parsing import StatementParser, Statement
# Set up readline
-from .rl_utils import rl_type, RlType, rl_get_point
+from .rl_utils import rl_type, RlType, rl_get_point, rl_set_prompt
if rl_type == RlType.NONE: # pragma: no cover
rl_warning = "Readline features including tab completion have been disabled since no \n" \
"supported version of readline was found. To resolve this, install \n" \
@@ -3248,6 +3248,64 @@ Script should contain one command per line, just like command would be typed in
# Redraw the prompt and input line
rl_force_redisplay()
+ def update_prompt(self, new_prompt: str) -> None:
+ """
+ Used to display an important message to the user while they are at the prompt.
+ The current prompt and input lines are erased, then the alert is printed in their place, and
+ finally the prompt and input lines restored below the alert. To the user it appears as if
+ an alert message is printed above the prompt.
+
+ :param alert_msg: the message to display to the user
+ """
+ if rl_type == RlType.NONE:
+ return
+
+ import shutil
+ import colorama.ansi as ansi
+ from colorama import Cursor
+
+ visible_prompt = self.visible_prompt
+
+ # Get the size of the terminal
+ terminal_size = shutil.get_terminal_size()
+
+ # Figure out how many lines the prompt and user input take up
+ total_str_size = len(visible_prompt) + len(readline.get_line_buffer())
+ num_input_lines = int(total_str_size / terminal_size.columns) + 1
+
+ # Get the cursor's offset from the beginning of the first input line
+ cursor_input_offset = len(visible_prompt) + rl_get_point()
+
+ # Calculate what input line the cursor is on
+ cursor_input_line = int(cursor_input_offset / terminal_size.columns) + 1
+
+ # Create a string that will clear all input lines
+ terminal_str = ''
+
+ # Move the cursor down to the last input line
+ if cursor_input_line != num_input_lines:
+ terminal_str += Cursor.DOWN(num_input_lines - cursor_input_line)
+
+ # Clear each input line from the bottom up so that the cursor ends up on the original first input line
+ terminal_str += (ansi.clear_line() + Cursor.UP(1)) * (num_input_lines - 1)
+ terminal_str += ansi.clear_line()
+
+ # Move the cursor to the beginning of the line
+ terminal_str += '\r'
+
+ # Set the new prompt
+ rl_set_prompt(new_prompt)
+ self.prompt = new_prompt
+
+ # Write the string to the terminal
+ if rl_type == RlType.GNU:
+ sys.stdout.write(terminal_str)
+ elif rl_type == RlType.PYREADLINE:
+ readline.rl.mode.console.write(terminal_str)
+
+ # Redraw the prompt and input line
+ rl_force_redisplay()
+
def alerter(self):
import time
while True:
@@ -3259,8 +3317,22 @@ Script should contain one command per line, just like command would be typed in
def do_alert(self, args):
import threading
- printer = threading.Thread(target=self.alerter, daemon=True)
- printer.start()
+ alert_thread = threading.Thread(target=self.alerter, daemon=True)
+ alert_thread.start()
+
+ def prompt_changer(self):
+ import time
+ counter = 1
+ while True:
+ time.sleep(1)
+ self.update_prompt("({:>3}) ".format(counter))
+ counter += 1
+
+ def do_update_prompt(self, args):
+ import threading
+ self.prompt = "( 0) "
+ change_thread = threading.Thread(target=self.prompt_changer, daemon=True)
+ change_thread.start()
def cmdloop(self, intro: Optional[str]=None) -> None:
"""This is an outer wrapper around _cmdloop() which deals with extra features provided by cmd2.