Skip to content

Prompt

cmd2 issues a configurable prompt before soliciting user input.

Customizing the Prompt

This prompt can be configured by setting the cmd2.Cmd.prompt instance attribute. This contains the string which should be printed as a prompt for user input. See the Pirate example for the simple use case of statically setting the prompt.

Continuation Prompt

When a user types a Multiline Command it may span more than one line of input. The prompt for the first line of input is specified by the cmd2.Cmd.prompt instance attribute. The prompt for subsequent lines of input is defined by the cmd2.Cmd.continuation_prompt attribute.See the Initialization example for a demonstration of customizing the continuation prompt.

Updating the prompt

If you wish to update the prompt between commands, you can do so using one of the Application Lifecycle Hooks such as a Postcommand hook. See PythonScripting for an example of dynamically updating the prompt.

Asynchronous Feedback

cmd2 provides these functions to provide asynchronous feedback to the user without interfering with the command line. This means the feedback is provided to the user when they are still entering text at the prompt. To use this functionality, the application must be running in a terminal that supports VT100 control characters and readline. Linux, Mac, and Windows 10 and greater all support these.

cmd2.Cmd.async_alert

async_alert(alert_msg, new_prompt=None)

Display an important message to the user while they are at a command line prompt. To the user it appears as if an alert message is printed above the prompt and their current input text and cursor location is left alone.

This function needs to acquire self.terminal_lock to ensure a prompt is on screen. Therefore, it is best to acquire the lock before calling this function to avoid raising a RuntimeError.

This function is only needed when you need to print an alert or update the prompt while the main thread is blocking at the prompt. Therefore, this should never be called from the main thread. Doing so will raise a RuntimeError.

PARAMETER DESCRIPTION
alert_msg

the message to display to the user

TYPE: str

new_prompt

If you also want to change the prompt that is displayed, then include it here. See async_update_prompt() docstring for guidance on updating a prompt.

TYPE: Optional[str] DEFAULT: None

RAISES DESCRIPTION
RuntimeError

if called from the main thread.

RuntimeError

if called while another thread holds terminal_lock

Source code in cmd2/cmd2.py
def async_alert(self, alert_msg: str, new_prompt: Optional[str] = None) -> None:  # pragma: no cover
    """
    Display an important message to the user while they are at a command line prompt.
    To the user it appears as if an alert message is printed above the prompt and their
    current input text and cursor location is left alone.

    This function needs to acquire self.terminal_lock to ensure a prompt is on screen.
    Therefore, it is best to acquire the lock before calling this function to avoid
    raising a RuntimeError.

    This function is only needed when you need to print an alert or update the prompt while the
    main thread is blocking at the prompt. Therefore, this should never be called from the main
    thread. Doing so will raise a RuntimeError.

    :param alert_msg: the message to display to the user
    :param new_prompt: If you also want to change the prompt that is displayed, then include it here.
                       See async_update_prompt() docstring for guidance on updating a prompt.
    :raises RuntimeError: if called from the main thread.
    :raises RuntimeError: if called while another thread holds `terminal_lock`
    """
    if threading.current_thread() is threading.main_thread():
        raise RuntimeError("async_alert should not be called from the main thread")

    if not (vt100_support and self.use_rawinput):
        return

    # Sanity check that can't fail if self.terminal_lock was acquired before calling this function
    if self.terminal_lock.acquire(blocking=False):
        # Windows terminals tend to flicker when we redraw the prompt and input lines.
        # To reduce how often this occurs, only update terminal if there are changes.
        update_terminal = False

        if alert_msg:
            alert_msg += '\n'
            update_terminal = True

        if new_prompt is not None:
            self.prompt = new_prompt

        # Check if the onscreen prompt needs to be refreshed to match self.prompt.
        if self.need_prompt_refresh():
            update_terminal = True
            rl_set_prompt(self.prompt)

        if update_terminal:
            import shutil

            # Prior to Python 3.11 this can return 0, so use a fallback if needed.
            terminal_columns = shutil.get_terminal_size().columns or constants.DEFAULT_TERMINAL_WIDTH

            # Print a string which replaces the onscreen prompt and input lines with the alert.
            terminal_str = ansi.async_alert_str(
                terminal_columns=terminal_columns,
                prompt=rl_get_display_prompt(),
                line=readline.get_line_buffer(),
                cursor_offset=rl_get_point(),
                alert_msg=alert_msg,
            )
            if rl_type == RlType.GNU:
                sys.stderr.write(terminal_str)
                sys.stderr.flush()
            elif rl_type == RlType.PYREADLINE:
                readline.rl.mode.console.write(terminal_str)

            # Redraw the prompt and input lines below the alert
            rl_force_redisplay()

        self.terminal_lock.release()

    else:
        raise RuntimeError("another thread holds terminal_lock")

cmd2.Cmd.async_update_prompt

async_update_prompt(new_prompt)

Update the command line prompt while the user is still typing at it.

This is good for alerting the user to system changes dynamically in between commands. For instance you could alter the color of the prompt to indicate a system status or increase a counter to report an event. If you do alter the actual text of the prompt, it is best to keep the prompt the same width as what's on screen. Otherwise the user's input text will be shifted and the update will not be seamless.

If user is at a continuation prompt while entering a multiline command, the onscreen prompt will not change. However, self.prompt will still be updated and display immediately after the multiline line command completes.

PARAMETER DESCRIPTION
new_prompt

what to change the prompt to

TYPE: str

RAISES DESCRIPTION
RuntimeError

if called from the main thread.

RuntimeError

if called while another thread holds terminal_lock

Source code in cmd2/cmd2.py
def async_update_prompt(self, new_prompt: str) -> None:  # pragma: no cover
    """
    Update the command line prompt while the user is still typing at it.

    This is good for alerting the user to system changes dynamically in between commands.
    For instance you could alter the color of the prompt to indicate a system status or increase a
    counter to report an event. If you do alter the actual text of the prompt, it is best to keep
    the prompt the same width as what's on screen. Otherwise the user's input text will be shifted
    and the update will not be seamless.

    If user is at a continuation prompt while entering a multiline command, the onscreen prompt will
    not change. However, self.prompt will still be updated and display immediately after the multiline
    line command completes.

    :param new_prompt: what to change the prompt to
    :raises RuntimeError: if called from the main thread.
    :raises RuntimeError: if called while another thread holds `terminal_lock`
    """
    self.async_alert('', new_prompt)

cmd2.Cmd.async_refresh_prompt

async_refresh_prompt()

Refresh the oncreen prompt to match self.prompt.

One case where the onscreen prompt and self.prompt can get out of sync is when async_alert() is called while a user is in search mode (e.g. Ctrl-r). To prevent overwriting readline's onscreen search prompt, self.prompt is updated but readline's saved prompt isn't.

Therefore when a user aborts a search, the old prompt is still on screen until they press Enter or this method is called. Call need_prompt_refresh() in an async print thread to know when a refresh is needed.

RAISES DESCRIPTION
RuntimeError

if called from the main thread.

RuntimeError

if called while another thread holds terminal_lock

Source code in cmd2/cmd2.py
def async_refresh_prompt(self) -> None:  # pragma: no cover
    """
    Refresh the oncreen prompt to match self.prompt.

    One case where the onscreen prompt and self.prompt can get out of sync is
    when async_alert() is called while a user is in search mode (e.g. Ctrl-r).
    To prevent overwriting readline's onscreen search prompt, self.prompt is updated
    but readline's saved prompt isn't.

    Therefore when a user aborts a search, the old prompt is still on screen until they
    press Enter or this method is called. Call need_prompt_refresh() in an async print
    thread to know when a refresh is needed.

    :raises RuntimeError: if called from the main thread.
    :raises RuntimeError: if called while another thread holds `terminal_lock`
    """
    self.async_alert('')

cmd2.Cmd.need_prompt_refresh

need_prompt_refresh()

Check whether the onscreen prompt needs to be asynchronously refreshed to match self.prompt.

Source code in cmd2/cmd2.py
def need_prompt_refresh(self) -> bool:  # pragma: no cover
    """Check whether the onscreen prompt needs to be asynchronously refreshed to match self.prompt."""
    if not (vt100_support and self.use_rawinput):
        return False

    # Don't overwrite a readline search prompt or a continuation prompt.
    return not rl_in_search_mode() and not self._at_continuation_prompt and self.prompt != rl_get_prompt()

cmd2 also provides a function to change the title of the terminal window. This feature requires the application be running in a terminal that supports VT100 control characters. Linux, Mac, and Windows 10 and greater all support these.

cmd2.Cmd.set_window_title staticmethod

set_window_title(title)

Set the terminal window title.

NOTE: This function writes to stderr. Therefore, if you call this during a command run by a pyscript, the string which updates the title will appear in that command's CommandResult.stderr data.

PARAMETER DESCRIPTION
title

the new window title

TYPE: str

Source code in cmd2/cmd2.py
@staticmethod
def set_window_title(title: str) -> None:  # pragma: no cover
    """
    Set the terminal window title.

    NOTE: This function writes to stderr. Therefore, if you call this during a command run by a pyscript,
          the string which updates the title will appear in that command's CommandResult.stderr data.

    :param title: the new window title
    """
    if not vt100_support:
        return

    try:
        sys.stderr.write(ansi.set_title(title))
        sys.stderr.flush()
    except AttributeError:
        # Debugging in Pycharm has issues with setting terminal title
        pass

The easiest way to understand these functions is to see the AsyncPrinting example for a demonstration.