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 '>'
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: