Created
November 28, 2019 22:07
-
-
Save 8bit-pixies/5acf8333c5ea6d5838b0bb01cc1ed6ac to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
Simple example of a full screen application with a vertical split. | |
This will show a window on the left for user input. When the user types, the | |
reversed input is shown on the right. Pressing Ctrl-Q will quit the application. | |
""" | |
from prompt_toolkit.application import Application | |
from prompt_toolkit.buffer import Buffer | |
from prompt_toolkit.key_binding import KeyBindings | |
from prompt_toolkit.layout.containers import HSplit, VSplit, HSplit, Window, WindowAlign | |
from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl | |
from prompt_toolkit.layout.layout import Layout | |
from prompt_toolkit.layout.dimension import Dimension | |
# 3. Create the buffers | |
# ------------------ | |
left_buffer = Buffer() | |
right_buffer = Buffer() | |
# 1. First we create the layout | |
# -------------------------- | |
command_window = Window(BufferControl(buffer=left_buffer)) | |
output_window = Window(BufferControl(buffer=right_buffer)) | |
body = HSplit( | |
[ | |
command_window, | |
# A vertical line in the middle. We explicitly specify the width, to make | |
# sure that the layout engine will not try to divide the whole width by | |
# three for all these windows. | |
Window(char="-", height=Dimension(min=1, max=1)), | |
# Display the Result buffer on the right. | |
output_window, | |
] | |
) | |
# As a demonstration. Let's add a title bar to the top, displaying "Hello world". | |
# somewhere, because usually the default key bindings include searching. (Press | |
# Ctrl-R.) It would be really annoying if the search key bindings are handled, | |
# but the user doesn't see any feedback. We will add the search toolbar to the | |
# bottom by using an HSplit. | |
def get_titlebar_text(): | |
return [ | |
("class:title", " Hello world "), | |
("class:title", " (Press [Ctrl-Q] to quit.)"), | |
] | |
root_container = HSplit( | |
[ | |
# The titlebar. | |
Window( | |
height=1, | |
content=FormattedTextControl(get_titlebar_text), | |
align=WindowAlign.CENTER, | |
), | |
# Horizontal separator. | |
Window(height=1, char="-", style="class:line"), | |
# The 'body', like defined above. | |
body, | |
] | |
) | |
# 2. Adding key bindings | |
# -------------------- | |
# As a demonstration, we will add just a ControlQ key binding to exit the | |
# application. Key bindings are registered in a | |
# `prompt_toolkit.key_bindings.registry.Registry` instance. We use the | |
# `load_default_key_bindings` utility function to create a registry that | |
# already contains the default key bindings. | |
kb = KeyBindings() | |
# Now add the Ctrl-Q binding. We have to pass `eager=True` here. The reason is | |
# that there is another key *sequence* that starts with Ctrl-Q as well. Yes, a | |
# key binding is linked to a sequence of keys, not necessarily one key. So, | |
# what happens if there is a key binding for the letter 'a' and a key binding | |
# for 'ab'. When 'a' has been pressed, nothing will happen yet. Because the | |
# next key could be a 'b', but it could as well be anything else. If it's a 'c' | |
# for instance, we'll handle the key binding for 'a' and then look for a key | |
# binding for 'c'. So, when there's a common prefix in a key binding sequence, | |
# prompt-toolkit will wait calling a handler, until we have enough information. | |
# Now, There is an Emacs key binding for the [Ctrl-Q Any] sequence by default. | |
# Pressing Ctrl-Q followed by any other key will do a quoted insert. So to be | |
# sure that we won't wait for that key binding to match, but instead execute | |
# Ctrl-Q immediately, we can pass eager=True. (Don't make a habit of adding | |
# `eager=True` to all key bindings, but do it when it conflicts with another | |
# existing key binding, and you definitely want to override that behaviour. | |
@kb.add("c-c", eager=True) | |
@kb.add("c-q", eager=True) | |
def _(event): | |
""" | |
Pressing Ctrl-Q or Ctrl-C will exit the user interface. | |
Setting a return value means: quit the event loop that drives the user | |
interface and return this value from the `Application.run()` call. | |
Note that Ctrl-Q does not work on all terminals. Sometimes it requires | |
executing `stty -ixon`. | |
""" | |
event.app.exit() | |
# Now we add an event handler that captures change events to the buffer on the | |
# left. If the text changes over there, we'll update the buffer on the right. | |
def default_buffer_changed(_): | |
""" | |
When the buffer on the left changes, update the buffer on | |
the right. We just reverse the text. | |
""" | |
right_buffer.text = left_buffer.text[::-1] | |
left_buffer.on_text_changed += default_buffer_changed | |
# 3. Creating an `Application` instance | |
# ---------------------------------- | |
# This glues everything together. | |
application = Application( | |
layout=Layout(root_container, focused_element=command_window), | |
key_bindings=kb, | |
# Let's add mouse support! | |
mouse_support=True, | |
# Using an alternate screen buffer means as much as: "run full screen". | |
# It switches the terminal to an alternate screen. | |
full_screen=True, | |
) | |
# 4. Run the application | |
# ------------------- | |
def run(): | |
# Run the interface. (This runs the event loop until Ctrl-Q is pressed.) | |
application.run() | |
if __name__ == "__main__": | |
run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment