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 the prompt in between commands.
        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.

        IMPORTANT: This function will not print an alert unless it can acquire self.terminal_lock to ensure
                   a prompt is onscreen.  Therefore it is best to acquire the lock before calling this function
                   to guarantee the alert prints.

        :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 while another thread holds terminal_lock
        """
        if not (vt100_support and self.use_rawinput):
            return

        import shutil
        import colorama.ansi as ansi
        from colorama import Cursor

        # Sanity check that can't fail if self.terminal_lock was acquired before calling this function
        if self.terminal_lock.acquire(blocking=False):

            # Figure out what prompt is displaying
            current_prompt = self.continuation_prompt if self.at_continuation_prompt else self.prompt

            # Only update terminal if there are changes
            update_terminal = False

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

            # Set the prompt if its changed
            if new_prompt is not None and new_prompt != self.prompt:
                self.prompt = new_prompt

                # If we aren't at a continuation prompt, then it's OK to update it
                if not self.at_continuation_prompt:
                    rl_set_prompt(self.prompt)
                    update_terminal = True

            if update_terminal:
                # Get the size of the terminal
                terminal_size = shutil.get_terminal_size()

                # Split the prompt lines since it can contain newline characters.
                prompt_lines = current_prompt.splitlines()

                # Calculate how many terminal lines are taken up by all prompt lines except for the last one.
                # That will be included in the input lines calculations since that is where the cursor is.
                num_prompt_terminal_lines = 0
                for line in prompt_lines[:-1]:
                    line_width = utils.ansi_safe_wcswidth(line)
                    num_prompt_terminal_lines += int(line_width / terminal_size.columns) + 1

                # Now calculate how many terminal lines are take up by the input
                last_prompt_line = prompt_lines[-1]
                last_prompt_line_width = utils.ansi_safe_wcswidth(last_prompt_line)

                input_width = last_prompt_line_width + utils.ansi_safe_wcswidth(readline.get_line_buffer())

                num_input_terminal_lines = int(input_width / terminal_size.columns) + 1

                # Get the cursor's offset from the beginning of the first input line
                cursor_input_offset = last_prompt_line_width + 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 when printed will clear all input lines and display the alert
                terminal_str = ''

                # Move the cursor down to the last input line
                if cursor_input_line != num_input_terminal_lines:
                    terminal_str += Cursor.DOWN(num_input_terminal_lines - cursor_input_line)

                # Clear each line from the bottom up so that the cursor ends up on the first prompt line
                total_lines = num_prompt_terminal_lines + num_input_terminal_lines
                terminal_str += (ansi.clear_line() + Cursor.UP(1)) * (total_lines - 1)

                # Clear the first prompt line
                terminal_str += ansi.clear_line()

                # Move the cursor to the beginning of the first prompt line and print the alert
                terminal_str += '\r' + alert_msg

                if rl_type == RlType.GNU:
                    sys.stderr.write(terminal_str)
                elif rl_type == RlType.PYREADLINE:
                    # noinspection PyUnresolvedReferences
                    readline.rl.mode.console.write(terminal_str)

                # Redraw the prompt and input lines
                rl_force_redisplay()

            self.terminal_lock.release()

        else:
            raise RuntimeError("another thread holds terminal_lock")
Display an important message to the user while they are at the prompt in between commands.
        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.

        IMPORTANT: This function will not print an alert unless it can acquire self.terminal_lock to ensure
                   a prompt is onscreen.  Therefore it is best to acquire the lock before calling this function
                   to guarantee the alert prints.

        :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 while another thread holds terminal_lock