1""" 
    2Filters that accept a `Application` as argument. 
    3""" 
    4 
    5from __future__ import annotations 
    6 
    7from typing import TYPE_CHECKING 
    8 
    9from prompt_toolkit.application.current import get_app 
    10from prompt_toolkit.cache import memoized 
    11from prompt_toolkit.enums import EditingMode 
    12 
    13from .base import Condition 
    14 
    15if TYPE_CHECKING: 
    16    from prompt_toolkit.layout.layout import FocusableElement 
    17 
    18 
    19__all__ = [ 
    20    "has_arg", 
    21    "has_completions", 
    22    "completion_is_selected", 
    23    "has_focus", 
    24    "buffer_has_focus", 
    25    "has_selection", 
    26    "has_suggestion", 
    27    "has_validation_error", 
    28    "is_done", 
    29    "is_read_only", 
    30    "is_multiline", 
    31    "renderer_height_is_known", 
    32    "in_editing_mode", 
    33    "in_paste_mode", 
    34    "vi_mode", 
    35    "vi_navigation_mode", 
    36    "vi_insert_mode", 
    37    "vi_insert_multiple_mode", 
    38    "vi_replace_mode", 
    39    "vi_selection_mode", 
    40    "vi_waiting_for_text_object_mode", 
    41    "vi_digraph_mode", 
    42    "vi_recording_macro", 
    43    "emacs_mode", 
    44    "emacs_insert_mode", 
    45    "emacs_selection_mode", 
    46    "shift_selection_mode", 
    47    "is_searching", 
    48    "control_is_searchable", 
    49    "vi_search_direction_reversed", 
    50] 
    51 
    52 
    53# NOTE: `has_focus` below should *not* be `memoized`. It can reference any user 
    54#       control. For instance, if we would continuously create new 
    55#       `PromptSession` instances, then previous instances won't be released, 
    56#       because this memoize (which caches results in the global scope) will 
    57#       still refer to each instance. 
    58def has_focus(value: FocusableElement) -> Condition: 
    59    """ 
    60    Enable when this buffer has the focus. 
    61    """ 
    62    from prompt_toolkit.buffer import Buffer 
    63    from prompt_toolkit.layout import walk 
    64    from prompt_toolkit.layout.containers import Window, to_container 
    65    from prompt_toolkit.layout.controls import UIControl 
    66 
    67    if isinstance(value, str): 
    68 
    69        def test() -> bool: 
    70            return get_app().current_buffer.name == value 
    71 
    72    elif isinstance(value, Buffer): 
    73 
    74        def test() -> bool: 
    75            return get_app().current_buffer == value 
    76 
    77    elif isinstance(value, UIControl): 
    78 
    79        def test() -> bool: 
    80            return get_app().layout.current_control == value 
    81 
    82    else: 
    83        value = to_container(value) 
    84 
    85        if isinstance(value, Window): 
    86 
    87            def test() -> bool: 
    88                return get_app().layout.current_window == value 
    89 
    90        else: 
    91 
    92            def test() -> bool: 
    93                # Consider focused when any window inside this container is 
    94                # focused. 
    95                current_window = get_app().layout.current_window 
    96 
    97                for c in walk(value): 
    98                    if isinstance(c, Window) and c == current_window: 
    99                        return True 
    100                return False 
    101 
    102    @Condition 
    103    def has_focus_filter() -> bool: 
    104        return test() 
    105 
    106    return has_focus_filter 
    107 
    108 
    109@Condition 
    110def buffer_has_focus() -> bool: 
    111    """ 
    112    Enabled when the currently focused control is a `BufferControl`. 
    113    """ 
    114    return get_app().layout.buffer_has_focus 
    115 
    116 
    117@Condition 
    118def has_selection() -> bool: 
    119    """ 
    120    Enable when the current buffer has a selection. 
    121    """ 
    122    return bool(get_app().current_buffer.selection_state) 
    123 
    124 
    125@Condition 
    126def has_suggestion() -> bool: 
    127    """ 
    128    Enable when the current buffer has a suggestion. 
    129    """ 
    130    buffer = get_app().current_buffer 
    131    return buffer.suggestion is not None and buffer.suggestion.text != "" 
    132 
    133 
    134@Condition 
    135def has_completions() -> bool: 
    136    """ 
    137    Enable when the current buffer has completions. 
    138    """ 
    139    state = get_app().current_buffer.complete_state 
    140    return state is not None and len(state.completions) > 0 
    141 
    142 
    143@Condition 
    144def completion_is_selected() -> bool: 
    145    """ 
    146    True when the user selected a completion. 
    147    """ 
    148    complete_state = get_app().current_buffer.complete_state 
    149    return complete_state is not None and complete_state.current_completion is not None 
    150 
    151 
    152@Condition 
    153def is_read_only() -> bool: 
    154    """ 
    155    True when the current buffer is read only. 
    156    """ 
    157    return get_app().current_buffer.read_only() 
    158 
    159 
    160@Condition 
    161def is_multiline() -> bool: 
    162    """ 
    163    True when the current buffer has been marked as multiline. 
    164    """ 
    165    return get_app().current_buffer.multiline() 
    166 
    167 
    168@Condition 
    169def has_validation_error() -> bool: 
    170    "Current buffer has validation error." 
    171    return get_app().current_buffer.validation_error is not None 
    172 
    173 
    174@Condition 
    175def has_arg() -> bool: 
    176    "Enable when the input processor has an 'arg'." 
    177    return get_app().key_processor.arg is not None 
    178 
    179 
    180@Condition 
    181def is_done() -> bool: 
    182    """ 
    183    True when the CLI is returning, aborting or exiting. 
    184    """ 
    185    return get_app().is_done 
    186 
    187 
    188@Condition 
    189def renderer_height_is_known() -> bool: 
    190    """ 
    191    Only True when the renderer knows it's real height. 
    192 
    193    (On VT100 terminals, we have to wait for a CPR response, before we can be 
    194    sure of the available height between the cursor position and the bottom of 
    195    the terminal. And usually it's nicer to wait with drawing bottom toolbars 
    196    until we receive the height, in order to avoid flickering -- first drawing 
    197    somewhere in the middle, and then again at the bottom.) 
    198    """ 
    199    return get_app().renderer.height_is_known 
    200 
    201 
    202@memoized() 
    203def in_editing_mode(editing_mode: EditingMode) -> Condition: 
    204    """ 
    205    Check whether a given editing mode is active. (Vi or Emacs.) 
    206    """ 
    207 
    208    @Condition 
    209    def in_editing_mode_filter() -> bool: 
    210        return get_app().editing_mode == editing_mode 
    211 
    212    return in_editing_mode_filter 
    213 
    214 
    215@Condition 
    216def in_paste_mode() -> bool: 
    217    return get_app().paste_mode() 
    218 
    219 
    220@Condition 
    221def vi_mode() -> bool: 
    222    return get_app().editing_mode == EditingMode.VI 
    223 
    224 
    225@Condition 
    226def vi_navigation_mode() -> bool: 
    227    """ 
    228    Active when the set for Vi navigation key bindings are active. 
    229    """ 
    230    from prompt_toolkit.key_binding.vi_state import InputMode 
    231 
    232    app = get_app() 
    233 
    234    if ( 
    235        app.editing_mode != EditingMode.VI 
    236        or app.vi_state.operator_func 
    237        or app.vi_state.waiting_for_digraph 
    238        or app.current_buffer.selection_state 
    239    ): 
    240        return False 
    241 
    242    return ( 
    243        app.vi_state.input_mode == InputMode.NAVIGATION 
    244        or app.vi_state.temporary_navigation_mode 
    245        or app.current_buffer.read_only() 
    246    ) 
    247 
    248 
    249@Condition 
    250def vi_insert_mode() -> bool: 
    251    from prompt_toolkit.key_binding.vi_state import InputMode 
    252 
    253    app = get_app() 
    254 
    255    if ( 
    256        app.editing_mode != EditingMode.VI 
    257        or app.vi_state.operator_func 
    258        or app.vi_state.waiting_for_digraph 
    259        or app.current_buffer.selection_state 
    260        or app.vi_state.temporary_navigation_mode 
    261        or app.current_buffer.read_only() 
    262    ): 
    263        return False 
    264 
    265    return app.vi_state.input_mode == InputMode.INSERT 
    266 
    267 
    268@Condition 
    269def vi_insert_multiple_mode() -> bool: 
    270    from prompt_toolkit.key_binding.vi_state import InputMode 
    271 
    272    app = get_app() 
    273 
    274    if ( 
    275        app.editing_mode != EditingMode.VI 
    276        or app.vi_state.operator_func 
    277        or app.vi_state.waiting_for_digraph 
    278        or app.current_buffer.selection_state 
    279        or app.vi_state.temporary_navigation_mode 
    280        or app.current_buffer.read_only() 
    281    ): 
    282        return False 
    283 
    284    return app.vi_state.input_mode == InputMode.INSERT_MULTIPLE 
    285 
    286 
    287@Condition 
    288def vi_replace_mode() -> bool: 
    289    from prompt_toolkit.key_binding.vi_state import InputMode 
    290 
    291    app = get_app() 
    292 
    293    if ( 
    294        app.editing_mode != EditingMode.VI 
    295        or app.vi_state.operator_func 
    296        or app.vi_state.waiting_for_digraph 
    297        or app.current_buffer.selection_state 
    298        or app.vi_state.temporary_navigation_mode 
    299        or app.current_buffer.read_only() 
    300    ): 
    301        return False 
    302 
    303    return app.vi_state.input_mode == InputMode.REPLACE 
    304 
    305 
    306@Condition 
    307def vi_replace_single_mode() -> bool: 
    308    from prompt_toolkit.key_binding.vi_state import InputMode 
    309 
    310    app = get_app() 
    311 
    312    if ( 
    313        app.editing_mode != EditingMode.VI 
    314        or app.vi_state.operator_func 
    315        or app.vi_state.waiting_for_digraph 
    316        or app.current_buffer.selection_state 
    317        or app.vi_state.temporary_navigation_mode 
    318        or app.current_buffer.read_only() 
    319    ): 
    320        return False 
    321 
    322    return app.vi_state.input_mode == InputMode.REPLACE_SINGLE 
    323 
    324 
    325@Condition 
    326def vi_selection_mode() -> bool: 
    327    app = get_app() 
    328    if app.editing_mode != EditingMode.VI: 
    329        return False 
    330 
    331    return bool(app.current_buffer.selection_state) 
    332 
    333 
    334@Condition 
    335def vi_waiting_for_text_object_mode() -> bool: 
    336    app = get_app() 
    337    if app.editing_mode != EditingMode.VI: 
    338        return False 
    339 
    340    return app.vi_state.operator_func is not None 
    341 
    342 
    343@Condition 
    344def vi_digraph_mode() -> bool: 
    345    app = get_app() 
    346    if app.editing_mode != EditingMode.VI: 
    347        return False 
    348 
    349    return app.vi_state.waiting_for_digraph 
    350 
    351 
    352@Condition 
    353def vi_recording_macro() -> bool: 
    354    "When recording a Vi macro." 
    355    app = get_app() 
    356    if app.editing_mode != EditingMode.VI: 
    357        return False 
    358 
    359    return app.vi_state.recording_register is not None 
    360 
    361 
    362@Condition 
    363def emacs_mode() -> bool: 
    364    "When the Emacs bindings are active." 
    365    return get_app().editing_mode == EditingMode.EMACS 
    366 
    367 
    368@Condition 
    369def emacs_insert_mode() -> bool: 
    370    app = get_app() 
    371    if ( 
    372        app.editing_mode != EditingMode.EMACS 
    373        or app.current_buffer.selection_state 
    374        or app.current_buffer.read_only() 
    375    ): 
    376        return False 
    377    return True 
    378 
    379 
    380@Condition 
    381def emacs_selection_mode() -> bool: 
    382    app = get_app() 
    383    return bool( 
    384        app.editing_mode == EditingMode.EMACS and app.current_buffer.selection_state 
    385    ) 
    386 
    387 
    388@Condition 
    389def shift_selection_mode() -> bool: 
    390    app = get_app() 
    391    return bool( 
    392        app.current_buffer.selection_state 
    393        and app.current_buffer.selection_state.shift_mode 
    394    ) 
    395 
    396 
    397@Condition 
    398def is_searching() -> bool: 
    399    "When we are searching." 
    400    app = get_app() 
    401    return app.layout.is_searching 
    402 
    403 
    404@Condition 
    405def control_is_searchable() -> bool: 
    406    "When the current UIControl is searchable." 
    407    from prompt_toolkit.layout.controls import BufferControl 
    408 
    409    control = get_app().layout.current_control 
    410 
    411    return ( 
    412        isinstance(control, BufferControl) and control.search_buffer_control is not None 
    413    ) 
    414 
    415 
    416@Condition 
    417def vi_search_direction_reversed() -> bool: 
    418    "When the '/' and '?' key bindings for Vi-style searching have been reversed." 
    419    return get_app().reverse_vi_search_direction()