summaryrefslogtreecommitdiffstats
path: root/docs/pages/advanced_topics/key_bindings.rst
blob: 8b334fc2d9bab6a39f5fa3c5c61b7779923933ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
.. _key_bindings:

More about key bindings
=======================

This page contains a few additional notes about key bindings.


Key bindings can be defined as follows by creating a
:class:`~prompt_toolkit.key_binding.KeyBindings` instance:


.. code:: python

    from prompt_toolkit.key_binding import KeyBindings

    bindings = KeyBindings()

    @bindings.add('a')
    def _(event):
        " Do something if 'a' has been pressed. "
        ...


    @bindings.add('c-t')
    def _(event):
        " Do something if Control-T has been pressed. "
        ...

.. note::

    :kbd:`c-q` (control-q) and :kbd:`c-s` (control-s) are often captured by the
    terminal, because they were used traditionally for software flow control.
    When this is enabled, the application will automatically freeze when
    :kbd:`c-s` is pressed, until :kbd:`c-q` is pressed. It won't be possible to
    bind these keys.

    In order to disable this, execute the following command in your shell, or even
    add it to your `.bashrc`.

    .. code::

        stty -ixon

Key bindings can even consist of a sequence of multiple keys. The binding is
only triggered when all the keys in this sequence are pressed.

.. code:: python

    @bindings.add('a', 'b')
    def _(event):
        " Do something if 'a' is pressed and then 'b' is pressed. "
        ...

If the user presses only `a`, then nothing will happen until either a second
key (like `b`) has been pressed or until the timeout expires (see later).


List of special keys
--------------------

Besides literal characters, any of the following keys can be used in a key
binding:

+-------------------+-----------------------------------------+
| Name              + Possible keys                           |
+===================+=========================================+
| Escape            | :kbd:`escape`                           |
| Shift + escape    | :kbd:`s-escape`                         |
+-------------------+-----------------------------------------+
| Arrows            | :kbd:`left`,                            |
|                   | :kbd:`right`,                           |
|                   | :kbd:`up`,                              |
|                   | :kbd:`down`                             |
+-------------------+-----------------------------------------+
| Navigation        | :kbd:`home`,                            |
|                   | :kbd:`end`,                             |
|                   | :kbd:`delete`,                          |
|                   | :kbd:`pageup`,                          |
|                   | :kbd:`pagedown`,                        |
|                   | :kbd:`insert`                           |
+-------------------+-----------------------------------------+
| Control+letter    | :kbd:`c-a`, :kbd:`c-b`, :kbd:`c-c`,     |
|                   | :kbd:`c-d`, :kbd:`c-e`, :kbd:`c-f`,     |
|                   | :kbd:`c-g`, :kbd:`c-h`, :kbd:`c-i`,     |
|                   | :kbd:`c-j`, :kbd:`c-k`, :kbd:`c-l`,     |
|                   |                                         |
|                   | :kbd:`c-m`, :kbd:`c-n`, :kbd:`c-o`,     |
|                   | :kbd:`c-p`, :kbd:`c-q`, :kbd:`c-r`,     |
|                   | :kbd:`c-s`, :kbd:`c-t`, :kbd:`c-u`,     |
|                   | :kbd:`c-v`, :kbd:`c-w`, :kbd:`c-x`,     |
|                   |                                         |
|                   | :kbd:`c-y`, :kbd:`c-z`                  |
+-------------------+-----------------------------------------+
| Control + number  | :kbd:`c-1`, :kbd:`c-2`, :kbd:`c-3`,     |
|                   | :kbd:`c-4`, :kbd:`c-5`, :kbd:`c-6`,     |
|                   | :kbd:`c-7`, :kbd:`c-8`, :kbd:`c-9`,     |
|                   | :kbd:`c-0`                              |
+-------------------+-----------------------------------------+
| Control + arrow   | :kbd:`c-left`,                          |
|                   | :kbd:`c-right`,                         |
|                   | :kbd:`c-up`,                            |
|                   | :kbd:`c-down`                           |
+-------------------+-----------------------------------------+
| Other control     | :kbd:`c-@`,                             |
| keys              | :kbd:`c-\\`,                            |
|                   | :kbd:`c-]`,                             |
|                   | :kbd:`c-^`,                             |
|                   | :kbd:`c-_`,                             |
|                   | :kbd:`c-delete`                         |
+-------------------+-----------------------------------------+
| Shift + arrow     | :kbd:`s-left`,                          |
|                   | :kbd:`s-right`,                         |
|                   | :kbd:`s-up`,                            |
|                   | :kbd:`s-down`                           |
+-------------------+-----------------------------------------+
| Control + Shift + | :kbd:`c-s-left`,                        |
| arrow             | :kbd:`c-s-right`,                       |
|                   | :kbd:`c-s-up`,                          |
|                   | :kbd:`c-s-down`                         |
+-------------------+-----------------------------------------+
| Other shift       | :kbd:`s-delete`,                        |
| keys              | :kbd:`s-tab`                            |
+-------------------+-----------------------------------------+
| F-keys            | :kbd:`f1`, :kbd:`f2`, :kbd:`f3`,        |
|                   | :kbd:`f4`, :kbd:`f5`, :kbd:`f6`,        |
|                   | :kbd:`f7`, :kbd:`f8`, :kbd:`f9`,        |
|                   | :kbd:`f10`, :kbd:`f11`, :kbd:`f12`,     |
|                   |                                         |
|                   | :kbd:`f13`, :kbd:`f14`, :kbd:`f15`,     |
|                   | :kbd:`f16`, :kbd:`f17`, :kbd:`f18`,     |
|                   | :kbd:`f19`, :kbd:`f20`, :kbd:`f21`,     |
|                   | :kbd:`f22`, :kbd:`f23`, :kbd:`f24`      |
+-------------------+-----------------------------------------+

