1# pylint: disable=function-redefined 
    2from __future__ import annotations 
    3 
    4from prompt_toolkit.application.current import get_app 
    5from prompt_toolkit.filters import ( 
    6    Condition, 
    7    emacs_insert_mode, 
    8    has_selection, 
    9    in_paste_mode, 
    10    is_multiline, 
    11    vi_insert_mode, 
    12) 
    13from prompt_toolkit.key_binding.key_processor import KeyPress, KeyPressEvent 
    14from prompt_toolkit.keys import Keys 
    15 
    16from ..key_bindings import KeyBindings 
    17from .named_commands import get_by_name 
    18 
    19__all__ = [ 
    20    "load_basic_bindings", 
    21] 
    22 
    23E = KeyPressEvent 
    24 
    25 
    26def if_no_repeat(event: E) -> bool: 
    27    """Callable that returns True when the previous event was delivered to 
    28    another handler.""" 
    29    return not event.is_repeat 
    30 
    31 
    32@Condition 
    33def has_text_before_cursor() -> bool: 
    34    return bool(get_app().current_buffer.text) 
    35 
    36 
    37@Condition 
    38def in_quoted_insert() -> bool: 
    39    return get_app().quoted_insert 
    40 
    41 
    42def load_basic_bindings() -> KeyBindings: 
    43    key_bindings = KeyBindings() 
    44    insert_mode = vi_insert_mode | emacs_insert_mode 
    45    handle = key_bindings.add 
    46 
    47    @handle("c-a") 
    48    @handle("c-b") 
    49    @handle("c-c") 
    50    @handle("c-d") 
    51    @handle("c-e") 
    52    @handle("c-f") 
    53    @handle("c-g") 
    54    @handle("c-h") 
    55    @handle("c-i") 
    56    @handle("c-j") 
    57    @handle("c-k") 
    58    @handle("c-l") 
    59    @handle("c-m") 
    60    @handle("c-n") 
    61    @handle("c-o") 
    62    @handle("c-p") 
    63    @handle("c-q") 
    64    @handle("c-r") 
    65    @handle("c-s") 
    66    @handle("c-t") 
    67    @handle("c-u") 
    68    @handle("c-v") 
    69    @handle("c-w") 
    70    @handle("c-x") 
    71    @handle("c-y") 
    72    @handle("c-z") 
    73    @handle("f1") 
    74    @handle("f2") 
    75    @handle("f3") 
    76    @handle("f4") 
    77    @handle("f5") 
    78    @handle("f6") 
    79    @handle("f7") 
    80    @handle("f8") 
    81    @handle("f9") 
    82    @handle("f10") 
    83    @handle("f11") 
    84    @handle("f12") 
    85    @handle("f13") 
    86    @handle("f14") 
    87    @handle("f15") 
    88    @handle("f16") 
    89    @handle("f17") 
    90    @handle("f18") 
    91    @handle("f19") 
    92    @handle("f20") 
    93    @handle("f21") 
    94    @handle("f22") 
    95    @handle("f23") 
    96    @handle("f24") 
    97    @handle("c-@")  # Also c-space. 
    98    @handle("c-\\") 
    99    @handle("c-]") 
    100    @handle("c-^") 
    101    @handle("c-_") 
    102    @handle("backspace") 
    103    @handle("up") 
    104    @handle("down") 
    105    @handle("right") 
    106    @handle("left") 
    107    @handle("s-up") 
    108    @handle("s-down") 
    109    @handle("s-right") 
    110    @handle("s-left") 
    111    @handle("home") 
    112    @handle("end") 
    113    @handle("s-home") 
    114    @handle("s-end") 
    115    @handle("delete") 
    116    @handle("s-delete") 
    117    @handle("c-delete") 
    118    @handle("pageup") 
    119    @handle("pagedown") 
    120    @handle("s-tab") 
    121    @handle("tab") 
    122    @handle("c-s-left") 
    123    @handle("c-s-right") 
    124    @handle("c-s-home") 
    125    @handle("c-s-end") 
    126    @handle("c-left") 
    127    @handle("c-right") 
    128    @handle("c-up") 
    129    @handle("c-down") 
    130    @handle("c-home") 
    131    @handle("c-end") 
    132    @handle("insert") 
    133    @handle("s-insert") 
    134    @handle("c-insert") 
    135    @handle("<sigint>") 
    136    @handle(Keys.Ignore) 
    137    def _ignore(event: E) -> None: 
    138        """ 
    139        First, for any of these keys, Don't do anything by default. Also don't 
    140        catch them in the 'Any' handler which will insert them as data. 
    141 
    142        If people want to insert these characters as a literal, they can always 
    143        do by doing a quoted insert. (ControlQ in emacs mode, ControlV in Vi 
    144        mode.) 
    145        """ 
    146        pass 
    147 
    148    # Readline-style bindings. 
    149    handle("home")(get_by_name("beginning-of-line")) 
    150    handle("end")(get_by_name("end-of-line")) 
    151    handle("left")(get_by_name("backward-char")) 
    152    handle("right")(get_by_name("forward-char")) 
    153    handle("c-up")(get_by_name("previous-history")) 
    154    handle("c-down")(get_by_name("next-history")) 
    155    handle("c-l")(get_by_name("clear-screen")) 
    156 
    157    handle("c-k", filter=insert_mode)(get_by_name("kill-line")) 
    158    handle("c-u", filter=insert_mode)(get_by_name("unix-line-discard")) 
    159    handle("backspace", filter=insert_mode, save_before=if_no_repeat)( 
    160        get_by_name("backward-delete-char") 
    161    ) 
    162    handle("delete", filter=insert_mode, save_before=if_no_repeat)( 
    163        get_by_name("delete-char") 
    164    ) 
    165    handle("c-delete", filter=insert_mode, save_before=if_no_repeat)( 
    166        get_by_name("delete-char") 
    167    ) 
    168    handle(Keys.Any, filter=insert_mode, save_before=if_no_repeat)( 
    169        get_by_name("self-insert") 
    170    ) 
    171    handle("c-t", filter=insert_mode)(get_by_name("transpose-chars")) 
    172    handle("c-i", filter=insert_mode)(get_by_name("menu-complete")) 
    173    handle("s-tab", filter=insert_mode)(get_by_name("menu-complete-backward")) 
    174 
    175    # Control-W should delete, using whitespace as separator, while M-Del 
    176    # should delete using [^a-zA-Z0-9] as a boundary. 
    177    handle("c-w", filter=insert_mode)(get_by_name("unix-word-rubout")) 
    178 
    179    handle("pageup", filter=~has_selection)(get_by_name("previous-history")) 
    180    handle("pagedown", filter=~has_selection)(get_by_name("next-history")) 
    181 
    182    # CTRL keys. 
    183 
    184    handle("c-d", filter=has_text_before_cursor & insert_mode)( 
    185        get_by_name("delete-char") 
    186    ) 
    187 
    188    @handle("enter", filter=insert_mode & is_multiline) 
    189    def _newline(event: E) -> None: 
    190        """ 
    191        Newline (in case of multiline input. 
    192        """ 
    193        event.current_buffer.newline(copy_margin=not in_paste_mode()) 
    194 
    195    @handle("c-j") 
    196    def _newline2(event: E) -> None: 
    197        r""" 
    198        By default, handle \n as if it were a \r (enter). 
    199        (It appears that some terminals send \n instead of \r when pressing 
    200        enter. - at least the Linux subsystem for Windows.) 
    201        """ 
    202        event.key_processor.feed(KeyPress(Keys.ControlM, "\r"), first=True) 
    203 
    204    # Delete the word before the cursor. 
    205 
    206    @handle("up") 
    207    def _go_up(event: E) -> None: 
    208        event.current_buffer.auto_up(count=event.arg) 
    209 
    210    @handle("down") 
    211    def _go_down(event: E) -> None: 
    212        event.current_buffer.auto_down(count=event.arg) 
    213 
    214    @handle("delete", filter=has_selection) 
    215    def _cut(event: E) -> None: 
    216        data = event.current_buffer.cut_selection() 
    217        event.app.clipboard.set_data(data) 
    218 
    219    # Global bindings. 
    220 
    221    @handle("c-z") 
    222    def _insert_ctrl_z(event: E) -> None: 
    223        """ 
    224        By default, control-Z should literally insert Ctrl-Z. 
    225        (Ansi Ctrl-Z, code 26 in MSDOS means End-Of-File. 
    226        In a Python REPL for instance, it's possible to type 
    227        Control-Z followed by enter to quit.) 
    228 
    229        When the system bindings are loaded and suspend-to-background is 
    230        supported, that will override this binding. 
    231        """ 
    232        event.current_buffer.insert_text(event.data) 
    233 
    234    @handle(Keys.BracketedPaste) 
    235    def _paste(event: E) -> None: 
    236        """ 
    237        Pasting from clipboard. 
    238        """ 
    239        data = event.data 
    240 
    241        # Be sure to use \n as line ending. 
    242        # Some terminals (Like iTerm2) seem to paste \r\n line endings in a 
    243        # bracketed paste. See: https://github.com/ipython/ipython/issues/9737 
    244        data = data.replace("\r\n", "\n") 
    245        data = data.replace("\r", "\n") 
    246 
    247        event.current_buffer.insert_text(data) 
    248 
    249    @handle(Keys.Any, filter=in_quoted_insert, eager=True) 
    250    def _insert_text(event: E) -> None: 
    251        """ 
    252        Handle quoted insert. 
    253        """ 
    254        event.current_buffer.insert_text(event.data, overwrite=False) 
    255        event.app.quoted_insert = False 
    256 
    257    return key_bindings