summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xexamples/dialogs/button_dialog.py19
-rwxr-xr-xexamples/dialogs/checkbox_dialog.py36
-rwxr-xr-xexamples/dialogs/input_dialog.py17
-rwxr-xr-xexamples/dialogs/messagebox.py16
-rwxr-xr-xexamples/dialogs/password_dialog.py19
-rwxr-xr-xexamples/dialogs/progress_dialog.py47
-rwxr-xr-xexamples/dialogs/radio_dialog.py39
-rwxr-xr-xexamples/dialogs/styled_messagebox.py37
-rwxr-xr-xexamples/dialogs/yes_no_dialog.py17
-rwxr-xr-xexamples/full-screen/ansi-art-and-textarea.py90
-rwxr-xr-xexamples/full-screen/buttons.py91
-rwxr-xr-xexamples/full-screen/calculator.py98
-rwxr-xr-xexamples/full-screen/dummy-app.py8
-rwxr-xr-xexamples/full-screen/full-screen-demo.py225
-rwxr-xr-xexamples/full-screen/hello-world.py43
-rw-r--r--examples/full-screen/no-layout.py7
-rwxr-xr-xexamples/full-screen/pager.py111
-rw-r--r--examples/full-screen/scrollable-panes/simple-example.py45
-rw-r--r--examples/full-screen/scrollable-panes/with-completion-menu.py120
-rwxr-xr-xexamples/full-screen/simple-demos/alignment.py60
-rwxr-xr-xexamples/full-screen/simple-demos/autocompletion.py100
-rwxr-xr-xexamples/full-screen/simple-demos/colorcolumn.py63
-rwxr-xr-xexamples/full-screen/simple-demos/cursorcolumn-cursorline.py59
-rwxr-xr-xexamples/full-screen/simple-demos/float-transparency.py87
-rwxr-xr-xexamples/full-screen/simple-demos/floats.py116
-rwxr-xr-xexamples/full-screen/simple-demos/focus.py98
-rwxr-xr-xexamples/full-screen/simple-demos/horizontal-align.py209
-rwxr-xr-xexamples/full-screen/simple-demos/horizontal-split.py44
-rwxr-xr-xexamples/full-screen/simple-demos/line-prefixes.py111
-rwxr-xr-xexamples/full-screen/simple-demos/margins.py71
-rwxr-xr-xexamples/full-screen/simple-demos/vertical-align.py168
-rwxr-xr-xexamples/full-screen/simple-demos/vertical-split.py44
-rwxr-xr-xexamples/full-screen/split-screen.py156
-rwxr-xr-xexamples/full-screen/text-editor.py383
-rwxr-xr-xexamples/gevent-get-input.py24
-rwxr-xr-xexamples/print-text/ansi-colors.py100
-rwxr-xr-xexamples/print-text/ansi.py50
-rwxr-xr-xexamples/print-text/html.py53
-rwxr-xr-xexamples/print-text/named-colors.py29
-rwxr-xr-xexamples/print-text/print-formatted-text.py46
-rwxr-xr-xexamples/print-text/print-frame.py14
-rwxr-xr-xexamples/print-text/prompt-toolkit-logo-ansi-art.py40
-rwxr-xr-xexamples/print-text/pygments-tokens.py44
-rwxr-xr-xexamples/print-text/true-color-demo.py35
-rwxr-xr-xexamples/progress-bar/a-lot-of-parallel-tasks.py65
-rwxr-xr-xexamples/progress-bar/colored-title-and-label.py22
-rwxr-xr-xexamples/progress-bar/custom-key-bindings.py51
-rwxr-xr-xexamples/progress-bar/many-parallel-tasks.py46
-rwxr-xr-xexamples/progress-bar/nested-progress-bars.py23
-rwxr-xr-xexamples/progress-bar/scrolling-task-name.py23
-rwxr-xr-xexamples/progress-bar/simple-progress-bar.py18
-rwxr-xr-xexamples/progress-bar/styled-1.py36
-rwxr-xr-xexamples/progress-bar/styled-2.py50
-rwxr-xr-xexamples/progress-bar/styled-apt-get-install.py38
-rwxr-xr-xexamples/progress-bar/styled-rainbow.py35
-rwxr-xr-xexamples/progress-bar/styled-tqdm-1.py40
-rwxr-xr-xexamples/progress-bar/styled-tqdm-2.py38
-rwxr-xr-xexamples/progress-bar/two-tasks.py39
-rwxr-xr-xexamples/progress-bar/unknown-length.py26
-rw-r--r--examples/prompts/accept-default.py16
-rwxr-xr-xexamples/prompts/asyncio-prompt.py69
-rwxr-xr-xexamples/prompts/auto-completion/autocomplete-with-control-space.py75
-rwxr-xr-xexamples/prompts/auto-completion/autocompletion-like-readline.py58
-rwxr-xr-xexamples/prompts/auto-completion/autocompletion.py60
-rwxr-xr-xexamples/prompts/auto-completion/colored-completions-with-formatted-text.py137
-rwxr-xr-xexamples/prompts/auto-completion/colored-completions.py78
-rwxr-xr-xexamples/prompts/auto-completion/combine-multiple-completers.py76
-rwxr-xr-xexamples/prompts/auto-completion/fuzzy-custom-completer.py57
-rwxr-xr-xexamples/prompts/auto-completion/fuzzy-word-completer.py59
-rwxr-xr-xexamples/prompts/auto-completion/multi-column-autocompletion-with-meta.py50
-rwxr-xr-xexamples/prompts/auto-completion/multi-column-autocompletion.py57
-rwxr-xr-xexamples/prompts/auto-completion/nested-autocompletion.py22
-rwxr-xr-xexamples/prompts/auto-completion/slow-completions.py103
-rwxr-xr-xexamples/prompts/auto-suggestion.py48
-rwxr-xr-xexamples/prompts/autocorrection.py44
-rwxr-xr-xexamples/prompts/bottom-toolbar.py80
-rwxr-xr-xexamples/prompts/clock-input.py25
-rwxr-xr-xexamples/prompts/colored-prompt.py81
-rwxr-xr-xexamples/prompts/confirmation-prompt.py9
-rwxr-xr-xexamples/prompts/cursor-shapes.py19
-rwxr-xr-xexamples/prompts/custom-key-binding.py77
-rwxr-xr-xexamples/prompts/custom-lexer.py29
-rwxr-xr-xexamples/prompts/custom-vi-operator-and-text-object.py70
-rwxr-xr-xexamples/prompts/enforce-tty-input-output.py13
-rwxr-xr-xexamples/prompts/fancy-zsh-prompt.py79
-rwxr-xr-xexamples/prompts/finalterm-shell-integration.py43
-rwxr-xr-xexamples/prompts/get-input-vi-mode.py7
-rwxr-xr-xexamples/prompts/get-input-with-default.py12
-rwxr-xr-xexamples/prompts/get-input.py9
-rwxr-xr-xexamples/prompts/get-multiline-input.py29
-rwxr-xr-xexamples/prompts/get-password-with-toggle-display-shortcut.py28
-rwxr-xr-xexamples/prompts/get-password.py6
-rwxr-xr-xexamples/prompts/history/persistent-history.py25
-rwxr-xr-xexamples/prompts/history/slow-history.py48
-rwxr-xr-xexamples/prompts/html-input.py18
-rwxr-xr-xexamples/prompts/input-validation.py35
-rwxr-xr-xexamples/prompts/inputhook.py84
-rwxr-xr-xexamples/prompts/mouse-support.py10
-rwxr-xr-xexamples/prompts/multiline-prompt.py11
-rwxr-xr-xexamples/prompts/no-wrapping.py6
-rwxr-xr-xexamples/prompts/operate-and-get-next.py18
-rwxr-xr-xexamples/prompts/patch-stdout.py41
-rwxr-xr-xexamples/prompts/placeholder-text.py13
-rwxr-xr-xexamples/prompts/regular-language.py108
-rwxr-xr-xexamples/prompts/rprompt.py53
-rwxr-xr-xexamples/prompts/swap-light-and-dark-colors.py78
-rwxr-xr-xexamples/prompts/switch-between-vi-emacs.py36
-rwxr-xr-xexamples/prompts/system-clipboard-integration.py17
-rwxr-xr-xexamples/prompts/system-prompt.py20
-rwxr-xr-xexamples/prompts/terminal-title.py10
-rwxr-xr-xexamples/prompts/up-arrow-partial-string-matching.py41
-rwxr-xr-xexamples/ssh/asyncssh-server.py122
-rwxr-xr-xexamples/telnet/chat-app.py101
-rwxr-xr-xexamples/telnet/dialog.py32
-rwxr-xr-xexamples/telnet/hello-world.py40
-rwxr-xr-xexamples/telnet/toolbar.py45
-rwxr-xr-xexamples/tutorial/README.md1
-rwxr-xr-xexamples/tutorial/sqlite-cli.py184
118 files changed, 6661 insertions, 0 deletions
diff --git a/examples/dialogs/button_dialog.py b/examples/dialogs/button_dialog.py
new file mode 100755
index 0000000..7a99b9a
--- /dev/null
+++ b/examples/dialogs/button_dialog.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+"""
+Example of button dialog window.
+"""
+from prompt_toolkit.shortcuts import button_dialog
+
+
+def main():
+ result = button_dialog(
+ title="Button dialog example",
+ text="Are you sure?",
+ buttons=[("Yes", True), ("No", False), ("Maybe...", None)],
+ ).run()
+
+ print(f"Result = {result}")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/dialogs/checkbox_dialog.py b/examples/dialogs/checkbox_dialog.py
new file mode 100755
index 0000000..90be263
--- /dev/null
+++ b/examples/dialogs/checkbox_dialog.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+"""
+Example of a checkbox-list-based dialog.
+"""
+from prompt_toolkit.formatted_text import HTML
+from prompt_toolkit.shortcuts import checkboxlist_dialog, message_dialog
+from prompt_toolkit.styles import Style
+
+results = checkboxlist_dialog(
+ title="CheckboxList dialog",
+ text="What would you like in your breakfast ?",
+ values=[
+ ("eggs", "Eggs"),
+ ("bacon", HTML("<blue>Bacon</blue>")),
+ ("croissants", "20 Croissants"),
+ ("daily", "The breakfast of the day"),
+ ],
+ style=Style.from_dict(
+ {
+ "dialog": "bg:#cdbbb3",
+ "button": "bg:#bf99a4",
+ "checkbox": "#e8612c",
+ "dialog.body": "bg:#a9cfd0",
+ "dialog shadow": "bg:#c98982",
+ "frame.label": "#fcaca3",
+ "dialog.body label": "#fd8bb6",
+ }
+ ),
+).run()
+if results:
+ message_dialog(
+ title="Room service",
+ text="You selected: %s\nGreat choice sir !" % ",".join(results),
+ ).run()
+else:
+ message_dialog("*starves*").run()
diff --git a/examples/dialogs/input_dialog.py b/examples/dialogs/input_dialog.py
new file mode 100755
index 0000000..6235265
--- /dev/null
+++ b/examples/dialogs/input_dialog.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+"""
+Example of an input box dialog.
+"""
+from prompt_toolkit.shortcuts import input_dialog
+
+
+def main():
+ result = input_dialog(
+ title="Input dialog example", text="Please type your name:"
+ ).run()
+
+ print(f"Result = {result}")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/dialogs/messagebox.py b/examples/dialogs/messagebox.py
new file mode 100755
index 0000000..4642b84
--- /dev/null
+++ b/examples/dialogs/messagebox.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+"""
+Example of a message box window.
+"""
+from prompt_toolkit.shortcuts import message_dialog
+
+
+def main():
+ message_dialog(
+ title="Example dialog window",
+ text="Do you want to continue?\nPress ENTER to quit.",
+ ).run()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/dialogs/password_dialog.py b/examples/dialogs/password_dialog.py
new file mode 100755
index 0000000..39d7b9c
--- /dev/null
+++ b/examples/dialogs/password_dialog.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+"""
+Example of an password input dialog.
+"""
+from prompt_toolkit.shortcuts import input_dialog
+
+
+def main():
+ result = input_dialog(
+ title="Password dialog example",
+ text="Please type your password:",
+ password=True,
+ ).run()
+
+ print(f"Result = {result}")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/dialogs/progress_dialog.py b/examples/dialogs/progress_dialog.py
new file mode 100755
index 0000000..1fd3ffb
--- /dev/null
+++ b/examples/dialogs/progress_dialog.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+"""
+Example of a progress bar dialog.
+"""
+import os
+import time
+
+from prompt_toolkit.shortcuts import progress_dialog
+
+
+def worker(set_percentage, log_text):
+ """
+ This worker function is called by `progress_dialog`. It will run in a
+ background thread.
+
+ The `set_percentage` function can be used to update the progress bar, while
+ the `log_text` function can be used to log text in the logging window.
+ """
+ percentage = 0
+ for dirpath, dirnames, filenames in os.walk("../.."):
+ for f in filenames:
+ log_text(f"{dirpath} / {f}\n")
+ set_percentage(percentage + 1)
+ percentage += 2
+ time.sleep(0.1)
+
+ if percentage == 100:
+ break
+ if percentage == 100:
+ break
+
+ # Show 100% for a second, before quitting.
+ set_percentage(100)
+ time.sleep(1)
+
+
+def main():
+ progress_dialog(
+ title="Progress dialog example",
+ text="As an examples, we walk through the filesystem and print "
+ "all directories",
+ run_callback=worker,
+ ).run()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/dialogs/radio_dialog.py b/examples/dialogs/radio_dialog.py
new file mode 100755
index 0000000..94d80e2
--- /dev/null
+++ b/examples/dialogs/radio_dialog.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+"""
+Example of a radio list box dialog.
+"""
+from prompt_toolkit.formatted_text import HTML
+from prompt_toolkit.shortcuts import radiolist_dialog
+
+
+def main():
+ result = radiolist_dialog(
+ values=[
+ ("red", "Red"),
+ ("green", "Green"),
+ ("blue", "Blue"),
+ ("orange", "Orange"),
+ ],
+ title="Radiolist dialog example",
+ text="Please select a color:",
+ ).run()
+
+ print(f"Result = {result}")
+
+ # With HTML.
+ result = radiolist_dialog(
+ values=[
+ ("red", HTML('<style bg="red" fg="white">Red</style>')),
+ ("green", HTML('<style bg="green" fg="white">Green</style>')),
+ ("blue", HTML('<style bg="blue" fg="white">Blue</style>')),
+ ("orange", HTML('<style bg="orange" fg="white">Orange</style>')),
+ ],
+ title=HTML("Radiolist dialog example <reverse>with colors</reverse>"),
+ text="Please select a color:",
+ ).run()
+
+ print(f"Result = {result}")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/dialogs/styled_messagebox.py b/examples/dialogs/styled_messagebox.py
new file mode 100755
index 0000000..3f6fc53
--- /dev/null
+++ b/examples/dialogs/styled_messagebox.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+"""
+Example of a style dialog window.
+All dialog shortcuts take a `style` argument in order to apply a custom
+styling.
+
+This also demonstrates that the `title` argument can be any kind of formatted
+text.
+"""
+from prompt_toolkit.formatted_text import HTML
+from prompt_toolkit.shortcuts import message_dialog
+from prompt_toolkit.styles import Style
+
+# Custom color scheme.
+example_style = Style.from_dict(
+ {
+ "dialog": "bg:#88ff88",
+ "dialog frame-label": "bg:#ffffff #000000",
+ "dialog.body": "bg:#000000 #00ff00",
+ "dialog shadow": "bg:#00aa00",
+ }
+)
+
+
+def main():
+ message_dialog(
+ title=HTML(
+ '<style bg="blue" fg="white">Styled</style> '
+ '<style fg="ansired">dialog</style> window'
+ ),
+ text="Do you want to continue?\nPress ENTER to quit.",
+ style=example_style,
+ ).run()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/dialogs/yes_no_dialog.py b/examples/dialogs/yes_no_dialog.py
new file mode 100755
index 0000000..4b08dd6
--- /dev/null
+++ b/examples/dialogs/yes_no_dialog.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+"""
+Example of confirmation (yes/no) dialog window.
+"""
+from prompt_toolkit.shortcuts import yes_no_dialog
+
+
+def main():
+ result = yes_no_dialog(
+ title="Yes/No dialog example", text="Do you want to confirm?"
+ ).run()
+
+ print(f"Result = {result}")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/full-screen/ansi-art-and-textarea.py b/examples/full-screen/ansi-art-and-textarea.py
new file mode 100755
index 0000000..ee6d93d
--- /dev/null
+++ b/examples/full-screen/ansi-art-and-textarea.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+
+from prompt_toolkit.application import Application
+from prompt_toolkit.formatted_text import ANSI, HTML
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.layout import (
+ FormattedTextControl,
+ HSplit,
+ Layout,
+ VSplit,
+ Window,
+ WindowAlign,
+)
+from prompt_toolkit.layout.dimension import D
+from prompt_toolkit.widgets import Dialog, Label, TextArea
+
+
+def main():
+ # Key bindings.
+ kb = KeyBindings()
+
+ @kb.add("c-c")
+ def _(event):
+ "Quit when control-c is pressed."
+ event.app.exit()
+
+ text_area = TextArea(text="You can type here...")
+ dialog_body = HSplit(
+ [
+ Label(
+ HTML("Press <reverse>control-c</reverse> to quit."),
+ align=WindowAlign.CENTER,
+ ),
+ VSplit(
+ [
+ Label(PROMPT_TOOLKIT_LOGO, align=WindowAlign.CENTER),
+ text_area,
+ ],
+ ),
+ ]
+ )
+
+ application = Application(
+ layout=Layout(
+ container=Dialog(
+ title="ANSI Art demo - Art on the left, text area on the right",
+ body=dialog_body,
+ with_background=True,
+ ),
+ focused_element=text_area,
+ ),
+ full_screen=True,
+ mouse_support=True,
+ key_bindings=kb,
+ )
+ application.run()
+
+
+PROMPT_TOOLKIT_LOGO = ANSI(
+ """
+\x1b[48;2;0;0;0m \x1b[m
+\x1b[48;2;0;0;0m \x1b[48;2;0;249;0m\x1b[38;2;0;0;0mâ–€\x1b[48;2;0;209;0mâ–€\x1b[48;2;0;207;0m\x1b[38;2;6;34;6mâ–€\x1b[48;2;0;66;0m\x1b[38;2;30;171;30mâ–€\x1b[48;2;0;169;0m\x1b[38;2;51;35;51mâ–€\x1b[48;2;0;248;0m\x1b[38;2;49;194;49mâ–€\x1b[48;2;0;111;0m\x1b[38;2;25;57;25mâ–€\x1b[48;2;140;195;140m\x1b[38;2;3;17;3mâ–€\x1b[48;2;30;171;30m\x1b[38;2;0;0;0mâ–€\x1b[48;2;0;0;0m \x1b[m
+\x1b[48;2;0;0;0m \x1b[48;2;77;127;78m\x1b[38;2;118;227;108m▀\x1b[48;2;216;1;13m\x1b[38;2;49;221;57m▀\x1b[48;2;26;142;76m\x1b[38;2;108;146;165m▀\x1b[48;2;26;142;90m\x1b[38;2;209;197;114m▀▀\x1b[38;2;209;146;114m▀\x1b[48;2;26;128;90m\x1b[38;2;158;197;114m▀\x1b[48;2;58;210;70m\x1b[38;2;223;152;89m▀\x1b[48;2;232;139;44m\x1b[38;2;97;121;146m▀\x1b[48;2;233;139;45m\x1b[38;2;140;188;183m▀\x1b[48;2;231;139;44m\x1b[38;2;40;168;8m▀\x1b[48;2;228;140;44m\x1b[38;2;37;169;7m▀\x1b[48;2;227;140;44m\x1b[38;2;36;169;7m▀\x1b[48;2;211;142;41m\x1b[38;2;23;171;5m▀\x1b[48;2;86;161;17m\x1b[38;2;2;174;1m▀\x1b[48;2;0;175;0m \x1b[48;2;0;254;0m\x1b[38;2;190;119;190m▀\x1b[48;2;92;39;23m\x1b[38;2;125;50;114m▀\x1b[48;2;43;246;41m\x1b[38;2;49;10;165m▀\x1b[48;2;12;128;90m\x1b[38;2;209;197;114m▀\x1b[48;2;26;128;90m▀▀▀▀\x1b[48;2;26;128;76m▀\x1b[48;2;26;128;90m\x1b[38;2;209;247;114m▀▀\x1b[38;2;209;197;114m▀\x1b[48;2;26;128;76m\x1b[38;2;209;247;114m▀\x1b[48;2;26;128;90m▀▀▀\x1b[48;2;26;128;76m▀\x1b[48;2;26;128;90m▀▀\x1b[48;2;12;128;76m▀\x1b[48;2;12;113;90m\x1b[38;2;209;247;64m▀\x1b[38;2;209;247;114m▀\x1b[48;2;12;128;90m▀\x1b[48;2;12;113;90m▀\x1b[48;2;12;113;76m\x1b[38;2;209;247;64m▀\x1b[48;2;12;128;90m▀\x1b[48;2;12;113;90m▀\x1b[48;2;12;113;76m\x1b[38;2;209;247;114m▀\x1b[48;2;12;113;90m\x1b[38;2;209;247;64m▀\x1b[48;2;26;128;90m\x1b[38;2;151;129;163m▀\x1b[48;2;115;120;103m\x1b[38;2;62;83;227m▀\x1b[48;2;138;14;25m\x1b[38;2;104;106;160m▀\x1b[48;2;0;0;57m\x1b[38;2;0;0;0m▀\x1b[m
+\x1b[48;2;249;147;8m\x1b[38;2;172;69;38m▀\x1b[48;2;197;202;10m\x1b[38;2;82;192;58m▀\x1b[48;2;248;124;45m\x1b[38;2;251;131;47m▀\x1b[48;2;248;124;44m▀\x1b[48;2;248;124;45m▀▀\x1b[48;2;248;124;44m▀\x1b[48;2;248;124;45m▀\x1b[48;2;248;125;45m\x1b[38;2;251;130;47m▀\x1b[48;2;248;124;45m\x1b[38;2;252;130;47m▀\x1b[48;2;248;125;45m\x1b[38;2;252;131;47m▀\x1b[38;2;252;130;47m▀\x1b[38;2;252;131;47m▀▀\x1b[48;2;249;125;45m\x1b[38;2;255;130;48m▀\x1b[48;2;233;127;42m\x1b[38;2;190;141;35m▀\x1b[48;2;57;163;10m\x1b[38;2;13;172;3m▀\x1b[48;2;0;176;0m\x1b[38;2;0;175;0m▀\x1b[48;2;7;174;1m\x1b[38;2;35;169;7m▀\x1b[48;2;178;139;32m\x1b[38;2;220;136;41m▀\x1b[48;2;252;124;45m\x1b[38;2;253;131;47m▀\x1b[48;2;248;125;45m\x1b[38;2;251;131;47m▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\x1b[48;2;248;125;44m▀\x1b[48;2;248;135;61m\x1b[38;2;251;132;48m▀\x1b[48;2;250;173;122m\x1b[38;2;251;133;50m▀\x1b[48;2;249;155;93m\x1b[38;2;251;132;49m▀\x1b[48;2;248;132;55m\x1b[38;2;251;132;48m▀\x1b[48;2;250;173;122m\x1b[38;2;251;134;51m▀\x1b[48;2;250;163;106m\x1b[38;2;251;134;50m▀\x1b[48;2;248;128;49m\x1b[38;2;251;132;47m▀\x1b[48;2;250;166;110m\x1b[38;2;251;135;52m▀\x1b[48;2;250;175;125m\x1b[38;2;251;136;54m▀\x1b[48;2;248;132;56m\x1b[38;2;251;132;48m▀\x1b[48;2;248;220;160m\x1b[38;2;105;247;172m▀\x1b[48;2;62;101;236m\x1b[38;2;11;207;160m▀\x1b[m
+\x1b[48;2;138;181;197m\x1b[38;2;205;36;219m▀\x1b[48;2;177;211;200m\x1b[38;2;83;231;105m▀\x1b[48;2;242;113;40m\x1b[38;2;245;119;42m▀\x1b[48;2;243;113;41m▀\x1b[48;2;245;114;41m▀▀▀▀▀▀▀▀\x1b[38;2;245;119;43m▀▀▀\x1b[48;2;247;114;41m\x1b[38;2;246;119;43m▀\x1b[48;2;202;125;34m\x1b[38;2;143;141;25m▀\x1b[48;2;84;154;14m\x1b[38;2;97;152;17m▀\x1b[48;2;36;166;6m▀\x1b[48;2;139;140;23m\x1b[38;2;183;133;32m▀\x1b[48;2;248;114;41m\x1b[38;2;248;118;43m▀\x1b[48;2;245;115;41m\x1b[38;2;245;119;43m▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\x1b[38;2;245;119;42m▀\x1b[48;2;246;117;44m\x1b[38;2;246;132;62m▀\x1b[48;2;246;123;54m\x1b[38;2;249;180;138m▀\x1b[48;2;246;120;49m\x1b[38;2;247;157;102m▀\x1b[48;2;246;116;42m\x1b[38;2;246;127;54m▀\x1b[48;2;246;121;50m\x1b[38;2;248;174;128m▀\x1b[48;2;246;120;48m\x1b[38;2;248;162;110m▀\x1b[48;2;246;116;41m\x1b[38;2;245;122;47m▀\x1b[48;2;246;118;46m\x1b[38;2;248;161;108m▀\x1b[48;2;244;118;47m\x1b[38;2;248;171;123m▀\x1b[48;2;243;115;42m\x1b[38;2;246;127;54m▀\x1b[48;2;179;52;29m\x1b[38;2;86;152;223m▀\x1b[48;2;141;225;95m\x1b[38;2;247;146;130m▀\x1b[m
+\x1b[48;2;50;237;108m\x1b[38;2;94;70;153m▀\x1b[48;2;206;221;133m\x1b[38;2;64;240;39m▀\x1b[48;2;233;100;36m\x1b[38;2;240;107;38m▀\x1b[48;2;114;56;22m\x1b[38;2;230;104;37m▀\x1b[48;2;24;20;10m\x1b[38;2;193;90;33m▀\x1b[48;2;21;19;9m\x1b[38;2;186;87;32m▀▀▀▀▀▀▀\x1b[38;2;186;87;33m▀▀▀\x1b[48;2;22;18;10m\x1b[38;2;189;86;33m▀\x1b[48;2;18;36;8m\x1b[38;2;135;107;24m▀\x1b[48;2;3;153;2m\x1b[38;2;5;171;1m▀\x1b[48;2;0;177;0m \x1b[48;2;4;158;2m\x1b[38;2;69;147;12m▀\x1b[48;2;19;45;8m\x1b[38;2;185;89;32m▀\x1b[48;2;22;17;10m\x1b[38;2;186;87;33m▀\x1b[48;2;21;19;9m▀▀▀▀▀▀▀▀\x1b[48;2;21;19;10m▀▀\x1b[48;2;21;19;9m▀▀▀▀\x1b[48;2;21;19;10m▀▀▀\x1b[38;2;186;87;32m▀▀\x1b[48;2;21;19;9m\x1b[38;2;186;87;33m▀\x1b[48;2;21;19;10m\x1b[38;2;186;87;32m▀▀\x1b[48;2;21;19;9m\x1b[38;2;186;87;33m▀\x1b[48;2;22;19;10m\x1b[38;2;191;89;33m▀\x1b[48;2;95;49;20m\x1b[38;2;226;103;37m▀\x1b[48;2;227;99;36m\x1b[38;2;241;109;39m▀\x1b[48;2;80;140;154m\x1b[38;2;17;240;92m▀\x1b[48;2;221;58;175m\x1b[38;2;71;14;245m▀\x1b[m
+\x1b[48;2;195;38;42m\x1b[38;2;5;126;86m▀\x1b[48;2;139;230;67m\x1b[38;2;253;201;228m▀\x1b[48;2;208;82;30m\x1b[38;2;213;89;32m▀\x1b[48;2;42;26;12m\x1b[38;2;44;27;12m▀\x1b[48;2;9;14;7m\x1b[38;2;8;13;7m▀\x1b[48;2;11;15;8m\x1b[38;2;10;14;7m▀▀▀▀▀▀▀▀▀▀▀\x1b[48;2;11;12;8m\x1b[38;2;10;17;7m▀\x1b[48;2;7;71;5m\x1b[38;2;4;120;3m▀\x1b[48;2;1;164;1m\x1b[38;2;0;178;0m▀\x1b[48;2;4;118;3m\x1b[38;2;0;177;0m▀\x1b[48;2;5;108;3m\x1b[38;2;4;116;3m▀\x1b[48;2;7;75;5m\x1b[38;2;10;23;7m▀\x1b[48;2;10;33;7m\x1b[38;2;10;12;7m▀\x1b[48;2;11;13;8m\x1b[38;2;10;14;7m▀\x1b[48;2;11;14;8m▀\x1b[48;2;11;15;8m▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\x1b[48;2;10;14;7m\x1b[38;2;9;14;7m▀\x1b[48;2;30;21;10m\x1b[38;2;30;22;10m▀\x1b[48;2;195;79;29m\x1b[38;2;200;84;31m▀\x1b[48;2;205;228;23m\x1b[38;2;111;40;217m▀\x1b[48;2;9;217;69m\x1b[38;2;115;137;104m▀\x1b[m
+\x1b[48;2;106;72;209m\x1b[38;2;151;183;253mâ–€\x1b[48;2;120;239;0m\x1b[38;2;25;2;162mâ–€\x1b[48;2;203;72;26m\x1b[38;2;206;77;28mâ–€\x1b[48;2;42;24;11m\x1b[38;2;42;25;11mâ–€\x1b[48;2;9;14;7m \x1b[48;2;11;15;8m \x1b[38;2;11;14;8mâ–€\x1b[48;2;11;13;8m\x1b[38;2;10;28;7mâ–€\x1b[48;2;9;36;6m\x1b[38;2;7;78;5mâ–€\x1b[48;2;2;153;1m\x1b[38;2;6;94;4mâ–€\x1b[48;2;0;178;0m\x1b[38;2;2;156;1mâ–€\x1b[48;2;0;175;0m\x1b[38;2;1;167;1mâ–€\x1b[48;2;0;177;0m\x1b[38;2;2;145;2mâ–€\x1b[48;2;2;147;2m\x1b[38;2;8;54;6mâ–€\x1b[48;2;9;38;6m\x1b[38;2;11;13;8mâ–€\x1b[48;2;11;13;8m\x1b[38;2;11;14;8mâ–€\x1b[48;2;11;15;8m \x1b[48;2;10;14;7m \x1b[48;2;29;20;10m\x1b[38;2;29;21;10mâ–€\x1b[48;2;190;69;25m\x1b[38;2;193;74;27mâ–€\x1b[48;2;136;91;148m\x1b[38;2;42;159;86mâ–€\x1b[48;2;89;85;149m\x1b[38;2;160;5;219mâ–€\x1b[m
+\x1b[48;2;229;106;143m\x1b[38;2;40;239;187m▀\x1b[48;2;196;134;237m\x1b[38;2;6;11;95m▀\x1b[48;2;197;60;22m\x1b[38;2;201;67;24m▀\x1b[48;2;41;22;10m\x1b[38;2;41;23;11m▀\x1b[48;2;9;14;7m \x1b[48;2;11;15;8m \x1b[48;2;10;14;7m\x1b[38;2;11;15;8m▀▀\x1b[48;2;11;15;8m \x1b[38;2;11;14;8m▀\x1b[48;2;11;14;8m\x1b[38;2;11;16;7m▀\x1b[48;2;11;15;7m\x1b[38;2;7;79;5m▀\x1b[48;2;7;68;5m\x1b[38;2;1;164;1m▀\x1b[48;2;2;153;1m\x1b[38;2;0;176;0m▀\x1b[48;2;2;154;1m\x1b[38;2;0;175;0m▀\x1b[48;2;5;107;3m\x1b[38;2;1;171;1m▀\x1b[48;2;4;115;3m\x1b[38;2;5;105;3m▀\x1b[48;2;6;84;4m\x1b[38;2;11;18;7m▀\x1b[48;2;10;30;7m\x1b[38;2;11;13;8m▀\x1b[48;2;11;13;8m\x1b[38;2;11;15;8m▀\x1b[48;2;11;14;8m▀\x1b[48;2;11;15;8m \x1b[48;2;10;14;7m \x1b[48;2;29;19;9m\x1b[38;2;29;20;10m▀\x1b[48;2;185;58;22m\x1b[38;2;188;64;24m▀\x1b[48;2;68;241;49m\x1b[38;2;199;22;211m▀\x1b[48;2;133;139;8m\x1b[38;2;239;129;78m▀\x1b[m
+\x1b[48;2;74;30;32m\x1b[38;2;163;185;76mâ–€\x1b[48;2;110;172;9m\x1b[38;2;177;1;123mâ–€\x1b[48;2;189;43;16m\x1b[38;2;193;52;19mâ–€\x1b[48;2;39;20;9m\x1b[38;2;40;21;10mâ–€\x1b[48;2;9;14;7m \x1b[48;2;11;15;8m \x1b[48;2;11;14;7m\x1b[38;2;11;15;8mâ–€\x1b[48;2;9;14;7m\x1b[38;2;11;14;8mâ–€\x1b[48;2;106;54;38m\x1b[38;2;31;24;15mâ–€\x1b[48;2;164;71;49m\x1b[38;2;24;20;12mâ–€\x1b[48;2;94;46;31m\x1b[38;2;8;14;7mâ–€\x1b[48;2;36;24;15m\x1b[38;2;9;14;7mâ–€\x1b[48;2;11;15;8m\x1b[38;2;11;14;7mâ–€\x1b[48;2;8;14;7m\x1b[38;2;11;15;8mâ–€\x1b[48;2;10;14;7mâ–€\x1b[48;2;11;15;8m \x1b[38;2;11;14;8mâ–€\x1b[48;2;11;14;8m\x1b[38;2;11;13;8mâ–€\x1b[48;2;11;13;8m\x1b[38;2;9;45;6mâ–€\x1b[48;2;10;19;7m\x1b[38;2;7;75;5mâ–€\x1b[48;2;6;83;4m\x1b[38;2;2;143;2mâ–€\x1b[48;2;2;156;1m\x1b[38;2;0;176;0mâ–€\x1b[48;2;0;177;0m\x1b[38;2;0;175;0mâ–€\x1b[38;2;3;134;2mâ–€\x1b[48;2;2;152;1m\x1b[38;2;9;46;6mâ–€\x1b[48;2;8;60;5m\x1b[38;2;11;13;8mâ–€\x1b[48;2;11;14;7m\x1b[38;2;11;14;8mâ–€\x1b[48;2;11;14;8m\x1b[38;2;11;15;8mâ–€\x1b[48;2;11;15;8m \x1b[48;2;10;14;7m \x1b[48;2;28;18;9m \x1b[48;2;177;43;16m\x1b[38;2;181;51;19mâ–€\x1b[48;2;93;35;236m\x1b[38;2;224;10;142mâ–€\x1b[48;2;72;51;52m\x1b[38;2;213;112;158mâ–€\x1b[m
+\x1b[48;2;175;209;155m\x1b[38;2;7;131;221mâ–€\x1b[48;2;24;0;85m\x1b[38;2;44;86;152mâ–€\x1b[48;2;181;27;10m\x1b[38;2;185;35;13mâ–€\x1b[48;2;38;17;8m\x1b[38;2;39;18;9mâ–€\x1b[48;2;9;14;7m \x1b[48;2;11;15;8m \x1b[48;2;11;14;7m \x1b[48;2;9;14;7m \x1b[48;2;87;43;32m\x1b[38;2;114;54;39mâ–€\x1b[48;2;188;71;54m\x1b[38;2;211;82;59mâ–€\x1b[48;2;203;73;55m\x1b[38;2;204;80;57mâ–€\x1b[48;2;205;73;55m\x1b[38;2;178;71;51mâ–€\x1b[48;2;204;74;55m\x1b[38;2;119;52;37mâ–€\x1b[48;2;188;69;52m\x1b[38;2;54;29;19mâ–€\x1b[48;2;141;55;41m\x1b[38;2;16;17;9mâ–€\x1b[48;2;75;35;24m\x1b[38;2;8;14;7mâ–€\x1b[48;2;26;20;12m\x1b[38;2;10;14;7mâ–€\x1b[48;2;9;14;7m\x1b[38;2;11;14;7mâ–€\x1b[38;2;11;15;8mâ–€\x1b[48;2;11;14;7mâ–€\x1b[48;2;11;15;8m \x1b[38;2;11;14;8mâ–€\x1b[48;2;11;14;8m \x1b[48;2;11;13;8m\x1b[38;2;9;45;6mâ–€\x1b[48;2;10;23;7m\x1b[38;2;4;123;3mâ–€\x1b[48;2;7;75;5m\x1b[38;2;1;172;1mâ–€\x1b[48;2;6;84;4m\x1b[38;2;2;154;1mâ–€\x1b[48;2;4;114;3m\x1b[38;2;5;107;3mâ–€\x1b[48;2;5;103;4m\x1b[38;2;10;29;7mâ–€\x1b[48;2;10;23;7m\x1b[38;2;11;13;8mâ–€\x1b[48;2;11;14;8m\x1b[38;2;11;15;8mâ–€\x1b[48;2;11;15;8m \x1b[48;2;10;14;7m \x1b[48;2;27;16;8m\x1b[38;2;27;17;9mâ–€\x1b[48;2;170;27;10m\x1b[38;2;174;35;13mâ–€\x1b[48;2;118;117;199m\x1b[38;2;249;61;74mâ–€\x1b[48;2;10;219;61m\x1b[38;2;187;245;202mâ–€\x1b[m
+\x1b[48;2;20;155;44m\x1b[38;2;86;54;110mâ–€\x1b[48;2;195;85;113m\x1b[38;2;214;171;227mâ–€\x1b[48;2;173;10;4m\x1b[38;2;177;19;7mâ–€\x1b[48;2;37;14;7m\x1b[38;2;37;16;8mâ–€\x1b[48;2;9;15;8m\x1b[38;2;9;14;7mâ–€\x1b[48;2;11;15;8m \x1b[38;2;11;14;7mâ–€\x1b[48;2;11;14;7m\x1b[38;2;15;17;9mâ–€\x1b[48;2;9;14;7m\x1b[38;2;50;29;20mâ–€\x1b[48;2;10;15;8m\x1b[38;2;112;47;36mâ–€\x1b[48;2;33;22;15m\x1b[38;2;170;61;48mâ–€\x1b[48;2;88;38;29m\x1b[38;2;197;66;53mâ–€\x1b[48;2;151;53;43m\x1b[38;2;201;67;53mâ–€\x1b[48;2;189;60;50mâ–€\x1b[48;2;198;60;51m\x1b[38;2;194;65;52mâ–€\x1b[38;2;160;56;44mâ–€\x1b[48;2;196;60;50m\x1b[38;2;99;40;30mâ–€\x1b[48;2;174;55;47m\x1b[38;2;41;24;16mâ–€\x1b[48;2;122;43;35m\x1b[38;2;12;15;8mâ–€\x1b[48;2;59;27;20m\x1b[38;2;8;14;7mâ–€\x1b[48;2;16;16;9m\x1b[38;2;10;14;7mâ–€\x1b[48;2;10;14;7m\x1b[38;2;11;15;8mâ–€\x1b[48;2;11;15;8m \x1b[38;2;11;14;8mâ–€\x1b[48;2;11;14;8m\x1b[38;2;11;12;8mâ–€\x1b[48;2;10;25;7m\x1b[38;2;7;79;5mâ–€\x1b[48;2;3;141;2m\x1b[38;2;1;174;1mâ–€\x1b[48;2;0;178;0m\x1b[38;2;1;169;1mâ–€\x1b[48;2;6;88;4m\x1b[38;2;8;56;6mâ–€\x1b[48;2;11;12;8m \x1b[48;2;11;14;8m\x1b[38;2;11;15;8mâ–€\x1b[48;2;11;15;8m \x1b[48;2;10;14;7m \x1b[48;2;26;15;8m\x1b[38;2;27;15;8mâ–€\x1b[48;2;162;12;5m\x1b[38;2;166;20;8mâ–€\x1b[48;2;143;168;130m\x1b[38;2;18;142;37mâ–€\x1b[48;2;240;96;105m\x1b[38;2;125;158;211mâ–€\x1b[m
+\x1b[48;2;54;0;0m\x1b[38;2;187;22;0mâ–€\x1b[48;2;204;0;0m\x1b[38;2;128;208;0mâ–€\x1b[48;2;162;1;1m\x1b[38;2;168;3;1mâ–€\x1b[48;2;35;13;7m\x1b[38;2;36;13;7mâ–€\x1b[48;2;9;15;8m \x1b[48;2;11;15;8m \x1b[38;2;11;14;7mâ–€\x1b[38;2;9;14;7mâ–€\x1b[38;2;8;14;7mâ–€\x1b[48;2;10;14;7m\x1b[38;2;21;18;11mâ–€\x1b[48;2;7;13;6m\x1b[38;2;65;30;23mâ–€\x1b[48;2;12;16;9m\x1b[38;2;129;45;38mâ–€\x1b[48;2;57;29;23m\x1b[38;2;176;53;47mâ–€\x1b[48;2;148;49;44m\x1b[38;2;191;53;48mâ–€\x1b[48;2;187;52;48m\x1b[38;2;192;53;48mâ–€\x1b[48;2;186;51;47m\x1b[38;2;194;54;49mâ–€\x1b[48;2;182;52;47m\x1b[38;2;178;52;46mâ–€\x1b[48;2;59;27;21m\x1b[38;2;53;26;19mâ–€\x1b[48;2;8;14;7m \x1b[48;2;11;15;8m \x1b[48;2;11;14;8m\x1b[38;2;11;15;8mâ–€\x1b[48;2;11;12;8m\x1b[38;2;11;14;8mâ–€\x1b[48;2;10;30;7m\x1b[38;2;10;23;7mâ–€\x1b[48;2;5;110;3m\x1b[38;2;3;138;2mâ–€\x1b[48;2;2;149;2m\x1b[38;2;0;181;0mâ–€\x1b[48;2;6;92;4m\x1b[38;2;5;100;4mâ–€\x1b[48;2;11;13;8m \x1b[48;2;11;14;8m \x1b[48;2;11;15;8m \x1b[48;2;10;15;8m \x1b[48;2;25;14;7m\x1b[38;2;26;14;7mâ–€\x1b[48;2;152;2;1m\x1b[38;2;158;5;2mâ–€\x1b[48;2;6;0;0m\x1b[38;2;44;193;0mâ–€\x1b[48;2;108;0;0m\x1b[38;2;64;70;0mâ–€\x1b[m
+\x1b[48;2;44;0;0m\x1b[38;2;177;0;0mâ–€\x1b[48;2;147;0;0m\x1b[38;2;71;0;0mâ–€\x1b[48;2;148;1;1m\x1b[38;2;155;1;1mâ–€\x1b[48;2;33;13;7m\x1b[38;2;34;13;7mâ–€\x1b[48;2;9;15;8m \x1b[48;2;11;15;8m \x1b[48;2;11;14;7m\x1b[38;2;11;15;8mâ–€\x1b[48;2;10;14;7mâ–€\x1b[48;2;9;14;7mâ–€\x1b[48;2;13;16;9m\x1b[38;2;11;14;7mâ–€\x1b[48;2;42;24;17m\x1b[38;2;9;14;7mâ–€\x1b[48;2;97;38;32m\x1b[38;2;10;15;8mâ–€\x1b[48;2;149;49;44m\x1b[38;2;30;21;14mâ–€\x1b[48;2;174;52;48m\x1b[38;2;79;34;28mâ–€\x1b[48;2;178;52;48m\x1b[38;2;136;45;40mâ–€\x1b[38;2;172;51;47mâ–€\x1b[48;2;173;52;48m\x1b[38;2;181;52;48mâ–€\x1b[48;2;147;47;42m\x1b[38;2;183;52;48mâ–€\x1b[48;2;94;35;30m\x1b[38;2;177;52;48mâ–€\x1b[48;2;25;19;12m\x1b[38;2;56;27;20mâ–€\x1b[48;2;10;14;7m\x1b[38;2;8;14;7mâ–€\x1b[48;2;11;12;8m\x1b[38;2;11;15;8mâ–€\x1b[48;2;10;23;7m\x1b[38;2;11;14;8mâ–€\x1b[48;2;7;76;5m\x1b[38;2;11;13;8mâ–€\x1b[48;2;2;152;1m\x1b[38;2;9;45;6mâ–€\x1b[48;2;0;177;0m\x1b[38;2;5;106;3mâ–€\x1b[48;2;0;178;0m\x1b[38;2;4;123;3mâ–€\x1b[48;2;1;168;1m\x1b[38;2;5;104;3mâ–€\x1b[48;2;8;53;6m\x1b[38;2;9;47;6mâ–€\x1b[48;2;11;12;8m\x1b[38;2;11;13;8mâ–€\x1b[48;2;11;15;8m \x1b[48;2;10;15;8m \x1b[48;2;24;14;7m\x1b[38;2;25;14;7mâ–€\x1b[48;2;140;2;1m\x1b[38;2;146;2;1mâ–€\x1b[48;2;219;0;0m\x1b[38;2;225;0;0mâ–€\x1b[48;2;126;0;0m\x1b[38;2;117;0;0mâ–€\x1b[m
+\x1b[48;2;34;0;0m\x1b[38;2;167;0;0mâ–€\x1b[48;2;89;0;0m\x1b[38;2;14;0;0mâ–€\x1b[48;2;134;1;1m\x1b[38;2;141;1;1mâ–€\x1b[48;2;31;13;7m\x1b[38;2;32;13;7mâ–€\x1b[48;2;10;15;8m \x1b[48;2;11;15;8m \x1b[48;2;11;14;7m\x1b[38;2;11;15;8mâ–€\x1b[48;2;10;14;7m\x1b[38;2;11;14;7mâ–€\x1b[48;2;53;29;22m\x1b[38;2;10;14;7mâ–€\x1b[48;2;127;46;41m\x1b[38;2;20;18;11mâ–€\x1b[48;2;158;51;47m\x1b[38;2;57;28;22mâ–€\x1b[48;2;166;52;48m\x1b[38;2;113;42;36mâ–€\x1b[48;2;167;52;48m\x1b[38;2;156;50;46mâ–€\x1b[48;2;164;52;48m\x1b[38;2;171;52;48mâ–€\x1b[48;2;146;48;44m\x1b[38;2;172;52;48mâ–€\x1b[48;2;102;38;33mâ–€\x1b[48;2;50;26;19m\x1b[38;2;161;51;46mâ–€\x1b[48;2;17;17;10m\x1b[38;2;126;44;38mâ–€\x1b[48;2;8;14;7m\x1b[38;2;71;31;25mâ–€\x1b[48;2;10;14;7m\x1b[38;2;27;19;13mâ–€\x1b[48;2;11;13;8m\x1b[38;2;10;14;7mâ–€\x1b[48;2;9;40;6m\x1b[38;2;10;13;7mâ–€\x1b[48;2;4;119;3m\x1b[38;2;11;20;7mâ–€\x1b[48;2;1;168;1m\x1b[38;2;8;63;5mâ–€\x1b[48;2;0;177;0m\x1b[38;2;3;130;2mâ–€\x1b[48;2;0;175;0m\x1b[38;2;1;171;1mâ–€\x1b[48;2;1;174;1m\x1b[38;2;0;176;0mâ–€\x1b[48;2;1;175;1m\x1b[38;2;1;174;1mâ–€\x1b[48;2;0;177;0m\x1b[38;2;0;176;0mâ–€\x1b[48;2;3;134;2m\x1b[38;2;2;158;1mâ–€\x1b[48;2;10;21;7m\x1b[38;2;9;38;6mâ–€\x1b[48;2;11;14;8m\x1b[38;2;11;13;8mâ–€\x1b[48;2;11;15;8m \x1b[48;2;10;15;8m \x1b[48;2;23;14;7m \x1b[48;2;127;2;1m\x1b[38;2;133;2;1mâ–€\x1b[48;2;176;0;0m\x1b[38;2;213;0;0mâ–€\x1b[48;2;109;0;0m\x1b[38;2;100;0;0mâ–€\x1b[m
+\x1b[48;2;24;0;0m\x1b[38;2;157;0;0m▀\x1b[48;2;32;0;0m\x1b[38;2;165;0;0m▀\x1b[48;2;121;1;1m\x1b[38;2;128;1;1m▀\x1b[48;2;28;13;7m\x1b[38;2;30;13;7m▀\x1b[48;2;10;15;8m \x1b[48;2;11;15;8m \x1b[48;2;11;14;7m \x1b[48;2;9;15;7m \x1b[48;2;88;41;34m\x1b[38;2;91;41;34m▀\x1b[48;2;145;51;47m\x1b[38;2;163;53;49m▀\x1b[48;2;107;42;36m\x1b[38;2;161;52;48m▀\x1b[48;2;58;29;22m\x1b[38;2;155;51;47m▀\x1b[48;2;21;18;11m\x1b[38;2;128;45;40m▀\x1b[48;2;9;14;7m\x1b[38;2;79;33;27m▀\x1b[38;2;33;21;15m▀\x1b[48;2;11;14;7m\x1b[38;2;12;15;8m▀\x1b[48;2;11;15;8m\x1b[38;2;9;14;7m▀\x1b[38;2;10;14;7m▀ \x1b[48;2;11;12;8m\x1b[38;2;11;14;8m▀\x1b[48;2;8;54;6m\x1b[38;2;10;28;7m▀\x1b[48;2;6;93;4m\x1b[38;2;4;125;3m▀\x1b[48;2;2;152;1m\x1b[38;2;0;175;0m▀\x1b[48;2;0;176;0m▀\x1b[48;2;0;175;0m\x1b[38;2;1;174;1m▀\x1b[48;2;0;177;0m\x1b[38;2;1;175;1m▀\x1b[48;2;0;175;0m▀▀\x1b[48;2;1;162;1m\x1b[38;2;0;176;0m▀\x1b[48;2;9;47;6m\x1b[38;2;6;95;4m▀\x1b[48;2;11;13;8m \x1b[48;2;11;15;8m\x1b[38;2;11;14;8m▀ \x1b[48;2;10;15;8m \x1b[48;2;21;13;7m\x1b[38;2;22;13;7m▀\x1b[48;2;114;2;1m\x1b[38;2;121;2;1m▀\x1b[48;2;164;0;0m\x1b[38;2;170;0;0m▀\x1b[48;2;127;0;0m\x1b[38;2;118;0;0m▀\x1b[m
+\x1b[48;2;14;0;0m\x1b[38;2;147;0;0m▀\x1b[48;2;183;0;0m\x1b[38;2;108;0;0m▀\x1b[48;2;107;1;1m\x1b[38;2;114;1;1m▀\x1b[48;2;26;13;7m\x1b[38;2;27;13;7m▀\x1b[48;2;10;15;8m \x1b[48;2;11;15;8m \x1b[38;2;11;14;7m▀ \x1b[48;2;10;14;7m\x1b[38;2;43;27;20m▀\x1b[48;2;9;14;7m\x1b[38;2;42;25;18m▀\x1b[48;2;11;14;7m\x1b[38;2;14;16;9m▀\x1b[48;2;11;15;8m\x1b[38;2;9;14;7m▀\x1b[38;2;10;14;7m▀\x1b[38;2;11;14;7m▀ \x1b[48;2;11;12;8m \x1b[48;2;9;49;6m\x1b[38;2;8;64;5m▀\x1b[48;2;1;166;1m\x1b[38;2;1;159;1m▀\x1b[48;2;0;175;0m\x1b[38;2;1;171;1m▀ \x1b[48;2;1;159;1m\x1b[38;2;1;167;1m▀\x1b[48;2;7;79;5m\x1b[38;2;4;122;3m▀\x1b[48;2;2;144;2m\x1b[38;2;2;158;1m▀\x1b[48;2;0;158;1m\x1b[38;2;0;177;0m▀\x1b[48;2;7;44;6m\x1b[38;2;4;112;3m▀\x1b[48;2;9;12;7m\x1b[38;2;11;17;7m▀\x1b[48;2;9;14;7m\x1b[38;2;11;14;8m▀\x1b[38;2;11;15;8m▀▀▀▀▀▀▀▀▀▀▀\x1b[48;2;11;14;7m▀\x1b[48;2;11;15;8m \x1b[48;2;10;15;8m \x1b[48;2;20;13;7m\x1b[38;2;21;13;7m▀\x1b[48;2;102;2;1m\x1b[38;2;108;2;1m▀\x1b[48;2;121;0;0m\x1b[38;2;127;0;0m▀\x1b[48;2;146;0;0m\x1b[38;2;136;0;0m▀\x1b[m
+\x1b[48;2;3;0;0m\x1b[38;2;137;0;0m▀\x1b[48;2;173;0;0m\x1b[38;2;50;0;0m▀\x1b[48;2;93;1;1m\x1b[38;2;100;1;1m▀\x1b[48;2;24;13;7m\x1b[38;2;25;13;7m▀\x1b[48;2;10;15;8m \x1b[48;2;11;15;8m \x1b[48;2;11;14;7m\x1b[38;2;11;15;8m▀▀\x1b[48;2;17;14;7m\x1b[38;2;11;14;8m▀\x1b[48;2;49;12;7m\x1b[38;2;9;24;7m▀\x1b[48;2;62;54;4m\x1b[38;2;8;133;2m▀\x1b[48;2;7;159;1m\x1b[38;2;2;176;0m▀\x1b[48;2;0;175;0m \x1b[48;2;1;172;1m\x1b[38;2;0;175;0m▀\x1b[48;2;1;159;1m\x1b[38;2;0;173;1m▀\x1b[48;2;46;122;19m\x1b[38;2;1;176;0m▀\x1b[48;2;122;63;45m\x1b[38;2;45;111;18m▀\x1b[48;2;135;52;49m\x1b[38;2;75;36;31m▀\x1b[48;2;135;53;49m\x1b[38;2;74;36;30m▀▀▀▀▀▀▀▀▀▀▀\x1b[48;2;136;53;49m\x1b[38;2;75;37;31m▀\x1b[48;2;119;49;45m\x1b[38;2;66;34;28m▀\x1b[48;2;25;20;13m\x1b[38;2;18;18;11m▀\x1b[48;2;10;14;7m \x1b[48;2;11;15;8m \x1b[48;2;10;15;8m \x1b[48;2;19;13;7m \x1b[48;2;89;2;1m\x1b[38;2;95;2;1m▀\x1b[48;2;77;0;0m\x1b[38;2;83;0;0m▀\x1b[48;2;128;0;0m\x1b[38;2;119;0;0m▀\x1b[m
+\x1b[48;2;60;0;0m\x1b[38;2;126;0;0m▀\x1b[48;2;182;0;0m\x1b[38;2;249;0;0m▀\x1b[48;2;83;1;1m\x1b[38;2;87;1;1m▀\x1b[48;2;22;13;7m\x1b[38;2;23;13;7m▀\x1b[48;2;10;15;8m \x1b[48;2;11;15;8m \x1b[48;2;11;14;7m\x1b[38;2;16;14;7m▀\x1b[48;2;14;14;7m\x1b[38;2;42;13;7m▀\x1b[48;2;58;13;6m\x1b[38;2;95;11;5m▀\x1b[48;2;34;13;7m\x1b[38;2;100;11;5m▀\x1b[48;2;9;14;7m\x1b[38;2;21;17;7m▀\x1b[48;2;11;12;8m\x1b[38;2;8;55;6m▀\x1b[38;2;7;75;5m▀\x1b[38;2;8;65;5m▀\x1b[48;2;11;13;8m\x1b[38;2;9;41;6m▀\x1b[48;2;12;15;8m\x1b[38;2;60;37;28m▀\x1b[38;2;90;42;37m▀\x1b[38;2;88;42;36m▀▀▀▀▀▀▀▀▀▀▀▀\x1b[38;2;89;42;37m▀\x1b[38;2;78;39;33m▀\x1b[48;2;11;15;8m\x1b[38;2;20;18;11m▀\x1b[48;2;11;14;7m\x1b[38;2;10;14;7m▀\x1b[48;2;11;15;8m \x1b[48;2;10;15;8m \x1b[48;2;18;13;7m \x1b[48;2;78;2;1m\x1b[38;2;83;2;1m▀\x1b[48;2;196;0;0m\x1b[38;2;40;0;0m▀\x1b[48;2;217;0;0m\x1b[38;2;137;0;0m▀\x1b[m
+\x1b[48;2;227;0;0m\x1b[38;2;16;0;0m▀\x1b[48;2;116;0;0m\x1b[38;2;21;0;0m▀\x1b[48;2;79;1;1m\x1b[38;2;81;1;1m▀\x1b[48;2;22;13;7m \x1b[48;2;10;15;8m \x1b[48;2;11;15;8m \x1b[38;2;10;15;8m▀\x1b[48;2;10;15;8m\x1b[38;2;21;14;7m▀\x1b[48;2;11;15;8m\x1b[38;2;14;14;7m▀\x1b[38;2;11;14;7m▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ \x1b[48;2;10;15;8m \x1b[48;2;17;13;7m\x1b[38;2;18;13;7m▀\x1b[48;2;75;2;1m\x1b[38;2;76;2;1m▀\x1b[48;2;97;0;0m\x1b[38;2;34;0;0m▀\x1b[48;2;76;0;0m\x1b[38;2;147;0;0m▀\x1b[m
+\x1b[48;2;161;0;0m\x1b[38;2;183;0;0mâ–€\x1b[48;2;49;0;0m\x1b[38;2;211;0;0mâ–€\x1b[48;2;75;1;1m\x1b[38;2;77;1;1mâ–€\x1b[48;2;21;13;7m \x1b[48;2;10;15;8m \x1b[48;2;11;15;8m \x1b[48;2;10;15;8m \x1b[48;2;17;13;7m \x1b[48;2;71;2;1m\x1b[38;2;73;2;1mâ–€\x1b[48;2;253;0;0m\x1b[38;2;159;0;0mâ–€\x1b[48;2;191;0;0m\x1b[38;2;5;0;0mâ–€\x1b[m
+\x1b[48;2;110;161;100m\x1b[38;2;116;0;0m▀\x1b[48;2;9;205;205m\x1b[38;2;192;0;0m▀\x1b[48;2;78;0;0m\x1b[38;2;77;1;0m▀\x1b[48;2;66;3;1m\x1b[38;2;30;11;6m▀\x1b[48;2;42;8;4m\x1b[38;2;9;15;8m▀\x1b[48;2;39;8;4m\x1b[38;2;10;15;8m▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\x1b[48;2;40;8;4m▀\x1b[48;2;39;8;4m▀▀▀▀▀▀▀\x1b[48;2;40;8;4m▀▀▀\x1b[48;2;39;8;4m▀\x1b[48;2;40;8;4m▀\x1b[48;2;39;8;4m▀\x1b[48;2;41;8;4m\x1b[38;2;9;15;8m▀\x1b[48;2;62;4;2m\x1b[38;2;24;13;7m▀\x1b[48;2;78;0;0m\x1b[38;2;74;1;1m▀\x1b[48;2;221;222;0m\x1b[38;2;59;0;0m▀\x1b[48;2;67;199;133m\x1b[38;2;85;0;0m▀\x1b[m
+\x1b[48;2;0;0;0m\x1b[38;2;143;233;149m▀\x1b[48;2;108;184;254m\x1b[38;2;213;6;76m▀\x1b[48;2;197;183;82m\x1b[38;2;76;0;0m▀\x1b[48;2;154;157;0m▀\x1b[48;2;96;0;0m▀\x1b[48;2;253;0;0m▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\x1b[48;2;226;0;0m▀\x1b[48;2;255;127;255m▀\x1b[48;2;84;36;66m\x1b[38;2;64;247;251m▀\x1b[48;2;0;0;0m\x1b[38;2;18;76;210m▀\x1b[m
+\x1b[48;2;0;0;0m \x1b[m
+\x1b[48;2;0;0;0m \x1b[m
+"""
+)
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/full-screen/buttons.py b/examples/full-screen/buttons.py
new file mode 100755
index 0000000..540194d
--- /dev/null
+++ b/examples/full-screen/buttons.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+"""
+A simple example of a few buttons and click handlers.
+"""
+from prompt_toolkit.application import Application
+from prompt_toolkit.application.current import get_app
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.key_binding.bindings.focus import focus_next, focus_previous
+from prompt_toolkit.layout import HSplit, Layout, VSplit
+from prompt_toolkit.styles import Style
+from prompt_toolkit.widgets import Box, Button, Frame, Label, TextArea
+
+
+# Event handlers for all the buttons.
+def button1_clicked():
+ text_area.text = "Button 1 clicked"
+
+
+def button2_clicked():
+ text_area.text = "Button 2 clicked"
+
+
+def button3_clicked():
+ text_area.text = "Button 3 clicked"
+
+
+def exit_clicked():
+ get_app().exit()
+
+
+# All the widgets for the UI.
+button1 = Button("Button 1", handler=button1_clicked)
+button2 = Button("Button 2", handler=button2_clicked)
+button3 = Button("Button 3", handler=button3_clicked)
+button4 = Button("Exit", handler=exit_clicked)
+text_area = TextArea(focusable=True)
+
+
+# Combine all the widgets in a UI.
+# The `Box` object ensures that padding will be inserted around the containing
+# widget. It adapts automatically, unless an explicit `padding` amount is given.
+root_container = Box(
+ HSplit(
+ [
+ Label(text="Press `Tab` to move the focus."),
+ VSplit(
+ [
+ Box(
+ body=HSplit([button1, button2, button3, button4], padding=1),
+ padding=1,
+ style="class:left-pane",
+ ),
+ Box(body=Frame(text_area), padding=1, style="class:right-pane"),
+ ]
+ ),
+ ]
+ ),
+)
+
+layout = Layout(container=root_container, focused_element=button1)
+
+
+# Key bindings.
+kb = KeyBindings()
+kb.add("tab")(focus_next)
+kb.add("s-tab")(focus_previous)
+
+
+# Styling.
+style = Style(
+ [
+ ("left-pane", "bg:#888800 #000000"),
+ ("right-pane", "bg:#00aa00 #000000"),
+ ("button", "#000000"),
+ ("button-arrow", "#000000"),
+ ("button focused", "bg:#ff0000"),
+ ("text-area focused", "bg:#ff0000"),
+ ]
+)
+
+
+# Build a main application object.
+application = Application(layout=layout, key_bindings=kb, style=style, full_screen=True)
+
+
+def main():
+ application.run()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/full-screen/calculator.py b/examples/full-screen/calculator.py
new file mode 100755
index 0000000..fda6567
--- /dev/null
+++ b/examples/full-screen/calculator.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+"""
+A simple example of a calculator program.
+This could be used as inspiration for a REPL.
+"""
+from prompt_toolkit.application import Application
+from prompt_toolkit.document import Document
+from prompt_toolkit.filters import has_focus
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.layout.containers import HSplit, Window
+from prompt_toolkit.layout.layout import Layout
+from prompt_toolkit.styles import Style
+from prompt_toolkit.widgets import SearchToolbar, TextArea
+
+help_text = """
+Type any expression (e.g. "4 + 4") followed by enter to execute.
+Press Control-C to exit.
+"""
+
+
+def main():
+ # The layout.
+ search_field = SearchToolbar() # For reverse search.
+
+ output_field = TextArea(style="class:output-field", text=help_text)
+ input_field = TextArea(
+ height=1,
+ prompt=">>> ",
+ style="class:input-field",
+ multiline=False,
+ wrap_lines=False,
+ search_field=search_field,
+ )
+
+ container = HSplit(
+ [
+ output_field,
+ Window(height=1, char="-", style="class:line"),
+ input_field,
+ search_field,
+ ]
+ )
+
+ # Attach accept handler to the input field. We do this by assigning the
+ # handler to the `TextArea` that we created earlier. it is also possible to
+ # pass it to the constructor of `TextArea`.
+ # NOTE: It's better to assign an `accept_handler`, rather then adding a
+ # custom ENTER key binding. This will automatically reset the input
+ # field and add the strings to the history.
+ def accept(buff):
+ # Evaluate "calculator" expression.
+ try:
+ output = "\n\nIn: {}\nOut: {}".format(
+ input_field.text, eval(input_field.text)
+ ) # Don't do 'eval' in real code!
+ except BaseException as e:
+ output = f"\n\n{e}"
+ new_text = output_field.text + output
+
+ # Add text to output buffer.
+ output_field.buffer.document = Document(
+ text=new_text, cursor_position=len(new_text)
+ )
+
+ input_field.accept_handler = accept
+
+ # The key bindings.
+ kb = KeyBindings()
+
+ @kb.add("c-c")
+ @kb.add("c-q")
+ def _(event):
+ "Pressing Ctrl-Q or Ctrl-C will exit the user interface."
+ event.app.exit()
+
+ # Style.
+ style = Style(
+ [
+ ("output-field", "bg:#000044 #ffffff"),
+ ("input-field", "bg:#000000 #ffffff"),
+ ("line", "#004400"),
+ ]
+ )
+
+ # Run application.
+ application = Application(
+ layout=Layout(container, focused_element=input_field),
+ key_bindings=kb,
+ style=style,
+ mouse_support=True,
+ full_screen=True,
+ )
+
+ application.run()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/full-screen/dummy-app.py b/examples/full-screen/dummy-app.py
new file mode 100755
index 0000000..7ea7506
--- /dev/null
+++ b/examples/full-screen/dummy-app.py
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+"""
+This is the most simple example possible.
+"""
+from prompt_toolkit import Application
+
+app = Application(full_screen=False)
+app.run()
diff --git a/examples/full-screen/full-screen-demo.py b/examples/full-screen/full-screen-demo.py
new file mode 100755
index 0000000..de7379a
--- /dev/null
+++ b/examples/full-screen/full-screen-demo.py
@@ -0,0 +1,225 @@
+#!/usr/bin/env python
+"""
+"""
+from pygments.lexers.html import HtmlLexer
+
+from prompt_toolkit.application import Application
+from prompt_toolkit.application.current import get_app
+from prompt_toolkit.completion import WordCompleter
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.key_binding.bindings.focus import focus_next, focus_previous
+from prompt_toolkit.layout.containers import Float, HSplit, VSplit
+from prompt_toolkit.layout.dimension import D
+from prompt_toolkit.layout.layout import Layout
+from prompt_toolkit.layout.menus import CompletionsMenu
+from prompt_toolkit.lexers import PygmentsLexer
+from prompt_toolkit.styles import Style
+from prompt_toolkit.widgets import (
+ Box,
+ Button,
+ Checkbox,
+ Dialog,
+ Frame,
+ Label,
+ MenuContainer,
+ MenuItem,
+ ProgressBar,
+ RadioList,
+ TextArea,
+)
+
+
+def accept_yes():
+ get_app().exit(result=True)
+
+
+def accept_no():
+ get_app().exit(result=False)
+
+
+def do_exit():
+ get_app().exit(result=False)
+
+
+yes_button = Button(text="Yes", handler=accept_yes)
+no_button = Button(text="No", handler=accept_no)
+textfield = TextArea(lexer=PygmentsLexer(HtmlLexer))
+checkbox1 = Checkbox(text="Checkbox")
+checkbox2 = Checkbox(text="Checkbox")
+
+radios = RadioList(
+ values=[
+ ("Red", "red"),
+ ("Green", "green"),
+ ("Blue", "blue"),
+ ("Orange", "orange"),
+ ("Yellow", "yellow"),
+ ("Purple", "Purple"),
+ ("Brown", "Brown"),
+ ]
+)
+
+animal_completer = WordCompleter(
+ [
+ "alligator",
+ "ant",
+ "ape",
+ "bat",
+ "bear",
+ "beaver",
+ "bee",
+ "bison",
+ "butterfly",
+ "cat",
+ "chicken",
+ "crocodile",
+ "dinosaur",
+ "dog",
+ "dolphin",
+ "dove",
+ "duck",
+ "eagle",
+ "elephant",
+ "fish",
+ "goat",
+ "gorilla",
+ "kangaroo",
+ "leopard",
+ "lion",
+ "mouse",
+ "rabbit",
+ "rat",
+ "snake",
+ "spider",
+ "turkey",
+ "turtle",
+ ],
+ ignore_case=True,
+)
+
+root_container = HSplit(
+ [
+ VSplit(
+ [
+ Frame(body=Label(text="Left frame\ncontent")),
+ Dialog(title="The custom window", body=Label("hello\ntest")),
+ textfield,
+ ],
+ height=D(),
+ ),
+ VSplit(
+ [
+ Frame(body=ProgressBar(), title="Progress bar"),
+ Frame(
+ title="Checkbox list",
+ body=HSplit([checkbox1, checkbox2]),
+ ),
+ Frame(title="Radio list", body=radios),
+ ],
+ padding=1,
+ ),
+ Box(
+ body=VSplit([yes_button, no_button], align="CENTER", padding=3),
+ style="class:button-bar",
+ height=3,
+ ),
+ ]
+)
+
+root_container = MenuContainer(
+ body=root_container,
+ menu_items=[
+ MenuItem(
+ "File",
+ children=[
+ MenuItem("New"),
+ MenuItem(
+ "Open",
+ children=[
+ MenuItem("From file..."),
+ MenuItem("From URL..."),
+ MenuItem(
+ "Something else..",
+ children=[
+ MenuItem("A"),
+ MenuItem("B"),
+ MenuItem("C"),
+ MenuItem("D"),
+ MenuItem("E"),
+ ],
+ ),
+ ],
+ ),
+ MenuItem("Save"),
+ MenuItem("Save as..."),
+ MenuItem("-", disabled=True),
+ MenuItem("Exit", handler=do_exit),
+ ],
+ ),
+ MenuItem(
+ "Edit",
+ children=[
+ MenuItem("Undo"),
+ MenuItem("Cut"),
+ MenuItem("Copy"),
+ MenuItem("Paste"),
+ MenuItem("Delete"),
+ MenuItem("-", disabled=True),
+ MenuItem("Find"),
+ MenuItem("Find next"),
+ MenuItem("Replace"),
+ MenuItem("Go To"),
+ MenuItem("Select All"),
+ MenuItem("Time/Date"),
+ ],
+ ),
+ MenuItem("View", children=[MenuItem("Status Bar")]),
+ MenuItem("Info", children=[MenuItem("About")]),
+ ],
+ floats=[
+ Float(
+ xcursor=True,
+ ycursor=True,
+ content=CompletionsMenu(max_height=16, scroll_offset=1),
+ ),
+ ],
+)
+
+# Global key bindings.
+bindings = KeyBindings()
+bindings.add("tab")(focus_next)
+bindings.add("s-tab")(focus_previous)
+
+
+style = Style.from_dict(
+ {
+ "window.border": "#888888",
+ "shadow": "bg:#222222",
+ "menu-bar": "bg:#aaaaaa #888888",
+ "menu-bar.selected-item": "bg:#ffffff #000000",
+ "menu": "bg:#888888 #ffffff",
+ "menu.border": "#aaaaaa",
+ "window.border shadow": "#444444",
+ "focused button": "bg:#880000 #ffffff noinherit",
+ # Styling for Dialog widgets.
+ "button-bar": "bg:#aaaaff",
+ }
+)
+
+
+application = Application(
+ layout=Layout(root_container, focused_element=yes_button),
+ key_bindings=bindings,
+ style=style,
+ mouse_support=True,
+ full_screen=True,
+)
+
+
+def run():
+ result = application.run()
+ print("You said: %r" % result)
+
+
+if __name__ == "__main__":
+ run()
diff --git a/examples/full-screen/hello-world.py b/examples/full-screen/hello-world.py
new file mode 100755
index 0000000..b818018
--- /dev/null
+++ b/examples/full-screen/hello-world.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+"""
+A simple example of a a text area displaying "Hello World!".
+"""
+from prompt_toolkit.application import Application
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.layout import Layout
+from prompt_toolkit.widgets import Box, Frame, TextArea
+
+# Layout for displaying hello world.
+# (The frame creates the border, the box takes care of the margin/padding.)
+root_container = Box(
+ Frame(
+ TextArea(
+ text="Hello world!\nPress control-c to quit.",
+ width=40,
+ height=10,
+ )
+ ),
+)
+layout = Layout(container=root_container)
+
+
+# Key bindings.
+kb = KeyBindings()
+
+
+@kb.add("c-c")
+def _(event):
+ "Quit when control-c is pressed."
+ event.app.exit()
+
+
+# Build a main application object.
+application = Application(layout=layout, key_bindings=kb, full_screen=True)
+
+
+def main():
+ application.run()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/full-screen/no-layout.py b/examples/full-screen/no-layout.py
new file mode 100644
index 0000000..be5c6f8
--- /dev/null
+++ b/examples/full-screen/no-layout.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+"""
+An empty full screen application without layout.
+"""
+from prompt_toolkit import Application
+
+Application(full_screen=True).run()
diff --git a/examples/full-screen/pager.py b/examples/full-screen/pager.py
new file mode 100755
index 0000000..799c834
--- /dev/null
+++ b/examples/full-screen/pager.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+"""
+A simple application that shows a Pager application.
+"""
+from pygments.lexers.python import PythonLexer
+
+from prompt_toolkit.application import Application
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.layout.containers import HSplit, Window
+from prompt_toolkit.layout.controls import FormattedTextControl
+from prompt_toolkit.layout.dimension import LayoutDimension as D
+from prompt_toolkit.layout.layout import Layout
+from prompt_toolkit.lexers import PygmentsLexer
+from prompt_toolkit.styles import Style
+from prompt_toolkit.widgets import SearchToolbar, TextArea
+
+# Create one text buffer for the main content.
+
+_pager_py_path = __file__
+
+
+with open(_pager_py_path, "rb") as f:
+ text = f.read().decode("utf-8")
+
+
+def get_statusbar_text():
+ return [
+ ("class:status", _pager_py_path + " - "),
+ (
+ "class:status.position",
+ "{}:{}".format(
+ text_area.document.cursor_position_row + 1,
+ text_area.document.cursor_position_col + 1,
+ ),
+ ),
+ ("class:status", " - Press "),
+ ("class:status.key", "Ctrl-C"),
+ ("class:status", " to exit, "),
+ ("class:status.key", "/"),
+ ("class:status", " for searching."),
+ ]
+
+
+search_field = SearchToolbar(
+ text_if_not_searching=[("class:not-searching", "Press '/' to start searching.")]
+)
+
+
+text_area = TextArea(
+ text=text,
+ read_only=True,
+ scrollbar=True,
+ line_numbers=True,
+ search_field=search_field,
+ lexer=PygmentsLexer(PythonLexer),
+)
+
+
+root_container = HSplit(
+ [
+ # The top toolbar.
+ Window(
+ content=FormattedTextControl(get_statusbar_text),
+ height=D.exact(1),
+ style="class:status",
+ ),
+ # The main content.
+ text_area,
+ search_field,
+ ]
+)
+
+
+# Key bindings.
+bindings = KeyBindings()
+
+
+@bindings.add("c-c")
+@bindings.add("q")
+def _(event):
+ "Quit."
+ event.app.exit()
+
+
+style = Style.from_dict(
+ {
+ "status": "reverse",
+ "status.position": "#aaaa00",
+ "status.key": "#ffaa00",
+ "not-searching": "#888888",
+ }
+)
+
+
+# create application.
+application = Application(
+ layout=Layout(root_container, focused_element=text_area),
+ key_bindings=bindings,
+ enable_page_navigation_bindings=True,
+ mouse_support=True,
+ style=style,
+ full_screen=True,
+)
+
+
+def run():
+ application.run()
+
+
+if __name__ == "__main__":
+ run()
diff --git a/examples/full-screen/scrollable-panes/simple-example.py b/examples/full-screen/scrollable-panes/simple-example.py
new file mode 100644
index 0000000..4606479
--- /dev/null
+++ b/examples/full-screen/scrollable-panes/simple-example.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+"""
+A simple example of a scrollable pane.
+"""
+from prompt_toolkit.application import Application
+from prompt_toolkit.application.current import get_app
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.key_binding.bindings.focus import focus_next, focus_previous
+from prompt_toolkit.layout import Dimension, HSplit, Layout, ScrollablePane
+from prompt_toolkit.widgets import Frame, Label, TextArea
+
+
+def main():
+ # Create a big layout of many text areas, then wrap them in a `ScrollablePane`.
+ root_container = Frame(
+ ScrollablePane(
+ HSplit(
+ [
+ Frame(TextArea(text=f"label-{i}"), width=Dimension())
+ for i in range(20)
+ ]
+ )
+ )
+ # ScrollablePane(HSplit([TextArea(text=f"label-{i}") for i in range(20)]))
+ )
+
+ layout = Layout(container=root_container)
+
+ # Key bindings.
+ kb = KeyBindings()
+
+ @kb.add("c-c")
+ def exit(event) -> None:
+ get_app().exit()
+
+ kb.add("tab")(focus_next)
+ kb.add("s-tab")(focus_previous)
+
+ # Create and run application.
+ application = Application(layout=layout, key_bindings=kb, full_screen=True)
+ application.run()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/full-screen/scrollable-panes/with-completion-menu.py b/examples/full-screen/scrollable-panes/with-completion-menu.py
new file mode 100644
index 0000000..fba8d17
--- /dev/null
+++ b/examples/full-screen/scrollable-panes/with-completion-menu.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env python
+"""
+A simple example of a scrollable pane.
+"""
+from prompt_toolkit.application import Application
+from prompt_toolkit.application.current import get_app
+from prompt_toolkit.completion import WordCompleter
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.key_binding.bindings.focus import focus_next, focus_previous
+from prompt_toolkit.layout import (
+ CompletionsMenu,
+ Float,
+ FloatContainer,
+ HSplit,
+ Layout,
+ ScrollablePane,
+ VSplit,
+)
+from prompt_toolkit.widgets import Frame, Label, TextArea
+
+
+def main():
+ # Create a big layout of many text areas, then wrap them in a `ScrollablePane`.
+ root_container = VSplit(
+ [
+ Label("<left column>"),
+ HSplit(
+ [
+ Label("ScrollContainer Demo"),
+ Frame(
+ ScrollablePane(
+ HSplit(
+ [
+ Frame(
+ TextArea(
+ text=f"label-{i}",
+ completer=animal_completer,
+ )
+ )
+ for i in range(20)
+ ]
+ )
+ ),
+ ),
+ ]
+ ),
+ ]
+ )
+
+ root_container = FloatContainer(
+ root_container,
+ floats=[
+ Float(
+ xcursor=True,
+ ycursor=True,
+ content=CompletionsMenu(max_height=16, scroll_offset=1),
+ ),
+ ],
+ )
+
+ layout = Layout(container=root_container)
+
+ # Key bindings.
+ kb = KeyBindings()
+
+ @kb.add("c-c")
+ def exit(event) -> None:
+ get_app().exit()
+
+ kb.add("tab")(focus_next)
+ kb.add("s-tab")(focus_previous)
+
+ # Create and run application.
+ application = Application(
+ layout=layout, key_bindings=kb, full_screen=True, mouse_support=True
+ )
+ application.run()
+
+
+animal_completer = WordCompleter(
+ [
+ "alligator",
+ "ant",
+ "ape",
+ "bat",
+ "bear",
+ "beaver",
+ "bee",
+ "bison",
+ "butterfly",
+ "cat",
+ "chicken",
+ "crocodile",
+ "dinosaur",
+ "dog",
+ "dolphin",
+ "dove",
+ "duck",
+ "eagle",
+ "elephant",
+ "fish",
+ "goat",
+ "gorilla",
+ "kangaroo",
+ "leopard",
+ "lion",
+ "mouse",
+ "rabbit",
+ "rat",
+ "snake",
+ "spider",
+ "turkey",
+ "turtle",
+ ],
+ ignore_case=True,
+)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/full-screen/simple-demos/alignment.py b/examples/full-screen/simple-demos/alignment.py
new file mode 100755
index 0000000..b20b43d
--- /dev/null
+++ b/examples/full-screen/simple-demos/alignment.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+"""
+Demo of the different Window alignment options.
+"""
+from prompt_toolkit.application import Application
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.layout.containers import HSplit, Window, WindowAlign
+from prompt_toolkit.layout.controls import FormattedTextControl
+from prompt_toolkit.layout.layout import Layout
+
+LIPSUM = """Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas
+quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est bibendum
+mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
+dignissim placerat. In vel dictum ex, vulputate accumsan mi. Donec ut quam
+placerat massa tempor elementum. Sed tristique mauris ac suscipit euismod. Ut
+tempus vehicula augue non venenatis. Mauris aliquam velit turpis, nec congue
+risus aliquam sit amet. Pellentesque blandit scelerisque felis, faucibus
+consequat ante. Curabitur tempor tortor a imperdiet tincidunt. Nam sed justo
+sit amet odio bibendum congue. Quisque varius ligula nec ligula gravida, sed
+convallis augue faucibus. Nunc ornare pharetra bibendum. Praesent blandit ex
+quis sodales maximus."""
+
+# 1. The layout
+
+left_text = '\nLeft aligned text. - (Press "q" to quit)\n\n' + LIPSUM
+center_text = "Centered text.\n\n" + LIPSUM
+right_text = "Right aligned text.\n\n" + LIPSUM
+
+
+body = HSplit(
+ [
+ Window(FormattedTextControl(left_text), align=WindowAlign.LEFT),
+ Window(height=1, char="-"),
+ Window(FormattedTextControl(center_text), align=WindowAlign.CENTER),
+ Window(height=1, char="-"),
+ Window(FormattedTextControl(right_text), align=WindowAlign.RIGHT),
+ ]
+)
+
+
+# 2. Key bindings
+kb = KeyBindings()
+
+
+@kb.add("q")
+def _(event):
+ "Quit application."
+ event.app.exit()
+
+
+# 3. The `Application`
+application = Application(layout=Layout(body), key_bindings=kb, full_screen=True)
+
+
+def run():
+ application.run()
+
+
+if __name__ == "__main__":
+ run()
diff --git a/examples/full-screen/simple-demos/autocompletion.py b/examples/full-screen/simple-demos/autocompletion.py
new file mode 100755
index 0000000..bcbb594
--- /dev/null
+++ b/examples/full-screen/simple-demos/autocompletion.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+"""
+An example of a BufferControl in a full screen layout that offers auto
+completion.
+
+Important is to make sure that there is a `CompletionsMenu` in the layout,
+otherwise the completions won't be visible.
+"""
+from prompt_toolkit.application import Application
+from prompt_toolkit.buffer import Buffer
+from prompt_toolkit.completion import WordCompleter
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.layout.containers import Float, FloatContainer, HSplit, Window
+from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
+from prompt_toolkit.layout.layout import Layout
+from prompt_toolkit.layout.menus import CompletionsMenu
+
+# The completer.
+animal_completer = WordCompleter(
+ [
+ "alligator",
+ "ant",
+ "ape",
+ "bat",
+ "bear",
+ "beaver",
+ "bee",
+ "bison",
+ "butterfly",
+ "cat",
+ "chicken",
+ "crocodile",
+ "dinosaur",
+ "dog",
+ "dolphin",
+ "dove",
+ "duck",
+ "eagle",
+ "elephant",
+ "fish",
+ "goat",
+ "gorilla",
+ "kangaroo",
+ "leopard",
+ "lion",
+ "mouse",
+ "rabbit",
+ "rat",
+ "snake",
+ "spider",
+ "turkey",
+ "turtle",
+ ],
+ ignore_case=True,
+)
+
+
+# The layout
+buff = Buffer(completer=animal_completer, complete_while_typing=True)
+
+body = FloatContainer(
+ content=HSplit(
+ [
+ Window(
+ FormattedTextControl('Press "q" to quit.'), height=1, style="reverse"
+ ),
+ Window(BufferControl(buffer=buff)),
+ ]
+ ),
+ floats=[
+ Float(
+ xcursor=True,
+ ycursor=True,
+ content=CompletionsMenu(max_height=16, scroll_offset=1),
+ )
+ ],
+)
+
+
+# Key bindings
+kb = KeyBindings()
+
+
+@kb.add("q")
+@kb.add("c-c")
+def _(event):
+ "Quit application."
+ event.app.exit()
+
+
+# The `Application`
+application = Application(layout=Layout(body), key_bindings=kb, full_screen=True)
+
+
+def run():
+ application.run()
+
+
+if __name__ == "__main__":
+ run()
diff --git a/examples/full-screen/simple-demos/colorcolumn.py b/examples/full-screen/simple-demos/colorcolumn.py
new file mode 100755
index 0000000..054aa44
--- /dev/null
+++ b/examples/full-screen/simple-demos/colorcolumn.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+"""
+Colorcolumn example.
+"""
+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 ColorColumn, HSplit, Window
+from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
+from prompt_toolkit.layout.layout import Layout
+
+LIPSUM = """
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas
+quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est bibendum
+mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
+dignissim placerat. In vel dictum ex, vulputate accumsan mi. Donec ut quam
+placerat massa tempor elementum. Sed tristique mauris ac suscipit euismod. Ut
+tempus vehicula augue non venenatis. Mauris aliquam velit turpis, nec congue
+risus aliquam sit amet. Pellentesque blandit scelerisque felis, faucibus
+consequat ante. Curabitur tempor tortor a imperdiet tincidunt. Nam sed justo
+sit amet odio bibendum congue. Quisque varius ligula nec ligula gravida, sed
+convallis augue faucibus. Nunc ornare pharetra bibendum. Praesent blandit ex
+quis sodales maximus."""
+
+# Create text buffers.
+buff = Buffer()
+buff.text = LIPSUM
+
+# 1. The layout
+color_columns = [
+ ColorColumn(50),
+ ColorColumn(80, style="bg:#ff0000"),
+ ColorColumn(10, style="bg:#ff0000"),
+]
+
+body = HSplit(
+ [
+ Window(FormattedTextControl('Press "q" to quit.'), height=1, style="reverse"),
+ Window(BufferControl(buffer=buff), colorcolumns=color_columns),
+ ]
+)
+
+
+# 2. Key bindings
+kb = KeyBindings()
+
+
+@kb.add("q")
+def _(event):
+ "Quit application."
+ event.app.exit()
+
+
+# 3. The `Application`
+application = Application(layout=Layout(body), key_bindings=kb, full_screen=True)
+
+
+def run():
+ application.run()
+
+
+if __name__ == "__main__":
+ run()
diff --git a/examples/full-screen/simple-demos/cursorcolumn-cursorline.py b/examples/full-screen/simple-demos/cursorcolumn-cursorline.py
new file mode 100755
index 0000000..505b3ee
--- /dev/null
+++ b/examples/full-screen/simple-demos/cursorcolumn-cursorline.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+"""
+Cursorcolumn / cursorline example.
+"""
+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, Window
+from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
+from prompt_toolkit.layout.layout import Layout
+
+LIPSUM = """
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas
+quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est bibendum
+mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
+dignissim placerat. In vel dictum ex, vulputate accumsan mi. Donec ut quam
+placerat massa tempor elementum. Sed tristique mauris ac suscipit euismod. Ut
+tempus vehicula augue non venenatis. Mauris aliquam velit turpis, nec congue
+risus aliquam sit amet. Pellentesque blandit scelerisque felis, faucibus
+consequat ante. Curabitur tempor tortor a imperdiet tincidunt. Nam sed justo
+sit amet odio bibendum congue. Quisque varius ligula nec ligula gravida, sed
+convallis augue faucibus. Nunc ornare pharetra bibendum. Praesent blandit ex
+quis sodales maximus."""
+
+# Create text buffers. Cursorcolumn/cursorline are mostly combined with an
+# (editable) text buffers, where the user can move the cursor.
+
+buff = Buffer()
+buff.text = LIPSUM
+
+# 1. The layout
+body = HSplit(
+ [
+ Window(FormattedTextControl('Press "q" to quit.'), height=1, style="reverse"),
+ Window(BufferControl(buffer=buff), cursorcolumn=True, cursorline=True),
+ ]
+)
+
+
+# 2. Key bindings
+kb = KeyBindings()
+
+
+@kb.add("q")
+def _(event):
+ "Quit application."
+ event.app.exit()
+
+
+# 3. The `Application`
+application = Application(layout=Layout(body), key_bindings=kb, full_screen=True)
+
+
+def run():
+ application.run()
+
+
+if __name__ == "__main__":
+ run()
diff --git a/examples/full-screen/simple-demos/float-transparency.py b/examples/full-screen/simple-demos/float-transparency.py
new file mode 100755
index 0000000..4dc38fc
--- /dev/null
+++ b/examples/full-screen/simple-demos/float-transparency.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+"""
+Example of the 'transparency' attribute of `Window' when used in a Float.
+"""
+from prompt_toolkit.application import Application
+from prompt_toolkit.formatted_text import HTML
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.layout.containers import Float, FloatContainer, Window
+from prompt_toolkit.layout.controls import FormattedTextControl
+from prompt_toolkit.layout.layout import Layout
+from prompt_toolkit.widgets import Frame
+
+LIPSUM = " ".join(
+ (
+ """Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+Maecenas quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est
+bibendum mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
+dignissim placerat. In vel dictum ex, vulputate accumsan mi. Donec ut quam
+placerat massa tempor elementum. Sed tristique mauris ac suscipit euismod. Ut
+tempus vehicula augue non venenatis. Mauris aliquam velit turpis, nec congue
+risus aliquam sit amet. Pellentesque blandit scelerisque felis, faucibus
+consequat ante. Curabitur tempor tortor a imperdiet tincidunt. Nam sed justo
+sit amet odio bibendum congue. Quisque varius ligula nec ligula gravida, sed
+convallis augue faucibus. Nunc ornare pharetra bibendum. Praesent blandit ex
+quis sodales maximus. """
+ * 100
+ ).split()
+)
+
+
+# 1. The layout
+left_text = HTML("<reverse>transparent=False</reverse>\n")
+right_text = HTML("<reverse>transparent=True</reverse>")
+quit_text = "Press 'q' to quit."
+
+
+body = FloatContainer(
+ content=Window(FormattedTextControl(LIPSUM), wrap_lines=True),
+ floats=[
+ # Important note: Wrapping the floating objects in a 'Frame' is
+ # only required for drawing the border around the
+ # floating text. We do it here to make the layout more
+ # obvious.
+ # Left float.
+ Float(
+ Frame(Window(FormattedTextControl(left_text), width=20, height=4)),
+ transparent=False,
+ left=0,
+ ),
+ # Right float.
+ Float(
+ Frame(Window(FormattedTextControl(right_text), width=20, height=4)),
+ transparent=True,
+ right=0,
+ ),
+ # Quit text.
+ Float(
+ Frame(
+ Window(FormattedTextControl(quit_text), width=18, height=1),
+ style="bg:#ff44ff #ffffff",
+ ),
+ top=1,
+ ),
+ ],
+)
+
+
+# 2. Key bindings
+kb = KeyBindings()
+
+
+@kb.add("q")
+def _(event):
+ "Quit application."
+ event.app.exit()
+
+
+# 3. The `Application`
+application = Application(layout=Layout(body), key_bindings=kb, full_screen=True)
+
+
+def run():
+ application.run()
+
+
+if __name__ == "__main__":
+ run()
diff --git a/examples/full-screen/simple-demos/floats.py b/examples/full-screen/simple-demos/floats.py
new file mode 100755
index 0000000..0d45be9
--- /dev/null
+++ b/examples/full-screen/simple-demos/floats.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python
+"""
+Horizontal split example.
+"""
+from prompt_toolkit.application import Application
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.layout.containers import Float, FloatContainer, Window
+from prompt_toolkit.layout.controls import FormattedTextControl
+from prompt_toolkit.layout.layout import Layout
+from prompt_toolkit.widgets import Frame
+
+LIPSUM = " ".join(
+ (
+ """Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+Maecenas quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est
+bibendum mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
+dignissim placerat. In vel dictum ex, vulputate accumsan mi. Donec ut quam
+placerat massa tempor elementum. Sed tristique mauris ac suscipit euismod. Ut
+tempus vehicula augue non venenatis. Mauris aliquam velit turpis, nec congue
+risus aliquam sit amet. Pellentesque blandit scelerisque felis, faucibus
+consequat ante. Curabitur tempor tortor a imperdiet tincidunt. Nam sed justo
+sit amet odio bibendum congue. Quisque varius ligula nec ligula gravida, sed
+convallis augue faucibus. Nunc ornare pharetra bibendum. Praesent blandit ex
+quis sodales maximus. """
+ * 100
+ ).split()
+)
+
+
+# 1. The layout
+left_text = "Floating\nleft"
+right_text = "Floating\nright"
+top_text = "Floating\ntop"
+bottom_text = "Floating\nbottom"
+center_text = "Floating\ncenter"
+quit_text = "Press 'q' to quit."
+
+
+body = FloatContainer(
+ content=Window(FormattedTextControl(LIPSUM), wrap_lines=True),
+ floats=[
+ # Important note: Wrapping the floating objects in a 'Frame' is
+ # only required for drawing the border around the
+ # floating text. We do it here to make the layout more
+ # obvious.
+ # Left float.
+ Float(
+ Frame(
+ Window(FormattedTextControl(left_text), width=10, height=2),
+ style="bg:#44ffff #ffffff",
+ ),
+ left=0,
+ ),
+ # Right float.
+ Float(
+ Frame(
+ Window(FormattedTextControl(right_text), width=10, height=2),
+ style="bg:#44ffff #ffffff",
+ ),
+ right=0,
+ ),
+ # Bottom float.
+ Float(
+ Frame(
+ Window(FormattedTextControl(bottom_text), width=10, height=2),
+ style="bg:#44ffff #ffffff",
+ ),
+ bottom=0,
+ ),
+ # Top float.
+ Float(
+ Frame(
+ Window(FormattedTextControl(top_text), width=10, height=2),
+ style="bg:#44ffff #ffffff",
+ ),
+ top=0,
+ ),
+ # Center float.
+ Float(
+ Frame(
+ Window(FormattedTextControl(center_text), width=10, height=2),
+ style="bg:#44ffff #ffffff",
+ )
+ ),
+ # Quit text.
+ Float(
+ Frame(
+ Window(FormattedTextControl(quit_text), width=18, height=1),
+ style="bg:#ff44ff #ffffff",
+ ),
+ top=6,
+ ),
+ ],
+)
+
+
+# 2. Key bindings
+kb = KeyBindings()
+
+
+@kb.add("q")
+def _(event):
+ "Quit application."
+ event.app.exit()
+
+
+# 3. The `Application`
+application = Application(layout=Layout(body), key_bindings=kb, full_screen=True)
+
+
+def run():
+ application.run()
+
+
+if __name__ == "__main__":
+ run()
diff --git a/examples/full-screen/simple-demos/focus.py b/examples/full-screen/simple-demos/focus.py
new file mode 100755
index 0000000..9fe9b8f
--- /dev/null
+++ b/examples/full-screen/simple-demos/focus.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+"""
+Demonstration of how to programmatically focus a certain widget.
+"""
+from prompt_toolkit.application import Application
+from prompt_toolkit.buffer import Buffer
+from prompt_toolkit.document import Document
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.layout.containers import HSplit, VSplit, Window
+from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
+from prompt_toolkit.layout.layout import Layout
+
+# 1. The layout
+top_text = (
+ "Focus example.\n"
+ "[q] Quit [a] Focus left top [b] Right top [c] Left bottom [d] Right bottom."
+)
+
+LIPSUM = """Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+Maecenas quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est
+bibendum mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
+dignissim placerat. In vel dictum ex, vulputate accumsan mi. Donec ut quam
+placerat massa tempor elementum. Sed tristique mauris ac suscipit euismod. Ut
+tempus vehicula augue non venenatis. Mauris aliquam velit turpis, nec congue
+risus aliquam sit amet. Pellentesque blandit scelerisque felis, faucibus
+consequat ante. Curabitur tempor tortor a imperdiet tincidunt. Nam sed justo
+sit amet odio bibendum congue. Quisque varius ligula nec ligula gravida, sed
+convallis augue faucibus. Nunc ornare pharetra bibendum. Praesent blandit ex
+quis sodales maximus. """
+
+
+left_top = Window(BufferControl(Buffer(document=Document(LIPSUM))))
+left_bottom = Window(BufferControl(Buffer(document=Document(LIPSUM))))
+right_top = Window(BufferControl(Buffer(document=Document(LIPSUM))))
+right_bottom = Window(BufferControl(Buffer(document=Document(LIPSUM))))
+
+
+body = HSplit(
+ [
+ Window(FormattedTextControl(top_text), height=2, style="reverse"),
+ Window(height=1, char="-"), # Horizontal line in the middle.
+ VSplit([left_top, Window(width=1, char="|"), right_top]),
+ Window(height=1, char="-"), # Horizontal line in the middle.
+ VSplit([left_bottom, Window(width=1, char="|"), right_bottom]),
+ ]
+)
+
+
+# 2. Key bindings
+kb = KeyBindings()
+
+
+@kb.add("q")
+def _(event):
+ "Quit application."
+ event.app.exit()
+
+
+@kb.add("a")
+def _(event):
+ event.app.layout.focus(left_top)
+
+
+@kb.add("b")
+def _(event):
+ event.app.layout.focus(right_top)
+
+
+@kb.add("c")
+def _(event):
+ event.app.layout.focus(left_bottom)
+
+
+@kb.add("d")
+def _(event):
+ event.app.layout.focus(right_bottom)
+
+
+@kb.add("tab")
+def _(event):
+ event.app.layout.focus_next()
+
+
+@kb.add("s-tab")
+def _(event):
+ event.app.layout.focus_previous()
+
+
+# 3. The `Application`
+application = Application(layout=Layout(body), key_bindings=kb, full_screen=True)
+
+
+def run():
+ application.run()
+
+
+if __name__ == "__main__":
+ run()
diff --git a/examples/full-screen/simple-demos/horizontal-align.py b/examples/full-screen/simple-demos/horizontal-align.py
new file mode 100755
index 0000000..f50b9e8
--- /dev/null
+++ b/examples/full-screen/simple-demos/horizontal-align.py
@@ -0,0 +1,209 @@
+#!/usr/bin/env python
+"""
+Horizontal align demo with HSplit.
+"""
+from prompt_toolkit.application import Application
+from prompt_toolkit.formatted_text import HTML
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.layout.containers import (
+ HorizontalAlign,
+ HSplit,
+ VerticalAlign,
+ VSplit,
+ Window,
+ WindowAlign,
+)
+from prompt_toolkit.layout.controls import FormattedTextControl
+from prompt_toolkit.layout.dimension import D
+from prompt_toolkit.layout.layout import Layout
+from prompt_toolkit.widgets import Frame
+
+TITLE = HTML(
+ """ <u>HSplit HorizontalAlign</u> example.
+ Press <b>'q'</b> to quit."""
+)
+
+LIPSUM = """\
+Lorem ipsum dolor
+sit amet, consectetur
+adipiscing elit.
+Maecenas quis
+interdum enim."""
+
+
+# 1. The layout
+body = HSplit(
+ [
+ Frame(
+ Window(FormattedTextControl(TITLE), height=2), style="bg:#88ff88 #000000"
+ ),
+ HSplit(
+ [
+ # Left alignment.
+ VSplit(
+ [
+ Window(
+ FormattedTextControl(HTML("<u>LEFT</u>")),
+ width=10,
+ ignore_content_width=True,
+ style="bg:#ff3333 ansiblack",
+ align=WindowAlign.CENTER,
+ ),
+ VSplit(
+ [
+ Window(
+ FormattedTextControl(LIPSUM),
+ height=4,
+ style="bg:#444488",
+ ),
+ Window(
+ FormattedTextControl(LIPSUM),
+ height=4,
+ style="bg:#444488",
+ ),
+ Window(
+ FormattedTextControl(LIPSUM),
+ height=4,
+ style="bg:#444488",
+ ),
+ ],
+ padding=1,
+ padding_style="bg:#888888",
+ align=HorizontalAlign.LEFT,
+ height=5,
+ padding_char="|",
+ ),
+ ]
+ ),
+ # Center alignment.
+ VSplit(
+ [
+ Window(
+ FormattedTextControl(HTML("<u>CENTER</u>")),
+ width=10,
+ ignore_content_width=True,
+ style="bg:#ff3333 ansiblack",
+ align=WindowAlign.CENTER,
+ ),
+ VSplit(
+ [
+ Window(
+ FormattedTextControl(LIPSUM),
+ height=4,
+ style="bg:#444488",
+ ),
+ Window(
+ FormattedTextControl(LIPSUM),
+ height=4,
+ style="bg:#444488",
+ ),
+ Window(
+ FormattedTextControl(LIPSUM),
+ height=4,
+ style="bg:#444488",
+ ),
+ ],
+ padding=1,
+ padding_style="bg:#888888",
+ align=HorizontalAlign.CENTER,
+ height=5,
+ padding_char="|",
+ ),
+ ]
+ ),
+ # Right alignment.
+ VSplit(
+ [
+ Window(
+ FormattedTextControl(HTML("<u>RIGHT</u>")),
+ width=10,
+ ignore_content_width=True,
+ style="bg:#ff3333 ansiblack",
+ align=WindowAlign.CENTER,
+ ),
+ VSplit(
+ [
+ Window(
+ FormattedTextControl(LIPSUM),
+ height=4,
+ style="bg:#444488",
+ ),
+ Window(
+ FormattedTextControl(LIPSUM),
+ height=4,
+ style="bg:#444488",
+ ),
+ Window(
+ FormattedTextControl(LIPSUM),
+ height=4,
+ style="bg:#444488",
+ ),
+ ],
+ padding=1,
+ padding_style="bg:#888888",
+ align=HorizontalAlign.RIGHT,
+ height=5,
+ padding_char="|",
+ ),
+ ]
+ ),
+ # Justify
+ VSplit(
+ [
+ Window(
+ FormattedTextControl(HTML("<u>JUSTIFY</u>")),
+ width=10,
+ ignore_content_width=True,
+ style="bg:#ff3333 ansiblack",
+ align=WindowAlign.CENTER,
+ ),
+ VSplit(
+ [
+ Window(
+ FormattedTextControl(LIPSUM), style="bg:#444488"
+ ),
+ Window(
+ FormattedTextControl(LIPSUM), style="bg:#444488"
+ ),
+ Window(
+ FormattedTextControl(LIPSUM), style="bg:#444488"
+ ),
+ ],
+ padding=1,
+ padding_style="bg:#888888",
+ align=HorizontalAlign.JUSTIFY,
+ height=5,
+ padding_char="|",
+ ),
+ ]
+ ),
+ ],
+ padding=1,
+ padding_style="bg:#ff3333 #ffffff",
+ padding_char=".",
+ align=VerticalAlign.TOP,
+ ),
+ ]
+)
+
+
+# 2. Key bindings
+kb = KeyBindings()
+
+
+@kb.add("q")
+def _(event):
+ "Quit application."
+ event.app.exit()
+
+
+# 3. The `Application`
+application = Application(layout=Layout(body), key_bindings=kb, full_screen=True)
+
+
+def run():
+ application.run()
+
+
+if __name__ == "__main__":
+ run()
diff --git a/examples/full-screen/simple-demos/horizontal-split.py b/examples/full-screen/simple-demos/horizontal-split.py
new file mode 100755
index 0000000..0427e67
--- /dev/null
+++ b/examples/full-screen/simple-demos/horizontal-split.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+"""
+Horizontal split example.
+"""
+from prompt_toolkit.application import Application
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.layout.containers import HSplit, Window
+from prompt_toolkit.layout.controls import FormattedTextControl
+from prompt_toolkit.layout.layout import Layout
+
+# 1. The layout
+left_text = "\nVertical-split example. Press 'q' to quit.\n\n(top pane.)"
+right_text = "\n(bottom pane.)"
+
+
+body = HSplit(
+ [
+ Window(FormattedTextControl(left_text)),
+ Window(height=1, char="-"), # Horizontal line in the middle.
+ Window(FormattedTextControl(right_text)),
+ ]
+)
+
+
+# 2. Key bindings
+kb = KeyBindings()
+
+
+@kb.add("q")
+def _(event):
+ "Quit application."
+ event.app.exit()
+
+
+# 3. The `Application`
+application = Application(layout=Layout(body), key_bindings=kb, full_screen=True)
+
+
+def run():
+ application.run()
+
+
+if __name__ == "__main__":
+ run()
diff --git a/examples/full-screen/simple-demos/line-prefixes.py b/examples/full-screen/simple-demos/line-prefixes.py
new file mode 100755
index 0000000..ab47ef6
--- /dev/null
+++ b/examples/full-screen/simple-demos/line-prefixes.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+"""
+An example of a BufferControl in a full screen layout that offers auto
+completion.
+
+Important is to make sure that there is a `CompletionsMenu` in the layout,
+otherwise the completions won't be visible.
+"""
+from prompt_toolkit.application import Application
+from prompt_toolkit.buffer import Buffer
+from prompt_toolkit.completion import WordCompleter
+from prompt_toolkit.filters import Condition
+from prompt_toolkit.formatted_text import HTML
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.layout.containers import Float, FloatContainer, HSplit, Window
+from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
+from prompt_toolkit.layout.layout import Layout
+from prompt_toolkit.layout.menus import CompletionsMenu
+
+LIPSUM = """
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas
+quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est bibendum
+mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
+dignissim placerat. In vel dictum ex, vulputate accumsan mi. Donec ut quam
+placerat massa tempor elementum. Sed tristique mauris ac suscipit euismod. Ut
+tempus vehicula augue non venenatis. Mauris aliquam velit turpis, nec congue
+risus aliquam sit amet. Pellentesque blandit scelerisque felis, faucibus
+consequat ante. Curabitur tempor tortor a imperdiet tincidunt. Nam sed justo
+sit amet odio bibendum congue. Quisque varius ligula nec ligula gravida, sed
+convallis augue faucibus. Nunc ornare pharetra bibendum. Praesent blandit ex
+quis sodales maximus."""
+
+
+def get_line_prefix(lineno, wrap_count):
+ if wrap_count == 0:
+ return HTML('[%s] <style bg="orange" fg="black">--&gt;</style> ') % lineno
+
+ text = str(lineno) + "-" + "*" * (lineno // 2) + ": "
+ return HTML('[%s.%s] <style bg="ansigreen" fg="ansiblack">%s</style>') % (
+ lineno,
+ wrap_count,
+ text,
+ )
+
+
+# Global wrap lines flag.
+wrap_lines = True
+
+
+# The layout
+buff = Buffer(complete_while_typing=True)
+buff.text = LIPSUM
+
+
+body = FloatContainer(
+ content=HSplit(
+ [
+ Window(
+ FormattedTextControl(
+ 'Press "q" to quit. Press "w" to enable/disable wrapping.'
+ ),
+ height=1,
+ style="reverse",
+ ),
+ Window(
+ BufferControl(buffer=buff),
+ get_line_prefix=get_line_prefix,
+ wrap_lines=Condition(lambda: wrap_lines),
+ ),
+ ]
+ ),
+ floats=[
+ Float(
+ xcursor=True,
+ ycursor=True,
+ content=CompletionsMenu(max_height=16, scroll_offset=1),
+ )
+ ],
+)
+
+
+# Key bindings
+kb = KeyBindings()
+
+
+@kb.add("q")
+@kb.add("c-c")
+def _(event):
+ "Quit application."
+ event.app.exit()
+
+
+@kb.add("w")
+def _(event):
+ "Disable/enable wrapping."
+ global wrap_lines
+ wrap_lines = not wrap_lines
+
+
+# The `Application`
+application = Application(
+ layout=Layout(body), key_bindings=kb, full_screen=True, mouse_support=True
+)
+
+
+def run():
+ application.run()
+
+
+if __name__ == "__main__":
+ run()
diff --git a/examples/full-screen/simple-demos/margins.py b/examples/full-screen/simple-demos/margins.py
new file mode 100755
index 0000000..467492d
--- /dev/null
+++ b/examples/full-screen/simple-demos/margins.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+"""
+Example of Window margins.
+
+This is mainly used for displaying line numbers and scroll bars, but it could
+be used to display any other kind of information as well.
+"""
+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, Window
+from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
+from prompt_toolkit.layout.layout import Layout
+from prompt_toolkit.layout.margins import NumberedMargin, ScrollbarMargin
+
+LIPSUM = (
+ """
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas
+quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est bibendum
+mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
+dignissim placerat. In vel dictum ex, vulputate accumsan mi. Donec ut quam
+placerat massa tempor elementum. Sed tristique mauris ac suscipit euismod. Ut
+tempus vehicula augue non venenatis. Mauris aliquam velit turpis, nec congue
+risus aliquam sit amet. Pellentesque blandit scelerisque felis, faucibus
+consequat ante. Curabitur tempor tortor a imperdiet tincidunt. Nam sed justo
+sit amet odio bibendum congue. Quisque varius ligula nec ligula gravida, sed
+convallis augue faucibus. Nunc ornare pharetra bibendum. Praesent blandit ex
+quis sodales maximus."""
+ * 40
+)
+
+# Create text buffers. The margins will update if you scroll up or down.
+
+buff = Buffer()
+buff.text = LIPSUM
+
+# 1. The layout
+body = HSplit(
+ [
+ Window(FormattedTextControl('Press "q" to quit.'), height=1, style="reverse"),
+ Window(
+ BufferControl(buffer=buff),
+ # Add margins.
+ left_margins=[NumberedMargin(), ScrollbarMargin()],
+ right_margins=[ScrollbarMargin(), ScrollbarMargin()],
+ ),
+ ]
+)
+
+
+# 2. Key bindings
+kb = KeyBindings()
+
+
+@kb.add("q")
+@kb.add("c-c")
+def _(event):
+ "Quit application."
+ event.app.exit()
+
+
+# 3. The `Application`
+application = Application(layout=Layout(body), key_bindings=kb, full_screen=True)
+
+
+def run():
+ application.run()
+
+
+if __name__ == "__main__":
+ run()
diff --git a/examples/full-screen/simple-demos/vertical-align.py b/examples/full-screen/simple-demos/vertical-align.py
new file mode 100755
index 0000000..824695e
--- /dev/null
+++ b/examples/full-screen/simple-demos/vertical-align.py
@@ -0,0 +1,168 @@
+#!/usr/bin/env python
+"""
+Vertical align demo with VSplit.
+"""
+from prompt_toolkit.application import Application
+from prompt_toolkit.formatted_text import HTML
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.layout.containers import (
+ HSplit,
+ VerticalAlign,
+ VSplit,
+ Window,
+ WindowAlign,
+)
+from prompt_toolkit.layout.controls import FormattedTextControl
+from prompt_toolkit.layout.dimension import D
+from prompt_toolkit.layout.layout import Layout
+from prompt_toolkit.widgets import Frame
+
+TITLE = HTML(
+ """ <u>VSplit VerticalAlign</u> example.
+ Press <b>'q'</b> to quit."""
+)
+
+LIPSUM = """
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas
+quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est bibendum
+mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
+dignissim placerat."""
+
+# 1. The layout
+body = HSplit(
+ [
+ Frame(
+ Window(FormattedTextControl(TITLE), height=2), style="bg:#88ff88 #000000"
+ ),
+ VSplit(
+ [
+ Window(
+ FormattedTextControl(HTML(" <u>VerticalAlign.TOP</u>")),
+ height=4,
+ ignore_content_width=True,
+ style="bg:#ff3333 #000000 bold",
+ align=WindowAlign.CENTER,
+ ),
+ Window(
+ FormattedTextControl(HTML(" <u>VerticalAlign.CENTER</u>")),
+ height=4,
+ ignore_content_width=True,
+ style="bg:#ff3333 #000000 bold",
+ align=WindowAlign.CENTER,
+ ),
+ Window(
+ FormattedTextControl(HTML(" <u>VerticalAlign.BOTTOM</u>")),
+ height=4,
+ ignore_content_width=True,
+ style="bg:#ff3333 #000000 bold",
+ align=WindowAlign.CENTER,
+ ),
+ Window(
+ FormattedTextControl(HTML(" <u>VerticalAlign.JUSTIFY</u>")),
+ height=4,
+ ignore_content_width=True,
+ style="bg:#ff3333 #000000 bold",
+ align=WindowAlign.CENTER,
+ ),
+ ],
+ height=1,
+ padding=1,
+ padding_style="bg:#ff3333",
+ ),
+ VSplit(
+ [
+ # Top alignment.
+ HSplit(
+ [
+ Window(
+ FormattedTextControl(LIPSUM), height=4, style="bg:#444488"
+ ),
+ Window(
+ FormattedTextControl(LIPSUM), height=4, style="bg:#444488"
+ ),
+ Window(
+ FormattedTextControl(LIPSUM), height=4, style="bg:#444488"
+ ),
+ ],
+ padding=1,
+ padding_style="bg:#888888",
+ align=VerticalAlign.TOP,
+ padding_char="~",
+ ),
+ # Center alignment.
+ HSplit(
+ [
+ Window(
+ FormattedTextControl(LIPSUM), height=4, style="bg:#444488"
+ ),
+ Window(
+ FormattedTextControl(LIPSUM), height=4, style="bg:#444488"
+ ),
+ Window(
+ FormattedTextControl(LIPSUM), height=4, style="bg:#444488"
+ ),
+ ],
+ padding=1,
+ padding_style="bg:#888888",
+ align=VerticalAlign.CENTER,
+ padding_char="~",
+ ),
+ # Bottom alignment.
+ HSplit(
+ [
+ Window(
+ FormattedTextControl(LIPSUM), height=4, style="bg:#444488"
+ ),
+ Window(
+ FormattedTextControl(LIPSUM), height=4, style="bg:#444488"
+ ),
+ Window(
+ FormattedTextControl(LIPSUM), height=4, style="bg:#444488"
+ ),
+ ],
+ padding=1,
+ padding_style="bg:#888888",
+ align=VerticalAlign.BOTTOM,
+ padding_char="~",
+ ),
+ # Justify
+ HSplit(
+ [
+ Window(FormattedTextControl(LIPSUM), style="bg:#444488"),
+ Window(FormattedTextControl(LIPSUM), style="bg:#444488"),
+ Window(FormattedTextControl(LIPSUM), style="bg:#444488"),
+ ],
+ padding=1,
+ padding_style="bg:#888888",
+ align=VerticalAlign.JUSTIFY,
+ padding_char="~",
+ ),
+ ],
+ padding=1,
+ padding_style="bg:#ff3333 #ffffff",
+ padding_char=".",
+ ),
+ ]
+)
+
+
+# 2. Key bindings
+kb = KeyBindings()
+
+
+@kb.add("q")
+def _(event):
+ "Quit application."
+ event.app.exit()
+
+
+# 3. The `Application`
+application = Application(layout=Layout(body), key_bindings=kb, full_screen=True)
+
+
+def run():
+ application.run()
+
+
+if __name__ == "__main__":
+ run()
diff --git a/examples/full-screen/simple-demos/vertical-split.py b/examples/full-screen/simple-demos/vertical-split.py
new file mode 100755
index 0000000..b48d106
--- /dev/null
+++ b/examples/full-screen/simple-demos/vertical-split.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+"""
+Vertical split example.
+"""
+from prompt_toolkit.application import Application
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.layout.containers import VSplit, Window
+from prompt_toolkit.layout.controls import FormattedTextControl
+from prompt_toolkit.layout.layout import Layout
+
+# 1. The layout
+left_text = "\nVertical-split example. Press 'q' to quit.\n\n(left pane.)"
+right_text = "\n(right pane.)"
+
+
+body = VSplit(
+ [
+ Window(FormattedTextControl(left_text)),
+ Window(width=1, char="|"), # Vertical line in the middle.
+ Window(FormattedTextControl(right_text)),
+ ]
+)
+
+
+# 2. Key bindings
+kb = KeyBindings()
+
+
+@kb.add("q")
+def _(event):
+ "Quit application."
+ event.app.exit()
+
+
+# 3. The `Application`
+application = Application(layout=Layout(body), key_bindings=kb, full_screen=True)
+
+
+def run():
+ application.run()
+
+
+if __name__ == "__main__":
+ run()
diff --git a/examples/full-screen/split-screen.py b/examples/full-screen/split-screen.py
new file mode 100755
index 0000000..fd654fb
--- /dev/null
+++ b/examples/full-screen/split-screen.py
@@ -0,0 +1,156 @@
+#!/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, Window, WindowAlign
+from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
+from prompt_toolkit.layout.layout import Layout
+
+# 3. Create the buffers
+# ------------------
+
+left_buffer = Buffer()
+right_buffer = Buffer()
+
+# 1. First we create the layout
+# --------------------------
+
+left_window = Window(BufferControl(buffer=left_buffer))
+right_window = Window(BufferControl(buffer=right_buffer))
+
+
+body = VSplit(
+ [
+ left_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(width=1, char="|", style="class:line"),
+ # Display the Result buffer on the right.
+ right_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=left_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()
diff --git a/examples/full-screen/text-editor.py b/examples/full-screen/text-editor.py
new file mode 100755
index 0000000..9c0a414
--- /dev/null
+++ b/examples/full-screen/text-editor.py
@@ -0,0 +1,383 @@
+#!/usr/bin/env python
+"""
+A simple example of a Notepad-like text editor.
+"""
+import datetime
+from asyncio import Future, ensure_future
+
+from prompt_toolkit.application import Application
+from prompt_toolkit.application.current import get_app
+from prompt_toolkit.completion import PathCompleter
+from prompt_toolkit.filters import Condition
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.layout.containers import (
+ ConditionalContainer,
+ Float,
+ HSplit,
+ VSplit,
+ Window,
+ WindowAlign,
+)
+from prompt_toolkit.layout.controls import FormattedTextControl
+from prompt_toolkit.layout.dimension import D
+from prompt_toolkit.layout.layout import Layout
+from prompt_toolkit.layout.menus import CompletionsMenu
+from prompt_toolkit.lexers import DynamicLexer, PygmentsLexer
+from prompt_toolkit.search import start_search
+from prompt_toolkit.styles import Style
+from prompt_toolkit.widgets import (
+ Button,
+ Dialog,
+ Label,
+ MenuContainer,
+ MenuItem,
+ SearchToolbar,
+ TextArea,
+)
+
+
+class ApplicationState:
+ """
+ Application state.
+
+ For the simplicity, we store this as a global, but better would be to
+ instantiate this as an object and pass at around.
+ """
+
+ show_status_bar = True
+ current_path = None
+
+
+def get_statusbar_text():
+ return " Press Ctrl-C to open menu. "
+
+
+def get_statusbar_right_text():
+ return " {}:{} ".format(
+ text_field.document.cursor_position_row + 1,
+ text_field.document.cursor_position_col + 1,
+ )
+
+
+search_toolbar = SearchToolbar()
+text_field = TextArea(
+ lexer=DynamicLexer(
+ lambda: PygmentsLexer.from_filename(
+ ApplicationState.current_path or ".txt", sync_from_start=False
+ )
+ ),
+ scrollbar=True,
+ line_numbers=True,
+ search_field=search_toolbar,
+)
+
+
+class TextInputDialog:
+ def __init__(self, title="", label_text="", completer=None):
+ self.future = Future()
+
+ def accept_text(buf):
+ get_app().layout.focus(ok_button)
+ buf.complete_state = None
+ return True
+
+ def accept():
+ self.future.set_result(self.text_area.text)
+
+ def cancel():
+ self.future.set_result(None)
+
+ self.text_area = TextArea(
+ completer=completer,
+ multiline=False,
+ width=D(preferred=40),
+ accept_handler=accept_text,
+ )
+
+ ok_button = Button(text="OK", handler=accept)
+ cancel_button = Button(text="Cancel", handler=cancel)
+
+ self.dialog = Dialog(
+ title=title,
+ body=HSplit([Label(text=label_text), self.text_area]),
+ buttons=[ok_button, cancel_button],
+ width=D(preferred=80),
+ modal=True,
+ )
+
+ def __pt_container__(self):
+ return self.dialog
+
+
+class MessageDialog:
+ def __init__(self, title, text):
+ self.future = Future()
+
+ def set_done():
+ self.future.set_result(None)
+
+ ok_button = Button(text="OK", handler=(lambda: set_done()))
+
+ self.dialog = Dialog(
+ title=title,
+ body=HSplit([Label(text=text)]),
+ buttons=[ok_button],
+ width=D(preferred=80),
+ modal=True,
+ )
+
+ def __pt_container__(self):
+ return self.dialog
+
+
+body = HSplit(
+ [
+ text_field,
+ search_toolbar,
+ ConditionalContainer(
+ content=VSplit(
+ [
+ Window(
+ FormattedTextControl(get_statusbar_text), style="class:status"
+ ),
+ Window(
+ FormattedTextControl(get_statusbar_right_text),
+ style="class:status.right",
+ width=9,
+ align=WindowAlign.RIGHT,
+ ),
+ ],
+ height=1,
+ ),
+ filter=Condition(lambda: ApplicationState.show_status_bar),
+ ),
+ ]
+)
+
+
+# Global key bindings.
+bindings = KeyBindings()
+
+
+@bindings.add("c-c")
+def _(event):
+ "Focus menu."
+ event.app.layout.focus(root_container.window)
+
+
+#
+# Handlers for menu items.
+#
+
+
+def do_open_file():
+ async def coroutine():
+ open_dialog = TextInputDialog(
+ title="Open file",
+ label_text="Enter the path of a file:",
+ completer=PathCompleter(),
+ )
+
+ path = await show_dialog_as_float(open_dialog)
+ ApplicationState.current_path = path
+
+ if path is not None:
+ try:
+ with open(path, "rb") as f:
+ text_field.text = f.read().decode("utf-8", errors="ignore")
+ except OSError as e:
+ show_message("Error", f"{e}")
+
+ ensure_future(coroutine())
+
+
+def do_about():
+ show_message("About", "Text editor demo.\nCreated by Jonathan Slenders.")
+
+
+def show_message(title, text):
+ async def coroutine():
+ dialog = MessageDialog(title, text)
+ await show_dialog_as_float(dialog)
+
+ ensure_future(coroutine())
+
+
+async def show_dialog_as_float(dialog):
+ "Coroutine."
+ float_ = Float(content=dialog)
+ root_container.floats.insert(0, float_)
+
+ app = get_app()
+
+ focused_before = app.layout.current_window
+ app.layout.focus(dialog)
+ result = await dialog.future
+ app.layout.focus(focused_before)
+
+ if float_ in root_container.floats:
+ root_container.floats.remove(float_)
+
+ return result
+
+
+def do_new_file():
+ text_field.text = ""
+
+
+def do_exit():
+ get_app().exit()
+
+
+def do_time_date():
+ text = datetime.datetime.now().isoformat()
+ text_field.buffer.insert_text(text)
+
+
+def do_go_to():
+ async def coroutine():
+ dialog = TextInputDialog(title="Go to line", label_text="Line number:")
+
+ line_number = await show_dialog_as_float(dialog)
+
+ try:
+ line_number = int(line_number)
+ except ValueError:
+ show_message("Invalid line number")
+ else:
+ text_field.buffer.cursor_position = (
+ text_field.buffer.document.translate_row_col_to_index(
+ line_number - 1, 0
+ )
+ )
+
+ ensure_future(coroutine())
+
+
+def do_undo():
+ text_field.buffer.undo()
+
+
+def do_cut():
+ data = text_field.buffer.cut_selection()
+ get_app().clipboard.set_data(data)
+
+
+def do_copy():
+ data = text_field.buffer.copy_selection()
+ get_app().clipboard.set_data(data)
+
+
+def do_delete():
+ text_field.buffer.cut_selection()
+
+
+def do_find():
+ start_search(text_field.control)
+
+
+def do_find_next():
+ search_state = get_app().current_search_state
+
+ cursor_position = text_field.buffer.get_search_position(
+ search_state, include_current_position=False
+ )
+ text_field.buffer.cursor_position = cursor_position
+
+
+def do_paste():
+ text_field.buffer.paste_clipboard_data(get_app().clipboard.get_data())
+
+
+def do_select_all():
+ text_field.buffer.cursor_position = 0
+ text_field.buffer.start_selection()
+ text_field.buffer.cursor_position = len(text_field.buffer.text)
+
+
+def do_status_bar():
+ ApplicationState.show_status_bar = not ApplicationState.show_status_bar
+
+
+#
+# The menu container.
+#
+
+
+root_container = MenuContainer(
+ body=body,
+ menu_items=[
+ MenuItem(
+ "File",
+ children=[
+ MenuItem("New...", handler=do_new_file),
+ MenuItem("Open...", handler=do_open_file),
+ MenuItem("Save"),
+ MenuItem("Save as..."),
+ MenuItem("-", disabled=True),
+ MenuItem("Exit", handler=do_exit),
+ ],
+ ),
+ MenuItem(
+ "Edit",
+ children=[
+ MenuItem("Undo", handler=do_undo),
+ MenuItem("Cut", handler=do_cut),
+ MenuItem("Copy", handler=do_copy),
+ MenuItem("Paste", handler=do_paste),
+ MenuItem("Delete", handler=do_delete),
+ MenuItem("-", disabled=True),
+ MenuItem("Find", handler=do_find),
+ MenuItem("Find next", handler=do_find_next),
+ MenuItem("Replace"),
+ MenuItem("Go To", handler=do_go_to),
+ MenuItem("Select All", handler=do_select_all),
+ MenuItem("Time/Date", handler=do_time_date),
+ ],
+ ),
+ MenuItem(
+ "View",
+ children=[MenuItem("Status Bar", handler=do_status_bar)],
+ ),
+ MenuItem(
+ "Info",
+ children=[MenuItem("About", handler=do_about)],
+ ),
+ ],
+ floats=[
+ Float(
+ xcursor=True,
+ ycursor=True,
+ content=CompletionsMenu(max_height=16, scroll_offset=1),
+ ),
+ ],
+ key_bindings=bindings,
+)
+
+
+style = Style.from_dict(
+ {
+ "status": "reverse",
+ "shadow": "bg:#440044",
+ }
+)
+
+
+layout = Layout(root_container, focused_element=text_field)
+
+
+application = Application(
+ layout=layout,
+ enable_page_navigation_bindings=True,
+ style=style,
+ mouse_support=True,
+ full_screen=True,
+)
+
+
+def run():
+ application.run()
+
+
+if __name__ == "__main__":
+ run()
diff --git a/examples/gevent-get-input.py b/examples/gevent-get-input.py
new file mode 100755
index 0000000..ecb89b4
--- /dev/null
+++ b/examples/gevent-get-input.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+"""
+For testing: test to make sure that everything still works when gevent monkey
+patches are applied.
+"""
+from gevent.monkey import patch_all
+
+from prompt_toolkit.eventloop.defaults import create_event_loop
+from prompt_toolkit.shortcuts import PromptSession
+
+if __name__ == "__main__":
+ # Apply patches.
+ patch_all()
+
+ # There were some issues in the past when the event loop had an input hook.
+ def dummy_inputhook(*a):
+ pass
+
+ eventloop = create_event_loop(inputhook=dummy_inputhook)
+
+ # Ask for input.
+ session = PromptSession("Give me some input: ", loop=eventloop)
+ answer = session.prompt()
+ print("You said: %s" % answer)
diff --git a/examples/print-text/ansi-colors.py b/examples/print-text/ansi-colors.py
new file mode 100755
index 0000000..7bd3831
--- /dev/null
+++ b/examples/print-text/ansi-colors.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+"""
+Demonstration of all the ANSI colors.
+"""
+from prompt_toolkit import print_formatted_text
+from prompt_toolkit.formatted_text import HTML, FormattedText
+
+print = print_formatted_text
+
+
+def main():
+ wide_space = ("", " ")
+ space = ("", " ")
+
+ print(HTML("\n<u>Foreground colors</u>"))
+ print(
+ FormattedText(
+ [
+ ("ansiblack", "ansiblack"),
+ wide_space,
+ ("ansired", "ansired"),
+ wide_space,
+ ("ansigreen", "ansigreen"),
+ wide_space,
+ ("ansiyellow", "ansiyellow"),
+ wide_space,
+ ("ansiblue", "ansiblue"),
+ wide_space,
+ ("ansimagenta", "ansimagenta"),
+ wide_space,
+ ("ansicyan", "ansicyan"),
+ wide_space,
+ ("ansigray", "ansigray"),
+ wide_space,
+ ("", "\n"),
+ ("ansibrightblack", "ansibrightblack"),
+ space,
+ ("ansibrightred", "ansibrightred"),
+ space,
+ ("ansibrightgreen", "ansibrightgreen"),
+ space,
+ ("ansibrightyellow", "ansibrightyellow"),
+ space,
+ ("ansibrightblue", "ansibrightblue"),
+ space,
+ ("ansibrightmagenta", "ansibrightmagenta"),
+ space,
+ ("ansibrightcyan", "ansibrightcyan"),
+ space,
+ ("ansiwhite", "ansiwhite"),
+ space,
+ ]
+ )
+ )
+
+ print(HTML("\n<u>Background colors</u>"))
+ print(
+ FormattedText(
+ [
+ ("bg:ansiblack ansiwhite", "ansiblack"),
+ wide_space,
+ ("bg:ansired", "ansired"),
+ wide_space,
+ ("bg:ansigreen", "ansigreen"),
+ wide_space,
+ ("bg:ansiyellow", "ansiyellow"),
+ wide_space,
+ ("bg:ansiblue ansiwhite", "ansiblue"),
+ wide_space,
+ ("bg:ansimagenta", "ansimagenta"),
+ wide_space,
+ ("bg:ansicyan", "ansicyan"),
+ wide_space,
+ ("bg:ansigray", "ansigray"),
+ wide_space,
+ ("", "\n"),
+ ("bg:ansibrightblack", "ansibrightblack"),
+ space,
+ ("bg:ansibrightred", "ansibrightred"),
+ space,
+ ("bg:ansibrightgreen", "ansibrightgreen"),
+ space,
+ ("bg:ansibrightyellow", "ansibrightyellow"),
+ space,
+ ("bg:ansibrightblue", "ansibrightblue"),
+ space,
+ ("bg:ansibrightmagenta", "ansibrightmagenta"),
+ space,
+ ("bg:ansibrightcyan", "ansibrightcyan"),
+ space,
+ ("bg:ansiwhite", "ansiwhite"),
+ space,
+ ]
+ )
+ )
+ print()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/print-text/ansi.py b/examples/print-text/ansi.py
new file mode 100755
index 0000000..618775c
--- /dev/null
+++ b/examples/print-text/ansi.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+"""
+Demonstration of how to print using ANSI escape sequences.
+
+The advantage here is that this is cross platform. The escape sequences will be
+parsed and turned into appropriate Win32 API calls on Windows.
+"""
+from prompt_toolkit import print_formatted_text
+from prompt_toolkit.formatted_text import ANSI, HTML
+
+print = print_formatted_text
+
+
+def title(text):
+ print(HTML("\n<u><b>{}</b></u>").format(text))
+
+
+def main():
+ title("Special formatting")
+ print(ANSI(" \x1b[1mBold"))
+ print(ANSI(" \x1b[6mBlink"))
+ print(ANSI(" \x1b[3mItalic"))
+ print(ANSI(" \x1b[7mReverse"))
+ print(ANSI(" \x1b[4mUnderline"))
+ print(ANSI(" \x1b[9mStrike"))
+ print(ANSI(" \x1b[8mHidden\x1b[0m (Hidden)"))
+
+ # Ansi colors.
+ title("ANSI colors")
+
+ print(ANSI(" \x1b[91mANSI Red"))
+ print(ANSI(" \x1b[94mANSI Blue"))
+
+ # Other named colors.
+ title("Named colors")
+
+ print(ANSI(" \x1b[38;5;214morange"))
+ print(ANSI(" \x1b[38;5;90mpurple"))
+
+ # Background colors.
+ title("Background colors")
+
+ print(ANSI(" \x1b[97;101mANSI Red"))
+ print(ANSI(" \x1b[97;104mANSI Blue"))
+
+ print()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/print-text/html.py b/examples/print-text/html.py
new file mode 100755
index 0000000..5276fe3
--- /dev/null
+++ b/examples/print-text/html.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+"""
+Demonstration of how to print using the HTML class.
+"""
+from prompt_toolkit import HTML, print_formatted_text
+
+print = print_formatted_text
+
+
+def title(text):
+ print(HTML("\n<u><b>{}</b></u>").format(text))
+
+
+def main():
+ title("Special formatting")
+ print(HTML(" <b>Bold</b>"))
+ print(HTML(" <blink>Blink</blink>"))
+ print(HTML(" <i>Italic</i>"))
+ print(HTML(" <reverse>Reverse</reverse>"))
+ print(HTML(" <u>Underline</u>"))
+ print(HTML(" <s>Strike</s>"))
+ print(HTML(" <hidden>Hidden</hidden> (hidden)"))
+
+ # Ansi colors.
+ title("ANSI colors")
+
+ print(HTML(" <ansired>ANSI Red</ansired>"))
+ print(HTML(" <ansiblue>ANSI Blue</ansiblue>"))
+
+ # Other named colors.
+ title("Named colors")
+
+ print(HTML(" <orange>orange</orange>"))
+ print(HTML(" <purple>purple</purple>"))
+
+ # Background colors.
+ title("Background colors")
+
+ print(HTML(' <style fg="ansiwhite" bg="ansired">ANSI Red</style>'))
+ print(HTML(' <style fg="ansiwhite" bg="ansiblue">ANSI Blue</style>'))
+
+ # Interpolation.
+ title("HTML interpolation (see source)")
+
+ print(HTML(" <i>{}</i>").format("<test>"))
+ print(HTML(" <b>{text}</b>").format(text="<test>"))
+ print(HTML(" <u>%s</u>") % ("<text>",))
+
+ print()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/print-text/named-colors.py b/examples/print-text/named-colors.py
new file mode 100755
index 0000000..ea3f0ba
--- /dev/null
+++ b/examples/print-text/named-colors.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+"""
+Demonstration of all the ANSI colors.
+"""
+from prompt_toolkit import HTML, print_formatted_text
+from prompt_toolkit.formatted_text import FormattedText
+from prompt_toolkit.output import ColorDepth
+from prompt_toolkit.styles.named_colors import NAMED_COLORS
+
+print = print_formatted_text
+
+
+def main():
+ tokens = FormattedText([("fg:" + name, name + " ") for name in NAMED_COLORS])
+
+ print(HTML("\n<u>Named colors, using 16 color output.</u>"))
+ print("(Note that it doesn't really make sense to use named colors ")
+ print("with only 16 color output.)")
+ print(tokens, color_depth=ColorDepth.DEPTH_4_BIT)
+
+ print(HTML("\n<u>Named colors, use 256 colors.</u>"))
+ print(tokens)
+
+ print(HTML("\n<u>Named colors, using True color output.</u>"))
+ print(tokens, color_depth=ColorDepth.TRUE_COLOR)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/print-text/print-formatted-text.py b/examples/print-text/print-formatted-text.py
new file mode 100755
index 0000000..4b09ae2
--- /dev/null
+++ b/examples/print-text/print-formatted-text.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+"""
+Example of printing colored text to the output.
+"""
+from prompt_toolkit import print_formatted_text
+from prompt_toolkit.formatted_text import ANSI, HTML, FormattedText
+from prompt_toolkit.styles import Style
+
+print = print_formatted_text
+
+
+def main():
+ style = Style.from_dict(
+ {
+ "hello": "#ff0066",
+ "world": "#44ff44 italic",
+ }
+ )
+
+ # Print using a a list of text fragments.
+ text_fragments = FormattedText(
+ [
+ ("class:hello", "Hello "),
+ ("class:world", "World"),
+ ("", "\n"),
+ ]
+ )
+ print(text_fragments, style=style)
+
+ # Print using an HTML object.
+ print(HTML("<hello>hello</hello> <world>world</world>\n"), style=style)
+
+ # Print using an HTML object with inline styling.
+ print(
+ HTML(
+ '<style fg="#ff0066">hello</style> '
+ '<style fg="#44ff44"><i>world</i></style>\n'
+ )
+ )
+
+ # Print using ANSI escape sequences.
+ print(ANSI("\x1b[31mhello \x1b[32mworld\n"))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/print-text/print-frame.py b/examples/print-text/print-frame.py
new file mode 100755
index 0000000..fb703c5
--- /dev/null
+++ b/examples/print-text/print-frame.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+"""
+Example usage of 'print_container', a tool to print
+any layout in a non-interactive way.
+"""
+from prompt_toolkit.shortcuts import print_container
+from prompt_toolkit.widgets import Frame, TextArea
+
+print_container(
+ Frame(
+ TextArea(text="Hello world!\n"),
+ title="Stage: parse",
+ )
+)
diff --git a/examples/print-text/prompt-toolkit-logo-ansi-art.py b/examples/print-text/prompt-toolkit-logo-ansi-art.py
new file mode 100755
index 0000000..d903fa9
--- /dev/null
+++ b/examples/print-text/prompt-toolkit-logo-ansi-art.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+r"""
+This prints the prompt_toolkit logo at the terminal.
+The ANSI output was generated using "pngtoansi": https://github.com/crgimenes/pngtoansi
+(ESC still had to be replaced with \x1b
+"""
+from prompt_toolkit import print_formatted_text
+from prompt_toolkit.formatted_text import ANSI, HTML, FormattedText
+
+print_formatted_text(
+ ANSI(
+ """
+\x1b[48;2;0;0;0m \x1b[m
+\x1b[48;2;0;0;0m \x1b[48;2;0;249;0m\x1b[38;2;0;0;0mâ–€\x1b[48;2;0;209;0mâ–€\x1b[48;2;0;207;0m\x1b[38;2;6;34;6mâ–€\x1b[48;2;0;66;0m\x1b[38;2;30;171;30mâ–€\x1b[48;2;0;169;0m\x1b[38;2;51;35;51mâ–€\x1b[48;2;0;248;0m\x1b[38;2;49;194;49mâ–€\x1b[48;2;0;111;0m\x1b[38;2;25;57;25mâ–€\x1b[48;2;140;195;140m\x1b[38;2;3;17;3mâ–€\x1b[48;2;30;171;30m\x1b[38;2;0;0;0mâ–€\x1b[48;2;0;0;0m \x1b[m
+\x1b[48;2;0;0;0m \x1b[48;2;77;127;78m\x1b[38;2;118;227;108m▀\x1b[48;2;216;1;13m\x1b[38;2;49;221;57m▀\x1b[48;2;26;142;76m\x1b[38;2;108;146;165m▀\x1b[48;2;26;142;90m\x1b[38;2;209;197;114m▀▀\x1b[38;2;209;146;114m▀\x1b[48;2;26;128;90m\x1b[38;2;158;197;114m▀\x1b[48;2;58;210;70m\x1b[38;2;223;152;89m▀\x1b[48;2;232;139;44m\x1b[38;2;97;121;146m▀\x1b[48;2;233;139;45m\x1b[38;2;140;188;183m▀\x1b[48;2;231;139;44m\x1b[38;2;40;168;8m▀\x1b[48;2;228;140;44m\x1b[38;2;37;169;7m▀\x1b[48;2;227;140;44m\x1b[38;2;36;169;7m▀\x1b[48;2;211;142;41m\x1b[38;2;23;171;5m▀\x1b[48;2;86;161;17m\x1b[38;2;2;174;1m▀\x1b[48;2;0;175;0m \x1b[48;2;0;254;0m\x1b[38;2;190;119;190m▀\x1b[48;2;92;39;23m\x1b[38;2;125;50;114m▀\x1b[48;2;43;246;41m\x1b[38;2;49;10;165m▀\x1b[48;2;12;128;90m\x1b[38;2;209;197;114m▀\x1b[48;2;26;128;90m▀▀▀▀\x1b[48;2;26;128;76m▀\x1b[48;2;26;128;90m\x1b[38;2;209;247;114m▀▀\x1b[38;2;209;197;114m▀\x1b[48;2;26;128;76m\x1b[38;2;209;247;114m▀\x1b[48;2;26;128;90m▀▀▀\x1b[48;2;26;128;76m▀\x1b[48;2;26;128;90m▀▀\x1b[48;2;12;128;76m▀\x1b[48;2;12;113;90m\x1b[38;2;209;247;64m▀\x1b[38;2;209;247;114m▀\x1b[48;2;12;128;90m▀\x1b[48;2;12;113;90m▀\x1b[48;2;12;113;76m\x1b[38;2;209;247;64m▀\x1b[48;2;12;128;90m▀\x1b[48;2;12;113;90m▀\x1b[48;2;12;113;76m\x1b[38;2;209;247;114m▀\x1b[48;2;12;113;90m\x1b[38;2;209;247;64m▀\x1b[48;2;26;128;90m\x1b[38;2;151;129;163m▀\x1b[48;2;115;120;103m\x1b[38;2;62;83;227m▀\x1b[48;2;138;14;25m\x1b[38;2;104;106;160m▀\x1b[48;2;0;0;57m\x1b[38;2;0;0;0m▀\x1b[m
+\x1b[48;2;249;147;8m\x1b[38;2;172;69;38m▀\x1b[48;2;197;202;10m\x1b[38;2;82;192;58m▀\x1b[48;2;248;124;45m\x1b[38;2;251;131;47m▀\x1b[48;2;248;124;44m▀\x1b[48;2;248;124;45m▀▀\x1b[48;2;248;124;44m▀\x1b[48;2;248;124;45m▀\x1b[48;2;248;125;45m\x1b[38;2;251;130;47m▀\x1b[48;2;248;124;45m\x1b[38;2;252;130;47m▀\x1b[48;2;248;125;45m\x1b[38;2;252;131;47m▀\x1b[38;2;252;130;47m▀\x1b[38;2;252;131;47m▀▀\x1b[48;2;249;125;45m\x1b[38;2;255;130;48m▀\x1b[48;2;233;127;42m\x1b[38;2;190;141;35m▀\x1b[48;2;57;163;10m\x1b[38;2;13;172;3m▀\x1b[48;2;0;176;0m\x1b[38;2;0;175;0m▀\x1b[48;2;7;174;1m\x1b[38;2;35;169;7m▀\x1b[48;2;178;139;32m\x1b[38;2;220;136;41m▀\x1b[48;2;252;124;45m\x1b[38;2;253;131;47m▀\x1b[48;2;248;125;45m\x1b[38;2;251;131;47m▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\x1b[48;2;248;125;44m▀\x1b[48;2;248;135;61m\x1b[38;2;251;132;48m▀\x1b[48;2;250;173;122m\x1b[38;2;251;133;50m▀\x1b[48;2;249;155;93m\x1b[38;2;251;132;49m▀\x1b[48;2;248;132;55m\x1b[38;2;251;132;48m▀\x1b[48;2;250;173;122m\x1b[38;2;251;134;51m▀\x1b[48;2;250;163;106m\x1b[38;2;251;134;50m▀\x1b[48;2;248;128;49m\x1b[38;2;251;132;47m▀\x1b[48;2;250;166;110m\x1b[38;2;251;135;52m▀\x1b[48;2;250;175;125m\x1b[38;2;251;136;54m▀\x1b[48;2;248;132;56m\x1b[38;2;251;132;48m▀\x1b[48;2;248;220;160m\x1b[38;2;105;247;172m▀\x1b[48;2;62;101;236m\x1b[38;2;11;207;160m▀\x1b[m
+\x1b[48;2;138;181;197m\x1b[38;2;205;36;219m▀\x1b[48;2;177;211;200m\x1b[38;2;83;231;105m▀\x1b[48;2;242;113;40m\x1b[38;2;245;119;42m▀\x1b[48;2;243;113;41m▀\x1b[48;2;245;114;41m▀▀▀▀▀▀▀▀\x1b[38;2;245;119;43m▀▀▀\x1b[48;2;247;114;41m\x1b[38;2;246;119;43m▀\x1b[48;2;202;125;34m\x1b[38;2;143;141;25m▀\x1b[48;2;84;154;14m\x1b[38;2;97;152;17m▀\x1b[48;2;36;166;6m▀\x1b[48;2;139;140;23m\x1b[38;2;183;133;32m▀\x1b[48;2;248;114;41m\x1b[38;2;248;118;43m▀\x1b[48;2;245;115;41m\x1b[38;2;245;119;43m▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\x1b[38;2;245;119;42m▀\x1b[48;2;246;117;44m\x1b[38;2;246;132;62m▀\x1b[48;2;246;123;54m\x1b[38;2;249;180;138m▀\x1b[48;2;246;120;49m\x1b[38;2;247;157;102m▀\x1b[48;2;246;116;42m\x1b[38;2;246;127;54m▀\x1b[48;2;246;121;50m\x1b[38;2;248;174;128m▀\x1b[48;2;246;120;48m\x1b[38;2;248;162;110m▀\x1b[48;2;246;116;41m\x1b[38;2;245;122;47m▀\x1b[48;2;246;118;46m\x1b[38;2;248;161;108m▀\x1b[48;2;244;118;47m\x1b[38;2;248;171;123m▀\x1b[48;2;243;115;42m\x1b[38;2;246;127;54m▀\x1b[48;2;179;52;29m\x1b[38;2;86;152;223m▀\x1b[48;2;141;225;95m\x1b[38;2;247;146;130m▀\x1b[m
+\x1b[48;2;50;237;108m\x1b[38;2;94;70;153m▀\x1b[48;2;206;221;133m\x1b[38;2;64;240;39m▀\x1b[48;2;233;100;36m\x1b[38;2;240;107;38m▀\x1b[48;2;114;56;22m\x1b[38;2;230;104;37m▀\x1b[48;2;24;20;10m\x1b[38;2;193;90;33m▀\x1b[48;2;21;19;9m\x1b[38;2;186;87;32m▀▀▀▀▀▀▀\x1b[38;2;186;87;33m▀▀▀\x1b[48;2;22;18;10m\x1b[38;2;189;86;33m▀\x1b[48;2;18;36;8m\x1b[38;2;135;107;24m▀\x1b[48;2;3;153;2m\x1b[38;2;5;171;1m▀\x1b[48;2;0;177;0m \x1b[48;2;4;158;2m\x1b[38;2;69;147;12m▀\x1b[48;2;19;45;8m\x1b[38;2;185;89;32m▀\x1b[48;2;22;17;10m\x1b[38;2;186;87;33m▀\x1b[48;2;21;19;9m▀▀▀▀▀▀▀▀\x1b[48;2;21;19;10m▀▀\x1b[48;2;21;19;9m▀▀▀▀\x1b[48;2;21;19;10m▀▀▀\x1b[38;2;186;87;32m▀▀\x1b[48;2;21;19;9m\x1b[38;2;186;87;33m▀\x1b[48;2;21;19;10m\x1b[38;2;186;87;32m▀▀\x1b[48;2;21;19;9m\x1b[38;2;186;87;33m▀\x1b[48;2;22;19;10m\x1b[38;2;191;89;33m▀\x1b[48;2;95;49;20m\x1b[38;2;226;103;37m▀\x1b[48;2;227;99;36m\x1b[38;2;241;109;39m▀\x1b[48;2;80;140;154m\x1b[38;2;17;240;92m▀\x1b[48;2;221;58;175m\x1b[38;2;71;14;245m▀\x1b[m
+\x1b[48;2;195;38;42m\x1b[38;2;5;126;86m▀\x1b[48;2;139;230;67m\x1b[38;2;253;201;228m▀\x1b[48;2;208;82;30m\x1b[38;2;213;89;32m▀\x1b[48;2;42;26;12m\x1b[38;2;44;27;12m▀\x1b[48;2;9;14;7m\x1b[38;2;8;13;7m▀\x1b[48;2;11;15;8m\x1b[38;2;10;14;7m▀▀▀▀▀▀▀▀▀▀▀\x1b[48;2;11;12;8m\x1b[38;2;10;17;7m▀\x1b[48;2;7;71;5m\x1b[38;2;4;120;3m▀\x1b[48;2;1;164;1m\x1b[38;2;0;178;0m▀\x1b[48;2;4;118;3m\x1b[38;2;0;177;0m▀\x1b[48;2;5;108;3m\x1b[38;2;4;116;3m▀\x1b[48;2;7;75;5m\x1b[38;2;10;23;7m▀\x1b[48;2;10;33;7m\x1b[38;2;10;12;7m▀\x1b[48;2;11;13;8m\x1b[38;2;10;14;7m▀\x1b[48;2;11;14;8m▀\x1b[48;2;11;15;8m▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\x1b[48;2;10;14;7m\x1b[38;2;9;14;7m▀\x1b[48;2;30;21;10m\x1b[38;2;30;22;10m▀\x1b[48;2;195;79;29m\x1b[38;2;200;84;31m▀\x1b[48;2;205;228;23m\x1b[38;2;111;40;217m▀\x1b[48;2;9;217;69m\x1b[38;2;115;137;104m▀\x1b[m
+\x1b[48;2;106;72;209m\x1b[38;2;151;183;253mâ–€\x1b[48;2;120;239;0m\x1b[38;2;25;2;162mâ–€\x1b[48;2;203;72;26m\x1b[38;2;206;77;28mâ–€\x1b[48;2;42;24;11m\x1b[38;2;42;25;11mâ–€\x1b[48;2;9;14;7m \x1b[48;2;11;15;8m \x1b[38;2;11;14;8mâ–€\x1b[48;2;11;13;8m\x1b[38;2;10;28;7mâ–€\x1b[48;2;9;36;6m\x1b[38;2;7;78;5mâ–€\x1b[48;2;2;153;1m\x1b[38;2;6;94;4mâ–€\x1b[48;2;0;178;0m\x1b[38;2;2;156;1mâ–€\x1b[48;2;0;175;0m\x1b[38;2;1;167;1mâ–€\x1b[48;2;0;177;0m\x1b[38;2;2;145;2mâ–€\x1b[48;2;2;147;2m\x1b[38;2;8;54;6mâ–€\x1b[48;2;9;38;6m\x1b[38;2;11;13;8mâ–€\x1b[48;2;11;13;8m\x1b[38;2;11;14;8mâ–€\x1b[48;2;11;15;8m \x1b[48;2;10;14;7m \x1b[48;2;29;20;10m\x1b[38;2;29;21;10mâ–€\x1b[48;2;190;69;25m\x1b[38;2;193;74;27mâ–€\x1b[48;2;136;91;148m\x1b[38;2;42;159;86mâ–€\x1b[48;2;89;85;149m\x1b[38;2;160;5;219mâ–€\x1b[m
+\x1b[48;2;229;106;143m\x1b[38;2;40;239;187m▀\x1b[48;2;196;134;237m\x1b[38;2;6;11;95m▀\x1b[48;2;197;60;22m\x1b[38;2;201;67;24m▀\x1b[48;2;41;22;10m\x1b[38;2;41;23;11m▀\x1b[48;2;9;14;7m \x1b[48;2;11;15;8m \x1b[48;2;10;14;7m\x1b[38;2;11;15;8m▀▀\x1b[48;2;11;15;8m \x1b[38;2;11;14;8m▀\x1b[48;2;11;14;8m\x1b[38;2;11;16;7m▀\x1b[48;2;11;15;7m\x1b[38;2;7;79;5m▀\x1b[48;2;7;68;5m\x1b[38;2;1;164;1m▀\x1b[48;2;2;153;1m\x1b[38;2;0;176;0m▀\x1b[48;2;2;154;1m\x1b[38;2;0;175;0m▀\x1b[48;2;5;107;3m\x1b[38;2;1;171;1m▀\x1b[48;2;4;115;3m\x1b[38;2;5;105;3m▀\x1b[48;2;6;84;4m\x1b[38;2;11;18;7m▀\x1b[48;2;10;30;7m\x1b[38;2;11;13;8m▀\x1b[48;2;11;13;8m\x1b[38;2;11;15;8m▀\x1b[48;2;11;14;8m▀\x1b[48;2;11;15;8m \x1b[48;2;10;14;7m \x1b[48;2;29;19;9m\x1b[38;2;29;20;10m▀\x1b[48;2;185;58;22m\x1b[38;2;188;64;24m▀\x1b[48;2;68;241;49m\x1b[38;2;199;22;211m▀\x1b[48;2;133;139;8m\x1b[38;2;239;129;78m▀\x1b[m
+\x1b[48;2;74;30;32m\x1b[38;2;163;185;76mâ–€\x1b[48;2;110;172;9m\x1b[38;2;177;1;123mâ–€\x1b[48;2;189;43;16m\x1b[38;2;193;52;19mâ–€\x1b[48;2;39;20;9m\x1b[38;2;40;21;10mâ–€\x1b[48;2;9;14;7m \x1b[48;2;11;15;8m \x1b[48;2;11;14;7m\x1b[38;2;11;15;8mâ–€\x1b[48;2;9;14;7m\x1b[38;2;11;14;8mâ–€\x1b[48;2;106;54;38m\x1b[38;2;31;24;15mâ–€\x1b[48;2;164;71;49m\x1b[38;2;24;20;12mâ–€\x1b[48;2;94;46;31m\x1b[38;2;8;14;7mâ–€\x1b[48;2;36;24;15m\x1b[38;2;9;14;7mâ–€\x1b[48;2;11;15;8m\x1b[38;2;11;14;7mâ–€\x1b[48;2;8;14;7m\x1b[38;2;11;15;8mâ–€\x1b[48;2;10;14;7mâ–€\x1b[48;2;11;15;8m \x1b[38;2;11;14;8mâ–€\x1b[48;2;11;14;8m\x1b[38;2;11;13;8mâ–€\x1b[48;2;11;13;8m\x1b[38;2;9;45;6mâ–€\x1b[48;2;10;19;7m\x1b[38;2;7;75;5mâ–€\x1b[48;2;6;83;4m\x1b[38;2;2;143;2mâ–€\x1b[48;2;2;156;1m\x1b[38;2;0;176;0mâ–€\x1b[48;2;0;177;0m\x1b[38;2;0;175;0mâ–€\x1b[38;2;3;134;2mâ–€\x1b[48;2;2;152;1m\x1b[38;2;9;46;6mâ–€\x1b[48;2;8;60;5m\x1b[38;2;11;13;8mâ–€\x1b[48;2;11;14;7m\x1b[38;2;11;14;8mâ–€\x1b[48;2;11;14;8m\x1b[38;2;11;15;8mâ–€\x1b[48;2;11;15;8m \x1b[48;2;10;14;7m \x1b[48;2;28;18;9m \x1b[48;2;177;43;16m\x1b[38;2;181;51;19mâ–€\x1b[48;2;93;35;236m\x1b[38;2;224;10;142mâ–€\x1b[48;2;72;51;52m\x1b[38;2;213;112;158mâ–€\x1b[m
+\x1b[48;2;175;209;155m\x1b[38;2;7;131;221mâ–€\x1b[48;2;24;0;85m\x1b[38;2;44;86;152mâ–€\x1b[48;2;181;27;10m\x1b[38;2;185;35;13mâ–€\x1b[48;2;38;17;8m\x1b[38;2;39;18;9mâ–€\x1b[48;2;9;14;7m \x1b[48;2;11;15;8m \x1b[48;2;11;14;7m \x1b[48;2;9;14;7m \x1b[48;2;87;43;32m\x1b[38;2;114;54;39mâ–€\x1b[48;2;188;71;54m\x1b[38;2;211;82;59mâ–€\x1b[48;2;203;73;55m\x1b[38;2;204;80;57mâ–€\x1b[48;2;205;73;55m\x1b[38;2;178;71;51mâ–€\x1b[48;2;204;74;55m\x1b[38;2;119;52;37mâ–€\x1b[48;2;188;69;52m\x1b[38;2;54;29;19mâ–€\x1b[48;2;141;55;41m\x1b[38;2;16;17;9mâ–€\x1b[48;2;75;35;24m\x1b[38;2;8;14;7mâ–€\x1b[48;2;26;20;12m\x1b[38;2;10;14;7mâ–€\x1b[48;2;9;14;7m\x1b[38;2;11;14;7mâ–€\x1b[38;2;11;15;8mâ–€\x1b[48;2;11;14;7mâ–€\x1b[48;2;11;15;8m \x1b[38;2;11;14;8mâ–€\x1b[48;2;11;14;8m \x1b[48;2;11;13;8m\x1b[38;2;9;45;6mâ–€\x1b[48;2;10;23;7m\x1b[38;2;4;123;3mâ–€\x1b[48;2;7;75;5m\x1b[38;2;1;172;1mâ–€\x1b[48;2;6;84;4m\x1b[38;2;2;154;1mâ–€\x1b[48;2;4;114;3m\x1b[38;2;5;107;3mâ–€\x1b[48;2;5;103;4m\x1b[38;2;10;29;7mâ–€\x1b[48;2;10;23;7m\x1b[38;2;11;13;8mâ–€\x1b[48;2;11;14;8m\x1b[38;2;11;15;8mâ–€\x1b[48;2;11;15;8m \x1b[48;2;10;14;7m \x1b[48;2;27;16;8m\x1b[38;2;27;17;9mâ–€\x1b[48;2;170;27;10m\x1b[38;2;174;35;13mâ–€\x1b[48;2;118;117;199m\x1b[38;2;249;61;74mâ–€\x1b[48;2;10;219;61m\x1b[38;2;187;245;202mâ–€\x1b[m
+\x1b[48;2;20;155;44m\x1b[38;2;86;54;110mâ–€\x1b[48;2;195;85;113m\x1b[38;2;214;171;227mâ–€\x1b[48;2;173;10;4m\x1b[38;2;177;19;7mâ–€\x1b[48;2;37;14;7m\x1b[38;2;37;16;8mâ–€\x1b[48;2;9;15;8m\x1b[38;2;9;14;7mâ–€\x1b[48;2;11;15;8m \x1b[38;2;11;14;7mâ–€\x1b[48;2;11;14;7m\x1b[38;2;15;17;9mâ–€\x1b[48;2;9;14;7m\x1b[38;2;50;29;20mâ–€\x1b[48;2;10;15;8m\x1b[38;2;112;47;36mâ–€\x1b[48;2;33;22;15m\x1b[38;2;170;61;48mâ–€\x1b[48;2;88;38;29m\x1b[38;2;197;66;53mâ–€\x1b[48;2;151;53;43m\x1b[38;2;201;67;53mâ–€\x1b[48;2;189;60;50mâ–€\x1b[48;2;198;60;51m\x1b[38;2;194;65;52mâ–€\x1b[38;2;160;56;44mâ–€\x1b[48;2;196;60;50m\x1b[38;2;99;40;30mâ–€\x1b[48;2;174;55;47m\x1b[38;2;41;24;16mâ–€\x1b[48;2;122;43;35m\x1b[38;2;12;15;8mâ–€\x1b[48;2;59;27;20m\x1b[38;2;8;14;7mâ–€\x1b[48;2;16;16;9m\x1b[38;2;10;14;7mâ–€\x1b[48;2;10;14;7m\x1b[38;2;11;15;8mâ–€\x1b[48;2;11;15;8m \x1b[38;2;11;14;8mâ–€\x1b[48;2;11;14;8m\x1b[38;2;11;12;8mâ–€\x1b[48;2;10;25;7m\x1b[38;2;7;79;5mâ–€\x1b[48;2;3;141;2m\x1b[38;2;1;174;1mâ–€\x1b[48;2;0;178;0m\x1b[38;2;1;169;1mâ–€\x1b[48;2;6;88;4m\x1b[38;2;8;56;6mâ–€\x1b[48;2;11;12;8m \x1b[48;2;11;14;8m\x1b[38;2;11;15;8mâ–€\x1b[48;2;11;15;8m \x1b[48;2;10;14;7m \x1b[48;2;26;15;8m\x1b[38;2;27;15;8mâ–€\x1b[48;2;162;12;5m\x1b[38;2;166;20;8mâ–€\x1b[48;2;143;168;130m\x1b[38;2;18;142;37mâ–€\x1b[48;2;240;96;105m\x1b[38;2;125;158;211mâ–€\x1b[m
+\x1b[48;2;54;0;0m\x1b[38;2;187;22;0mâ–€\x1b[48;2;204;0;0m\x1b[38;2;128;208;0mâ–€\x1b[48;2;162;1;1m\x1b[38;2;168;3;1mâ–€\x1b[48;2;35;13;7m\x1b[38;2;36;13;7mâ–€\x1b[48;2;9;15;8m \x1b[48;2;11;15;8m \x1b[38;2;11;14;7mâ–€\x1b[38;2;9;14;7mâ–€\x1b[38;2;8;14;7mâ–€\x1b[48;2;10;14;7m\x1b[38;2;21;18;11mâ–€\x1b[48;2;7;13;6m\x1b[38;2;65;30;23mâ–€\x1b[48;2;12;16;9m\x1b[38;2;129;45;38mâ–€\x1b[48;2;57;29;23m\x1b[38;2;176;53;47mâ–€\x1b[48;2;148;49;44m\x1b[38;2;191;53;48mâ–€\x1b[48;2;187;52;48m\x1b[38;2;192;53;48mâ–€\x1b[48;2;186;51;47m\x1b[38;2;194;54;49mâ–€\x1b[48;2;182;52;47m\x1b[38;2;178;52;46mâ–€\x1b[48;2;59;27;21m\x1b[38;2;53;26;19mâ–€\x1b[48;2;8;14;7m \x1b[48;2;11;15;8m \x1b[48;2;11;14;8m\x1b[38;2;11;15;8mâ–€\x1b[48;2;11;12;8m\x1b[38;2;11;14;8mâ–€\x1b[48;2;10;30;7m\x1b[38;2;10;23;7mâ–€\x1b[48;2;5;110;3m\x1b[38;2;3;138;2mâ–€\x1b[48;2;2;149;2m\x1b[38;2;0;181;0mâ–€\x1b[48;2;6;92;4m\x1b[38;2;5;100;4mâ–€\x1b[48;2;11;13;8m \x1b[48;2;11;14;8m \x1b[48;2;11;15;8m \x1b[48;2;10;15;8m \x1b[48;2;25;14;7m\x1b[38;2;26;14;7mâ–€\x1b[48;2;152;2;1m\x1b[38;2;158;5;2mâ–€\x1b[48;2;6;0;0m\x1b[38;2;44;193;0mâ–€\x1b[48;2;108;0;0m\x1b[38;2;64;70;0mâ–€\x1b[m
+\x1b[48;2;44;0;0m\x1b[38;2;177;0;0mâ–€\x1b[48;2;147;0;0m\x1b[38;2;71;0;0mâ–€\x1b[48;2;148;1;1m\x1b[38;2;155;1;1mâ–€\x1b[48;2;33;13;7m\x1b[38;2;34;13;7mâ–€\x1b[48;2;9;15;8m \x1b[48;2;11;15;8m \x1b[48;2;11;14;7m\x1b[38;2;11;15;8mâ–€\x1b[48;2;10;14;7mâ–€\x1b[48;2;9;14;7mâ–€\x1b[48;2;13;16;9m\x1b[38;2;11;14;7mâ–€\x1b[48;2;42;24;17m\x1b[38;2;9;14;7mâ–€\x1b[48;2;97;38;32m\x1b[38;2;10;15;8mâ–€\x1b[48;2;149;49;44m\x1b[38;2;30;21;14mâ–€\x1b[48;2;174;52;48m\x1b[38;2;79;34;28mâ–€\x1b[48;2;178;52;48m\x1b[38;2;136;45;40mâ–€\x1b[38;2;172;51;47mâ–€\x1b[48;2;173;52;48m\x1b[38;2;181;52;48mâ–€\x1b[48;2;147;47;42m\x1b[38;2;183;52;48mâ–€\x1b[48;2;94;35;30m\x1b[38;2;177;52;48mâ–€\x1b[48;2;25;19;12m\x1b[38;2;56;27;20mâ–€\x1b[48;2;10;14;7m\x1b[38;2;8;14;7mâ–€\x1b[48;2;11;12;8m\x1b[38;2;11;15;8mâ–€\x1b[48;2;10;23;7m\x1b[38;2;11;14;8mâ–€\x1b[48;2;7;76;5m\x1b[38;2;11;13;8mâ–€\x1b[48;2;2;152;1m\x1b[38;2;9;45;6mâ–€\x1b[48;2;0;177;0m\x1b[38;2;5;106;3mâ–€\x1b[48;2;0;178;0m\x1b[38;2;4;123;3mâ–€\x1b[48;2;1;168;1m\x1b[38;2;5;104;3mâ–€\x1b[48;2;8;53;6m\x1b[38;2;9;47;6mâ–€\x1b[48;2;11;12;8m\x1b[38;2;11;13;8mâ–€\x1b[48;2;11;15;8m \x1b[48;2;10;15;8m \x1b[48;2;24;14;7m\x1b[38;2;25;14;7mâ–€\x1b[48;2;140;2;1m\x1b[38;2;146;2;1mâ–€\x1b[48;2;219;0;0m\x1b[38;2;225;0;0mâ–€\x1b[48;2;126;0;0m\x1b[38;2;117;0;0mâ–€\x1b[m
+\x1b[48;2;34;0;0m\x1b[38;2;167;0;0mâ–€\x1b[48;2;89;0;0m\x1b[38;2;14;0;0mâ–€\x1b[48;2;134;1;1m\x1b[38;2;141;1;1mâ–€\x1b[48;2;31;13;7m\x1b[38;2;32;13;7mâ–€\x1b[48;2;10;15;8m \x1b[48;2;11;15;8m \x1b[48;2;11;14;7m\x1b[38;2;11;15;8mâ–€\x1b[48;2;10;14;7m\x1b[38;2;11;14;7mâ–€\x1b[48;2;53;29;22m\x1b[38;2;10;14;7mâ–€\x1b[48;2;127;46;41m\x1b[38;2;20;18;11mâ–€\x1b[48;2;158;51;47m\x1b[38;2;57;28;22mâ–€\x1b[48;2;166;52;48m\x1b[38;2;113;42;36mâ–€\x1b[48;2;167;52;48m\x1b[38;2;156;50;46mâ–€\x1b[48;2;164;52;48m\x1b[38;2;171;52;48mâ–€\x1b[48;2;146;48;44m\x1b[38;2;172;52;48mâ–€\x1b[48;2;102;38;33mâ–€\x1b[48;2;50;26;19m\x1b[38;2;161;51;46mâ–€\x1b[48;2;17;17;10m\x1b[38;2;126;44;38mâ–€\x1b[48;2;8;14;7m\x1b[38;2;71;31;25mâ–€\x1b[48;2;10;14;7m\x1b[38;2;27;19;13mâ–€\x1b[48;2;11;13;8m\x1b[38;2;10;14;7mâ–€\x1b[48;2;9;40;6m\x1b[38;2;10;13;7mâ–€\x1b[48;2;4;119;3m\x1b[38;2;11;20;7mâ–€\x1b[48;2;1;168;1m\x1b[38;2;8;63;5mâ–€\x1b[48;2;0;177;0m\x1b[38;2;3;130;2mâ–€\x1b[48;2;0;175;0m\x1b[38;2;1;171;1mâ–€\x1b[48;2;1;174;1m\x1b[38;2;0;176;0mâ–€\x1b[48;2;1;175;1m\x1b[38;2;1;174;1mâ–€\x1b[48;2;0;177;0m\x1b[38;2;0;176;0mâ–€\x1b[48;2;3;134;2m\x1b[38;2;2;158;1mâ–€\x1b[48;2;10;21;7m\x1b[38;2;9;38;6mâ–€\x1b[48;2;11;14;8m\x1b[38;2;11;13;8mâ–€\x1b[48;2;11;15;8m \x1b[48;2;10;15;8m \x1b[48;2;23;14;7m \x1b[48;2;127;2;1m\x1b[38;2;133;2;1mâ–€\x1b[48;2;176;0;0m\x1b[38;2;213;0;0mâ–€\x1b[48;2;109;0;0m\x1b[38;2;100;0;0mâ–€\x1b[m
+\x1b[48;2;24;0;0m\x1b[38;2;157;0;0m▀\x1b[48;2;32;0;0m\x1b[38;2;165;0;0m▀\x1b[48;2;121;1;1m\x1b[38;2;128;1;1m▀\x1b[48;2;28;13;7m\x1b[38;2;30;13;7m▀\x1b[48;2;10;15;8m \x1b[48;2;11;15;8m \x1b[48;2;11;14;7m \x1b[48;2;9;15;7m \x1b[48;2;88;41;34m\x1b[38;2;91;41;34m▀\x1b[48;2;145;51;47m\x1b[38;2;163;53;49m▀\x1b[48;2;107;42;36m\x1b[38;2;161;52;48m▀\x1b[48;2;58;29;22m\x1b[38;2;155;51;47m▀\x1b[48;2;21;18;11m\x1b[38;2;128;45;40m▀\x1b[48;2;9;14;7m\x1b[38;2;79;33;27m▀\x1b[38;2;33;21;15m▀\x1b[48;2;11;14;7m\x1b[38;2;12;15;8m▀\x1b[48;2;11;15;8m\x1b[38;2;9;14;7m▀\x1b[38;2;10;14;7m▀ \x1b[48;2;11;12;8m\x1b[38;2;11;14;8m▀\x1b[48;2;8;54;6m\x1b[38;2;10;28;7m▀\x1b[48;2;6;93;4m\x1b[38;2;4;125;3m▀\x1b[48;2;2;152;1m\x1b[38;2;0;175;0m▀\x1b[48;2;0;176;0m▀\x1b[48;2;0;175;0m\x1b[38;2;1;174;1m▀\x1b[48;2;0;177;0m\x1b[38;2;1;175;1m▀\x1b[48;2;0;175;0m▀▀\x1b[48;2;1;162;1m\x1b[38;2;0;176;0m▀\x1b[48;2;9;47;6m\x1b[38;2;6;95;4m▀\x1b[48;2;11;13;8m \x1b[48;2;11;15;8m\x1b[38;2;11;14;8m▀ \x1b[48;2;10;15;8m \x1b[48;2;21;13;7m\x1b[38;2;22;13;7m▀\x1b[48;2;114;2;1m\x1b[38;2;121;2;1m▀\x1b[48;2;164;0;0m\x1b[38;2;170;0;0m▀\x1b[48;2;127;0;0m\x1b[38;2;118;0;0m▀\x1b[m
+\x1b[48;2;14;0;0m\x1b[38;2;147;0;0m▀\x1b[48;2;183;0;0m\x1b[38;2;108;0;0m▀\x1b[48;2;107;1;1m\x1b[38;2;114;1;1m▀\x1b[48;2;26;13;7m\x1b[38;2;27;13;7m▀\x1b[48;2;10;15;8m \x1b[48;2;11;15;8m \x1b[38;2;11;14;7m▀ \x1b[48;2;10;14;7m\x1b[38;2;43;27;20m▀\x1b[48;2;9;14;7m\x1b[38;2;42;25;18m▀\x1b[48;2;11;14;7m\x1b[38;2;14;16;9m▀\x1b[48;2;11;15;8m\x1b[38;2;9;14;7m▀\x1b[38;2;10;14;7m▀\x1b[38;2;11;14;7m▀ \x1b[48;2;11;12;8m \x1b[48;2;9;49;6m\x1b[38;2;8;64;5m▀\x1b[48;2;1;166;1m\x1b[38;2;1;159;1m▀\x1b[48;2;0;175;0m\x1b[38;2;1;171;1m▀ \x1b[48;2;1;159;1m\x1b[38;2;1;167;1m▀\x1b[48;2;7;79;5m\x1b[38;2;4;122;3m▀\x1b[48;2;2;144;2m\x1b[38;2;2;158;1m▀\x1b[48;2;0;158;1m\x1b[38;2;0;177;0m▀\x1b[48;2;7;44;6m\x1b[38;2;4;112;3m▀\x1b[48;2;9;12;7m\x1b[38;2;11;17;7m▀\x1b[48;2;9;14;7m\x1b[38;2;11;14;8m▀\x1b[38;2;11;15;8m▀▀▀▀▀▀▀▀▀▀▀\x1b[48;2;11;14;7m▀\x1b[48;2;11;15;8m \x1b[48;2;10;15;8m \x1b[48;2;20;13;7m\x1b[38;2;21;13;7m▀\x1b[48;2;102;2;1m\x1b[38;2;108;2;1m▀\x1b[48;2;121;0;0m\x1b[38;2;127;0;0m▀\x1b[48;2;146;0;0m\x1b[38;2;136;0;0m▀\x1b[m
+\x1b[48;2;3;0;0m\x1b[38;2;137;0;0m▀\x1b[48;2;173;0;0m\x1b[38;2;50;0;0m▀\x1b[48;2;93;1;1m\x1b[38;2;100;1;1m▀\x1b[48;2;24;13;7m\x1b[38;2;25;13;7m▀\x1b[48;2;10;15;8m \x1b[48;2;11;15;8m \x1b[48;2;11;14;7m\x1b[38;2;11;15;8m▀▀\x1b[48;2;17;14;7m\x1b[38;2;11;14;8m▀\x1b[48;2;49;12;7m\x1b[38;2;9;24;7m▀\x1b[48;2;62;54;4m\x1b[38;2;8;133;2m▀\x1b[48;2;7;159;1m\x1b[38;2;2;176;0m▀\x1b[48;2;0;175;0m \x1b[48;2;1;172;1m\x1b[38;2;0;175;0m▀\x1b[48;2;1;159;1m\x1b[38;2;0;173;1m▀\x1b[48;2;46;122;19m\x1b[38;2;1;176;0m▀\x1b[48;2;122;63;45m\x1b[38;2;45;111;18m▀\x1b[48;2;135;52;49m\x1b[38;2;75;36;31m▀\x1b[48;2;135;53;49m\x1b[38;2;74;36;30m▀▀▀▀▀▀▀▀▀▀▀\x1b[48;2;136;53;49m\x1b[38;2;75;37;31m▀\x1b[48;2;119;49;45m\x1b[38;2;66;34;28m▀\x1b[48;2;25;20;13m\x1b[38;2;18;18;11m▀\x1b[48;2;10;14;7m \x1b[48;2;11;15;8m \x1b[48;2;10;15;8m \x1b[48;2;19;13;7m \x1b[48;2;89;2;1m\x1b[38;2;95;2;1m▀\x1b[48;2;77;0;0m\x1b[38;2;83;0;0m▀\x1b[48;2;128;0;0m\x1b[38;2;119;0;0m▀\x1b[m
+\x1b[48;2;60;0;0m\x1b[38;2;126;0;0m▀\x1b[48;2;182;0;0m\x1b[38;2;249;0;0m▀\x1b[48;2;83;1;1m\x1b[38;2;87;1;1m▀\x1b[48;2;22;13;7m\x1b[38;2;23;13;7m▀\x1b[48;2;10;15;8m \x1b[48;2;11;15;8m \x1b[48;2;11;14;7m\x1b[38;2;16;14;7m▀\x1b[48;2;14;14;7m\x1b[38;2;42;13;7m▀\x1b[48;2;58;13;6m\x1b[38;2;95;11;5m▀\x1b[48;2;34;13;7m\x1b[38;2;100;11;5m▀\x1b[48;2;9;14;7m\x1b[38;2;21;17;7m▀\x1b[48;2;11;12;8m\x1b[38;2;8;55;6m▀\x1b[38;2;7;75;5m▀\x1b[38;2;8;65;5m▀\x1b[48;2;11;13;8m\x1b[38;2;9;41;6m▀\x1b[48;2;12;15;8m\x1b[38;2;60;37;28m▀\x1b[38;2;90;42;37m▀\x1b[38;2;88;42;36m▀▀▀▀▀▀▀▀▀▀▀▀\x1b[38;2;89;42;37m▀\x1b[38;2;78;39;33m▀\x1b[48;2;11;15;8m\x1b[38;2;20;18;11m▀\x1b[48;2;11;14;7m\x1b[38;2;10;14;7m▀\x1b[48;2;11;15;8m \x1b[48;2;10;15;8m \x1b[48;2;18;13;7m \x1b[48;2;78;2;1m\x1b[38;2;83;2;1m▀\x1b[48;2;196;0;0m\x1b[38;2;40;0;0m▀\x1b[48;2;217;0;0m\x1b[38;2;137;0;0m▀\x1b[m
+\x1b[48;2;227;0;0m\x1b[38;2;16;0;0m▀\x1b[48;2;116;0;0m\x1b[38;2;21;0;0m▀\x1b[48;2;79;1;1m\x1b[38;2;81;1;1m▀\x1b[48;2;22;13;7m \x1b[48;2;10;15;8m \x1b[48;2;11;15;8m \x1b[38;2;10;15;8m▀\x1b[48;2;10;15;8m\x1b[38;2;21;14;7m▀\x1b[48;2;11;15;8m\x1b[38;2;14;14;7m▀\x1b[38;2;11;14;7m▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ \x1b[48;2;10;15;8m \x1b[48;2;17;13;7m\x1b[38;2;18;13;7m▀\x1b[48;2;75;2;1m\x1b[38;2;76;2;1m▀\x1b[48;2;97;0;0m\x1b[38;2;34;0;0m▀\x1b[48;2;76;0;0m\x1b[38;2;147;0;0m▀\x1b[m
+\x1b[48;2;161;0;0m\x1b[38;2;183;0;0mâ–€\x1b[48;2;49;0;0m\x1b[38;2;211;0;0mâ–€\x1b[48;2;75;1;1m\x1b[38;2;77;1;1mâ–€\x1b[48;2;21;13;7m \x1b[48;2;10;15;8m \x1b[48;2;11;15;8m \x1b[48;2;10;15;8m \x1b[48;2;17;13;7m \x1b[48;2;71;2;1m\x1b[38;2;73;2;1mâ–€\x1b[48;2;253;0;0m\x1b[38;2;159;0;0mâ–€\x1b[48;2;191;0;0m\x1b[38;2;5;0;0mâ–€\x1b[m
+\x1b[48;2;110;161;100m\x1b[38;2;116;0;0m▀\x1b[48;2;9;205;205m\x1b[38;2;192;0;0m▀\x1b[48;2;78;0;0m\x1b[38;2;77;1;0m▀\x1b[48;2;66;3;1m\x1b[38;2;30;11;6m▀\x1b[48;2;42;8;4m\x1b[38;2;9;15;8m▀\x1b[48;2;39;8;4m\x1b[38;2;10;15;8m▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\x1b[48;2;40;8;4m▀\x1b[48;2;39;8;4m▀▀▀▀▀▀▀\x1b[48;2;40;8;4m▀▀▀\x1b[48;2;39;8;4m▀\x1b[48;2;40;8;4m▀\x1b[48;2;39;8;4m▀\x1b[48;2;41;8;4m\x1b[38;2;9;15;8m▀\x1b[48;2;62;4;2m\x1b[38;2;24;13;7m▀\x1b[48;2;78;0;0m\x1b[38;2;74;1;1m▀\x1b[48;2;221;222;0m\x1b[38;2;59;0;0m▀\x1b[48;2;67;199;133m\x1b[38;2;85;0;0m▀\x1b[m
+\x1b[48;2;0;0;0m\x1b[38;2;143;233;149m▀\x1b[48;2;108;184;254m\x1b[38;2;213;6;76m▀\x1b[48;2;197;183;82m\x1b[38;2;76;0;0m▀\x1b[48;2;154;157;0m▀\x1b[48;2;96;0;0m▀\x1b[48;2;253;0;0m▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀\x1b[48;2;226;0;0m▀\x1b[48;2;255;127;255m▀\x1b[48;2;84;36;66m\x1b[38;2;64;247;251m▀\x1b[48;2;0;0;0m\x1b[38;2;18;76;210m▀\x1b[m
+\x1b[48;2;0;0;0m \x1b[m
+\x1b[48;2;0;0;0m \x1b[m
+"""
+ )
+)
diff --git a/examples/print-text/pygments-tokens.py b/examples/print-text/pygments-tokens.py
new file mode 100755
index 0000000..3470e8e
--- /dev/null
+++ b/examples/print-text/pygments-tokens.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+"""
+Printing a list of Pygments (Token, text) tuples,
+or an output of a Pygments lexer.
+"""
+import pygments
+from pygments.lexers.python import PythonLexer
+from pygments.token import Token
+
+from prompt_toolkit import print_formatted_text
+from prompt_toolkit.formatted_text import PygmentsTokens
+from prompt_toolkit.styles import Style
+
+
+def main():
+ # Printing a manually constructed list of (Token, text) tuples.
+ text = [
+ (Token.Keyword, "print"),
+ (Token.Punctuation, "("),
+ (Token.Literal.String.Double, '"'),
+ (Token.Literal.String.Double, "hello"),
+ (Token.Literal.String.Double, '"'),
+ (Token.Punctuation, ")"),
+ (Token.Text, "\n"),
+ ]
+
+ print_formatted_text(PygmentsTokens(text))
+
+ # Printing the output of a pygments lexer.
+ tokens = list(pygments.lex('print("Hello")', lexer=PythonLexer()))
+ print_formatted_text(PygmentsTokens(tokens))
+
+ # With a custom style.
+ style = Style.from_dict(
+ {
+ "pygments.keyword": "underline",
+ "pygments.literal.string": "bg:#00ff00 #ffffff",
+ }
+ )
+ print_formatted_text(PygmentsTokens(tokens), style=style)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/print-text/true-color-demo.py b/examples/print-text/true-color-demo.py
new file mode 100755
index 0000000..a241006
--- /dev/null
+++ b/examples/print-text/true-color-demo.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+"""
+Demonstration of all the ANSI colors.
+"""
+from prompt_toolkit import print_formatted_text
+from prompt_toolkit.formatted_text import HTML, FormattedText
+from prompt_toolkit.output import ColorDepth
+
+print = print_formatted_text
+
+
+def main():
+ print(HTML("\n<u>True color test.</u>"))
+
+ for template in [
+ "bg:#{0:02x}0000", # Red.
+ "bg:#00{0:02x}00", # Green.
+ "bg:#0000{0:02x}", # Blue.
+ "bg:#{0:02x}{0:02x}00", # Yellow.
+ "bg:#{0:02x}00{0:02x}", # Magenta.
+ "bg:#00{0:02x}{0:02x}", # Cyan.
+ "bg:#{0:02x}{0:02x}{0:02x}", # Gray.
+ ]:
+ fragments = []
+ for i in range(0, 256, 4):
+ fragments.append((template.format(i), " "))
+
+ print(FormattedText(fragments), color_depth=ColorDepth.DEPTH_4_BIT)
+ print(FormattedText(fragments), color_depth=ColorDepth.DEPTH_8_BIT)
+ print(FormattedText(fragments), color_depth=ColorDepth.DEPTH_24_BIT)
+ print()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/progress-bar/a-lot-of-parallel-tasks.py b/examples/progress-bar/a-lot-of-parallel-tasks.py
new file mode 100755
index 0000000..31110ac
--- /dev/null
+++ b/examples/progress-bar/a-lot-of-parallel-tasks.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+"""
+More complex demonstration of what's possible with the progress bar.
+"""
+import random
+import threading
+import time
+
+from prompt_toolkit import HTML
+from prompt_toolkit.shortcuts import ProgressBar
+
+
+def main():
+ with ProgressBar(
+ title=HTML("<b>Example of many parallel tasks.</b>"),
+ bottom_toolbar=HTML("<b>[Control-L]</b> clear <b>[Control-C]</b> abort"),
+ ) as pb:
+
+ def run_task(label, total, sleep_time):
+ """Complete a normal run."""
+ for i in pb(range(total), label=label):
+ time.sleep(sleep_time)
+
+ def stop_task(label, total, sleep_time):
+ """Stop at some random index.
+
+ Breaking out of iteration at some stop index mimics how progress
+ bars behave in cases where errors are raised.
+ """
+ stop_i = random.randrange(total)
+ bar = pb(range(total), label=label)
+ for i in bar:
+ if stop_i == i:
+ bar.label = f"{label} BREAK"
+ break
+ time.sleep(sleep_time)
+
+ threads = []
+
+ for i in range(160):
+ label = "Task %i" % i
+ total = random.randrange(50, 200)
+ sleep_time = random.randrange(5, 20) / 100.0
+
+ threads.append(
+ threading.Thread(
+ target=random.choice((run_task, stop_task)),
+ args=(label, total, sleep_time),
+ )
+ )
+
+ for t in threads:
+ t.daemon = True
+ t.start()
+
+ # Wait for the threads to finish. We use a timeout for the join() call,
+ # because on Windows, join cannot be interrupted by Control-C or any other
+ # signal.
+ for t in threads:
+ while t.is_alive():
+ t.join(timeout=0.5)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/progress-bar/colored-title-and-label.py b/examples/progress-bar/colored-title-and-label.py
new file mode 100755
index 0000000..0b5e73a
--- /dev/null
+++ b/examples/progress-bar/colored-title-and-label.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+"""
+A progress bar that displays a formatted title above the progress bar and has a
+colored label.
+"""
+import time
+
+from prompt_toolkit.formatted_text import HTML
+from prompt_toolkit.shortcuts import ProgressBar
+
+
+def main():
+ title = HTML('Downloading <style bg="yellow" fg="black">4 files...</style>')
+ label = HTML("<ansired>some file</ansired>: ")
+
+ with ProgressBar(title=title) as pb:
+ for i in pb(range(800), label=label):
+ time.sleep(0.01)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/progress-bar/custom-key-bindings.py b/examples/progress-bar/custom-key-bindings.py
new file mode 100755
index 0000000..f700811
--- /dev/null
+++ b/examples/progress-bar/custom-key-bindings.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+"""
+A very simple progress bar which keep track of the progress as we consume an
+iterator.
+"""
+import os
+import signal
+import time
+
+from prompt_toolkit import HTML
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.patch_stdout import patch_stdout
+from prompt_toolkit.shortcuts import ProgressBar
+
+
+def main():
+ bottom_toolbar = HTML(
+ ' <b>[f]</b> Print "f" <b>[q]</b> Abort <b>[x]</b> Send Control-C.'
+ )
+
+ # Create custom key bindings first.
+ kb = KeyBindings()
+ cancel = [False]
+
+ @kb.add("f")
+ def _(event):
+ print("You pressed `f`.")
+
+ @kb.add("q")
+ def _(event):
+ "Quit by setting cancel flag."
+ cancel[0] = True
+
+ @kb.add("x")
+ def _(event):
+ "Quit by sending SIGINT to the main thread."
+ os.kill(os.getpid(), signal.SIGINT)
+
+ # Use `patch_stdout`, to make sure that prints go above the
+ # application.
+ with patch_stdout():
+ with ProgressBar(key_bindings=kb, bottom_toolbar=bottom_toolbar) as pb:
+ for i in pb(range(800)):
+ time.sleep(0.01)
+
+ if cancel[0]:
+ break
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/progress-bar/many-parallel-tasks.py b/examples/progress-bar/many-parallel-tasks.py
new file mode 100755
index 0000000..dc34ef2
--- /dev/null
+++ b/examples/progress-bar/many-parallel-tasks.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+"""
+More complex demonstration of what's possible with the progress bar.
+"""
+import threading
+import time
+
+from prompt_toolkit import HTML
+from prompt_toolkit.shortcuts import ProgressBar
+
+
+def main():
+ with ProgressBar(
+ title=HTML("<b>Example of many parallel tasks.</b>"),
+ bottom_toolbar=HTML("<b>[Control-L]</b> clear <b>[Control-C]</b> abort"),
+ ) as pb:
+
+ def run_task(label, total, sleep_time):
+ for i in pb(range(total), label=label):
+ time.sleep(sleep_time)
+
+ threads = [
+ threading.Thread(target=run_task, args=("First task", 50, 0.1)),
+ threading.Thread(target=run_task, args=("Second task", 100, 0.1)),
+ threading.Thread(target=run_task, args=("Third task", 8, 3)),
+ threading.Thread(target=run_task, args=("Fourth task", 200, 0.1)),
+ threading.Thread(target=run_task, args=("Fifth task", 40, 0.2)),
+ threading.Thread(target=run_task, args=("Sixth task", 220, 0.1)),
+ threading.Thread(target=run_task, args=("Seventh task", 85, 0.05)),
+ threading.Thread(target=run_task, args=("Eight task", 200, 0.05)),
+ ]
+
+ for t in threads:
+ t.daemon = True
+ t.start()
+
+ # Wait for the threads to finish. We use a timeout for the join() call,
+ # because on Windows, join cannot be interrupted by Control-C or any other
+ # signal.
+ for t in threads:
+ while t.is_alive():
+ t.join(timeout=0.5)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/progress-bar/nested-progress-bars.py b/examples/progress-bar/nested-progress-bars.py
new file mode 100755
index 0000000..a585ca1
--- /dev/null
+++ b/examples/progress-bar/nested-progress-bars.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+"""
+Example of nested progress bars.
+"""
+import time
+
+from prompt_toolkit import HTML
+from prompt_toolkit.shortcuts import ProgressBar
+
+
+def main():
+ with ProgressBar(
+ title=HTML('<b fg="#aa00ff">Nested progress bars</b>'),
+ bottom_toolbar=HTML(" <b>[Control-L]</b> clear <b>[Control-C]</b> abort"),
+ ) as pb:
+
+ for i in pb(range(6), label="Main task"):
+ for j in pb(range(200), label=f"Subtask <{i + 1}>", remove_when_done=True):
+ time.sleep(0.01)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/progress-bar/scrolling-task-name.py b/examples/progress-bar/scrolling-task-name.py
new file mode 100755
index 0000000..bce155f
--- /dev/null
+++ b/examples/progress-bar/scrolling-task-name.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+"""
+A very simple progress bar where the name of the task scrolls, because it's too long.
+iterator.
+"""
+import time
+
+from prompt_toolkit.shortcuts import ProgressBar
+
+
+def main():
+ with ProgressBar(
+ title="Scrolling task name (make sure the window is not too big)."
+ ) as pb:
+ for i in pb(
+ range(800),
+ label="This is a very very very long task that requires horizontal scrolling ...",
+ ):
+ time.sleep(0.01)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/progress-bar/simple-progress-bar.py b/examples/progress-bar/simple-progress-bar.py
new file mode 100755
index 0000000..c8776e5
--- /dev/null
+++ b/examples/progress-bar/simple-progress-bar.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+"""
+A very simple progress bar which keep track of the progress as we consume an
+iterator.
+"""
+import time
+
+from prompt_toolkit.shortcuts import ProgressBar
+
+
+def main():
+ with ProgressBar() as pb:
+ for i in pb(range(800)):
+ time.sleep(0.01)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/progress-bar/styled-1.py b/examples/progress-bar/styled-1.py
new file mode 100755
index 0000000..d972e55
--- /dev/null
+++ b/examples/progress-bar/styled-1.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+"""
+A very simple progress bar which keep track of the progress as we consume an
+iterator.
+"""
+import time
+
+from prompt_toolkit.shortcuts import ProgressBar
+from prompt_toolkit.styles import Style
+
+style = Style.from_dict(
+ {
+ "title": "#4444ff underline",
+ "label": "#ff4400 bold",
+ "percentage": "#00ff00",
+ "bar-a": "bg:#00ff00 #004400",
+ "bar-b": "bg:#00ff00 #000000",
+ "bar-c": "#000000 underline",
+ "current": "#448844",
+ "total": "#448844",
+ "time-elapsed": "#444488",
+ "time-left": "bg:#88ff88 #000000",
+ }
+)
+
+
+def main():
+ with ProgressBar(
+ style=style, title="Progress bar example with custom styling."
+ ) as pb:
+ for i in pb(range(1600), label="Downloading..."):
+ time.sleep(0.01)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/progress-bar/styled-2.py b/examples/progress-bar/styled-2.py
new file mode 100755
index 0000000..eb2c479
--- /dev/null
+++ b/examples/progress-bar/styled-2.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+"""
+A very simple progress bar which keep track of the progress as we consume an
+iterator.
+"""
+import time
+
+from prompt_toolkit.formatted_text import HTML
+from prompt_toolkit.shortcuts import ProgressBar
+from prompt_toolkit.shortcuts.progress_bar import formatters
+from prompt_toolkit.styles import Style
+
+style = Style.from_dict(
+ {
+ "progressbar title": "#0000ff",
+ "item-title": "#ff4400 underline",
+ "percentage": "#00ff00",
+ "bar-a": "bg:#00ff00 #004400",
+ "bar-b": "bg:#00ff00 #000000",
+ "bar-c": "bg:#000000 #000000",
+ "tildes": "#444488",
+ "time-left": "bg:#88ff88 #ffffff",
+ "spinning-wheel": "bg:#ffff00 #000000",
+ }
+)
+
+
+def main():
+ custom_formatters = [
+ formatters.Label(),
+ formatters.Text(" "),
+ formatters.SpinningWheel(),
+ formatters.Text(" "),
+ formatters.Text(HTML("<tildes>~~~</tildes>")),
+ formatters.Bar(sym_a="#", sym_b="#", sym_c="."),
+ formatters.Text(" left: "),
+ formatters.TimeLeft(),
+ ]
+ with ProgressBar(
+ title="Progress bar example with custom formatter.",
+ formatters=custom_formatters,
+ style=style,
+ ) as pb:
+
+ for i in pb(range(20), label="Downloading..."):
+ time.sleep(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/progress-bar/styled-apt-get-install.py b/examples/progress-bar/styled-apt-get-install.py
new file mode 100755
index 0000000..bafe70b
--- /dev/null
+++ b/examples/progress-bar/styled-apt-get-install.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+"""
+Styled just like an apt-get installation.
+"""
+import time
+
+from prompt_toolkit.shortcuts import ProgressBar
+from prompt_toolkit.shortcuts.progress_bar import formatters
+from prompt_toolkit.styles import Style
+
+style = Style.from_dict(
+ {
+ "label": "bg:#ffff00 #000000",
+ "percentage": "bg:#ffff00 #000000",
+ "current": "#448844",
+ "bar": "",
+ }
+)
+
+
+def main():
+ custom_formatters = [
+ formatters.Label(),
+ formatters.Text(": [", style="class:percentage"),
+ formatters.Percentage(),
+ formatters.Text("]", style="class:percentage"),
+ formatters.Text(" "),
+ formatters.Bar(sym_a="#", sym_b="#", sym_c="."),
+ formatters.Text(" "),
+ ]
+
+ with ProgressBar(style=style, formatters=custom_formatters) as pb:
+ for i in pb(range(1600), label="Installing"):
+ time.sleep(0.01)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/progress-bar/styled-rainbow.py b/examples/progress-bar/styled-rainbow.py
new file mode 100755
index 0000000..e45a916
--- /dev/null
+++ b/examples/progress-bar/styled-rainbow.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+"""
+A simple progress bar, visualised with rainbow colors (for fun).
+"""
+import time
+
+from prompt_toolkit.output import ColorDepth
+from prompt_toolkit.shortcuts import ProgressBar
+from prompt_toolkit.shortcuts.progress_bar import formatters
+from prompt_toolkit.shortcuts.prompt import confirm
+
+
+def main():
+ true_color = confirm("Yes true colors? (y/n) ")
+
+ custom_formatters = [
+ formatters.Label(),
+ formatters.Text(" "),
+ formatters.Rainbow(formatters.Bar()),
+ formatters.Text(" left: "),
+ formatters.Rainbow(formatters.TimeLeft()),
+ ]
+
+ if true_color:
+ color_depth = ColorDepth.DEPTH_24_BIT
+ else:
+ color_depth = ColorDepth.DEPTH_8_BIT
+
+ with ProgressBar(formatters=custom_formatters, color_depth=color_depth) as pb:
+ for i in pb(range(20), label="Downloading..."):
+ time.sleep(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/progress-bar/styled-tqdm-1.py b/examples/progress-bar/styled-tqdm-1.py
new file mode 100755
index 0000000..9484ac0
--- /dev/null
+++ b/examples/progress-bar/styled-tqdm-1.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+"""
+Styled similar to tqdm, another progress bar implementation in Python.
+
+See: https://github.com/noamraph/tqdm
+"""
+import time
+
+from prompt_toolkit.shortcuts import ProgressBar
+from prompt_toolkit.shortcuts.progress_bar import formatters
+from prompt_toolkit.styles import Style
+
+style = Style.from_dict({"": "cyan"})
+
+
+def main():
+ custom_formatters = [
+ formatters.Label(suffix=": "),
+ formatters.Bar(start="|", end="|", sym_a="#", sym_b="#", sym_c="-"),
+ formatters.Text(" "),
+ formatters.Progress(),
+ formatters.Text(" "),
+ formatters.Percentage(),
+ formatters.Text(" [elapsed: "),
+ formatters.TimeElapsed(),
+ formatters.Text(" left: "),
+ formatters.TimeLeft(),
+ formatters.Text(", "),
+ formatters.IterationsPerSecond(),
+ formatters.Text(" iters/sec]"),
+ formatters.Text(" "),
+ ]
+
+ with ProgressBar(style=style, formatters=custom_formatters) as pb:
+ for i in pb(range(1600), label="Installing"):
+ time.sleep(0.01)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/progress-bar/styled-tqdm-2.py b/examples/progress-bar/styled-tqdm-2.py
new file mode 100755
index 0000000..0e66e90
--- /dev/null
+++ b/examples/progress-bar/styled-tqdm-2.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+"""
+Styled similar to tqdm, another progress bar implementation in Python.
+
+See: https://github.com/noamraph/tqdm
+"""
+import time
+
+from prompt_toolkit.shortcuts import ProgressBar
+from prompt_toolkit.shortcuts.progress_bar import formatters
+from prompt_toolkit.styles import Style
+
+style = Style.from_dict({"bar-a": "reverse"})
+
+
+def main():
+ custom_formatters = [
+ formatters.Label(suffix=": "),
+ formatters.Percentage(),
+ formatters.Bar(start="|", end="|", sym_a=" ", sym_b=" ", sym_c=" "),
+ formatters.Text(" "),
+ formatters.Progress(),
+ formatters.Text(" ["),
+ formatters.TimeElapsed(),
+ formatters.Text("<"),
+ formatters.TimeLeft(),
+ formatters.Text(", "),
+ formatters.IterationsPerSecond(),
+ formatters.Text("it/s]"),
+ ]
+
+ with ProgressBar(style=style, formatters=custom_formatters) as pb:
+ for i in pb(range(1600), label="Installing"):
+ time.sleep(0.01)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/progress-bar/two-tasks.py b/examples/progress-bar/two-tasks.py
new file mode 100755
index 0000000..c78604e
--- /dev/null
+++ b/examples/progress-bar/two-tasks.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+"""
+Two progress bars that run in parallel.
+"""
+import threading
+import time
+
+from prompt_toolkit.shortcuts import ProgressBar
+
+
+def main():
+ with ProgressBar() as pb:
+ # Two parallal tasks.
+ def task_1():
+ for i in pb(range(100)):
+ time.sleep(0.05)
+
+ def task_2():
+ for i in pb(range(150)):
+ time.sleep(0.08)
+
+ # Start threads.
+ t1 = threading.Thread(target=task_1)
+ t2 = threading.Thread(target=task_2)
+ t1.daemon = True
+ t2.daemon = True
+ t1.start()
+ t2.start()
+
+ # Wait for the threads to finish. We use a timeout for the join() call,
+ # because on Windows, join cannot be interrupted by Control-C or any other
+ # signal.
+ for t in [t1, t2]:
+ while t.is_alive():
+ t.join(timeout=0.5)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/progress-bar/unknown-length.py b/examples/progress-bar/unknown-length.py
new file mode 100755
index 0000000..e39ac39
--- /dev/null
+++ b/examples/progress-bar/unknown-length.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+"""
+A very simple progress bar which keep track of the progress as we consume an
+iterator.
+"""
+import time
+
+from prompt_toolkit.shortcuts import ProgressBar
+
+
+def data():
+ """
+ A generator that produces items. len() doesn't work here, so the progress
+ bar can't estimate the time it will take.
+ """
+ yield from range(1000)
+
+
+def main():
+ with ProgressBar() as pb:
+ for i in pb(data()):
+ time.sleep(0.1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/accept-default.py b/examples/prompts/accept-default.py
new file mode 100644
index 0000000..311ef46
--- /dev/null
+++ b/examples/prompts/accept-default.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+"""
+Example of `accept_default`, a way to automatically accept the input that the
+user typed without allowing him/her to edit it.
+
+This should display the prompt with all the formatting like usual, but not
+allow any editing.
+"""
+from prompt_toolkit import HTML, prompt
+
+if __name__ == "__main__":
+ answer = prompt(
+ HTML("<b>Type <u>some input</u>: </b>"), accept_default=True, default="test"
+ )
+
+ print("You said: %s" % answer)
diff --git a/examples/prompts/asyncio-prompt.py b/examples/prompts/asyncio-prompt.py
new file mode 100755
index 0000000..5a30e73
--- /dev/null
+++ b/examples/prompts/asyncio-prompt.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+"""
+(Python >= 3.6)
+This is an example of how to prompt inside an application that uses the asyncio
+eventloop. The ``prompt_toolkit`` library will make sure that when other
+coroutines are writing to stdout, they write above the prompt, not destroying
+the input line.
+This example does several things:
+ 1. It starts a simple coroutine, printing a counter to stdout every second.
+ 2. It starts a simple input/echo app loop which reads from stdin.
+Very important is the following patch. If you are passing stdin by reference to
+other parts of the code, make sure that this patch is applied as early as
+possible. ::
+ sys.stdout = app.stdout_proxy()
+"""
+
+import asyncio
+
+from prompt_toolkit.patch_stdout import patch_stdout
+from prompt_toolkit.shortcuts import PromptSession
+
+
+async def print_counter():
+ """
+ Coroutine that prints counters.
+ """
+ try:
+ i = 0
+ while True:
+ print("Counter: %i" % i)
+ i += 1
+ await asyncio.sleep(3)
+ except asyncio.CancelledError:
+ print("Background task cancelled.")
+
+
+async def interactive_shell():
+ """
+ Like `interactive_shell`, but doing things manual.
+ """
+ # Create Prompt.
+ session = PromptSession("Say something: ")
+
+ # Run echo loop. Read text from stdin, and reply it back.
+ while True:
+ try:
+ result = await session.prompt_async()
+ print(f'You said: "{result}"')
+ except (EOFError, KeyboardInterrupt):
+ return
+
+
+async def main():
+ with patch_stdout():
+ background_task = asyncio.create_task(print_counter())
+ try:
+ await interactive_shell()
+ finally:
+ background_task.cancel()
+ print("Quitting event loop. Bye.")
+
+
+if __name__ == "__main__":
+ try:
+ from asyncio import run
+ except ImportError:
+ asyncio.run_until_complete(main())
+ else:
+ asyncio.run(main())
diff --git a/examples/prompts/auto-completion/autocomplete-with-control-space.py b/examples/prompts/auto-completion/autocomplete-with-control-space.py
new file mode 100755
index 0000000..61160a3
--- /dev/null
+++ b/examples/prompts/auto-completion/autocomplete-with-control-space.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+"""
+Example of using the control-space key binding for auto completion.
+"""
+from prompt_toolkit import prompt
+from prompt_toolkit.completion import WordCompleter
+from prompt_toolkit.key_binding import KeyBindings
+
+animal_completer = WordCompleter(
+ [
+ "alligator",
+ "ant",
+ "ape",
+ "bat",
+ "bear",
+ "beaver",
+ "bee",
+ "bison",
+ "butterfly",
+ "cat",
+ "chicken",
+ "crocodile",
+ "dinosaur",
+ "dog",
+ "dolphin",
+ "dove",
+ "duck",
+ "eagle",
+ "elephant",
+ "fish",
+ "goat",
+ "gorilla",
+ "kangaroo",
+ "leopard",
+ "lion",
+ "mouse",
+ "rabbit",
+ "rat",
+ "snake",
+ "spider",
+ "turkey",
+ "turtle",
+ ],
+ ignore_case=True,
+)
+
+
+kb = KeyBindings()
+
+
+@kb.add("c-space")
+def _(event):
+ """
+ Start auto completion. If the menu is showing already, select the next
+ completion.
+ """
+ b = event.app.current_buffer
+ if b.complete_state:
+ b.complete_next()
+ else:
+ b.start_completion(select_first=False)
+
+
+def main():
+ text = prompt(
+ "Give some animals: ",
+ completer=animal_completer,
+ complete_while_typing=False,
+ key_bindings=kb,
+ )
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/auto-completion/autocompletion-like-readline.py b/examples/prompts/auto-completion/autocompletion-like-readline.py
new file mode 100755
index 0000000..613d3e7
--- /dev/null
+++ b/examples/prompts/auto-completion/autocompletion-like-readline.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+"""
+Autocompletion example that displays the autocompletions like readline does by
+binding a custom handler to the Tab key.
+"""
+from prompt_toolkit.completion import WordCompleter
+from prompt_toolkit.shortcuts import CompleteStyle, prompt
+
+animal_completer = WordCompleter(
+ [
+ "alligator",
+ "ant",
+ "ape",
+ "bat",
+ "bear",
+ "beaver",
+ "bee",
+ "bison",
+ "butterfly",
+ "cat",
+ "chicken",
+ "crocodile",
+ "dinosaur",
+ "dog",
+ "dolphin",
+ "dove",
+ "duck",
+ "eagle",
+ "elephant",
+ "fish",
+ "goat",
+ "gorilla",
+ "kangaroo",
+ "leopard",
+ "lion",
+ "mouse",
+ "rabbit",
+ "rat",
+ "snake",
+ "spider",
+ "turkey",
+ "turtle",
+ ],
+ ignore_case=True,
+)
+
+
+def main():
+ text = prompt(
+ "Give some animals: ",
+ completer=animal_completer,
+ complete_style=CompleteStyle.READLINE_LIKE,
+ )
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/auto-completion/autocompletion.py b/examples/prompts/auto-completion/autocompletion.py
new file mode 100755
index 0000000..fc9dda0
--- /dev/null
+++ b/examples/prompts/auto-completion/autocompletion.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+"""
+Autocompletion example.
+
+Press [Tab] to complete the current word.
+- The first Tab press fills in the common part of all completions
+ and shows all the completions. (In the menu)
+- Any following tab press cycles through all the possible completions.
+"""
+from prompt_toolkit import prompt
+from prompt_toolkit.completion import WordCompleter
+
+animal_completer = WordCompleter(
+ [
+ "alligator",
+ "ant",
+ "ape",
+ "bat",
+ "bear",
+ "beaver",
+ "bee",
+ "bison",
+ "butterfly",
+ "cat",
+ "chicken",
+ "crocodile",
+ "dinosaur",
+ "dog",
+ "dolphin",
+ "dove",
+ "duck",
+ "eagle",
+ "elephant",
+ "fish",
+ "goat",
+ "gorilla",
+ "kangaroo",
+ "leopard",
+ "lion",
+ "mouse",
+ "rabbit",
+ "rat",
+ "snake",
+ "spider",
+ "turkey",
+ "turtle",
+ ],
+ ignore_case=True,
+)
+
+
+def main():
+ text = prompt(
+ "Give some animals: ", completer=animal_completer, complete_while_typing=False
+ )
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/auto-completion/colored-completions-with-formatted-text.py b/examples/prompts/auto-completion/colored-completions-with-formatted-text.py
new file mode 100755
index 0000000..8a89c7a
--- /dev/null
+++ b/examples/prompts/auto-completion/colored-completions-with-formatted-text.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python
+"""
+Demonstration of a custom completer class and the possibility of styling
+completions independently by passing formatted text objects to the "display"
+and "display_meta" arguments of "Completion".
+"""
+from prompt_toolkit.completion import Completer, Completion
+from prompt_toolkit.formatted_text import HTML
+from prompt_toolkit.shortcuts import CompleteStyle, prompt
+
+animals = [
+ "alligator",
+ "ant",
+ "ape",
+ "bat",
+ "bear",
+ "beaver",
+ "bee",
+ "bison",
+ "butterfly",
+ "cat",
+ "chicken",
+ "crocodile",
+ "dinosaur",
+ "dog",
+ "dolphin",
+ "dove",
+ "duck",
+ "eagle",
+ "elephant",
+]
+
+animal_family = {
+ "alligator": "reptile",
+ "ant": "insect",
+ "ape": "mammal",
+ "bat": "mammal",
+ "bear": "mammal",
+ "beaver": "mammal",
+ "bee": "insect",
+ "bison": "mammal",
+ "butterfly": "insect",
+ "cat": "mammal",
+ "chicken": "bird",
+ "crocodile": "reptile",
+ "dinosaur": "reptile",
+ "dog": "mammal",
+ "dolphin": "mammal",
+ "dove": "bird",
+ "duck": "bird",
+ "eagle": "bird",
+ "elephant": "mammal",
+}
+
+family_colors = {
+ "mammal": "ansimagenta",
+ "insect": "ansigreen",
+ "reptile": "ansired",
+ "bird": "ansiyellow",
+}
+
+meta = {
+ "alligator": HTML(
+ "An <ansired>alligator</ansired> is a <u>crocodilian</u> in the genus Alligator of the family Alligatoridae."
+ ),
+ "ant": HTML(
+ "<ansired>Ants</ansired> are eusocial <u>insects</u> of the family Formicidae."
+ ),
+ "ape": HTML(
+ "<ansired>Apes</ansired> (Hominoidea) are a branch of Old World tailless anthropoid catarrhine <u>primates</u>."
+ ),
+ "bat": HTML("<ansired>Bats</ansired> are mammals of the order <u>Chiroptera</u>."),
+ "bee": HTML(
+ "<ansired>Bees</ansired> are flying <u>insects</u> closely related to wasps and ants."
+ ),
+ "beaver": HTML(
+ "The <ansired>beaver</ansired> (genus Castor) is a large, primarily <u>nocturnal</u>, semiaquatic <u>rodent</u>."
+ ),
+ "bear": HTML(
+ "<ansired>Bears</ansired> are carnivoran <u>mammals</u> of the family Ursidae."
+ ),
+ "butterfly": HTML(
+ "<ansiblue>Butterflies</ansiblue> are <u>insects</u> in the macrolepidopteran clade Rhopalocera from the order Lepidoptera."
+ ),
+ # ...
+}
+
+
+class AnimalCompleter(Completer):
+ def get_completions(self, document, complete_event):
+ word = document.get_word_before_cursor()
+ for animal in animals:
+ if animal.startswith(word):
+ if animal in animal_family:
+ family = animal_family[animal]
+ family_color = family_colors.get(family, "default")
+
+ display = HTML(
+ "%s<b>:</b> <ansired>(<"
+ + family_color
+ + ">%s</"
+ + family_color
+ + ">)</ansired>"
+ ) % (animal, family)
+ else:
+ display = animal
+
+ yield Completion(
+ animal,
+ start_position=-len(word),
+ display=display,
+ display_meta=meta.get(animal),
+ )
+
+
+def main():
+ # Simple completion menu.
+ print("(The completion menu displays colors.)")
+ prompt("Type an animal: ", completer=AnimalCompleter())
+
+ # Multi-column menu.
+ prompt(
+ "Type an animal: ",
+ completer=AnimalCompleter(),
+ complete_style=CompleteStyle.MULTI_COLUMN,
+ )
+
+ # Readline-like
+ prompt(
+ "Type an animal: ",
+ completer=AnimalCompleter(),
+ complete_style=CompleteStyle.READLINE_LIKE,
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/auto-completion/colored-completions.py b/examples/prompts/auto-completion/colored-completions.py
new file mode 100755
index 0000000..9c5cba3
--- /dev/null
+++ b/examples/prompts/auto-completion/colored-completions.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+"""
+Demonstration of a custom completer class and the possibility of styling
+completions independently.
+"""
+from prompt_toolkit.completion import Completer, Completion
+from prompt_toolkit.output.color_depth import ColorDepth
+from prompt_toolkit.shortcuts import CompleteStyle, prompt
+
+colors = [
+ "red",
+ "blue",
+ "green",
+ "orange",
+ "purple",
+ "yellow",
+ "cyan",
+ "magenta",
+ "pink",
+]
+
+
+class ColorCompleter(Completer):
+ def get_completions(self, document, complete_event):
+ word = document.get_word_before_cursor()
+ for color in colors:
+ if color.startswith(word):
+ yield Completion(
+ color,
+ start_position=-len(word),
+ style="fg:" + color,
+ selected_style="fg:white bg:" + color,
+ )
+
+
+def main():
+ # Simple completion menu.
+ print("(The completion menu displays colors.)")
+ prompt("Type a color: ", completer=ColorCompleter())
+
+ # Multi-column menu.
+ prompt(
+ "Type a color: ",
+ completer=ColorCompleter(),
+ complete_style=CompleteStyle.MULTI_COLUMN,
+ )
+
+ # Readline-like
+ prompt(
+ "Type a color: ",
+ completer=ColorCompleter(),
+ complete_style=CompleteStyle.READLINE_LIKE,
+ )
+
+ # Prompt with true color output.
+ message = [
+ ("#cc2244", "T"),
+ ("#bb4444", "r"),
+ ("#996644", "u"),
+ ("#cc8844", "e "),
+ ("#ccaa44", "C"),
+ ("#bbaa44", "o"),
+ ("#99aa44", "l"),
+ ("#778844", "o"),
+ ("#55aa44", "r "),
+ ("#33aa44", "p"),
+ ("#11aa44", "r"),
+ ("#11aa66", "o"),
+ ("#11aa88", "m"),
+ ("#11aaaa", "p"),
+ ("#11aacc", "t"),
+ ("#11aaee", ": "),
+ ]
+ prompt(message, completer=ColorCompleter(), color_depth=ColorDepth.TRUE_COLOR)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/auto-completion/combine-multiple-completers.py b/examples/prompts/auto-completion/combine-multiple-completers.py
new file mode 100755
index 0000000..273ebe5
--- /dev/null
+++ b/examples/prompts/auto-completion/combine-multiple-completers.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+"""
+Example of multiple individual completers that are combined into one.
+"""
+from prompt_toolkit import prompt
+from prompt_toolkit.completion import Completer, WordCompleter, merge_completers
+
+animal_completer = WordCompleter(
+ [
+ "alligator",
+ "ant",
+ "ape",
+ "bat",
+ "bear",
+ "beaver",
+ "bee",
+ "bison",
+ "butterfly",
+ "cat",
+ "chicken",
+ "crocodile",
+ "dinosaur",
+ "dog",
+ "dolphin",
+ "dove",
+ "duck",
+ "eagle",
+ "elephant",
+ "fish",
+ "goat",
+ "gorilla",
+ "kangaroo",
+ "leopard",
+ "lion",
+ "mouse",
+ "rabbit",
+ "rat",
+ "snake",
+ "spider",
+ "turkey",
+ "turtle",
+ ],
+ ignore_case=True,
+)
+
+color_completer = WordCompleter(
+ [
+ "red",
+ "green",
+ "blue",
+ "yellow",
+ "white",
+ "black",
+ "orange",
+ "gray",
+ "pink",
+ "purple",
+ "cyan",
+ "magenta",
+ "violet",
+ ],
+ ignore_case=True,
+)
+
+
+def main():
+ completer = merge_completers([animal_completer, color_completer])
+
+ text = prompt(
+ "Give some animals: ", completer=completer, complete_while_typing=False
+ )
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/auto-completion/fuzzy-custom-completer.py b/examples/prompts/auto-completion/fuzzy-custom-completer.py
new file mode 100755
index 0000000..4052929
--- /dev/null
+++ b/examples/prompts/auto-completion/fuzzy-custom-completer.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+"""
+Demonstration of a custom completer wrapped in a `FuzzyCompleter` for fuzzy
+matching.
+"""
+from prompt_toolkit.completion import Completer, Completion, FuzzyCompleter
+from prompt_toolkit.output.color_depth import ColorDepth
+from prompt_toolkit.shortcuts import CompleteStyle, prompt
+
+colors = [
+ "red",
+ "blue",
+ "green",
+ "orange",
+ "purple",
+ "yellow",
+ "cyan",
+ "magenta",
+ "pink",
+]
+
+
+class ColorCompleter(Completer):
+ def get_completions(self, document, complete_event):
+ word = document.get_word_before_cursor()
+ for color in colors:
+ if color.startswith(word):
+ yield Completion(
+ color,
+ start_position=-len(word),
+ style="fg:" + color,
+ selected_style="fg:white bg:" + color,
+ )
+
+
+def main():
+ # Simple completion menu.
+ print("(The completion menu displays colors.)")
+ prompt("Type a color: ", completer=FuzzyCompleter(ColorCompleter()))
+
+ # Multi-column menu.
+ prompt(
+ "Type a color: ",
+ completer=FuzzyCompleter(ColorCompleter()),
+ complete_style=CompleteStyle.MULTI_COLUMN,
+ )
+
+ # Readline-like
+ prompt(
+ "Type a color: ",
+ completer=FuzzyCompleter(ColorCompleter()),
+ complete_style=CompleteStyle.READLINE_LIKE,
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/auto-completion/fuzzy-word-completer.py b/examples/prompts/auto-completion/fuzzy-word-completer.py
new file mode 100755
index 0000000..329c0c1
--- /dev/null
+++ b/examples/prompts/auto-completion/fuzzy-word-completer.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+"""
+Autocompletion example.
+
+Press [Tab] to complete the current word.
+- The first Tab press fills in the common part of all completions
+ and shows all the completions. (In the menu)
+- Any following tab press cycles through all the possible completions.
+"""
+from prompt_toolkit.completion import FuzzyWordCompleter
+from prompt_toolkit.shortcuts import prompt
+
+animal_completer = FuzzyWordCompleter(
+ [
+ "alligator",
+ "ant",
+ "ape",
+ "bat",
+ "bear",
+ "beaver",
+ "bee",
+ "bison",
+ "butterfly",
+ "cat",
+ "chicken",
+ "crocodile",
+ "dinosaur",
+ "dog",
+ "dolphin",
+ "dove",
+ "duck",
+ "eagle",
+ "elephant",
+ "fish",
+ "goat",
+ "gorilla",
+ "kangaroo",
+ "leopard",
+ "lion",
+ "mouse",
+ "rabbit",
+ "rat",
+ "snake",
+ "spider",
+ "turkey",
+ "turtle",
+ ]
+)
+
+
+def main():
+ text = prompt(
+ "Give some animals: ", completer=animal_completer, complete_while_typing=True
+ )
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/auto-completion/multi-column-autocompletion-with-meta.py b/examples/prompts/auto-completion/multi-column-autocompletion-with-meta.py
new file mode 100755
index 0000000..5ba3ab5
--- /dev/null
+++ b/examples/prompts/auto-completion/multi-column-autocompletion-with-meta.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+"""
+Autocompletion example that shows meta-information alongside the completions.
+"""
+from prompt_toolkit.completion import WordCompleter
+from prompt_toolkit.shortcuts import CompleteStyle, prompt
+
+animal_completer = WordCompleter(
+ [
+ "alligator",
+ "ant",
+ "ape",
+ "bat",
+ "bear",
+ "beaver",
+ "bee",
+ "bison",
+ "butterfly",
+ "cat",
+ "chicken",
+ "crocodile",
+ "dinosaur",
+ "dog",
+ "dolphin",
+ "dove",
+ "duck",
+ "eagle",
+ "elephant",
+ ],
+ meta_dict={
+ "alligator": "An alligator is a crocodilian in the genus Alligator of the family Alligatoridae.",
+ "ant": "Ants are eusocial insects of the family Formicidae",
+ "ape": "Apes (Hominoidea) are a branch of Old World tailless anthropoid catarrhine primates ",
+ "bat": "Bats are mammals of the order Chiroptera",
+ },
+ ignore_case=True,
+)
+
+
+def main():
+ text = prompt(
+ "Give some animals: ",
+ completer=animal_completer,
+ complete_style=CompleteStyle.MULTI_COLUMN,
+ )
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/auto-completion/multi-column-autocompletion.py b/examples/prompts/auto-completion/multi-column-autocompletion.py
new file mode 100755
index 0000000..7fcfc52
--- /dev/null
+++ b/examples/prompts/auto-completion/multi-column-autocompletion.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+"""
+Similar to the autocompletion example. But display all the completions in multiple columns.
+"""
+from prompt_toolkit.completion import WordCompleter
+from prompt_toolkit.shortcuts import CompleteStyle, prompt
+
+animal_completer = WordCompleter(
+ [
+ "alligator",
+ "ant",
+ "ape",
+ "bat",
+ "bear",
+ "beaver",
+ "bee",
+ "bison",
+ "butterfly",
+ "cat",
+ "chicken",
+ "crocodile",
+ "dinosaur",
+ "dog",
+ "dolphin",
+ "dove",
+ "duck",
+ "eagle",
+ "elephant",
+ "fish",
+ "goat",
+ "gorilla",
+ "kangaroo",
+ "leopard",
+ "lion",
+ "mouse",
+ "rabbit",
+ "rat",
+ "snake",
+ "spider",
+ "turkey",
+ "turtle",
+ ],
+ ignore_case=True,
+)
+
+
+def main():
+ text = prompt(
+ "Give some animals: ",
+ completer=animal_completer,
+ complete_style=CompleteStyle.MULTI_COLUMN,
+ )
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/auto-completion/nested-autocompletion.py b/examples/prompts/auto-completion/nested-autocompletion.py
new file mode 100755
index 0000000..cd85b8c
--- /dev/null
+++ b/examples/prompts/auto-completion/nested-autocompletion.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+"""
+Example of nested autocompletion.
+"""
+from prompt_toolkit import prompt
+from prompt_toolkit.completion import NestedCompleter
+
+completer = NestedCompleter.from_nested_dict(
+ {
+ "show": {"version": None, "clock": None, "ip": {"interface": {"brief": None}}},
+ "exit": None,
+ }
+)
+
+
+def main():
+ text = prompt("Type a command: ", completer=completer)
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/auto-completion/slow-completions.py b/examples/prompts/auto-completion/slow-completions.py
new file mode 100755
index 0000000..cce9d59
--- /dev/null
+++ b/examples/prompts/auto-completion/slow-completions.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+"""
+An example of how to deal with slow auto completion code.
+
+- Running the completions in a thread is possible by wrapping the
+ `Completer` object in a `ThreadedCompleter`. This makes sure that the
+ ``get_completions`` generator is executed in a background thread.
+
+ For the `prompt` shortcut, we don't have to wrap the completer ourselves.
+ Passing `complete_in_thread=True` is sufficient.
+
+- We also set a `loading` boolean in the completer function to keep track of
+ when the completer is running, and display this in the toolbar.
+"""
+import time
+
+from prompt_toolkit.completion import Completer, Completion
+from prompt_toolkit.shortcuts import CompleteStyle, prompt
+
+WORDS = [
+ "alligator",
+ "ant",
+ "ape",
+ "bat",
+ "bear",
+ "beaver",
+ "bee",
+ "bison",
+ "butterfly",
+ "cat",
+ "chicken",
+ "crocodile",
+ "dinosaur",
+ "dog",
+ "dolphin",
+ "dove",
+ "duck",
+ "eagle",
+ "elephant",
+ "fish",
+ "goat",
+ "gorilla",
+ "kangaroo",
+ "leopard",
+ "lion",
+ "mouse",
+ "rabbit",
+ "rat",
+ "snake",
+ "spider",
+ "turkey",
+ "turtle",
+]
+
+
+class SlowCompleter(Completer):
+ """
+ This is a completer that's very slow.
+ """
+
+ def __init__(self):
+ self.loading = 0
+
+ def get_completions(self, document, complete_event):
+ # Keep count of how many completion generators are running.
+ self.loading += 1
+ word_before_cursor = document.get_word_before_cursor()
+
+ try:
+ for word in WORDS:
+ if word.startswith(word_before_cursor):
+ time.sleep(0.2) # Simulate slowness.
+ yield Completion(word, -len(word_before_cursor))
+
+ finally:
+ # We use try/finally because this generator can be closed if the
+ # input text changes before all completions are generated.
+ self.loading -= 1
+
+
+def main():
+ # We wrap it in a ThreadedCompleter, to make sure it runs in a different
+ # thread. That way, we don't block the UI while running the completions.
+ slow_completer = SlowCompleter()
+
+ # Add a bottom toolbar that display when completions are loading.
+ def bottom_toolbar():
+ return " Loading completions... " if slow_completer.loading > 0 else ""
+
+ # Display prompt.
+ text = prompt(
+ "Give some animals: ",
+ completer=slow_completer,
+ complete_in_thread=True,
+ complete_while_typing=True,
+ bottom_toolbar=bottom_toolbar,
+ complete_style=CompleteStyle.MULTI_COLUMN,
+ )
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/auto-suggestion.py b/examples/prompts/auto-suggestion.py
new file mode 100755
index 0000000..6660777
--- /dev/null
+++ b/examples/prompts/auto-suggestion.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+"""
+Simple example of a CLI that demonstrates fish-style auto suggestion.
+
+When you type some input, it will match the input against the history. If One
+entry of the history starts with the given input, then it will show the
+remaining part as a suggestion. Pressing the right arrow will insert this
+suggestion.
+"""
+from prompt_toolkit import PromptSession
+from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
+from prompt_toolkit.history import InMemoryHistory
+
+
+def main():
+ # Create some history first. (Easy for testing.)
+ history = InMemoryHistory()
+ history.append_string("import os")
+ history.append_string('print("hello")')
+ history.append_string('print("world")')
+ history.append_string("import path")
+
+ # Print help.
+ print("This CLI has fish-style auto-suggestion enable.")
+ print('Type for instance "pri", then you\'ll see a suggestion.')
+ print("Press the right arrow to insert the suggestion.")
+ print("Press Control-C to retry. Control-D to exit.")
+ print()
+
+ session = PromptSession(
+ history=history,
+ auto_suggest=AutoSuggestFromHistory(),
+ enable_history_search=True,
+ )
+
+ while True:
+ try:
+ text = session.prompt("Say something: ")
+ except KeyboardInterrupt:
+ pass # Ctrl-C pressed. Try again.
+ else:
+ break
+
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/autocorrection.py b/examples/prompts/autocorrection.py
new file mode 100755
index 0000000..6378132
--- /dev/null
+++ b/examples/prompts/autocorrection.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+"""
+Example of implementing auto correction while typing.
+
+The word "impotr" will be corrected when the user types a space afterwards.
+"""
+from prompt_toolkit import prompt
+from prompt_toolkit.key_binding import KeyBindings
+
+# Database of words to be replaced by typing.
+corrections = {
+ "impotr": "import",
+ "wolrd": "world",
+}
+
+
+def main():
+ # We start with a `KeyBindings` for our extra key bindings.
+ bindings = KeyBindings()
+
+ # We add a custom key binding to space.
+ @bindings.add(" ")
+ def _(event):
+ """
+ When space is pressed, we check the word before the cursor, and
+ autocorrect that.
+ """
+ b = event.app.current_buffer
+ w = b.document.get_word_before_cursor()
+
+ if w is not None:
+ if w in corrections:
+ b.delete_before_cursor(count=len(w))
+ b.insert_text(corrections[w])
+
+ b.insert_text(" ")
+
+ # Read input.
+ text = prompt("Say something: ", key_bindings=bindings)
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/bottom-toolbar.py b/examples/prompts/bottom-toolbar.py
new file mode 100755
index 0000000..4980e5b
--- /dev/null
+++ b/examples/prompts/bottom-toolbar.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+"""
+A few examples of displaying a bottom toolbar.
+
+The ``prompt`` function takes a ``bottom_toolbar`` attribute.
+This can be any kind of formatted text (plain text, HTML or ANSI), or
+it can be a callable that takes an App and returns an of these.
+
+The bottom toolbar will always receive the style 'bottom-toolbar', and the text
+inside will get 'bottom-toolbar.text'. These can be used to change the default
+style.
+"""
+import time
+
+from prompt_toolkit import prompt
+from prompt_toolkit.formatted_text import ANSI, HTML
+from prompt_toolkit.styles import Style
+
+
+def main():
+ # Example 1: fixed text.
+ text = prompt("Say something: ", bottom_toolbar="This is a toolbar")
+ print("You said: %s" % text)
+
+ # Example 2: fixed text from a callable:
+ def get_toolbar():
+ return "Bottom toolbar: time=%r" % time.time()
+
+ text = prompt("Say something: ", bottom_toolbar=get_toolbar, refresh_interval=0.5)
+ print("You said: %s" % text)
+
+ # Example 3: Using HTML:
+ text = prompt(
+ "Say something: ",
+ bottom_toolbar=HTML(
+ '(html) <b>This</b> <u>is</u> a <style bg="ansired">toolbar</style>'
+ ),
+ )
+ print("You said: %s" % text)
+
+ # Example 4: Using ANSI:
+ text = prompt(
+ "Say something: ",
+ bottom_toolbar=ANSI(
+ "(ansi): \x1b[1mThis\x1b[0m \x1b[4mis\x1b[0m a \x1b[91mtoolbar"
+ ),
+ )
+ print("You said: %s" % text)
+
+ # Example 5: styling differently.
+ style = Style.from_dict(
+ {
+ "bottom-toolbar": "#aaaa00 bg:#ff0000",
+ "bottom-toolbar.text": "#aaaa44 bg:#aa4444",
+ }
+ )
+
+ text = prompt("Say something: ", bottom_toolbar="This is a toolbar", style=style)
+ print("You said: %s" % text)
+
+ # Example 6: Using a list of tokens.
+ def get_bottom_toolbar():
+ return [
+ ("", " "),
+ ("bg:#ff0000 fg:#000000", "This"),
+ ("", " is a "),
+ ("bg:#ff0000 fg:#000000", "toolbar"),
+ ("", ". "),
+ ]
+
+ text = prompt("Say something: ", bottom_toolbar=get_bottom_toolbar)
+ print("You said: %s" % text)
+
+ # Example 7: multiline fixed text.
+ text = prompt("Say something: ", bottom_toolbar="This is\na multiline toolbar")
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/clock-input.py b/examples/prompts/clock-input.py
new file mode 100755
index 0000000..e43abd8
--- /dev/null
+++ b/examples/prompts/clock-input.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+"""
+Example of a 'dynamic' prompt. On that shows the current time in the prompt.
+"""
+import datetime
+
+from prompt_toolkit.shortcuts import prompt
+
+
+def get_prompt():
+ "Tokens to be shown before the prompt."
+ now = datetime.datetime.now()
+ return [
+ ("bg:#008800 #ffffff", f"{now.hour}:{now.minute}:{now.second}"),
+ ("bg:cornsilk fg:maroon", " Enter something: "),
+ ]
+
+
+def main():
+ result = prompt(get_prompt, refresh_interval=0.5)
+ print("You said: %s" % result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/colored-prompt.py b/examples/prompts/colored-prompt.py
new file mode 100755
index 0000000..1e63e29
--- /dev/null
+++ b/examples/prompts/colored-prompt.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python
+"""
+Example of a colored prompt.
+"""
+from prompt_toolkit import prompt
+from prompt_toolkit.formatted_text import ANSI, HTML
+from prompt_toolkit.styles import Style
+
+style = Style.from_dict(
+ {
+ # Default style.
+ "": "#ff0066",
+ # Prompt.
+ "username": "#884444 italic",
+ "at": "#00aa00",
+ "colon": "#00aa00",
+ "pound": "#00aa00",
+ "host": "#000088 bg:#aaaaff",
+ "path": "#884444 underline",
+ # Make a selection reverse/underlined.
+ # (Use Control-Space to select.)
+ "selected-text": "reverse underline",
+ }
+)
+
+
+def example_1():
+ """
+ Style and list of (style, text) tuples.
+ """
+ # Not that we can combine class names and inline styles.
+ prompt_fragments = [
+ ("class:username", "john"),
+ ("class:at", "@"),
+ ("class:host", "localhost"),
+ ("class:colon", ":"),
+ ("class:path", "/user/john"),
+ ("bg:#00aa00 #ffffff", "#"),
+ ("", " "),
+ ]
+
+ answer = prompt(prompt_fragments, style=style)
+ print("You said: %s" % answer)
+
+
+def example_2():
+ """
+ Using HTML for the formatting.
+ """
+ answer = prompt(
+ HTML(
+ "<username>john</username><at>@</at>"
+ "<host>localhost</host>"
+ "<colon>:</colon>"
+ "<path>/user/john</path>"
+ '<style bg="#00aa00" fg="#ffffff">#</style> '
+ ),
+ style=style,
+ )
+ print("You said: %s" % answer)
+
+
+def example_3():
+ """
+ Using ANSI for the formatting.
+ """
+ answer = prompt(
+ ANSI(
+ "\x1b[31mjohn\x1b[0m@"
+ "\x1b[44mlocalhost\x1b[0m:"
+ "\x1b[4m/user/john\x1b[0m"
+ "# "
+ )
+ )
+ print("You said: %s" % answer)
+
+
+if __name__ == "__main__":
+ example_1()
+ example_2()
+ example_3()
diff --git a/examples/prompts/confirmation-prompt.py b/examples/prompts/confirmation-prompt.py
new file mode 100755
index 0000000..bd52b9e
--- /dev/null
+++ b/examples/prompts/confirmation-prompt.py
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+"""
+Example of a confirmation prompt.
+"""
+from prompt_toolkit.shortcuts import confirm
+
+if __name__ == "__main__":
+ answer = confirm("Should we do that?")
+ print("You said: %s" % answer)
diff --git a/examples/prompts/cursor-shapes.py b/examples/prompts/cursor-shapes.py
new file mode 100755
index 0000000..e668243
--- /dev/null
+++ b/examples/prompts/cursor-shapes.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+"""
+Example of cursor shape configurations.
+"""
+from prompt_toolkit import prompt
+from prompt_toolkit.cursor_shapes import CursorShape, ModalCursorShapeConfig
+
+# NOTE: We pass `enable_suspend=True`, so that we can easily see what happens
+# to the cursor shapes when the application is suspended.
+
+prompt("(block): ", cursor=CursorShape.BLOCK, enable_suspend=True)
+prompt("(underline): ", cursor=CursorShape.UNDERLINE, enable_suspend=True)
+prompt("(beam): ", cursor=CursorShape.BEAM, enable_suspend=True)
+prompt(
+ "(modal - according to vi input mode): ",
+ cursor=ModalCursorShapeConfig(),
+ vi_mode=True,
+ enable_suspend=True,
+)
diff --git a/examples/prompts/custom-key-binding.py b/examples/prompts/custom-key-binding.py
new file mode 100755
index 0000000..32d889e
--- /dev/null
+++ b/examples/prompts/custom-key-binding.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+"""
+Example of adding a custom key binding to a prompt.
+"""
+import asyncio
+
+from prompt_toolkit import prompt
+from prompt_toolkit.application import in_terminal, run_in_terminal
+from prompt_toolkit.key_binding import KeyBindings
+
+
+def main():
+ # We start with a `KeyBindings` of default key bindings.
+ bindings = KeyBindings()
+
+ # Add our own key binding.
+ @bindings.add("f4")
+ def _(event):
+ """
+ When F4 has been pressed. Insert "hello world" as text.
+ """
+ event.app.current_buffer.insert_text("hello world")
+
+ @bindings.add("x", "y")
+ def _(event):
+ """
+ (Useless, but for demoing.)
+ Typing 'xy' will insert 'z'.
+
+ Note that when you type for instance 'xa', the insertion of 'x' is
+ postponed until the 'a' is typed. because we don't know earlier whether
+ or not a 'y' will follow. However, prompt-toolkit should already give
+ some visual feedback of the typed character.
+ """
+ event.app.current_buffer.insert_text("z")
+
+ @bindings.add("a", "b", "c")
+ def _(event):
+ "Typing 'abc' should insert 'd'."
+ event.app.current_buffer.insert_text("d")
+
+ @bindings.add("c-t")
+ def _(event):
+ """
+ Print 'hello world' in the terminal when ControlT is pressed.
+
+ We use ``run_in_terminal``, because that ensures that the prompt is
+ hidden right before ``print_hello`` gets executed and it's drawn again
+ after it. (Otherwise this would destroy the output.)
+ """
+
+ def print_hello():
+ print("hello world")
+
+ run_in_terminal(print_hello)
+
+ @bindings.add("c-k")
+ async def _(event):
+ """
+ Example of asyncio coroutine as a key binding.
+ """
+ try:
+ for i in range(5):
+ async with in_terminal():
+ print("hello")
+ await asyncio.sleep(1)
+ except asyncio.CancelledError:
+ print("Prompt terminated before we completed.")
+
+ # Read input.
+ print('Press F4 to insert "hello world", type "xy" to insert "z":')
+ text = prompt("> ", key_bindings=bindings)
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/custom-lexer.py b/examples/prompts/custom-lexer.py
new file mode 100755
index 0000000..1255d9f
--- /dev/null
+++ b/examples/prompts/custom-lexer.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+"""
+An example of a custom lexer that prints the input text in random colors.
+"""
+from prompt_toolkit.lexers import Lexer
+from prompt_toolkit.shortcuts import prompt
+from prompt_toolkit.styles.named_colors import NAMED_COLORS
+
+
+class RainbowLexer(Lexer):
+ def lex_document(self, document):
+ colors = list(sorted(NAMED_COLORS, key=NAMED_COLORS.get))
+
+ def get_line(lineno):
+ return [
+ (colors[i % len(colors)], c)
+ for i, c in enumerate(document.lines[lineno])
+ ]
+
+ return get_line
+
+
+def main():
+ answer = prompt("Give me some input: ", lexer=RainbowLexer())
+ print("You said: %s" % answer)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/custom-vi-operator-and-text-object.py b/examples/prompts/custom-vi-operator-and-text-object.py
new file mode 100755
index 0000000..7478afc
--- /dev/null
+++ b/examples/prompts/custom-vi-operator-and-text-object.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+"""
+Example of adding a custom Vi operator and text object.
+(Note that this API is not guaranteed to remain stable.)
+"""
+from prompt_toolkit import prompt
+from prompt_toolkit.enums import EditingMode
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.key_binding.bindings.vi import (
+ TextObject,
+ create_operator_decorator,
+ create_text_object_decorator,
+)
+
+
+def main():
+ # We start with a `Registry` of default key bindings.
+ bindings = KeyBindings()
+
+ # Create the decorators to be used for registering text objects and
+ # operators in this registry.
+ operator = create_operator_decorator(bindings)
+ text_object = create_text_object_decorator(bindings)
+
+ # Create a custom operator.
+
+ @operator("R")
+ def _(event, text_object):
+ "Custom operator that reverses text."
+ buff = event.current_buffer
+
+ # Get relative start/end coordinates.
+ start, end = text_object.operator_range(buff.document)
+ start += buff.cursor_position
+ end += buff.cursor_position
+
+ text = buff.text[start:end]
+ text = "".join(reversed(text))
+
+ event.app.current_buffer.text = buff.text[:start] + text + buff.text[end:]
+
+ # Create a text object.
+
+ @text_object("A")
+ def _(event):
+ "A custom text object that involves everything."
+ # Note that a `TextObject` has coordinates, relative to the cursor position.
+ buff = event.current_buffer
+ return TextObject(
+ -buff.document.cursor_position, # The start.
+ len(buff.text) - buff.document.cursor_position,
+ ) # The end.
+
+ # Read input.
+ print('There is a custom text object "A" that applies to everything')
+ print('and a custom operator "r" that reverses the text object.\n')
+
+ print("Things that are possible:")
+ print("- Riw - reverse inner word.")
+ print("- yA - yank everything.")
+ print("- RA - reverse everything.")
+
+ text = prompt(
+ "> ", default="hello world", key_bindings=bindings, editing_mode=EditingMode.VI
+ )
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/enforce-tty-input-output.py b/examples/prompts/enforce-tty-input-output.py
new file mode 100755
index 0000000..93b43ee
--- /dev/null
+++ b/examples/prompts/enforce-tty-input-output.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+"""
+This will display a prompt that will always use the terminal for input and
+output, even if sys.stdin/stdout are connected to pipes.
+
+For testing, run as:
+ cat /dev/null | python ./enforce-tty-input-output.py > /dev/null
+"""
+from prompt_toolkit.application import create_app_session_from_tty
+from prompt_toolkit.shortcuts import prompt
+
+with create_app_session_from_tty():
+ prompt(">")
diff --git a/examples/prompts/fancy-zsh-prompt.py b/examples/prompts/fancy-zsh-prompt.py
new file mode 100755
index 0000000..4761c08
--- /dev/null
+++ b/examples/prompts/fancy-zsh-prompt.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+"""
+Example of the fancy ZSH prompt that @anki-code was using.
+
+The theme is coming from the xonsh plugin from the xxh project:
+https://github.com/xxh/xxh-plugin-xonsh-theme-bar
+
+See:
+- https://github.com/xonsh/xonsh/issues/3356
+- https://github.com/prompt-toolkit/python-prompt-toolkit/issues/1111
+"""
+import datetime
+
+from prompt_toolkit import prompt
+from prompt_toolkit.application import get_app
+from prompt_toolkit.formatted_text import (
+ HTML,
+ fragment_list_width,
+ merge_formatted_text,
+ to_formatted_text,
+)
+from prompt_toolkit.styles import Style
+
+style = Style.from_dict(
+ {
+ "username": "#aaaaaa italic",
+ "path": "#ffffff bold",
+ "branch": "bg:#666666",
+ "branch exclamation-mark": "#ff0000",
+ "env": "bg:#666666",
+ "left-part": "bg:#444444",
+ "right-part": "bg:#444444",
+ "padding": "bg:#444444",
+ }
+)
+
+
+def get_prompt() -> HTML:
+ """
+ Build the prompt dynamically every time its rendered.
+ """
+ left_part = HTML(
+ "<left-part>"
+ " <username>root</username> "
+ " abc "
+ "<path>~/.oh-my-zsh/themes</path>"
+ "</left-part>"
+ )
+ right_part = HTML(
+ "<right-part> "
+ "<branch> master<exclamation-mark>!</exclamation-mark> </branch> "
+ " <env> py36 </env> "
+ " <time>%s</time> "
+ "</right-part>"
+ ) % (datetime.datetime.now().isoformat(),)
+
+ used_width = sum(
+ [
+ fragment_list_width(to_formatted_text(left_part)),
+ fragment_list_width(to_formatted_text(right_part)),
+ ]
+ )
+
+ total_width = get_app().output.get_size().columns
+ padding_size = total_width - used_width
+
+ padding = HTML("<padding>%s</padding>") % (" " * padding_size,)
+
+ return merge_formatted_text([left_part, padding, right_part, "\n", "# "])
+
+
+def main() -> None:
+ while True:
+ answer = prompt(get_prompt, style=style, refresh_interval=1)
+ print("You said: %s" % answer)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/finalterm-shell-integration.py b/examples/prompts/finalterm-shell-integration.py
new file mode 100755
index 0000000..30c7a7f
--- /dev/null
+++ b/examples/prompts/finalterm-shell-integration.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+"""
+Mark the start and end of the prompt with Final term (iterm2) escape sequences.
+See: https://iterm2.com/finalterm.html
+"""
+import sys
+
+from prompt_toolkit import prompt
+from prompt_toolkit.formatted_text import ANSI
+
+BEFORE_PROMPT = "\033]133;A\a"
+AFTER_PROMPT = "\033]133;B\a"
+BEFORE_OUTPUT = "\033]133;C\a"
+AFTER_OUTPUT = (
+ "\033]133;D;{command_status}\a" # command_status is the command status, 0-255
+)
+
+
+def get_prompt_text():
+ # Generate the text fragments for the prompt.
+ # Important: use the `ZeroWidthEscape` fragment only if you are sure that
+ # writing this as raw text to the output will not introduce any
+ # cursor movements.
+ return [
+ ("[ZeroWidthEscape]", BEFORE_PROMPT),
+ ("", "Say something: # "),
+ ("[ZeroWidthEscape]", AFTER_PROMPT),
+ ]
+
+
+if __name__ == "__main__":
+ # Option 1: Using a `get_prompt_text` function:
+ answer = prompt(get_prompt_text)
+
+ # Option 2: Using ANSI escape sequences.
+ before = "\001" + BEFORE_PROMPT + "\002"
+ after = "\001" + AFTER_PROMPT + "\002"
+ answer = prompt(ANSI(f"{before}Say something: # {after}"))
+
+ # Output.
+ sys.stdout.write(BEFORE_OUTPUT)
+ print("You said: %s" % answer)
+ sys.stdout.write(AFTER_OUTPUT.format(command_status=0))
diff --git a/examples/prompts/get-input-vi-mode.py b/examples/prompts/get-input-vi-mode.py
new file mode 100755
index 0000000..566ffd5
--- /dev/null
+++ b/examples/prompts/get-input-vi-mode.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+from prompt_toolkit import prompt
+
+if __name__ == "__main__":
+ print("You have Vi keybindings here. Press [Esc] to go to navigation mode.")
+ answer = prompt("Give me some input: ", multiline=False, vi_mode=True)
+ print("You said: %s" % answer)
diff --git a/examples/prompts/get-input-with-default.py b/examples/prompts/get-input-with-default.py
new file mode 100755
index 0000000..67446d5
--- /dev/null
+++ b/examples/prompts/get-input-with-default.py
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+"""
+Example of a call to `prompt` with a default value.
+The input is pre-filled, but the user can still edit the default.
+"""
+import getpass
+
+from prompt_toolkit import prompt
+
+if __name__ == "__main__":
+ answer = prompt("What is your name: ", default="%s" % getpass.getuser())
+ print("You said: %s" % answer)
diff --git a/examples/prompts/get-input.py b/examples/prompts/get-input.py
new file mode 100755
index 0000000..5529bbb
--- /dev/null
+++ b/examples/prompts/get-input.py
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+"""
+The most simple prompt example.
+"""
+from prompt_toolkit import prompt
+
+if __name__ == "__main__":
+ answer = prompt("Give me some input: ")
+ print("You said: %s" % answer)
diff --git a/examples/prompts/get-multiline-input.py b/examples/prompts/get-multiline-input.py
new file mode 100755
index 0000000..eda35be
--- /dev/null
+++ b/examples/prompts/get-multiline-input.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+from prompt_toolkit import prompt
+from prompt_toolkit.formatted_text import HTML
+
+
+def prompt_continuation(width, line_number, wrap_count):
+ """
+ The continuation: display line numbers and '->' before soft wraps.
+
+ Notice that we can return any kind of formatted text from here.
+
+ The prompt continuation doesn't have to be the same width as the prompt
+ which is displayed before the first line, but in this example we choose to
+ align them. The `width` input that we receive here represents the width of
+ the prompt.
+ """
+ if wrap_count > 0:
+ return " " * (width - 3) + "-> "
+ else:
+ text = ("- %i - " % (line_number + 1)).rjust(width)
+ return HTML("<strong>%s</strong>") % text
+
+
+if __name__ == "__main__":
+ print("Press [Meta+Enter] or [Esc] followed by [Enter] to accept input.")
+ answer = prompt(
+ "Multiline input: ", multiline=True, prompt_continuation=prompt_continuation
+ )
+ print("You said: %s" % answer)
diff --git a/examples/prompts/get-password-with-toggle-display-shortcut.py b/examples/prompts/get-password-with-toggle-display-shortcut.py
new file mode 100755
index 0000000..b89cb41
--- /dev/null
+++ b/examples/prompts/get-password-with-toggle-display-shortcut.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+"""
+get_password function that displays asterisks instead of the actual characters.
+With the addition of a ControlT shortcut to hide/show the input.
+"""
+from prompt_toolkit import prompt
+from prompt_toolkit.filters import Condition
+from prompt_toolkit.key_binding import KeyBindings
+
+
+def main():
+ hidden = [True] # Nonlocal
+ bindings = KeyBindings()
+
+ @bindings.add("c-t")
+ def _(event):
+ "When ControlT has been pressed, toggle visibility."
+ hidden[0] = not hidden[0]
+
+ print("Type Control-T to toggle password visible.")
+ password = prompt(
+ "Password: ", is_password=Condition(lambda: hidden[0]), key_bindings=bindings
+ )
+ print("You said: %s" % password)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/get-password.py b/examples/prompts/get-password.py
new file mode 100755
index 0000000..1c9517c
--- /dev/null
+++ b/examples/prompts/get-password.py
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+from prompt_toolkit import prompt
+
+if __name__ == "__main__":
+ password = prompt("Password: ", is_password=True)
+ print("You said: %s" % password)
diff --git a/examples/prompts/history/persistent-history.py b/examples/prompts/history/persistent-history.py
new file mode 100755
index 0000000..2bdb758
--- /dev/null
+++ b/examples/prompts/history/persistent-history.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+"""
+Simple example of a CLI that keeps a persistent history of all the entered
+strings in a file. When you run this script for a second time, pressing
+arrow-up will go back in history.
+"""
+from prompt_toolkit import PromptSession
+from prompt_toolkit.history import FileHistory
+
+
+def main():
+ our_history = FileHistory(".example-history-file")
+
+ # The history needs to be passed to the `PromptSession`. It can't be passed
+ # to the `prompt` call because only one history can be used during a
+ # session.
+ session = PromptSession(history=our_history)
+
+ while True:
+ text = session.prompt("Say something: ")
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/history/slow-history.py b/examples/prompts/history/slow-history.py
new file mode 100755
index 0000000..5b6a7a2
--- /dev/null
+++ b/examples/prompts/history/slow-history.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+"""
+Simple example of a custom, very slow history, that is loaded asynchronously.
+
+By wrapping it in `ThreadedHistory`, the history will load in the background
+without blocking any user interaction.
+"""
+import time
+
+from prompt_toolkit import PromptSession
+from prompt_toolkit.history import History, ThreadedHistory
+
+
+class SlowHistory(History):
+ """
+ Example class that loads the history very slowly...
+ """
+
+ def load_history_strings(self):
+ for i in range(1000):
+ time.sleep(1) # Emulate slowness.
+ yield f"item-{i}"
+
+ def store_string(self, string):
+ pass # Don't store strings.
+
+
+def main():
+ print(
+ "Asynchronous loading of history. Notice that the up-arrow will work "
+ "for as far as the completions are loaded.\n"
+ "Even when the input is accepted, loading will continue in the "
+ "background and when the next prompt is displayed.\n"
+ )
+ our_history = ThreadedHistory(SlowHistory())
+
+ # The history needs to be passed to the `PromptSession`. It can't be passed
+ # to the `prompt` call because only one history can be used during a
+ # session.
+ session = PromptSession(history=our_history)
+
+ while True:
+ text = session.prompt("Say something: ")
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/html-input.py b/examples/prompts/html-input.py
new file mode 100755
index 0000000..4c51737
--- /dev/null
+++ b/examples/prompts/html-input.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+"""
+Simple example of a syntax-highlighted HTML input line.
+(This requires Pygments to be installed.)
+"""
+from pygments.lexers.html import HtmlLexer
+
+from prompt_toolkit import prompt
+from prompt_toolkit.lexers import PygmentsLexer
+
+
+def main():
+ text = prompt("Enter HTML: ", lexer=PygmentsLexer(HtmlLexer))
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/input-validation.py b/examples/prompts/input-validation.py
new file mode 100755
index 0000000..d8bd3ee
--- /dev/null
+++ b/examples/prompts/input-validation.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+"""
+Simple example of input validation.
+"""
+from prompt_toolkit import prompt
+from prompt_toolkit.validation import Validator
+
+
+def is_valid_email(text):
+ return "@" in text
+
+
+validator = Validator.from_callable(
+ is_valid_email,
+ error_message="Not a valid e-mail address (Does not contain an @).",
+ move_cursor_to_end=True,
+)
+
+
+def main():
+ # Validate when pressing ENTER.
+ text = prompt(
+ "Enter e-mail address: ", validator=validator, validate_while_typing=False
+ )
+ print("You said: %s" % text)
+
+ # While typing
+ text = prompt(
+ "Enter e-mail address: ", validator=validator, validate_while_typing=True
+ )
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/inputhook.py b/examples/prompts/inputhook.py
new file mode 100755
index 0000000..8520790
--- /dev/null
+++ b/examples/prompts/inputhook.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+"""
+An example that demonstrates how inputhooks can be used in prompt-toolkit.
+
+An inputhook is a callback that an eventloop calls when it's idle. For
+instance, readline calls `PyOS_InputHook`. This allows us to do other work in
+the same thread, while waiting for input. Important however is that we give the
+control back to prompt-toolkit when some input is ready to be processed.
+
+There are two ways to know when input is ready. One way is to poll
+`InputHookContext.input_is_ready()`. Another way is to check for
+`InputHookContext.fileno()` to be ready. In this example we do the latter.
+"""
+import gobject
+import gtk
+from pygments.lexers.python import PythonLexer
+
+from prompt_toolkit.eventloop.defaults import create_event_loop
+from prompt_toolkit.lexers import PygmentsLexer
+from prompt_toolkit.patch_stdout import patch_stdout
+from prompt_toolkit.shortcuts import PromptSession
+
+
+def hello_world_window():
+ """
+ Create a GTK window with one 'Hello world' button.
+ """
+ # Create a new window.
+ window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ window.set_border_width(50)
+
+ # Create a new button with the label "Hello World".
+ button = gtk.Button("Hello World")
+ window.add(button)
+
+ # Clicking the button prints some text.
+ def clicked(data):
+ print("Button clicked!")
+
+ button.connect("clicked", clicked)
+
+ # Display the window.
+ button.show()
+ window.show()
+
+
+def inputhook(context):
+ """
+ When the eventloop of prompt-toolkit is idle, call this inputhook.
+
+ This will run the GTK main loop until the file descriptor
+ `context.fileno()` becomes ready.
+
+ :param context: An `InputHookContext` instance.
+ """
+
+ def _main_quit(*a, **kw):
+ gtk.main_quit()
+ return False
+
+ gobject.io_add_watch(context.fileno(), gobject.IO_IN, _main_quit)
+ gtk.main()
+
+
+def main():
+ # Create user interface.
+ hello_world_window()
+
+ # Enable threading in GTK. (Otherwise, GTK will keep the GIL.)
+ gtk.gdk.threads_init()
+
+ # Read input from the command line, using an event loop with this hook.
+ # We use `patch_stdout`, because clicking the button will print something;
+ # and that should print nicely 'above' the input line.
+ with patch_stdout():
+ session = PromptSession(
+ "Python >>> ", inputhook=inputhook, lexer=PygmentsLexer(PythonLexer)
+ )
+ result = session.prompt()
+ print("You said: %s" % result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/mouse-support.py b/examples/prompts/mouse-support.py
new file mode 100755
index 0000000..1e4ee76
--- /dev/null
+++ b/examples/prompts/mouse-support.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+from prompt_toolkit import prompt
+
+if __name__ == "__main__":
+ print(
+ "This is multiline input. press [Meta+Enter] or [Esc] followed by [Enter] to accept input."
+ )
+ print("You can click with the mouse in order to select text.")
+ answer = prompt("Multiline input: ", multiline=True, mouse_support=True)
+ print("You said: %s" % answer)
diff --git a/examples/prompts/multiline-prompt.py b/examples/prompts/multiline-prompt.py
new file mode 100755
index 0000000..d6a7698
--- /dev/null
+++ b/examples/prompts/multiline-prompt.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+"""
+Demonstration of how the input can be indented.
+"""
+from prompt_toolkit import prompt
+
+if __name__ == "__main__":
+ answer = prompt(
+ "Give me some input: (ESCAPE followed by ENTER to accept)\n > ", multiline=True
+ )
+ print("You said: %s" % answer)
diff --git a/examples/prompts/no-wrapping.py b/examples/prompts/no-wrapping.py
new file mode 100755
index 0000000..371486e
--- /dev/null
+++ b/examples/prompts/no-wrapping.py
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+from prompt_toolkit import prompt
+
+if __name__ == "__main__":
+ answer = prompt("Give me some input: ", wrap_lines=False, multiline=True)
+ print("You said: %s" % answer)
diff --git a/examples/prompts/operate-and-get-next.py b/examples/prompts/operate-and-get-next.py
new file mode 100755
index 0000000..6ea4d79
--- /dev/null
+++ b/examples/prompts/operate-and-get-next.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+"""
+Demo of "operate-and-get-next".
+
+(Actually, this creates one prompt application, and keeps running the same app
+over and over again. -- For now, this is the only way to get this working.)
+"""
+from prompt_toolkit.shortcuts import PromptSession
+
+
+def main():
+ session = PromptSession("prompt> ")
+ while True:
+ session.prompt()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/patch-stdout.py b/examples/prompts/patch-stdout.py
new file mode 100755
index 0000000..1c83524
--- /dev/null
+++ b/examples/prompts/patch-stdout.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+"""
+An example that demonstrates how `patch_stdout` works.
+
+This makes sure that output from other threads doesn't disturb the rendering of
+the prompt, but instead is printed nicely above the prompt.
+"""
+import threading
+import time
+
+from prompt_toolkit import prompt
+from prompt_toolkit.patch_stdout import patch_stdout
+
+
+def main():
+ # Print a counter every second in another thread.
+ running = True
+
+ def thread():
+ i = 0
+ while running:
+ i += 1
+ print("i=%i" % i)
+ time.sleep(1)
+
+ t = threading.Thread(target=thread)
+ t.daemon = True
+ t.start()
+
+ # Now read the input. The print statements of the other thread
+ # should not disturb anything.
+ with patch_stdout():
+ result = prompt("Say something: ")
+ print("You said: %s" % result)
+
+ # Stop thread.
+ running = False
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/placeholder-text.py b/examples/prompts/placeholder-text.py
new file mode 100755
index 0000000..e113330
--- /dev/null
+++ b/examples/prompts/placeholder-text.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+"""
+Example of a placeholer that's displayed as long as no input is given.
+"""
+from prompt_toolkit import prompt
+from prompt_toolkit.formatted_text import HTML
+
+if __name__ == "__main__":
+ answer = prompt(
+ "Give me some input: ",
+ placeholder=HTML('<style color="#888888">(please type something)</style>'),
+ )
+ print("You said: %s" % answer)
diff --git a/examples/prompts/regular-language.py b/examples/prompts/regular-language.py
new file mode 100755
index 0000000..cbe7256
--- /dev/null
+++ b/examples/prompts/regular-language.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+"""
+This is an example of "prompt_toolkit.contrib.regular_languages" which
+implements a little calculator.
+
+Type for instance::
+
+ > add 4 4
+ > sub 4 4
+ > sin 3.14
+
+This example shows how you can define the grammar of a regular language and how
+to use variables in this grammar with completers and tokens attached.
+"""
+import math
+
+from prompt_toolkit import prompt
+from prompt_toolkit.completion import WordCompleter
+from prompt_toolkit.contrib.regular_languages.compiler import compile
+from prompt_toolkit.contrib.regular_languages.completion import GrammarCompleter
+from prompt_toolkit.contrib.regular_languages.lexer import GrammarLexer
+from prompt_toolkit.lexers import SimpleLexer
+from prompt_toolkit.styles import Style
+
+operators1 = ["add", "sub", "div", "mul"]
+operators2 = ["cos", "sin"]
+
+
+def create_grammar():
+ return compile(
+ r"""
+ (\s* (?P<operator1>[a-z]+) \s+ (?P<var1>[0-9.]+) \s+ (?P<var2>[0-9.]+) \s*) |
+ (\s* (?P<operator2>[a-z]+) \s+ (?P<var1>[0-9.]+) \s*)
+ """
+ )
+
+
+example_style = Style.from_dict(
+ {
+ "operator": "#33aa33 bold",
+ "number": "#ff0000 bold",
+ "trailing-input": "bg:#662222 #ffffff",
+ }
+)
+
+
+if __name__ == "__main__":
+ g = create_grammar()
+
+ lexer = GrammarLexer(
+ g,
+ lexers={
+ "operator1": SimpleLexer("class:operator"),
+ "operator2": SimpleLexer("class:operator"),
+ "var1": SimpleLexer("class:number"),
+ "var2": SimpleLexer("class:number"),
+ },
+ )
+
+ completer = GrammarCompleter(
+ g,
+ {
+ "operator1": WordCompleter(operators1),
+ "operator2": WordCompleter(operators2),
+ },
+ )
+
+ try:
+ # REPL loop.
+ while True:
+ # Read input and parse the result.
+ text = prompt(
+ "Calculate: ", lexer=lexer, completer=completer, style=example_style
+ )
+ m = g.match(text)
+ if m:
+ vars = m.variables()
+ else:
+ print("Invalid command\n")
+ continue
+
+ print(vars)
+ if vars.get("operator1") or vars.get("operator2"):
+ try:
+ var1 = float(vars.get("var1", 0))
+ var2 = float(vars.get("var2", 0))
+ except ValueError:
+ print("Invalid command (2)\n")
+ continue
+
+ # Turn the operator string into a function.
+ operator = {
+ "add": (lambda a, b: a + b),
+ "sub": (lambda a, b: a - b),
+ "mul": (lambda a, b: a * b),
+ "div": (lambda a, b: a / b),
+ "sin": (lambda a, b: math.sin(a)),
+ "cos": (lambda a, b: math.cos(a)),
+ }[vars.get("operator1") or vars.get("operator2")]
+
+ # Execute and print the result.
+ print("Result: %s\n" % (operator(var1, var2)))
+
+ elif vars.get("operator2"):
+ print("Operator 2")
+
+ except EOFError:
+ pass
diff --git a/examples/prompts/rprompt.py b/examples/prompts/rprompt.py
new file mode 100755
index 0000000..f7656b7
--- /dev/null
+++ b/examples/prompts/rprompt.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+"""
+Example of a right prompt. This is an additional prompt that is displayed on
+the right side of the terminal. It will be hidden automatically when the input
+is long enough to cover the right side of the terminal.
+
+This is similar to RPROMPT is Zsh.
+"""
+from prompt_toolkit import prompt
+from prompt_toolkit.formatted_text import ANSI, HTML
+from prompt_toolkit.styles import Style
+
+example_style = Style.from_dict(
+ {
+ # The 'rprompt' gets by default the 'rprompt' class. We can use this
+ # for the styling.
+ "rprompt": "bg:#ff0066 #ffffff",
+ }
+)
+
+
+def get_rprompt_text():
+ return [
+ ("", " "),
+ ("underline", "<rprompt>"),
+ ("", " "),
+ ]
+
+
+def main():
+ # Option 1: pass a string to 'rprompt':
+ answer = prompt("> ", rprompt=" <rprompt> ", style=example_style)
+ print("You said: %s" % answer)
+
+ # Option 2: pass HTML:
+ answer = prompt("> ", rprompt=HTML(" <u>&lt;rprompt&gt;</u> "), style=example_style)
+ print("You said: %s" % answer)
+
+ # Option 3: pass ANSI:
+ answer = prompt(
+ "> ", rprompt=ANSI(" \x1b[4m<rprompt>\x1b[0m "), style=example_style
+ )
+ print("You said: %s" % answer)
+
+ # Option 4: Pass a callable. (This callable can either return plain text,
+ # an HTML object, an ANSI object or a list of (style, text)
+ # tuples.
+ answer = prompt("> ", rprompt=get_rprompt_text, style=example_style)
+ print("You said: %s" % answer)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/swap-light-and-dark-colors.py b/examples/prompts/swap-light-and-dark-colors.py
new file mode 100755
index 0000000..e602449
--- /dev/null
+++ b/examples/prompts/swap-light-and-dark-colors.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+"""
+Demonstration of swapping light/dark colors in prompt_toolkit using the
+`swap_light_and_dark_colors` parameter.
+
+Notice that this doesn't swap foreground and background like "reverse" does. It
+turns light green into dark green and the other way around. Foreground and
+background are independent of each other.
+"""
+from pygments.lexers.html import HtmlLexer
+
+from prompt_toolkit import prompt
+from prompt_toolkit.completion import WordCompleter
+from prompt_toolkit.filters import Condition
+from prompt_toolkit.formatted_text import HTML
+from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.lexers import PygmentsLexer
+
+html_completer = WordCompleter(
+ [
+ "<body>",
+ "<div>",
+ "<head>",
+ "<html>",
+ "<img>",
+ "<li>",
+ "<link>",
+ "<ol>",
+ "<p>",
+ "<span>",
+ "<table>",
+ "<td>",
+ "<th>",
+ "<tr>",
+ "<ul>",
+ ],
+ ignore_case=True,
+)
+
+
+def main():
+ swapped = [False] # Nonlocal
+ bindings = KeyBindings()
+
+ @bindings.add("c-t")
+ def _(event):
+ "When ControlT has been pressed, toggle light/dark colors."
+ swapped[0] = not swapped[0]
+
+ def bottom_toolbar():
+ if swapped[0]:
+ on = "on=true"
+ else:
+ on = "on=false"
+
+ return (
+ HTML(
+ 'Press <style bg="#222222" fg="#ff8888">[control-t]</style> '
+ "to swap between dark/light colors. "
+ '<style bg="ansiblack" fg="ansiwhite">[%s]</style>'
+ )
+ % on
+ )
+
+ text = prompt(
+ HTML('<style fg="#aaaaaa">Give some animals</style>: '),
+ completer=html_completer,
+ complete_while_typing=True,
+ bottom_toolbar=bottom_toolbar,
+ key_bindings=bindings,
+ lexer=PygmentsLexer(HtmlLexer),
+ swap_light_and_dark_colors=Condition(lambda: swapped[0]),
+ )
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/prompts/switch-between-vi-emacs.py b/examples/prompts/switch-between-vi-emacs.py
new file mode 100755
index 0000000..249c7ef
--- /dev/null
+++ b/examples/prompts/switch-between-vi-emacs.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+"""
+Example that displays how to switch between Emacs and Vi input mode.
+
+"""
+from prompt_toolkit import prompt
+from prompt_toolkit.application.current import get_app
+from prompt_toolkit.enums import EditingMode
+from prompt_toolkit.key_binding import KeyBindings
+
+
+def run():
+ # Create a `KeyBindings` that contains the default key bindings.
+ bindings = KeyBindings()
+
+ # Add an additional key binding for toggling this flag.
+ @bindings.add("f4")
+ def _(event):
+ "Toggle between Emacs and Vi mode."
+ if event.app.editing_mode == EditingMode.VI:
+ event.app.editing_mode = EditingMode.EMACS
+ else:
+ event.app.editing_mode = EditingMode.VI
+
+ def bottom_toolbar():
+ "Display the current input mode."
+ if get_app().editing_mode == EditingMode.VI:
+ return " [F4] Vi "
+ else:
+ return " [F4] Emacs "
+
+ prompt("> ", key_bindings=bindings, bottom_toolbar=bottom_toolbar)
+
+
+if __name__ == "__main__":
+ run()
diff --git a/examples/prompts/system-clipboard-integration.py b/examples/prompts/system-clipboard-integration.py
new file mode 100755
index 0000000..f605921
--- /dev/null
+++ b/examples/prompts/system-clipboard-integration.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+"""
+Demonstration of a custom clipboard class.
+This requires the 'pyperclip' library to be installed.
+"""
+from prompt_toolkit import prompt
+from prompt_toolkit.clipboard.pyperclip import PyperclipClipboard
+
+if __name__ == "__main__":
+ print("Emacs shortcuts:")
+ print(" Press Control-Y to paste from the system clipboard.")
+ print(" Press Control-Space or Control-@ to enter selection mode.")
+ print(" Press Control-W to cut to clipboard.")
+ print("")
+
+ answer = prompt("Give me some input: ", clipboard=PyperclipClipboard())
+ print("You said: %s" % answer)
diff --git a/examples/prompts/system-prompt.py b/examples/prompts/system-prompt.py
new file mode 100755
index 0000000..47aa2a5
--- /dev/null
+++ b/examples/prompts/system-prompt.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+from prompt_toolkit import prompt
+
+if __name__ == "__main__":
+ # System prompt.
+ print(
+ "(1/3) If you press meta-! or esc-! at the following prompt, you can enter system commands."
+ )
+ answer = prompt("Give me some input: ", enable_system_prompt=True)
+ print("You said: %s" % answer)
+
+ # Enable suspend.
+ print("(2/3) If you press Control-Z, the application will suspend.")
+ answer = prompt("Give me some input: ", enable_suspend=True)
+ print("You said: %s" % answer)
+
+ # Enable open_in_editor
+ print("(3/3) If you press Control-X Control-E, the prompt will open in $EDITOR.")
+ answer = prompt("Give me some input: ", enable_open_in_editor=True)
+ print("You said: %s" % answer)
diff --git a/examples/prompts/terminal-title.py b/examples/prompts/terminal-title.py
new file mode 100755
index 0000000..14f9459
--- /dev/null
+++ b/examples/prompts/terminal-title.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+from prompt_toolkit import prompt
+from prompt_toolkit.shortcuts import set_title
+
+if __name__ == "__main__":
+ set_title("This is the terminal title")
+ answer = prompt("Give me some input: ")
+ set_title("")
+
+ print("You said: %s" % answer)
diff --git a/examples/prompts/up-arrow-partial-string-matching.py b/examples/prompts/up-arrow-partial-string-matching.py
new file mode 100755
index 0000000..742a12e
--- /dev/null
+++ b/examples/prompts/up-arrow-partial-string-matching.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+"""
+Simple example of a CLI that demonstrates up-arrow partial string matching.
+
+When you type some input, it's possible to use the up arrow to filter the
+history on the items starting with the given input text.
+"""
+from prompt_toolkit import PromptSession
+from prompt_toolkit.history import InMemoryHistory
+
+
+def main():
+ # Create some history first. (Easy for testing.)
+ history = InMemoryHistory()
+ history.append_string("import os")
+ history.append_string('print("hello")')
+ history.append_string('print("world")')
+ history.append_string("import path")
+
+ # Print help.
+ print("This CLI has up-arrow partial string matching enabled.")
+ print('Type for instance "pri" followed by up-arrow and you')
+ print('get the last items starting with "pri".')
+ print("Press Control-C to retry. Control-D to exit.")
+ print()
+
+ session = PromptSession(history=history, enable_history_search=True)
+
+ while True:
+ try:
+ text = session.prompt("Say something: ")
+ except KeyboardInterrupt:
+ pass # Ctrl-C pressed. Try again.
+ else:
+ break
+
+ print("You said: %s" % text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/ssh/asyncssh-server.py b/examples/ssh/asyncssh-server.py
new file mode 100755
index 0000000..1fa1800
--- /dev/null
+++ b/examples/ssh/asyncssh-server.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+"""
+Example of running a prompt_toolkit application in an asyncssh server.
+"""
+import asyncio
+import logging
+
+import asyncssh
+from pygments.lexers.html import HtmlLexer
+
+from prompt_toolkit.completion import WordCompleter
+from prompt_toolkit.contrib.ssh import PromptToolkitSSHServer, PromptToolkitSSHSession
+from prompt_toolkit.eventloop import get_event_loop
+from prompt_toolkit.lexers import PygmentsLexer
+from prompt_toolkit.shortcuts import ProgressBar, print_formatted_text
+from prompt_toolkit.shortcuts.dialogs import input_dialog, yes_no_dialog
+from prompt_toolkit.shortcuts.prompt import PromptSession
+
+animal_completer = WordCompleter(
+ [
+ "alligator",
+ "ant",
+ "ape",
+ "bat",
+ "bear",
+ "beaver",
+ "bee",
+ "bison",
+ "butterfly",
+ "cat",
+ "chicken",
+ "crocodile",
+ "dinosaur",
+ "dog",
+ "dolphin",
+ "dove",
+ "duck",
+ "eagle",
+ "elephant",
+ "fish",
+ "goat",
+ "gorilla",
+ "kangaroo",
+ "leopard",
+ "lion",
+ "mouse",
+ "rabbit",
+ "rat",
+ "snake",
+ "spider",
+ "turkey",
+ "turtle",
+ ],
+ ignore_case=True,
+)
+
+
+async def interact(ssh_session: PromptToolkitSSHSession) -> None:
+ """
+ The application interaction.
+
+ This will run automatically in a prompt_toolkit AppSession, which means
+ that any prompt_toolkit application (dialogs, prompts, etc...) will use the
+ SSH channel for input and output.
+ """
+ prompt_session = PromptSession()
+
+ # Alias 'print_formatted_text', so that 'print' calls go to the SSH client.
+ print = print_formatted_text
+
+ print("We will be running a few prompt_toolkit applications through this ")
+ print("SSH connection.\n")
+
+ # Simple progress bar.
+ with ProgressBar() as pb:
+ for i in pb(range(50)):
+ await asyncio.sleep(0.1)
+
+ # Normal prompt.
+ text = await prompt_session.prompt_async("(normal prompt) Type something: ")
+ print("You typed", text)
+
+ # Prompt with auto completion.
+ text = await prompt_session.prompt_async(
+ "(autocompletion) Type an animal: ", completer=animal_completer
+ )
+ print("You typed", text)
+
+ # prompt with syntax highlighting.
+ text = await prompt_session.prompt_async(
+ "(HTML syntax highlighting) Type something: ", lexer=PygmentsLexer(HtmlLexer)
+ )
+ print("You typed", text)
+
+ # Show yes/no dialog.
+ await prompt_session.prompt_async("Showing yes/no dialog... [ENTER]")
+ await yes_no_dialog("Yes/no dialog", "Running over asyncssh").run_async()
+
+ # Show input dialog
+ await prompt_session.prompt_async("Showing input dialog... [ENTER]")
+ await input_dialog("Input dialog", "Running over asyncssh").run_async()
+
+
+def main(port=8222):
+ # Set up logging.
+ logging.basicConfig()
+ logging.getLogger().setLevel(logging.DEBUG)
+
+ loop = get_event_loop()
+ loop.run_until_complete(
+ asyncssh.create_server(
+ lambda: PromptToolkitSSHServer(interact),
+ "",
+ port,
+ server_host_keys=["/etc/ssh/ssh_host_ecdsa_key"],
+ )
+ )
+ loop.run_forever()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/telnet/chat-app.py b/examples/telnet/chat-app.py
new file mode 100755
index 0000000..1880a36
--- /dev/null
+++ b/examples/telnet/chat-app.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+"""
+A simple chat application over telnet.
+Everyone that connects is asked for his name, and then people can chat with
+each other.
+"""
+import logging
+import random
+
+from prompt_toolkit.contrib.telnet.server import TelnetServer
+from prompt_toolkit.eventloop import get_event_loop
+from prompt_toolkit.formatted_text import HTML
+from prompt_toolkit.shortcuts import PromptSession, clear, prompt
+
+# Set up logging
+logging.basicConfig()
+logging.getLogger().setLevel(logging.INFO)
+
+# List of connections.
+_connections = []
+_connection_to_color = {}
+
+
+COLORS = [
+ "ansired",
+ "ansigreen",
+ "ansiyellow",
+ "ansiblue",
+ "ansifuchsia",
+ "ansiturquoise",
+ "ansilightgray",
+ "ansidarkgray",
+ "ansidarkred",
+ "ansidarkgreen",
+ "ansibrown",
+ "ansidarkblue",
+ "ansipurple",
+ "ansiteal",
+]
+
+
+async def interact(connection):
+ write = connection.send
+ prompt_session = PromptSession()
+
+ # When a client is connected, erase the screen from the client and say
+ # Hello.
+ clear()
+ write("Welcome to our chat application!\n")
+ write("All connected clients will receive what you say.\n")
+
+ name = await prompt_session.prompt_async(message="Type your name: ")
+
+ # Random color.
+ color = random.choice(COLORS)
+ _connection_to_color[connection] = color
+
+ # Send 'connected' message.
+ _send_to_everyone(connection, name, "(connected)", color)
+
+ # Prompt.
+ prompt_msg = HTML('<reverse fg="{}">[{}]</reverse> &gt; ').format(color, name)
+
+ _connections.append(connection)
+ try:
+ # Set Application.
+ while True:
+ try:
+ result = await prompt_session.prompt_async(message=prompt_msg)
+ _send_to_everyone(connection, name, result, color)
+ except KeyboardInterrupt:
+ pass
+ except EOFError:
+ _send_to_everyone(connection, name, "(leaving)", color)
+ finally:
+ _connections.remove(connection)
+
+
+def _send_to_everyone(sender_connection, name, message, color):
+ """
+ Send a message to all the clients.
+ """
+ for c in _connections:
+ if c != sender_connection:
+ c.send_above_prompt(
+ [
+ ("fg:" + color, "[%s]" % name),
+ ("", " "),
+ ("fg:" + color, "%s\n" % message),
+ ]
+ )
+
+
+def main():
+ server = TelnetServer(interact=interact, port=2323)
+ server.start()
+ get_event_loop().run_forever()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/telnet/dialog.py b/examples/telnet/dialog.py
new file mode 100755
index 0000000..8605711
--- /dev/null
+++ b/examples/telnet/dialog.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+"""
+Example of a telnet application that displays a dialog window.
+"""
+import logging
+
+from prompt_toolkit.contrib.telnet.server import TelnetServer
+from prompt_toolkit.eventloop import get_event_loop
+from prompt_toolkit.shortcuts.dialogs import yes_no_dialog
+
+# Set up logging
+logging.basicConfig()
+logging.getLogger().setLevel(logging.INFO)
+
+
+async def interact(connection):
+ result = await yes_no_dialog(
+ title="Yes/no dialog demo", text="Press yes or no"
+ ).run_async()
+
+ connection.send(f"You said: {result}\n")
+ connection.send("Bye.\n")
+
+
+def main():
+ server = TelnetServer(interact=interact, port=2323)
+ server.start()
+ get_event_loop().run_forever()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/telnet/hello-world.py b/examples/telnet/hello-world.py
new file mode 100755
index 0000000..e9d48f6
--- /dev/null
+++ b/examples/telnet/hello-world.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+"""
+A simple Telnet application that asks for input and responds.
+
+The interaction function is a prompt_toolkit coroutine.
+Also see the `hello-world-asyncio.py` example which uses an asyncio coroutine.
+That is probably the preferred way if you only need Python 3 support.
+"""
+import logging
+
+from prompt_toolkit.contrib.telnet.server import TelnetServer
+from prompt_toolkit.eventloop import get_event_loop
+from prompt_toolkit.shortcuts import PromptSession, clear
+
+# Set up logging
+logging.basicConfig()
+logging.getLogger().setLevel(logging.INFO)
+
+
+async def interact(connection):
+ clear()
+ connection.send("Welcome!\n")
+
+ # Ask for input.
+ session = PromptSession()
+ result = await session.prompt_async(message="Say something: ")
+
+ # Send output.
+ connection.send(f"You said: {result}\n")
+ connection.send("Bye.\n")
+
+
+def main():
+ server = TelnetServer(interact=interact, port=2323)
+ server.start()
+ get_event_loop().run_forever()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/telnet/toolbar.py b/examples/telnet/toolbar.py
new file mode 100755
index 0000000..cc40ec1
--- /dev/null
+++ b/examples/telnet/toolbar.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+"""
+Example of a telnet application that displays a bottom toolbar and completions
+in the prompt.
+"""
+import logging
+
+from prompt_toolkit.completion import WordCompleter
+from prompt_toolkit.contrib.telnet.server import TelnetServer
+from prompt_toolkit.eventloop import get_event_loop
+from prompt_toolkit.shortcuts import PromptSession
+
+# Set up logging
+logging.basicConfig()
+logging.getLogger().setLevel(logging.INFO)
+
+
+async def interact(connection):
+ # When a client is connected, erase the screen from the client and say
+ # Hello.
+ connection.send("Welcome!\n")
+
+ # Display prompt with bottom toolbar.
+ animal_completer = WordCompleter(["alligator", "ant"])
+
+ def get_toolbar():
+ return "Bottom toolbar..."
+
+ session = PromptSession()
+ result = await session.prompt_async(
+ "Say something: ", bottom_toolbar=get_toolbar, completer=animal_completer
+ )
+
+ connection.send(f"You said: {result}\n")
+ connection.send("Bye.\n")
+
+
+def main():
+ server = TelnetServer(interact=interact, port=2323)
+ server.start()
+ get_event_loop().run_forever()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/tutorial/README.md b/examples/tutorial/README.md
new file mode 100755
index 0000000..3aa5f70
--- /dev/null
+++ b/examples/tutorial/README.md
@@ -0,0 +1 @@
+See http://python-prompt-toolkit.readthedocs.io/en/stable/pages/tutorials/repl.html
diff --git a/examples/tutorial/sqlite-cli.py b/examples/tutorial/sqlite-cli.py
new file mode 100755
index 0000000..ea3e2c8
--- /dev/null
+++ b/examples/tutorial/sqlite-cli.py
@@ -0,0 +1,184 @@
+#!/usr/bin/env python
+import sqlite3
+import sys
+
+from pygments.lexers.sql import SqlLexer
+
+from prompt_toolkit import PromptSession
+from prompt_toolkit.completion import WordCompleter
+from prompt_toolkit.lexers import PygmentsLexer
+from prompt_toolkit.styles import Style
+
+sql_completer = WordCompleter(
+ [
+ "abort",
+ "action",
+ "add",
+ "after",
+ "all",
+ "alter",
+ "analyze",
+ "and",
+ "as",
+ "asc",
+ "attach",
+ "autoincrement",
+ "before",
+ "begin",
+ "between",
+ "by",
+ "cascade",
+ "case",
+ "cast",
+ "check",
+ "collate",
+ "column",
+ "commit",
+ "conflict",
+ "constraint",
+ "create",
+ "cross",
+ "current_date",
+ "current_time",
+ "current_timestamp",
+ "database",
+ "default",
+ "deferrable",
+ "deferred",
+ "delete",
+ "desc",
+ "detach",
+ "distinct",
+ "drop",
+ "each",
+ "else",
+ "end",
+ "escape",
+ "except",
+ "exclusive",
+ "exists",
+ "explain",
+ "fail",
+ "for",
+ "foreign",
+ "from",
+ "full",
+ "glob",
+ "group",
+ "having",
+ "if",
+ "ignore",
+ "immediate",
+ "in",
+ "index",
+ "indexed",
+ "initially",
+ "inner",
+ "insert",
+ "instead",
+ "intersect",
+ "into",
+ "is",
+ "isnull",
+ "join",
+ "key",
+ "left",
+ "like",
+ "limit",
+ "match",
+ "natural",
+ "no",
+ "not",
+ "notnull",
+ "null",
+ "of",
+ "offset",
+ "on",
+ "or",
+ "order",
+ "outer",
+ "plan",
+ "pragma",
+ "primary",
+ "query",
+ "raise",
+ "recursive",
+ "references",
+ "regexp",
+ "reindex",
+ "release",
+ "rename",
+ "replace",
+ "restrict",
+ "right",
+ "rollback",
+ "row",
+ "savepoint",
+ "select",
+ "set",
+ "table",
+ "temp",
+ "temporary",
+ "then",
+ "to",
+ "transaction",
+ "trigger",
+ "union",
+ "unique",
+ "update",
+ "using",
+ "vacuum",
+ "values",
+ "view",
+ "virtual",
+ "when",
+ "where",
+ "with",
+ "without",
+ ],
+ ignore_case=True,
+)
+
+style = Style.from_dict(
+ {
+ "completion-menu.completion": "bg:#008888 #ffffff",
+ "completion-menu.completion.current": "bg:#00aaaa #000000",
+ "scrollbar.background": "bg:#88aaaa",
+ "scrollbar.button": "bg:#222222",
+ }
+)
+
+
+def main(database):
+ connection = sqlite3.connect(database)
+ session = PromptSession(
+ lexer=PygmentsLexer(SqlLexer), completer=sql_completer, style=style
+ )
+
+ while True:
+ try:
+ text = session.prompt("> ")
+ except KeyboardInterrupt:
+ continue # Control-C pressed. Try again.
+ except EOFError:
+ break # Control-D pressed.
+
+ with connection:
+ try:
+ messages = connection.execute(text)
+ except Exception as e:
+ print(repr(e))
+ else:
+ for message in messages:
+ print(message)
+
+ print("GoodBye!")
+
+
+if __name__ == "__main__":
+ if len(sys.argv) < 2:
+ db = ":memory:"
+ else:
+ db = sys.argv[1]
+
+ main(db)