There are a couple of useful aliases as well:

+-------------------+-------------------+
| :kbd:`c-h`        | :kbd:`backspace`  |
+-------------------+-------------------+
| :kbd:`c-@`        | :kbd:`c-space`    |
+-------------------+-------------------+
| :kbd:`c-m`        | :kbd:`enter`      |
+-------------------+-------------------+
| :kbd:`c-i`        | :kbd:`tab`        |
+-------------------+-------------------+

.. note::

    Note that the supported keys are limited to what typical VT100 terminals
    offer. Binding :kbd:`c-7` (control + number 7) for instance is not
    supported.


Binding alt+something, option+something or meta+something
---------------------------------------------------------

Vt100 terminals translate the alt key into a leading :kbd:`escape` key.
For instance, in order to handle :kbd:`alt-f`, we have to handle
:kbd:`escape` + :kbd:`f`. Notice that we receive this as two individual keys.
This means that it's exactly the same as first typing :kbd:`escape` and then
typing :kbd:`f`. Something this alt-key is also known as option or meta.

In code that looks as follows:

.. code:: python

    @bindings.add('escape', 'f')
    def _(event):
        " Do something if alt-f or meta-f have been pressed. "


Wildcards
---------

Sometimes you want to catch any key that follows after a certain key stroke.
This is possible by binding the '<any>' key:

.. code:: python

    @bindings.add('a', '<any>')
    def _(event):
        ...

This will handle `aa`, `ab`, `ac`, etcetera. The key binding can check the
`event` object for which keys exactly have been pressed.


Attaching a filter (condition)
------------------------------

In order to enable a key binding according to a certain condition, we have to
pass it a :class:`~prompt_toolkit.filters.Filter`, usually a
:class:`~prompt_toolkit.filters.Condition` instance. (:ref:`Read more about
filters <filters>`.)

.. code:: python

    from prompt_toolkit.filters import Condition

    @Condition
    def is_active():
        " Only activate key binding on the second half of each minute. "
        return datetime.datetime.now().second > 30

    @bindings.add('c-t', filter=is_active)
    def _(event):
        # ...
        pass

The key binding will be ignored when this condition is not satisfied.


ConditionalKeyBindings: Disabling a set of key bindings
-------------------------------------------------------

Sometimes you want to enable or disable a whole set of key bindings according
to a certain condition. This is possible by wrapping it in a
:class:`~prompt_toolkit.key_binding.ConditionalKeyBindings` object.

.. code:: python

    from prompt_toolkit.key_binding import ConditionalKeyBindings

    @Condition
    def is_active():
        " Only activate key binding on the second half of each minute. "
        return datetime.datetime.now().second > 30

     bindings = ConditionalKeyBindings(
         key_bindings=my_bindings,
         filter=is_active)

