prompt_toolkit Keys add_binding not working

752 views Asked by At

I am learning prompt-toolkit and try to solve a custom prompt using prompt-toolkit (I already know there is a std. prompt that works differently). I am following the description given by Jonathan for a similar question.

So far I took out and stitched together the suggested parts from the ptpython sample he gave and striped it down so it comes close to what I want to do. Obviously I missed something which implements the UP, DOWN events and selects the choices. Any ideas?

from __future__ import unicode_literals
from prompt_toolkit.application import Application
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.document import Document
from prompt_toolkit.enums import DEFAULT_BUFFER
from prompt_toolkit.interface import CommandLineInterface
from prompt_toolkit.key_binding.manager import KeyBindingManager
from prompt_toolkit.keys import Keys
from prompt_toolkit.layout.containers import Window
from prompt_toolkit.layout.controls import BufferControl
from prompt_toolkit.layout.margins import ScrollbarMargin
from prompt_toolkit.shortcuts import create_eventloop
from prompt_toolkit.filters import IsDone
from prompt_toolkit.layout.controls import TokenListControl
from prompt_toolkit.layout.containers import ConditionalContainer, ScrollOffsets, VSplit, HSplit
from prompt_toolkit.layout.screen import Char
from prompt_toolkit.layout.dimension import LayoutDimension
from prompt_toolkit.mouse_events import MouseEventTypes

from pygments.token import Token


# maybe better use TokenListControl mouse_handler?
def if_mousedown(handler):
    def handle_if_mouse_down(cli, mouse_event):
        if mouse_event.event_type == MouseEventTypes.MOUSE_DOWN:
            return handler(cli, mouse_event)
        else:
            return NotImplemented
    return handle_if_mouse_down



class SelIpt(object):
    show_sidebar = False
    selected_option_index = 0
    option_count = 0

select_input = SelIpt()


tokens = []
T = Token.Sidebar

def get_tokens(cli):
    return tokens


def append(index, label):
    selected = (index == select_input.selected_option_index)

    @if_mousedown
    def select_item(cli, mouse_event):
        # bind option with this index to mouse event
        select_input.selected_option_index = index

    token = T.Selected if selected else T

    tokens.append((T, ' > ' if selected else '   '))
    if selected:
        tokens.append((Token.SetCursorPosition, ''))

    tokens.append((token.Label, '%-24s' % label, select_item))
    tokens.append((T, '\n'))


# prepare the select choices
options = ['mini', 'mausi', 'hasi']
for i, option in enumerate(options):
    append(i, option)
tokens.pop()  # Remove last newline.
select_input.option_count = 3


manager = KeyBindingManager.for_prompt()


class SelectControl(TokenListControl):
    # SelectControl implements the key bindings
    @manager.registry.add_binding(Keys.Down, eager=True)
    def move_cursor_down(self, cli):
        select_input.selected_option_index = (
            (select_input.selected_option_index + 1) % select_input.option_count)

    @manager.registry.add_binding(Keys.Up, eager=True)
    def move_cursor_up(self, cli):
        select_input.selected_option_index = (
            (select_input.selected_option_index - 1) % select_input.option_count)


buffers={
        DEFAULT_BUFFER: Buffer(initial_document=Document('my selection', 0)),
        'QUESTION': Buffer(initial_document=Document('what do you want to select?', 0))
    }

@manager.registry.add_binding(Keys.Enter, eager=True)
def set_answer(event):
    print('moin moin')
    buffers[DEFAULT_BUFFER].text = option[select_input.selected_option_index]
    event.cli.set_return_value(None)


@manager.registry.add_binding(Keys.ControlQ, eager=True)
@manager.registry.add_binding(Keys.ControlC, eager=True)
def _(event):
    event.cli.set_return_value(None)


# assemble layout
prompt = VSplit([
    Window(content=BufferControl(buffer_name='QUESTION')),
    Window(content=BufferControl(buffer_name=DEFAULT_BUFFER)),
])

select = ConditionalContainer(
    Window(
        SelectControl(get_tokens, Char(token=Token.Sidebar)),
        width=LayoutDimension.exact(43),
        height=LayoutDimension(min=3),
        scroll_offsets=ScrollOffsets(top=1, bottom=1)
    ),
    filter=~IsDone()
)

layout = HSplit([prompt, select])


app = Application(
    layout=layout,
    buffers=buffers,
    key_bindings_registry=manager.registry,
    mouse_support=True
    #use_alternate_screen=True
)

eventloop = create_eventloop()
try:
    cli = CommandLineInterface(application=app, eventloop=eventloop)
    cli.run(reset_current_buffer=False)
finally:
    eventloop.close()


# TODO
# move selection to DEFAULT_BUFFER
# make select window disapear after CTRL-Q
# colorize '>'
1

There are 1 answers

4
jmunsch On BEST ANSWER

Write the handlers for which keys you want to be able to handle Keys.Up, Keys.Down, etc.

Here is an example:

And more directly:

class SelectControl(TokenListControl):
    @manager.registry.add_binding(Keys.Down, eager=True)
    def move_cursor_down(event):
        print(event)

    @manager.registry.add_binding(Keys.Up, eager=True)
    def move_cursor_up(event):
        print(event)