1from __future__ import annotations 
    2 
    3from asyncio.events import AbstractEventLoop 
    4from typing import TYPE_CHECKING, Any, TextIO 
    5 
    6from prompt_toolkit.application import Application 
    7from prompt_toolkit.application.current import get_app_or_none, get_app_session 
    8from prompt_toolkit.application.run_in_terminal import run_in_terminal 
    9from prompt_toolkit.formatted_text import ( 
    10    FormattedText, 
    11    StyleAndTextTuples, 
    12    to_formatted_text, 
    13) 
    14from prompt_toolkit.input import DummyInput 
    15from prompt_toolkit.layout import Layout 
    16from prompt_toolkit.output import ColorDepth, Output 
    17from prompt_toolkit.output.defaults import create_output 
    18from prompt_toolkit.renderer import ( 
    19    print_formatted_text as renderer_print_formatted_text, 
    20) 
    21from prompt_toolkit.styles import ( 
    22    BaseStyle, 
    23    StyleTransformation, 
    24    default_pygments_style, 
    25    default_ui_style, 
    26    merge_styles, 
    27) 
    28 
    29if TYPE_CHECKING: 
    30    from prompt_toolkit.layout.containers import AnyContainer 
    31 
    32__all__ = [ 
    33    "print_formatted_text", 
    34    "print_container", 
    35    "clear", 
    36    "set_title", 
    37    "clear_title", 
    38] 
    39 
    40 
    41def print_formatted_text( 
    42    *values: Any, 
    43    sep: str = " ", 
    44    end: str = "\n", 
    45    file: TextIO | None = None, 
    46    flush: bool = False, 
    47    style: BaseStyle | None = None, 
    48    output: Output | None = None, 
    49    color_depth: ColorDepth | None = None, 
    50    style_transformation: StyleTransformation | None = None, 
    51    include_default_pygments_style: bool = True, 
    52) -> None: 
    53    """ 
    54    :: 
    55 
    56        print_formatted_text(*values, sep=' ', end='\\n', file=None, flush=False, style=None, output=None) 
    57 
    58    Print text to stdout. This is supposed to be compatible with Python's print 
    59    function, but supports printing of formatted text. You can pass a 
    60    :class:`~prompt_toolkit.formatted_text.FormattedText`, 
    61    :class:`~prompt_toolkit.formatted_text.HTML` or 
    62    :class:`~prompt_toolkit.formatted_text.ANSI` object to print formatted 
    63    text. 
    64 
    65    * Print HTML as follows:: 
    66 
    67        print_formatted_text(HTML('<i>Some italic text</i> <ansired>This is red!</ansired>')) 
    68 
    69        style = Style.from_dict({ 
    70            'hello': '#ff0066', 
    71            'world': '#884444 italic', 
    72        }) 
    73        print_formatted_text(HTML('<hello>Hello</hello> <world>world</world>!'), style=style) 
    74 
    75    * Print a list of (style_str, text) tuples in the given style to the 
    76      output.  E.g.:: 
    77 
    78        style = Style.from_dict({ 
    79            'hello': '#ff0066', 
    80            'world': '#884444 italic', 
    81        }) 
    82        fragments = FormattedText([ 
    83            ('class:hello', 'Hello'), 
    84            ('class:world', 'World'), 
    85        ]) 
    86        print_formatted_text(fragments, style=style) 
    87 
    88    If you want to print a list of Pygments tokens, wrap it in 
    89    :class:`~prompt_toolkit.formatted_text.PygmentsTokens` to do the 
    90    conversion. 
    91 
    92    If a prompt_toolkit `Application` is currently running, this will always 
    93    print above the application or prompt (similar to `patch_stdout`). So, 
    94    `print_formatted_text` will erase the current application, print the text, 
    95    and render the application again. 
    96 
    97    :param values: Any kind of printable object, or formatted string. 
    98    :param sep: String inserted between values, default a space. 
    99    :param end: String appended after the last value, default a newline. 
    100    :param style: :class:`.Style` instance for the color scheme. 
    101    :param include_default_pygments_style: `bool`. Include the default Pygments 
    102        style when set to `True` (the default). 
    103    """ 
    104    assert not (output and file) 
    105 
    106    # Create Output object. 
    107    if output is None: 
    108        if file: 
    109            output = create_output(stdout=file) 
    110        else: 
    111            output = get_app_session().output 
    112 
    113    assert isinstance(output, Output) 
    114 
    115    # Get color depth. 
    116    color_depth = color_depth or output.get_default_color_depth() 
    117 
    118    # Merges values. 
    119    def to_text(val: Any) -> StyleAndTextTuples: 
    120        # Normal lists which are not instances of `FormattedText` are 
    121        # considered plain text. 
    122        if isinstance(val, list) and not isinstance(val, FormattedText): 
    123            return to_formatted_text(f"{val}") 
    124        return to_formatted_text(val, auto_convert=True) 
    125 
    126    fragments = [] 
    127    for i, value in enumerate(values): 
    128        fragments.extend(to_text(value)) 
    129 
    130        if sep and i != len(values) - 1: 
    131            fragments.extend(to_text(sep)) 
    132 
    133    fragments.extend(to_text(end)) 
    134 
    135    # Print output. 
    136    def render() -> None: 
    137        assert isinstance(output, Output) 
    138 
    139        renderer_print_formatted_text( 
    140            output, 
    141            fragments, 
    142            _create_merged_style( 
    143                style, include_default_pygments_style=include_default_pygments_style 
    144            ), 
    145            color_depth=color_depth, 
    146            style_transformation=style_transformation, 
    147        ) 
    148 
    149        # Flush the output stream. 
    150        if flush: 
    151            output.flush() 
    152 
    153    # If an application is running, print above the app. This does not require 
    154    # `patch_stdout`. 
    155    loop: AbstractEventLoop | None = None 
    156 
    157    app = get_app_or_none() 
    158    if app is not None: 
    159        loop = app.loop 
    160 
    161    if loop is not None: 
    162        loop.call_soon_threadsafe(lambda: run_in_terminal(render)) 
    163    else: 
    164        render() 
    165 
    166 
    167def print_container( 
    168    container: AnyContainer, 
    169    file: TextIO | None = None, 
    170    style: BaseStyle | None = None, 
    171    include_default_pygments_style: bool = True, 
    172) -> None: 
    173    """ 
    174    Print any layout to the output in a non-interactive way. 
    175 
    176    Example usage:: 
    177 
    178        from prompt_toolkit.widgets import Frame, TextArea 
    179        print_container( 
    180            Frame(TextArea(text='Hello world!'))) 
    181    """ 
    182    if file: 
    183        output = create_output(stdout=file) 
    184    else: 
    185        output = get_app_session().output 
    186 
    187    app: Application[None] = Application( 
    188        layout=Layout(container=container), 
    189        output=output, 
    190        # `DummyInput` will cause the application to terminate immediately. 
    191        input=DummyInput(), 
    192        style=_create_merged_style( 
    193            style, include_default_pygments_style=include_default_pygments_style 
    194        ), 
    195    ) 
    196    try: 
    197        app.run(in_thread=True) 
    198    except EOFError: 
    199        pass 
    200 
    201 
    202def _create_merged_style( 
    203    style: BaseStyle | None, include_default_pygments_style: bool 
    204) -> BaseStyle: 
    205    """ 
    206    Merge user defined style with built-in style. 
    207    """ 
    208    styles = [default_ui_style()] 
    209    if include_default_pygments_style: 
    210        styles.append(default_pygments_style()) 
    211    if style: 
    212        styles.append(style) 
    213 
    214    return merge_styles(styles) 
    215 
    216 
    217def clear() -> None: 
    218    """ 
    219    Clear the screen. 
    220    """ 
    221    output = get_app_session().output 
    222    output.erase_screen() 
    223    output.cursor_goto(0, 0) 
    224    output.flush() 
    225 
    226 
    227def set_title(text: str) -> None: 
    228    """ 
    229    Set the terminal title. 
    230    """ 
    231    output = get_app_session().output 
    232    output.set_title(text) 
    233 
    234 
    235def clear_title() -> None: 
    236    """ 
    237    Erase the current title. 
    238    """ 
    239    set_title("")