If the condition is not satisfied, all the key bindings in `my_bindings` above
will be ignored.


Merging key bindings
--------------------

Sometimes you have different parts of your application generate a collection of
key bindings. It is possible to merge them together through the
:func:`~prompt_toolkit.key_binding.merge_key_bindings` function. This is
preferred above passing a :class:`~prompt_toolkit.key_binding.KeyBindings`
object around and having everyone populate it.

.. code:: python

    from prompt_toolkit.key_binding import merge_key_bindings

    bindings = merge_key_bindings([
        bindings1,
        bindings2,
    ])


Eager
-----

Usually not required, but if ever you have to override an existing key binding,
the `eager` flag can be useful.

Suppose that there is already an active binding for `ab` and you'd like to add
a second binding that only handles `a`. When the user presses only `a`,
prompt_toolkit has to wait for the next key press in order to know which
handler to call.

By passing the `eager` flag to this second binding, we are actually saying that
prompt_toolkit shouldn't wait for longer matches when all the keys in this key
binding are matched. So, if `a` has been pressed, this second binding will be
called, even if there's an active `ab` binding.

.. code:: python

    @bindings.add('a', 'b')
    def binding_1(event):
        ...

    @bindings.add('a', eager=True)
    def binding_2(event):
        ...

This is mainly useful in order to conditionally override another binding.

Asyncio coroutines
------------------

Key binding handlers can be asyncio coroutines.

.. code:: python

    from prompt_toolkit.application import in_terminal

    @bindings.add('x')
    async def print_hello(event):
        """
        Pressing 'x' will print 5 times "hello" in the background above the
        prompt.
        """
        for i in range(5):
            # Print hello above the current prompt.
            async with in_terminal():
                print('hello')

            # Sleep, but allow further input editing in the meantime.
            await asyncio.sleep(1)

If the user accepts the input on the prompt, while this coroutine is not yet
finished , an `asyncio.CancelledError` exception will be thrown in this
coroutine.


Timeouts
--------

There are two timeout settings that effect the handling of keys.

- ``Application.ttimeoutlen``: Like Vim's `ttimeoutlen` option.
  When to flush the input (For flushing escape keys.) This is important on
  terminals that use vt100 input. We can't distinguish the escape key from for
  instance the left-arrow key, if we don't know what follows after "\x1b". This
  little timer will consider "\x1b" to be escape if nothing did follow in this
  time span.  This seems to work like the `ttimeoutlen` option in Vim.

- ``KeyProcessor.timeoutlen``: like Vim's `timeoutlen` option.
  This can be `None` or a float.  For instance, suppose that we have a key
  binding AB and a second key binding A. If the uses presses A and then waits,
  we don't handle this binding yet (unless it was marked 'eager'), because we
  don't know what will follow. This timeout is the maximum amount of time that
  we wait until we call the handlers anyway. Pass `None` to disable this
  timeout.


Recording macros
----------------

Both Emacs and Vi mode allow macro recording. By default, all key presses are
recorded during a macro, but it is possible to exclude certain keys by setting
the `record_in_macro` parameter to `False`:

.. code:: python

    @bindings.add('c-t', record_in_macro=False)
    def _(event):
        # ...
        pass


Creating new Vi text objects and operators
------------------------------------------

We tried very hard to ship prompt_toolkit with as many as possible Vi text
objects and operators, so that text editing feels as natural as possible to Vi
users.

If you wish to create a new text object or key binding, that is actually
possible. Check the `custom-vi-operator-and-text-object.py` example for more
information.


Handling SIGINT
---------------

The SIGINT Unix signal can be handled by binding ``<sigint>``. For instance:

.. code:: python

    @bindings.add('<sigint>')
    def _(event):
        # ...
        pass

This will handle a SIGINT that was sent by an external application into the
process. Handling control-c should be done by binding ``c-c``. (The terminal
input is set to raw mode, which means that a ``c-c`` won't be translated into a
SIGINT.)

For a ``PromptSession``, there is a default binding for ``<sigint>`` that
corresponds to ``c-c``: it will exit the prompt, raising a
``KeyboardInterrupt`` exception.


Processing `.inputrc`
---------------------

GNU readline can be configured using an `.inputrc` configuration file. This file
contains key bindings as well as certain settings. Right now, prompt_toolkit
doesn't support `.inputrc`, but it should be possible in the future.