prompt-toolkit / python-prompt-toolkit

Library for building powerful interactive command line applications in Python
https://python-prompt-toolkit.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
9.24k stars 714 forks source link

More xterm escape codes #892

Open WojciechMigda opened 5 years ago

WojciechMigda commented 5 years ago

There are some xterm escape codes which are not handled by prompt_toolkit. These include, but are not limited to, modified (ctrl- / alt- / shift-ctrl- / ...) function keys. http://aperiodic.net/phil/archives/Geekery/term-function-keys.html https://www.xfree86.org/current/ctlseqs.html

It is possible to work around this by having key bindings defined as follows, though:

    @kb.add('escape', '[', '1', '5', ';', '5', '~')
    def cf5(event):
        logger.info('c-f5 captured')

Would adding support for some of them be a good idea for a PR?

asmeurer commented 5 years ago

I personally do something like

from prompt_toolkit.keys import Keys, ALL_KEYS
from prompt_toolkit.input.vt100_parser import ANSI_SEQUENCES

Keys.ControlF5 = "<Control-F5>"
ALL_KEYS.append('<Control-F5>')
ANSI_SEQUENCES['\x1b[15;5~'] = Keys.ControlF5

That way you can just use

@kb.add_binding(Keys.ControlF5)
def cf5(event):
    ...

Though I am also +1 to adding them directly into prompt-toolkit, so long as they are real xterm key sequences. These are also described here https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-PC-Style-Function-Keys.

WojciechMigda commented 5 years ago

I ended up doing the same, but like this:

# -*- coding: utf-8 -*-

from prompt_toolkit import keys
keys.Keys.ControlF1 = 'c-f1'
keys.Keys.ControlF2 = 'c-f2'
keys.Keys.ControlF3 = 'c-f3'
keys.Keys.ControlF4 = 'c-f4'
keys.Keys.ControlF5 = 'c-f5'
keys.Keys.ControlF6 = 'c-f6'
keys.Keys.ControlF7 = 'c-f7'
keys.Keys.ControlF8 = 'c-f8'
keys.Keys.ControlF9 = 'c-f9'
keys.Keys.ControlF10 = 'c-f10'
keys.Keys.ControlF11 = 'c-f11'
keys.Keys.ControlF12 = 'c-f12'

from prompt_toolkit.input.ansi_escape_sequences import ANSI_SEQUENCES
ANSI_SEQUENCES.update({
    '\x1b[O5P': keys.Keys.ControlF1,
    '\x1b[O5Q': keys.Keys.ControlF2,
    '\x1b[O5R': keys.Keys.ControlF3,
    '\x1b[O5S': keys.Keys.ControlF4,
    '\x1b[15;5~': keys.Keys.ControlF5,
    '\x1b[17;5~': keys.Keys.ControlF6,
    '\x1b[18;5~': keys.Keys.ControlF7,
    '\x1b[19;5~': keys.Keys.ControlF8,
    '\x1b[20;5~': keys.Keys.ControlF9,
    '\x1b[21;5~': keys.Keys.ControlF10,
    '\x1b[23;5~': keys.Keys.ControlF11,
    '\x1b[24;5~': keys.Keys.ControlF12,
})

XTERM_KEYS = [getattr(keys.Keys, k) for k in dir(keys.Keys) if not (k.startswith('_') or k in keys.ALL_KEYS)]

keys.ALL_KEYS += XTERM_KEYS

The downside is that these sequences are not captured in load_basic_bindings and end up being displayed in the prompt.

jonathanslenders commented 5 years ago

@WojciechMigda,

If you have time, feel free to create a pull request with the additional escape sequences in promp_toolkit/input/ansi_escape_sequences.py. I don't want custom sequences in prompt_toolkit, but all xterm sequences are fine. In the escape sequences file, I think I'd like them to be called F1-F48. This also means that you have to add them to the Keys enumeration in prompt_toolkit/keys.py.

Further, if we want to be able to use the shift/control notation in the key bindings. This can be added to the KEY_ALIASES in keys.py. s-f12 maps to f24 for instance and c-f12 maps to f36. c-s-f12 maps to f48. Maybe a few for-loops to generate them will do.

Right now, the master branch is prompt_toolkit 3.0. For this, we need either a PR against master, or against both master and the 2.0 branch.