python-prompt-toolkit Documentation

Library for building powerful interactive command line applications in Python

10,596 stars Python Python 28 files ยท ~45,068 tokens
RAW Doc

Technical Documentation: prompt-toolkit/python-prompt-toolkit

โ„น๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference

Overview (`examples/tutorial/README.md`)

See http://python-prompt-toolkit.readthedocs.io/en/stable/pages/tutorials/repl.html


Index (`docs/index.rst`)

Python Prompt Toolkit 3.0

prompt_toolkit is a library for building powerful interactive command line
and terminal applications in Python.

It can be a very advanced pure Python replacement for GNU readline <https://tiswww.case.edu/php/chet/readline/rltop.html>_, but it can also be
used for building full screen applications.

.. image:: images/ptpython-2.png

Some features:

  • Syntax highlighting of the input while typing. (For instance, with a Pygments lexer.)
  • Multi-line input editing.
  • Advanced code completion.
  • Selecting text for copy/paste. (Both Emacs and Vi style.)
  • Mouse support for cursor positioning and scrolling.
  • Auto suggestions. (Like fish shell <http://fishshell.com/>_.)
  • No global state.

Like readline:

  • Both Emacs and Vi key bindings.
  • Reverse and forward incremental search.
  • Works well with Unicode double width characters. (Chinese input.)

Works everywhere:

  • Pure Python. Runs on all Python versions starting at Python 3.6.
    (Python 2.6 - 3.x is supported in prompt_toolkit 2.0; not 3.0).
  • Runs on Linux, OS X, OpenBSD and Windows systems.
  • Lightweight, the only dependencies are Pygments and wcwidth.
  • No assumptions about I/O are made. Every prompt_toolkit application should
    also run in a telnet/ssh server or an asyncio <https://docs.python.org/3/library/asyncio.html>_ process.

Have a look at :ref:the gallery <gallery> to get an idea of what is possible.

Getting started

Go to :ref:getting started <getting_started> and build your first prompt.
Issues are tracked on the Github project <https://github.com/prompt-toolkit/python-prompt-toolkit>_.

Thanks to:

A special thanks to all the contributors <https://github.com/prompt-toolkit/python-prompt-toolkit/graphs/contributors>_
for making prompt_toolkit possible.

Also, a special thanks to the Pygments <http://pygments.org/>_ and wcwidth <https://github.com/jquast/wcwidth>_ libraries.

Table of contents

.. toctree::
:maxdepth: 2

pages/gallery
pages/getting_started
pages/upgrading/index
pages/printing_text
pages/asking_for_input
pages/asking_for_a_choice
pages/dialogs
pages/progress_bars
pages/full_screen_apps
pages/tutorials/index
pages/advanced_topics/index
pages/reference
pages/related_projects

Indices and tables

  • :ref:genindex
  • :ref:modindex
  • :ref:search

Prompt_toolkit was created by Jonathan Slenders <http://github.com/prompt-toolkit/>_.


Requirements (`docs/requirements.txt`)

Sphinx>=8,<9
wcwidth<1
pyperclip<2
sphinx_copybutton>=0.5.2,<1.0.0
sphinx-nefertiti>=0.8.8


Pages Asking For A Choice (`docs/pages/asking_for_a_choice.rst`)

.. _asking_for_a_choice:

Asking for a choice

Similar to how the :func:~prompt_toolkit.shortcuts.prompt function allows for
text input, prompt_toolkit has a
:func:~prompt_toolkit.shortcuts.choice function to ask for a choice
from a list of options:

.. code:: python

text
from prompt_toolkit.shortcuts import choice

result = choice(
    message="Please choose a dish:",
    options=[
        ("pizza", "Pizza with mushrooms"),
        ("salad", "Salad with tomatoes"),
        ("sushi", "Sushi"),
    ],
    default="salad",
)
print(f"You have chosen: {result}")

.. image:: ../images/choice-input.png

Coloring the options

It is possible to customize the colors and styles. The message parameter
takes any :ref:formatted text <formatted_text>, and the labels (2nd argument
from the options) can be :ref:formatted text <formatted_text> as well.
Further, we can pass a :class:~prompt_toolkit.styles.Style instance using the
:meth:~prompt_toolkit.styles.Style.from_dict function:

.. code:: python

text
from prompt_toolkit.formatted_text import HTML
from prompt_toolkit.shortcuts import choice
from prompt_toolkit.styles import Style

style = Style.from_dict(
    {
        "input-selection": "fg:#ff0000",
        "number": "fg:#884444 bold",
        "selected-option": "underline",
    }
)

result = choice(
    message=HTML("Please select a dish:"),
    options=[
        ("pizza", "Pizza with mushrooms"),
        (
            "salad",
            HTML("<ansigreen>Salad</ansigreen> with <ansired>tomatoes</ansired>"),
        ),
        ("sushi", "Sushi"),
    ],
    style=style,
)
print(f"You have chosen: {result}")

.. image:: ../images/colored-choice.png

Adding a frame

The :func:~prompt_toolkit.shortcuts.choice function takes a
show_frame argument. When True, the input is displayed within a frame.
It is also possible to pass a :ref:filter <filters>, like ~is_done, so
that the frame is only displayed when asking for input, but hidden once the
input is accepted.

.. code:: python

text
from prompt_toolkit.shortcuts import choice
from prompt_toolkit.filters import is_done
from prompt_toolkit.styles import Style

style = Style.from_dict(
    {
        "frame.border": "#884444",
        "selected-option": "bold",
    }
)
result = choice(
    message="Please select a dish:",
    options=[
        ("pizza", "Pizza with mushrooms"),
        ("salad", "Salad with tomatoes"),
        ("sushi", "Sushi"),
    ],
    style=style,
    show_frame=~is_done,
)
print(f"You have chosen: {result}")

.. image:: ../images/choice-with-frame.png

Adding a bottom toolbar

Adding a bottom toolbar can be done by passing a bottom_toolbar argument to
:func:~prompt_toolkit.shortcuts.choice. This argument can be plain text,
:ref:formatted text <formatted_text> or a callable that returns plain or
formatted text.

.. code:: python

text
from prompt_toolkit.filters import is_done
from prompt_toolkit.formatted_text import HTML
from prompt_toolkit.shortcuts import choice
from prompt_toolkit.styles import Style

style = Style.from_dict(
    {
        "frame.border": "#ff4444",
        "selected-option": "bold",
        # ('noreverse' because the default toolbar style uses 'reverse')
        "bottom-toolbar": "#ffffff bg:#333333 noreverse",
    }
)

result = choice(
    message=HTML("Please select a dish:"),
    options=[
        ("pizza", "Pizza with mushrooms"),
        ("salad", "Salad with tomatoes"),
        ("sushi", "Sushi"),
    ],
    style=style,
    bottom_toolbar=HTML(
        " Press **[Up]**/**[Down]** to select, **[Enter]** to accept."
    ),
    show_frame=~is_done,
)
print(f"You have chosen: {result}")

.. image:: ../images/choice-with-frame-and-bottom-toolbar.png


Pages Asking For Input (`docs/pages/asking_for_input.rst`)

.. _asking_for_input:

Asking for input (prompts)

This page is about building prompts. Pieces of code that we can embed in a
program for asking the user for input. Even if you want to use prompt_toolkit
for building full screen terminal applications, it is probably still a good
idea to read this first, before heading to the :ref:building full screen applications <full_screen_applications> page.

In this page, we will cover autocompletion, syntax highlighting, key bindings,
and so on.

Hello world

The following snippet is the most simple example, it uses the
:func:~prompt_toolkit.shortcuts.prompt function to ask the user for input
and returns the text. Just like (raw_)input.

.. code:: python

text
from prompt_toolkit import prompt

text = prompt("Give me some input: ")
print(f"You said: {text}")

.. image:: ../images/hello-world-prompt.png

What we get here is a simple prompt that supports the Emacs key bindings like
readline, but further nothing special. However,
:func:~prompt_toolkit.shortcuts.prompt has a lot of configuration options.
In the following sections, we will discover all these parameters.

The `PromptSession` object

Instead of calling the :func:~prompt_toolkit.shortcuts.prompt function, it's
also possible to create a :class:~prompt_toolkit.shortcuts.PromptSession
instance followed by calling its
:meth:~prompt_toolkit.shortcuts.PromptSession.prompt method for every input
call. This creates a kind of an input session.

.. code:: python

text
from prompt_toolkit import PromptSession

# Create prompt object.
session = PromptSession()

# Do multiple input calls.
text1 = session.prompt()
text2 = session.prompt()

This has mainly two advantages:

  • The input history will be kept between consecutive
    :meth:~prompt_toolkit.shortcuts.PromptSession.prompt calls.

  • The :func:~prompt_toolkit.shortcuts.PromptSession instance and its
    :meth:~prompt_toolkit.shortcuts.PromptSession.prompt method take about the
    same arguments, like all the options described below (highlighting,
    completion, etc...). So if you want to ask for multiple inputs, but each
    input call needs about the same arguments, they can be passed to the
    :func:~prompt_toolkit.shortcuts.PromptSession instance as well, and they
    can be overridden by passing values to the
    :meth:~prompt_toolkit.shortcuts.PromptSession.prompt method.

Syntax highlighting

Adding syntax highlighting is as simple as adding a lexer. All of the Pygments <http://pygments.org/>_ lexers can be used after wrapping them in a
:class:~prompt_toolkit.lexers.PygmentsLexer. It is also possible to create a
custom lexer by implementing the :class:~prompt_toolkit.lexers.Lexer abstract
base class.

.. code:: python

text
from pygments.lexers.html import HtmlLexer
from prompt_toolkit.shortcuts import prompt
from prompt_toolkit.lexers import PygmentsLexer

text = prompt("Enter HTML: ", lexer=PygmentsLexer(HtmlLexer))
print(f"You said: {text}")

.. image:: ../images/html-input.png

The default Pygments colorscheme is included as part of the default style in
prompt_toolkit. If you want to use another Pygments style along with the lexer,
you can do the following:

.. code:: python

text
from pygments.lexers.html import HtmlLexer
from pygments.styles import get_style_by_name
from prompt_toolkit.shortcuts import prompt
from prompt_toolkit.lexers import PygmentsLexer
from prompt_toolkit.styles.pygments import style_from_pygments_cls

style = style_from_pygments_cls(get_style_by_name("monokai"))
text = prompt(
    "Enter HTML: ",
    lexer=PygmentsLexer(HtmlLexer),
    style=style,
    include_default_pygments_style=False
)
print(f"You said: {text}")

We pass include_default_pygments_style=False, because otherwise, both
styles will be merged, possibly giving slightly different colors in the outcome
for cases where where our custom Pygments style doesn't specify a color.

.. _colors:

Colors

The colors for syntax highlighting are defined by a
:class:~prompt_toolkit.styles.Style instance. By default, a neutral
built-in style is used, but any style instance can be passed to the
:func:~prompt_toolkit.shortcuts.prompt function. A simple way to create a
style, is by using the :meth:~prompt_toolkit.styles.Style.from_dict
function:

.. code:: python

text
from pygments.lexers.html import HtmlLexer
from prompt_toolkit.shortcuts import prompt
from prompt_toolkit.styles import Style
from prompt_toolkit.lexers import PygmentsLexer

our_style = Style.from_dict({
    "pygments.comment": "#888888 bold",
    "pygments.keyword": "#ff88ff bold",
})

text = prompt(
    "Enter HTML: ",
    lexer=PygmentsLexer(HtmlLexer),
    style=our_style
)

The style dictionary is very similar to the Pygments styles dictionary,
with a few differences:

  • The roman, sans, mono and border options are ignored.
  • The style has a few additions: blink, noblink, reverse and noreverse.
  • Colors can be in the #ff0000 format, but they can be one of the built-in
    ANSI color names as well. In that case, they map directly to the 16 color
    palette of the terminal.

:ref:Read more about styling <styling>.

Using a Pygments style
^^^^^^^^^^^^^^^^^^^^^^

All Pygments style classes can be used as well, when they are wrapped through
:func:~prompt_toolkit.styles.style_from_pygments_cls.

Suppose we'd like to use a Pygments style, for instance
pygments.styles.tango.TangoStyle, that is possible like this:

.. code:: python

text
from prompt_toolkit.shortcuts import prompt
from prompt_toolkit.styles import style_from_pygments_cls
from prompt_toolkit.lexers import PygmentsLexer
from pygments.styles.tango import TangoStyle
from pygments.lexers.html import HtmlLexer

tango_style = style_from_pygments_cls(TangoStyle)

text = prompt(
    "Enter HTML: ",
    lexer=PygmentsLexer(HtmlLexer),
    style=tango_style
)

Creating a custom style could be done like this:

.. code:: python

text
from prompt_toolkit.shortcuts import prompt
from prompt_toolkit.styles import Style, style_from_pygments_cls, merge_styles
from prompt_toolkit.lexers import PygmentsLexer

from pygments.styles.tango import TangoStyle
from pygments.lexers.html import HtmlLexer

our_style = merge_styles([
    style_from_pygments_cls(TangoStyle),
    Style.from_dict({
        "pygments.comment": "#888888 bold",
        "pygments.keyword": "#ff88ff bold",
    })
])

text = prompt(
    "Enter HTML: ",
    lexer=PygmentsLexer(HtmlLexer),
    style=our_style
)

Coloring the prompt itself
^^^^^^^^^^^^^^^^^^^^^^^^^^

It is possible to add some colors to the prompt itself. For this, we need to
build some :ref:formatted text <formatted_text>. One way of doing this is by
creating a list of style/text tuples. In the following example, we use class
names to refer to the style.

.. code:: python

text
from prompt_toolkit.shortcuts import prompt
from prompt_toolkit.styles import Style

style = Style.from_dict({
    # User input (default text).
    "":          "#ff0066",

    # Prompt.
    "username": "#884444",
    "at":       "#00aa00",
    "colon":    "#0000aa",
    "pound":    "#00aa00",
    "host":     "#00ffff bg:#444400",
    "path":     "ansicyan underline",
})

message = [
    ("class:username", "john"),
    ("class:at",       "@"),
    ("class:host",     "localhost"),
    ("class:colon",    ":"),
    ("class:path",     "/user/john"),
    ("class:pound",    "# "),
]

text = prompt(message, style=style)

.. image:: ../images/colored-prompt.png

The message can be any kind of formatted text, as discussed :ref:here <formatted_text>. It can also be a callable that returns some formatted text.

By default, colors are taken from the 256 color palette. If you want to have
24bit true color, this is possible by adding the
color_depth=ColorDepth.TRUE_COLOR option to the
:func:~prompt_toolkit.shortcuts.prompt.prompt function.

.. code:: python

text
from prompt_toolkit.output import ColorDepth

text = prompt(message, style=style, color_depth=ColorDepth.TRUE_COLOR)

Autocompletion

Autocompletion can be added by passing a completer parameter. This should
be an instance of the :class:~prompt_toolkit.completion.Completer abstract
base class. :class:~prompt_toolkit.completion.WordCompleter is an example of
a completer that implements that interface.

.. code:: python

text
from prompt_toolkit import prompt
from prompt_toolkit.completion import WordCompleter

html_completer = WordCompleter(["<html>", "", "<head>", "<title>"])
text = prompt("Enter HTML: ", completer=html_completer)
print(f"You said: {text}")

:class:~prompt_toolkit.completion.WordCompleter is a simple completer that
completes the last word before the cursor with any of the given words.

.. image:: ../images/html-completion.png

.. note::

text
Note that in prompt_toolkit 2.0, the auto completion became synchronous. This
means that if it takes a long time to compute the completions, that this
will block the event loop and the input processing.

For heavy completion algorithms, it is recommended to wrap the completer in
a :class:`~prompt_toolkit.completion.ThreadedCompleter` in order to run it
in a background thread.

Nested completion
^^^^^^^^^^^^^^^^^

Sometimes you have a command line interface where the completion depends on the
previous words from the input. Examples are the CLIs from routers and switches.
A simple :class:~prompt_toolkit.completion.WordCompleter is not enough in
that case. We want to to be able to define completions at multiple hierarchical
levels. :class:~prompt_toolkit.completion.NestedCompleter solves this issue:

.. code:: python

text
from prompt_toolkit import prompt
from prompt_toolkit.completion import NestedCompleter

completer = NestedCompleter.from_nested_dict({
    "show": {
        "version": None,
        "clock": None,
        "ip": {
            "interface": {"brief"}
        }
    },
    "exit": None,
})

text = prompt("# ", completer=completer)
print(f"You said: {text}")

Whenever there is a None value in the dictionary, it means that there is no
further nested completion at that point. When all values of a dictionary would
be None, it can also be replaced with a set.

A custom completer
^^^^^^^^^^^^^^^^^^

For more complex examples, it makes sense to create a custom completer. For
instance:

.. code:: python

text
from prompt_toolkit import prompt
from prompt_toolkit.completion import Completer, Completion

class MyCustomCompleter(Completer):
    def get_completions(self, document, complete_event):
        yield Completion("completion", start_position=0)

text = prompt("> ", completer=MyCustomCompleter())

A :class:~prompt_toolkit.completion.Completer class has to implement a
generator named :meth:~prompt_toolkit.completion.Completer.get_completions
that takes a :class:~prompt_toolkit.document.Document and yields the current
:class:~prompt_toolkit.completion.Completion instances. Each completion
contains a portion of text, and a position.

The position is used for fixing text before the cursor. Pressing the tab key
could for instance turn parts of the input from lowercase to uppercase. This
makes sense for a case insensitive completer. Or in case of a fuzzy completion,
it could fix typos. When start_position is something negative, this amount
of characters will be deleted and replaced.

Styling individual completions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Each completion can provide a custom style, which is used when it is rendered
in the completion menu or toolbar. This is possible by passing a style to each
:class:~prompt_toolkit.completion.Completion instance.

.. code:: python

text
from prompt_toolkit.completion import Completer, Completion

class MyCustomCompleter(Completer):
    def get_completions(self, document, complete_event):
        # Display this completion, black on yellow.
        yield Completion(
            "completion1",
            start_position=0,
            style="bg:ansiyellow fg:ansiblack"
        )

        # Underline completion.
        yield Completion(
            "completion2",
            start_position=0,
            style="underline"
        )

        # Specify class name, which will be looked up in the style sheet.
        yield Completion(
            "completion3",
            start_position=0,
            style="class:special-completion"
        )

The "colorful-prompts.py" example uses completion styling:

.. image:: ../images/colorful-completions.png

Finally, it is possible to pass :ref:formatted text <formatted_text> for the
display attribute of a :class:~prompt_toolkit.completion.Completion. This
provides all the freedom you need to display the text in any possible way. It
can also be combined with the style attribute. For instance:

.. code:: python

text
from prompt_toolkit.completion import Completer, Completion
from prompt_toolkit.formatted_text import HTML

class MyCustomCompleter(Completer):
    def get_completions(self, document, complete_event):
        yield Completion(
            "completion1",
            start_position=0,
            display=HTML("**completion**<ansired>1</ansired>"),
            style="bg:ansiyellow"
        )

Fuzzy completion
^^^^^^^^^^^^^^^^

If one possible completions is "django_migrations", a fuzzy completer would
allow you to get this by typing "djm" only, a subset of characters for this
string.

Prompt_toolkit ships with a :class:~prompt_toolkit.completion.FuzzyCompleter
and :class:~prompt_toolkit.completion.FuzzyWordCompleter class. These provide
the means for doing this kind of "fuzzy completion". The first one can take any
completer instance and wrap it so that it becomes a fuzzy completer. The second
one behaves like a :class:~prompt_toolkit.completion.WordCompleter wrapped
into a :class:~prompt_toolkit.completion.FuzzyCompleter.

Complete while typing
^^^^^^^^^^^^^^^^^^^^^

Autcompletions can be generated automatically while typing or when the user
presses the tab key. This can be configured with the complete_while_typing
option:

.. code:: python

text
text = prompt(
    "Enter HTML: ",
    completer=my_completer,
    complete_while_typing=True
)

Notice that this setting is incompatible with the enable_history_search
option. The reason for this is that the up and down key bindings would conflict
otherwise. So, make sure to disable history search for this.

Asynchronous completion
^^^^^^^^^^^^^^^^^^^^^^^

When generating the completions takes a lot of time, it's better to do this in
a background thread. This is possible by wrapping the completer in a
:class:~prompt_toolkit.completion.ThreadedCompleter, but also by passing the
complete_in_thread=True argument.

.. code:: python

text
text = prompt("> ", completer=MyCustomCompleter(), complete_in_thread=True)

Input validation

A prompt can have a validator attached. This is some code that will check
whether the given input is acceptable and it will only return it if that's the
case. Otherwise it will show an error message and move the cursor to a given
position.

A validator should implements the :class:~prompt_toolkit.validation.Validator
abstract base class. This requires only one method, named validate that
takes a :class:~prompt_toolkit.document.Document as input and raises
:class:~prompt_toolkit.validation.ValidationError when the validation fails.

.. code:: python

text
from prompt_toolkit.validation import Validator, ValidationError
from prompt_toolkit import prompt

class NumberValidator(Validator):
    def validate(self, document):
        text = document.text

        if text and not text.isdigit():
            i = 0

            # Get index of first non numeric character.
            # We want to move the cursor here.
            for i, c in enumerate(text):
                if not c.isdigit():
                    break

            raise ValidationError(
                message="This input contains non-numeric characters",
                cursor_position=i
            )

number = int(prompt("Give a number: ", validator=NumberValidator()))
print(f"You said: {number}")

.. image:: ../images/number-validator.png

By default, the input is validated in real-time while the user is typing, but
prompt_toolkit can also validate after the user presses the enter key:

.. code:: python

text
prompt(
    "Give a number: ",
    validator=NumberValidator(),
    validate_while_typing=False
)

If the input validation contains some heavy CPU intensive code, but you don't
want to block the event loop, then it's recommended to wrap the validator class
in a :class:~prompt_toolkit.validation.ThreadedValidator.

Validator from a callable
^^^^^^^^^^^^^^^^^^^^^^^^^

Instead of implementing the :class:~prompt_toolkit.validation.Validator
abstract base class, it is also possible to start from a simple function and
use the :meth:~prompt_toolkit.validation.Validator.from_callable classmethod.
This is easier and sufficient for probably 90% of the validators. It looks as
follows:

.. code:: python

text
from prompt_toolkit.validation import Validator
from prompt_toolkit import prompt

def is_number(text):
    return text.isdigit()

validator = Validator.from_callable(
    is_number,
    error_message="This input contains non-numeric characters",
    move_cursor_to_end=True
)

number = int(prompt("Give a number: ", validator=validator))
print(f"You said: {number}")

We define a function that takes a string, and tells whether it's valid input or
not by returning a boolean.
:meth:~prompt_toolkit.validation.Validator.from_callable turns that into a
:class:~prompt_toolkit.validation.Validator instance. Notice that setting the
cursor position is not possible this way.

History

A :class:~prompt_toolkit.history.History object keeps track of all the
previously entered strings, so that the up-arrow can reveal previously entered
items.

The recommended way is to use a
:class:~prompt_toolkit.shortcuts.PromptSession, which uses an
:class:~prompt_toolkit.history.InMemoryHistory for the entire session by
default. The following example has a history out of the box:

.. code:: python

from prompt_toolkit import PromptSession

session = PromptSession()

while True:
session.prompt()

To persist a history to disk, use a :class:~prompt_toolkit.history.FileHistory
instead of the default
:class:~prompt_toolkit.history.InMemoryHistory. This history object can be
passed either to a :class:~prompt_toolkit.shortcuts.PromptSession or to the
:meth:~prompt_toolkit.shortcuts.prompt function. For instance:

.. code:: python

from prompt_toolkit import PromptSession
from prompt_toolkit.history import FileHistory

session = PromptSession(history=FileHistory("~/.myhistory"))

while True:
session.prompt()

Auto suggestion

Auto suggestion is a way to propose some input completions to the user like the
fish shell <http://fishshell.com/>_.

Usually, the input is compared to the history and when there is another entry
starting with the given text, the completion will be shown as gray text behind
the current input. Pressing the right arrow :kbd:โ†’ or :kbd:c-e will insert
this suggestion, :kbd:alt-f will insert the first word of the suggestion.

.. note::

text
When suggestions are based on the history, don't forget to share one
:class:`~prompt_toolkit.history.History` object between consecutive
:func:`~prompt_toolkit.shortcuts.prompt` calls. Using a
:class:`~prompt_toolkit.shortcuts.PromptSession` does this for you.

Example:

.. code:: python

text
from prompt_toolkit import PromptSession
from prompt_toolkit.history import InMemoryHistory
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory

session = PromptSession()

while True:
    text = session.prompt("> ", auto_suggest=AutoSuggestFromHistory())
    print(f"You said: {text}")

.. image:: ../images/auto-suggestion.png

A suggestion does not have to come from the history. Any implementation of the
:class:~prompt_toolkit.auto_suggest.AutoSuggest abstract base class can be
passed as an argument.

Adding a bottom toolbar

Adding a bottom toolbar is as easy as passing a bottom_toolbar argument to
:func:~prompt_toolkit.shortcuts.prompt. This argument be either plain text,
:ref:formatted text <formatted_text> or a callable that returns plain or
formatted text.

When a function is given, it will be called every time the prompt is rendered,
so the bottom toolbar can be used to display dynamic information.

The toolbar is always erased when the prompt returns.
Here we have an example of a callable that returns an
:class:~prompt_toolkit.formatted_text.HTML object. By default, the toolbar
has the reversed style, which is why we are setting the background instead
of the foreground.

.. code:: python

text
from prompt_toolkit import prompt
from prompt_toolkit.formatted_text import HTML

def bottom_toolbar():
    return HTML('This is a **<style bg="ansired">Toolbar</style>**!')

text = prompt("> ", bottom_toolbar=bottom_toolbar)
print(f"You said: {text}")

.. image:: ../images/bottom-toolbar.png

Similar, we could use a list of style/text tuples.

.. code:: python

text
from prompt_toolkit import prompt
from prompt_toolkit.styles import Style

def bottom_toolbar():
    return [("class:bottom-toolbar", " This is a toolbar. ")]

style = Style.from_dict({
    "bottom-toolbar": "#ffffff bg:#333333",
})

text = prompt("> ", bottom_toolbar=bottom_toolbar, style=style)
print(f"You said: {text}")

The default class name is bottom-toolbar and that will also be used to fill
the background of the toolbar.

Adding a right prompt

The :func:~prompt_toolkit.shortcuts.prompt function has out of the box
support for right prompts as well. People familiar to ZSH could recognize this
as the RPROMPT option.

So, similar to adding a bottom toolbar, we can pass an rprompt argument.
This can be either plain text, :ref:formatted text <formatted_text> or a
callable which returns either.

.. code:: python

text
from prompt_toolkit import prompt
from prompt_toolkit.styles import Style

example_style = Style.from_dict({
    "rprompt": "bg:#ff0066 #ffffff",
})

def get_rprompt():
    return "<rprompt>"

answer = prompt("> ", rprompt=get_rprompt, style=example_style)

.. image:: ../images/rprompt.png

The get_rprompt function can return any kind of formatted text such as
:class:~prompt_toolkit.formatted_text.HTML. it is also possible to pass text
directly to the rprompt argument of the
:func:~prompt_toolkit.shortcuts.prompt function. It does not have to be a
callable.

Vi input mode

Prompt-toolkit supports both Emacs and Vi key bindings, similar to Readline.
The :func:~prompt_toolkit.shortcuts.prompt function will use Emacs bindings by
default. This is done because on most operating systems, also the Bash shell
uses Emacs bindings by default, and that is more intuitive. If however, Vi
binding are required, just pass vi_mode=True.

.. code:: python

text
from prompt_toolkit import prompt

prompt("> ", vi_mode=True)

Adding custom key bindings

By default, every prompt already has a set of key bindings which implements the
usual Vi or Emacs behavior. We can extend this by passing another
:class:~prompt_toolkit.key_binding.KeyBindings instance to the
key_bindings argument of the :func:~prompt_toolkit.shortcuts.prompt
function or the :class:~prompt_toolkit.shortcuts.PromptSession class.

An example of a prompt that prints 'hello world' when :kbd:Control-T is
pressed.

.. code:: python

text
from prompt_toolkit import prompt
from prompt_toolkit.application import run_in_terminal
from prompt_toolkit.key_binding import KeyBindings

bindings = KeyBindings()

@bindings.add("c-t")
def _(event):
    " Say "hello" when `c-t` is pressed. "
    def print_hello():
        print("hello world")
    run_in_terminal(print_hello)

@bindings.add("c-x")
def _(event):
    " Exit when `c-x` is pressed. "
    event.app.exit()

text = prompt("> ", key_bindings=bindings)
print(f"You said: {text}")

Note that we use
:meth:~prompt_toolkit.application.run_in_terminal for the first key binding.
This ensures that the output of the print-statement and the prompt don't mix
up. If the key bindings doesn't print anything, then it can be handled directly
without nesting functions.

Enable key bindings according to a condition
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Often, some key bindings can be enabled or disabled according to a certain
condition. For instance, the Emacs and Vi bindings will never be active at the
same time, but it is possible to switch between Emacs and Vi bindings at run
time.

In order to enable a key binding according to a certain condition, we have to
pass it a :class:~prompt_toolkit.filters.Filter, usually a
:class:~prompt_toolkit.filters.Condition instance. (:ref:Read more about filters <filters>.)

.. code:: python

text
from prompt_toolkit import prompt
from prompt_toolkit.filters import Condition
from prompt_toolkit.key_binding import KeyBindings

bindings = KeyBindings()

@Condition
def is_active():
    " Only activate key binding on the second half of each minute. "
    return datetime.datetime.now().second > 30

@bindings.add("c-t", filter=is_active)
def _(event):
    # ...
    pass

prompt("> ", key_bindings=bindings)

Dynamically switch between Emacs and Vi mode
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The :class:~prompt_toolkit.application.Application has an editing_mode
attribute. We can change the key bindings by changing this attribute from
EditingMode.VI to EditingMode.EMACS.

.. code:: python

text
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 set of key bindings.
    bindings = KeyBindings()

    # Add an additional key binding for toggling this flag.
    @bindings.add("f4")
    def _(event):
        " Toggle between Emacs and Vi mode. "
        app = event.app

        if app.editing_mode == EditingMode.VI:
            app.editing_mode = EditingMode.EMACS
        else:
            app.editing_mode = EditingMode.VI

    # Add a toolbar at the bottom to display the current input mode.
    def bottom_toolbar():
        " Display the current input mode. "
        text = "Vi" if get_app().editing_mode == EditingMode.VI else "Emacs"
        return [
            ("class:toolbar", " [F4] %s " % text)
        ]

    prompt("> ", key_bindings=bindings, bottom_toolbar=bottom_toolbar)

run()

:ref:Read more about key bindings ...<key_bindings>

Using control-space for completion
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

An popular short cut that people sometimes use it to use control-space for
opening the autocompletion menu instead of the tab key. This can be done with
the following key binding.

.. code:: python

text
kb = KeyBindings()

@kb.add("c-space")
def _(event):
    " Initialize autocompletion, or select the next completion. "
    buff = event.app.current_buffer
    if buff.complete_state:
        buff.complete_next()
    else:
        buff.start_completion(select_first=False)

Other prompt options

Multiline input
^^^^^^^^^^^^^^^

Reading multiline input is as easy as passing the multiline=True parameter.

.. code:: python

text
from prompt_toolkit import prompt

prompt("> ", multiline=True)

A side effect of this is that the enter key will now insert a newline instead
of accepting and returning the input. The user will now have to press
:kbd:Meta+Enter in order to accept the input. (Or :kbd:Escape followed by
:kbd:Enter.)

It is possible to specify a continuation prompt. This works by passing a
prompt_continuation callable to :func:~prompt_toolkit.shortcuts.prompt.
This function is supposed to return :ref:formatted text <formatted_text>, or
a list of (style, text) tuples. The width of the returned text should not
exceed the given width. (The width of the prompt margin is defined by the
prompt.)

.. code:: python

text
from prompt_toolkit import prompt

def prompt_continuation(width, line_number, is_soft_wrap):
    return "." * width
    # Or: return [("", "." * width)]

prompt(
    "multiline input> ",
    multiline=True,
    prompt_continuation=prompt_continuation
)

.. image:: ../images/multiline-input.png

Passing a default
^^^^^^^^^^^^^^^^^

A default value can be given:

.. code:: python

text
from prompt_toolkit import prompt
import getpass

prompt("What is your name: ", default=f"{getpass.getuser()}")

Mouse support
^^^^^^^^^^^^^

There is limited mouse support for positioning the cursor, for scrolling (in
case of large multiline inputs) and for clicking in the autocompletion menu.

Enabling can be done by passing the mouse_support=True option.

.. code:: python

text
from prompt_toolkit import prompt

prompt("What is your name: ", mouse_support=True)

Line wrapping
^^^^^^^^^^^^^

Line wrapping is enabled by default. This is what most people are used to and
this is what GNU Readline does. When it is disabled, the input string will
scroll horizontally.

.. code:: python

text
from prompt_toolkit import prompt

prompt("What is your name: ", wrap_lines=False)

Password input
^^^^^^^^^^^^^^

When the is_password=True flag has been given, the input is replaced by
asterisks (* characters).

.. code:: python

text
from prompt_toolkit import prompt

prompt("Enter password: ", is_password=True)

Cursor shapes

Many terminals support displaying different types of cursor shapes. The most
common are block, beam or underscore. Either blinking or not. It is possible to
decide which cursor to display while asking for input, or in case of Vi input
mode, have a modal prompt for which its cursor shape changes according to the
input mode.

.. code:: python

text
from prompt_toolkit import prompt
from prompt_toolkit.cursor_shapes import CursorShape, ModalCursorShapeConfig

# Several possible values for the `cursor_shape_config` parameter:
prompt(">", cursor=CursorShape.BLOCK)
prompt(">", cursor=CursorShape.UNDERLINE)
prompt(">", cursor=CursorShape.BEAM)
prompt(">", cursor=CursorShape.BLINKING_BLOCK)
prompt(">", cursor=CursorShape.BLINKING_UNDERLINE)
prompt(">", cursor=CursorShape.BLINKING_BEAM)
prompt(">", cursor=ModalCursorShapeConfig())

Adding a frame

A frame can be displayed around the input by passing show_frame=True as a
parameter. The color of the frame can be chosen by styling the frame.border
element:

.. code:: python

text
from prompt_toolkit import prompt
from prompt_toolkit.styles import Style

style = Style.from_dict(
    {
        "frame.border": "#884444",
    }
)

answer = prompt("Say something > ", style=style, show_frame=True)
print(f"You said: {answer}")

.. image:: ../images/prompt-with-frame.png

It is also possible to pass a :ref:filter <filters>, for instance
show_frame=~is_done, so that the frame is only displayed when asking for
input, but hidden once the input is accepted.

.. code:: python

text
from prompt_toolkit import prompt
from prompt_toolkit.filters import is_done

answer = prompt("Say something > ", show_frame=~is_done)
print(f"You said: {answer}")

Prompt in an `asyncio` application

.. note::

text
New in prompt_toolkit 3.0. (In prompt_toolkit 2.0 this was possible using a
work-around).

For asyncio <https://docs.python.org/3/library/asyncio.html>_ applications,
it's very important to never block the eventloop. However,
:func:~prompt_toolkit.shortcuts.prompt is blocking, and calling this would
freeze the whole application. Asyncio actually won't even allow us to run that
function within a coroutine.

The answer is to call
:meth:~prompt_toolkit.shortcuts.PromptSession.prompt_async instead of
:meth:~prompt_toolkit.shortcuts.PromptSession.prompt. The async variation
returns a coroutines and is awaitable.

.. code:: python

text
from prompt_toolkit import PromptSession
from prompt_toolkit.patch_stdout import patch_stdout

async def my_coroutine():
    session = PromptSession()
    while True:
        with patch_stdout():
            result = await session.prompt_async("Say something: ")
        print(f"You said: {result}")

The :func:~prompt_toolkit.patch_stdout.patch_stdout context manager is
optional, but it's recommended, because other coroutines could print to stdout.
This ensures that other output won't destroy the prompt.

Reading keys from stdin, one key at a time, but without a prompt

Suppose that you want to use prompt_toolkit to read the keys from stdin, one
key at a time, but not render a prompt to the output, that is also possible:

.. code:: python

text
import asyncio

from prompt_toolkit.input import create_input
from prompt_toolkit.keys import Keys


async def main() -> None:
    done = asyncio.Event()
    input = create_input()

    def keys_ready():
        for key_press in input.read_keys():
            print(key_press)

            if key_press.key == Keys.ControlC:
                done.set()

    with input.raw_mode():
        with input.attach(keys_ready):
            await done.wait()


if __name__ == "__main__":
    asyncio.run(main())

The above snippet will print the KeyPress object whenever a key is pressed.
This is also cross platform, and should work on Windows.


Pages Dialogs (`docs/pages/dialogs.rst`)

.. _dialogs:

Dialogs

Prompt_toolkit ships with a high level API for displaying dialogs, similar to
the Whiptail program, but in pure Python.

Message box

Use the :func:~prompt_toolkit.shortcuts.message_dialog function to display a
simple message box. For instance:

.. code:: python

text
from prompt_toolkit.shortcuts import message_dialog

message_dialog(
    title='Example dialog window',
    text='Do you want to continue?\nPress ENTER to quit.').run()

.. image:: ../images/dialogs/messagebox.png

Input box

The :func:~prompt_toolkit.shortcuts.input_dialog function can display an
input box. It will return the user input as a string.

.. code:: python

text
from prompt_toolkit.shortcuts import input_dialog

text = input_dialog(
    title='Input dialog example',
    text='Please type your name:').run()

.. image:: ../images/dialogs/inputbox.png

The password=True option can be passed to the
:func:~prompt_toolkit.shortcuts.input_dialog function to turn this into a
password input box.

Yes/No confirmation dialog

The :func:~prompt_toolkit.shortcuts.yes_no_dialog function displays a yes/no
confirmation dialog. It will return a boolean according to the selection.

.. code:: python

text
from prompt_toolkit.shortcuts import yes_no_dialog

result = yes_no_dialog(
    title='Yes/No dialog example',
    text='Do you want to confirm?').run()

.. image:: ../images/dialogs/confirm.png

Button dialog

The :func:~prompt_toolkit.shortcuts.button_dialog function displays a dialog
with choices offered as buttons. Buttons are indicated as a list of tuples,
each providing the label (first) and return value if clicked (second).

.. code:: python

text
from prompt_toolkit.shortcuts import button_dialog

result = button_dialog(
    title='Button dialog example',
    text='Do you want to confirm?',
    buttons=[
        ('Yes', True),
        ('No', False),
        ('Maybe...', None)
    ],
).run()

.. image:: ../images/dialogs/button.png

Radio list dialog

The :func:~prompt_toolkit.shortcuts.radiolist_dialog function displays a dialog
with choices offered as a radio list. The values are provided as a list of tuples,
each providing the return value (first element) and the displayed value (second element).

.. code:: python

text
from prompt_toolkit.shortcuts import radiolist_dialog

result = radiolist_dialog(
    title="RadioList dialog",
    text="Which breakfast would you like ?",
    values=[
        ("breakfast1", "Eggs and beacon"),
        ("breakfast2", "French breakfast"),
        ("breakfast3", "Equestrian breakfast")
    ]
).run()

Checkbox list dialog

The :func:~prompt_toolkit.shortcuts.checkboxlist_dialog has the same usage and purpose than the Radiolist dialog, but allows several values to be selected and therefore returned.

.. code:: python

text
from prompt_toolkit.shortcuts import checkboxlist_dialog

results_array = checkboxlist_dialog(
    title="CheckboxList dialog",
    text="What would you like in your breakfast ?",
    values=[
        ("eggs", "Eggs"),
        ("bacon", "Bacon"),
        ("croissants", "20 Croissants"),
        ("daily", "The breakfast of the day")
    ]
).run()

Styling of dialogs

A custom :class:~prompt_toolkit.styles.Style instance can be passed to all
dialogs to override the default style. Also, text can be styled by passing an
:class:~prompt_toolkit.formatted_text.HTML object.

.. code:: python

text
from prompt_toolkit.formatted_text import HTML
from prompt_toolkit.shortcuts import message_dialog
from prompt_toolkit.styles import Style

example_style = Style.from_dict({
    'dialog':             'bg:#88ff88',
    'dialog frame.label': 'bg:#ffffff #000000',
    'dialog.body':        'bg:#000000 #00ff00',
    'dialog shadow':      'bg:#00aa00',
})

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()

.. image:: ../images/dialogs/styled.png

Styling reference sheet

In reality, the shortcut commands presented above build a full-screen frame by using a list of components. The two tables below allow you to get the classnames available for each shortcut, therefore you will be able to provide a custom style for every element that is displayed, using the method provided above.

.. note:: All the shortcuts use the Dialog component, therefore it isn't specified explicitly below.

+--------------------------+-------------------------+
| Shortcut | Components used |
+==========================+=========================+
| yes_no_dialog | - Label |
| | - Button (x2) |
+--------------------------+-------------------------+
| button_dialog | - Label |
| | - Button |
+--------------------------+-------------------------+
| input_dialog | - TextArea |
| | - Button (x2) |
+--------------------------+-------------------------+
| message_dialog | - Label |
| | - Button |
+--------------------------+-------------------------+
| radiolist_dialog | - Label |
| | - RadioList |
| | - Button (x2) |
+--------------------------+-------------------------+
| checkboxlist_dialog | - Label |
| | - CheckboxList |
| | - Button (x2) |
+--------------------------+-------------------------+
| progress_dialog | - Label |
| | - TextArea (locked) |
| | - ProgressBar |
+--------------------------+-------------------------+

+----------------+-----------------------------+
| Components | Available classnames |
+================+=============================+
| Dialog | - dialog |
| | - dialog.body |
+----------------+-----------------------------+
| TextArea | - text-area |
| | - text-area.prompt |
+----------------+-----------------------------+
| Label | - label |
+----------------+-----------------------------+
| Button | - button |
| | - button.focused |
| | - button.arrow |
| | - button.text |
+----------------+-----------------------------+
| Frame | - frame |
| | - frame.border |
| | - frame.label |
+----------------+-----------------------------+
| Shadow | - shadow |
+----------------+-----------------------------+
| RadioList | - radio-list |
| | - radio |
| | - radio-checked |
| | - radio-selected |
+----------------+-----------------------------+
| CheckboxList | - checkbox-list |
| | - checkbox |
| | - checkbox-checked |
| | - checkbox-selected |
+----------------+-----------------------------+
| VerticalLine | - line |
| | - vertical-line |
+----------------+-----------------------------+
| HorizontalLine | - line |
| | - horizontal-line |
+----------------+-----------------------------+
| ProgressBar | - progress-bar |
| | - progress-bar.used |
+----------------+-----------------------------+

Example


Let's customize the example of the checkboxlist_dialog.

It uses 2 Button, a CheckboxList and a Label, packed inside a Dialog.
Therefore we can customize each of these elements separately, using for instance:

.. code:: python

text
from prompt_toolkit.shortcuts import checkboxlist_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", "Bacon"),
        ("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()

Pages Full Screen Apps (`docs/pages/full_screen_apps.rst`)

.. _full_screen_applications:

Building full screen applications

prompt_toolkit can be used to create complex full screen terminal
applications. Typically, an application consists of a layout (to describe the
graphical part) and a set of key bindings.

The sections below describe the components required for full screen
applications (or custom, non full screen applications), and how to assemble
them together.

Before going through this page, it could be helpful to go through :ref:asking for input <asking_for_input> (prompts) first. Many things that apply to an
input prompt, like styling, key bindings and so on, also apply to full screen
applications.

.. note::

text
Also remember that the ``examples`` directory of the prompt_toolkit
repository contains plenty of examples. Each example is supposed to explain
one idea. So, this as well should help you get started.

Don't hesitate to open a GitHub issue if you feel that a certain example is
missing.

A simple application

Every prompt_toolkit application is an instance of an
:class:~prompt_toolkit.application.Application object. The simplest full
screen example would look like this:

.. code:: python

text
from prompt_toolkit import Application

app = Application(full_screen=True)
app.run()

This will display a dummy application that says "No layout specified. Press
ENTER to quit.".

.. note::

text
If we wouldn't set the ``full_screen`` option, the application would
    not run in the alternate screen buffer, and only consume the least
    amount of space required for the layout.

An application consists of several components. The most important are:

  • I/O objects: the input and output device.
  • The layout: this defines the graphical structure of the application. For
    instance, a text box on the left side, and a button on the right side.
    You can also think of the layout as a collection of 'widgets'.
  • A style: this defines what colors and underline/bold/italic styles are used
    everywhere.
  • A set of key bindings.

We will discuss all of these in more detail below.

I/O objects

Every :class:~prompt_toolkit.application.Application instance requires an I/O
object for input and output:

  • An :class:~prompt_toolkit.input.Input instance, which is an abstraction
    of the input stream (stdin).
  • An :class:~prompt_toolkit.output.Output instance, which is an
    abstraction of the output stream, and is called by the renderer.

Both are optional and normally not needed to pass explicitly. Usually, the
default works fine.

There is a third I/O object which is also required by the application, but not
passed inside. This is the event loop, an
:class:~prompt_toolkit.eventloop instance. This is basically a
while-true loop that waits for user input, and when it receives something (like
a key press), it will send that to the the appropriate handler, like for
instance, a key binding.

When :func:~prompt_toolkit.application.Application.run() is called, the event
loop will run until the application is done. An application will quit when
:func:~prompt_toolkit.application.Application.exit() is called.

The layout

A layered layout architecture
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

There are several ways to create a prompt_toolkit layout, depending on how
customizable you want things to be. In fact, there are several layers of
abstraction.

  • The most low-level way of creating a layout is by combining
    :class:~prompt_toolkit.layout.Container and
    :class:~prompt_toolkit.layout.UIControl objects.

    Examples of :class:~prompt_toolkit.layout.Container objects are
    :class:~prompt_toolkit.layout.VSplit (vertical split),
    :class:~prompt_toolkit.layout.HSplit (horizontal split) and
    :class:~prompt_toolkit.layout.FloatContainer. These containers arrange the
    layout and can split it in multiple regions. Each container can recursively
    contain multiple other containers. They can be combined in any way to define
    the "shape" of the layout.

    The :class:~prompt_toolkit.layout.Window object is a special kind of
    container that can contain a :class:~prompt_toolkit.layout.UIControl
    object. The :class:~prompt_toolkit.layout.UIControl object is responsible
    for the generation of the actual content. The
    :class:~prompt_toolkit.layout.Window object acts as an adaptor between the
    :class:~prompt_toolkit.layout.UIControl and other containers, but it's also
    responsible for the scrolling and line wrapping of the content.

    Examples of :class:~prompt_toolkit.layout.UIControl objects are
    :class:~prompt_toolkit.layout.BufferControl for showing the content of an
    editable/scrollable buffer, and
    :class:~prompt_toolkit.layout.FormattedTextControl for displaying
    (:ref:formatted <formatted_text>) text.

    Normally, it is never needed to create new
    :class:~prompt_toolkit.layout.UIControl or
    :class:~prompt_toolkit.layout.Container classes, but instead you would
    create the layout by composing instances of the existing built-ins.

  • A higher level abstraction of building a layout is by using "widgets". A
    widget is a reusable layout component that can contain multiple containers
    and controls. Widgets have a __pt_container__ function, which returns
    the root container for this widget. Prompt_toolkit contains a couple of
    widgets like :class:~prompt_toolkit.widgets.TextArea,
    :class:~prompt_toolkit.widgets.Button,
    :class:~prompt_toolkit.widgets.Frame,
    :class:~prompt_toolkit.widgets.VerticalLine and so on.

  • The highest level abstractions can be found in the shortcuts module.
    There we don't have to think about the layout, controls and containers at
    all. This is the simplest way to use prompt_toolkit, but is only meant for
    specific use cases, like a prompt or a simple dialog window.

Containers and controls
^^^^^^^^^^^^^^^^^^^^^^^

The biggest difference between containers and controls is that containers
arrange the layout by splitting the screen in many regions, while controls are
responsible for generating the actual content.

.. note::

Under the hood, the difference is:

  • containers use absolute coordinates, and paint on a
    :class:~prompt_toolkit.layout.screen.Screen instance.
  • user controls create a :class:~prompt_toolkit.layout.controls.UIContent
    instance. This is a collection of lines that represent the actual
    content. A :class:~prompt_toolkit.layout.controls.UIControl is not aware
    of the screen.

+---------------------------------------------+------------------------------------------------------+
| Abstract base class | Examples |
+=============================================+======================================================+
| :class:~prompt_toolkit.layout.Container | :class:~prompt_toolkit.layout.HSplit |
| | :class:~prompt_toolkit.layout.VSplit |
| | :class:~prompt_toolkit.layout.FloatContainer |
| | :class:~prompt_toolkit.layout.Window |
| | :class:~prompt_toolkit.layout.ScrollablePane |
+---------------------------------------------+------------------------------------------------------+
| :class:~prompt_toolkit.layout.UIControl | :class:~prompt_toolkit.layout.BufferControl |
| | :class:~prompt_toolkit.layout.FormattedTextControl |
+---------------------------------------------+------------------------------------------------------+

The :class:~prompt_toolkit.layout.Window class itself is
particular: it is a :class:~prompt_toolkit.layout.Container that
can contain a :class:~prompt_toolkit.layout.UIControl. Thus, it's the adaptor
between the two. The :class:~prompt_toolkit.layout.Window class also takes
care of scrolling the content and wrapping the lines if needed.

Finally, there is the :class:~prompt_toolkit.layout.Layout class which wraps
the whole layout. This is responsible for keeping track of which window has the
focus.

Here is an example of a layout that displays the content of the default buffer
on the left, and displays "Hello world" on the right. In between it shows a
vertical line:

.. code:: python

text
from prompt_toolkit import Application
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.layout.containers import VSplit, Window
from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
from prompt_toolkit.layout.layout import Layout

buffer1 = Buffer()  # Editable buffer.

root_container = VSplit([
    # One window that holds the BufferControl with the default buffer on
    # the left.
    Window(content=BufferControl(buffer=buffer1)),

    # 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. The window will simply fill its
    # content by repeating this character.
    Window(width=1, char='|'),

    # Display the text 'Hello world' on the right.
    Window(content=FormattedTextControl(text='Hello world')),
])

layout = Layout(root_container)

app = Application(layout=layout, full_screen=True)
app.run() # You won't be able to Exit this app

Notice that if you execute this right now, there is no way to quit this
application yet. This is something we explain in the next section below.

More complex layouts can be achieved by nesting multiple
:class:~prompt_toolkit.layout.VSplit,
:class:~prompt_toolkit.layout.HSplit and
:class:~prompt_toolkit.layout.FloatContainer objects.

If you want to make some part of the layout only visible when a certain
condition is satisfied, use a
:class:~prompt_toolkit.layout.ConditionalContainer.

Finally, there is :class:~prompt_toolkit.layout.ScrollablePane, a container
class that can be used to create long forms or nested layouts that are
scrollable as a whole.

Focusing windows
^^^^^^^^^^^^^^^^^

Focusing something can be done by calling the
:meth:~prompt_toolkit.layout.Layout.focus method. This method is very
flexible and accepts a :class:~prompt_toolkit.layout.Window, a
:class:~prompt_toolkit.buffer.Buffer, a
:class:~prompt_toolkit.layout.controls.UIControl and more.

In the following example, we use :func:~prompt_toolkit.application.get_app
for getting the active application.

.. code:: python

text
from prompt_toolkit.application import get_app

# This window was created earlier.
w = Window()

# ...

# Now focus it.
get_app().layout.focus(w)

Changing the focus is something which is typically done in a key binding, so
read on to see how to define key bindings.

Key bindings

In order to react to user actions, we need to create a
:class:~prompt_toolkit.key_binding.KeyBindings object and pass
that to our :class:~prompt_toolkit.application.Application.

There are two kinds of key bindings:

  • Global key bindings, which are always active.
  • Key bindings that belong to a certain
    :class:~prompt_toolkit.layout.controls.UIControl and are only active when
    this control is focused. Both
    :class:~prompt_toolkit.layout.BufferControl
    :class:~prompt_toolkit.layout.FormattedTextControl take a key_bindings
    argument.

Global key bindings
^^^^^^^^^^^^^^^^^^^

Key bindings can be passed to the application as follows:

.. code:: python

text
from prompt_toolkit import Application
from prompt_toolkit.key_binding import KeyBindings

kb = KeyBindings()
app = Application(key_bindings=kb)
app.run()

To register a new keyboard shortcut, we can use the
:meth:~prompt_toolkit.key_binding.KeyBindings.add method as a decorator of
the key handler:

.. code:: python

text
from prompt_toolkit import Application
from prompt_toolkit.key_binding import KeyBindings

kb = KeyBindings()

@kb.add('c-q')
def exit_(event):
    """
    Pressing Ctrl-Q 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.
    """
    event.app.exit()

app = Application(key_bindings=kb, full_screen=True)
app.run()

The callback function is named exit_ for clarity, but it could have been
named _ (underscore) as well, because we won't refer to this name.

:ref:Read more about key bindings ...<key_bindings>

Modal containers
^^^^^^^^^^^^^^^^

The following container objects take a modal argument
:class:~prompt_toolkit.layout.VSplit,
:class:~prompt_toolkit.layout.HSplit, and
:class:~prompt_toolkit.layout.FloatContainer.

Setting modal=True makes what is called a modal container. Normally, a
child container would inherit its parent key bindings. This does not apply to
modal containers.

Consider a modal container (e.g. :class:~prompt_toolkit.layout.VSplit)
is child of another container, its parent. Any key bindings from the parent
are not taken into account if the modal container (child) has the focus.

This is useful in a complex layout, where many controls have their own key
bindings, but you only want to enable the key bindings for a certain region of
the layout.

The global key bindings are always active.

More about the Window class

As said earlier, a :class:~prompt_toolkit.layout.Window is a
:class:~prompt_toolkit.layout.Container that wraps a
:class:~prompt_toolkit.layout.UIControl, like a
:class:~prompt_toolkit.layout.BufferControl or
:class:~prompt_toolkit.layout.FormattedTextControl.

.. note::

text
Basically, windows are the leaves in the tree structure that represent the UI.

A :class:~prompt_toolkit.layout.Window provides a "view" on the
:class:~prompt_toolkit.layout.UIControl, which provides lines of content. The
window is in the first place responsible for the line wrapping and scrolling of
the content, but there are much more options.

  • Adding left or right margins. These are used for displaying scroll bars or
    line numbers.
  • There are the cursorline and cursorcolumn options. These allow
    highlighting the line or column of the cursor position.
  • Alignment of the content. The content can be left aligned, right aligned or
    centered.
  • Finally, the background can be filled with a default character.

More about buffers and `BufferControl`

Input processors
^^^^^^^^^^^^^^^^

A :class:~prompt_toolkit.layout.processors.Processor is used to postprocess
the content of a :class:~prompt_toolkit.layout.BufferControl before it's
displayed. It can for instance highlight matching brackets or change the
visualization of tabs and so on.

A :class:~prompt_toolkit.layout.processors.Processor operates on individual
lines. Basically, it takes a (formatted) line and produces a new (formatted)
line.

Some built-in processors:

+----------------------------------------------------------------------------+-----------------------------------------------------------+
| Processor | Usage: |
+============================================================================+===========================================================+
| :class:~prompt_toolkit.layout.processors.HighlightSearchProcessor | Highlight the current search results. |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| :class:~prompt_toolkit.layout.processors.HighlightSelectionProcessor | Highlight the selection. |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| :class:~prompt_toolkit.layout.processors.PasswordProcessor | Display input as asterisks. (* characters). |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| :class:~prompt_toolkit.layout.processors.BracketsMismatchProcessor | Highlight open/close mismatches for brackets. |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| :class:~prompt_toolkit.layout.processors.BeforeInput | Insert some text before. |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| :class:~prompt_toolkit.layout.processors.AfterInput | Insert some text after. |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| :class:~prompt_toolkit.layout.processors.AppendAutoSuggestion | Append auto suggestion text. |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| :class:~prompt_toolkit.layout.processors.ShowLeadingWhiteSpaceProcessor | Visualize leading whitespace. |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| :class:~prompt_toolkit.layout.processors.ShowTrailingWhiteSpaceProcessor | Visualize trailing whitespace. |
+----------------------------------------------------------------------------+-----------------------------------------------------------+
| :class:~prompt_toolkit.layout.processors.TabsProcessor | Visualize tabs as n spaces, or some symbols. |
+----------------------------------------------------------------------------+-----------------------------------------------------------+

A :class:~prompt_toolkit.layout.BufferControl takes only one processor as
input, but it is possible to "merge" multiple processors into one with the
:func:~prompt_toolkit.layout.processors.merge_processors function.


.. _gallery:

Showcase, demonstrating the possibilities of prompt_toolkit.

Ptpython, a Python REPL
^^^^^^^^^^^^^^^^^^^^^^^

The prompt:

.. image:: ../images/ptpython.png

The configuration menu of ptpython.

.. image:: ../images/ptpython-menu.png

The history page with its help. (This is a full-screen layout.)

.. image:: ../images/ptpython-history-help.png

Pyvim, a Vim clone
^^^^^^^^^^^^^^^^^^

.. image:: ../images/pyvim.png

Pymux, a terminal multiplexer (like tmux) in Python
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. image:: ../images/pymux.png


Pages Getting Started (`docs/pages/getting_started.rst`)

.. _getting_started:

Getting started

Installation

::

text
pip install prompt_toolkit

For Conda, do:

::

text
conda install -c https://conda.anaconda.org/conda-forge prompt_toolkit

Several use cases: prompts versus full screen terminal applications

prompt_toolkit was in the first place meant to be a replacement for readline.
However, when it became more mature, we realized that all the components for
full screen applications are there and prompt_toolkit is very capable of
handling many use situations. Pyvim <http://github.com/prompt-toolkit/pyvim>_ and pymux <http://github.com/prompt-toolkit/pymux>_ are examples of full screen
applications.

.. image:: ../images/pyvim.png

Basically, at the core, prompt_toolkit has a layout engine, that supports
horizontal and vertical splits as well as floats, where each "window" can
display a user control. The API for user controls is simple yet powerful.

When prompt_toolkit is used as a readline replacement, (to simply read some
input from the user), it uses a rather simple built-in layout. One that
displays the default input buffer and the prompt, a float for the
autocompletions and a toolbar for input validation which is hidden by default.

For full screen applications, usually we build a custom layout ourselves.

Further, there is a very flexible key binding system that can be programmed for
all the needs of full screen applications.

A simple prompt

The following snippet is the most simple example, it uses the
:func:~prompt_toolkit.shortcuts.prompt function to asks the user for input
and returns the text. Just like (raw_)input.

.. code:: python

text
from prompt_toolkit import prompt

text = prompt("Give me some input: ")
print(f"You said: {text}")

Learning `prompt_toolkit`

In order to learn and understand prompt_toolkit, it is best to go through the
all sections in the order below. Also don't forget to have a look at all the
examples <https://github.com/prompt-toolkit/python-prompt-toolkit/tree/master/examples>_
in the repository.

  • First, :ref:learn how to print text . This is important,
    because it covers how to use "formatted text", which is something you'll use
    whenever you want to use colors anywhere.

  • Secondly, go through the :ref:asking for input <asking_for_input> section.
    This is useful for almost any use case, even for full screen applications.
    It covers autocompletions, syntax highlighting, key bindings, and so on.

  • Then, learn about :ref:dialogs, which is easy and fun.

  • Finally, learn about :ref:full screen applications <full_screen_applications> and read through :ref:the advanced topics <advanced_topics>.


Pages Printing Text (`docs/pages/printing_text.rst`)

.. _printing_text:

Printing (and using) formatted text

Prompt_toolkit ships with a
:func:~prompt_toolkit.shortcuts.print_formatted_text function that's meant to
be (as much as possible) compatible with the built-in print function, but on
top of that, also supports colors and formatting.

On Linux systems, this will output VT100 escape sequences, while on Windows it
will use Win32 API calls or VT100 sequences, depending on what is available.

.. note::

text
This page is also useful if you'd like to learn how to use formatting
    in other places, like in a prompt or a toolbar. Just like
    :func:`~prompt_toolkit.shortcuts.print_formatted_text` takes any kind
    of "formatted text" as input, prompts and toolbars also accept
    "formatted text".

Printing plain text

The print function can be imported as follows:

.. code:: python

text
from prompt_toolkit import print_formatted_text

print_formatted_text('Hello world')

You can replace the built in print function as follows, if you want to.

.. code:: python

text
from prompt_toolkit import print_formatted_text as print

print('Hello world')

.. note::

text
If you're using Python 2, make sure to add ``from __future__ import
print_function``. Otherwise, it will not be possible to import a function
named ``print``.

.. _formatted_text:

Formatted text

There are several ways to display colors:

  • By creating an :class:~prompt_toolkit.formatted_text.HTML object.
  • By creating an :class:~prompt_toolkit.formatted_text.ANSI object that
    contains ANSI escape sequences.
  • By creating a list of (style, text) tuples.
  • By creating a list of (pygments.Token, text) tuples, and wrapping it in
    :class:~prompt_toolkit.formatted_text.PygmentsTokens.

An instance of any of these four kinds of objects is called "formatted text".
There are various places in prompt toolkit, where we accept not just plain text
(as a string), but also formatted text.

HTML
^^^^

:class:~prompt_toolkit.formatted_text.HTML can be used to indicate that a
string contains HTML-like formatting. It recognizes the basic tags for bold,
italic and underline: , and ````.

.. code:: python

text
from prompt_toolkit import print_formatted_text, HTML

print_formatted_text(HTML('**This is bold**'))
print_formatted_text(HTML('*This is italic*'))
print_formatted_text(HTML('This is underlined'))

Further, it's possible to use tags for foreground colors:

.. code:: python

text
# Colors from the ANSI palette.
print_formatted_text(HTML('<ansired>This is red</ansired>'))
print_formatted_text(HTML('<ansigreen>This is green</ansigreen>'))

# Named colors (256 color palette, or true color, depending on the output).
print_formatted_text(HTML('<skyblue>This is sky blue</skyblue>'))
print_formatted_text(HTML('<seagreen>This is sea green</seagreen>'))
print_formatted_text(HTML('<violet>This is violet</violet>'))

Both foreground and background colors can also be specified setting the fg
and bg attributes of any HTML tag:

.. code:: python

text
# Colors from the ANSI palette.
print_formatted_text(HTML('<aaa fg="ansiwhite" bg="ansigreen">White on green</aaa>'))

Underneath, all HTML tags are mapped to classes from a stylesheet, so you can
assign a style for a custom tag.

.. code:: python

text
from prompt_toolkit import print_formatted_text, HTML
from prompt_toolkit.styles import Style

style = Style.from_dict({
    'aaa': '#ff0066',
    'bbb': '#44ff00 italic',
})

print_formatted_text(HTML('<aaa>Hello</aaa> world!'), style=style)

ANSI
^^^^

Some people like to use the VT100 ANSI escape sequences to generate output.
Natively, this is however only supported on VT100 terminals, but prompt_toolkit
can parse these, and map them to formatted text instances. This means that they
will work on Windows as well. The :class:~prompt_toolkit.formatted_text.ANSI
class takes care of that.

.. code:: python

text
from prompt_toolkit import print_formatted_text, ANSI

print_formatted_text(ANSI('\x1b[31mhello \x1b[32mworld'))

Keep in mind that even on a Linux VT100 terminal, the final output produced by
prompt_toolkit, is not necessarily exactly the same. Depending on the color
depth, it is possible that colors are mapped to different colors, and unknown
tags will be removed.

(style, text) tuples
^^^^^^^^^^^^^^^^^^^^

Internally, both :class:~prompt_toolkit.formatted_text.HTML and
:class:~prompt_toolkit.formatted_text.ANSI objects are mapped to a list of
(style, text) tuples. It is however also possible to create such a list
manually with :class:~prompt_toolkit.formatted_text.FormattedText class.
This is a little more verbose, but it's probably the most powerful
way of expressing formatted text.

.. code:: python

text
from prompt_toolkit import print_formatted_text
from prompt_toolkit.formatted_text import FormattedText

text = FormattedText([
    ('#ff0066', 'Hello'),
    ('', ' '),
    ('#44ff00 italic', 'World'),
])

print_formatted_text(text)

Similar to the :class:~prompt_toolkit.formatted_text.HTML example, it is also
possible to use class names, and separate the styling in a style sheet.

.. code:: python

text
from prompt_toolkit import print_formatted_text
from prompt_toolkit.formatted_text import FormattedText
from prompt_toolkit.styles import Style

# The text.
text = FormattedText([
    ('class:aaa', 'Hello'),
    ('', ' '),
    ('class:bbb', 'World'),
])

# The style sheet.
style = Style.from_dict({
    'aaa': '#ff0066',
    'bbb': '#44ff00 italic',
})

print_formatted_text(text, style=style)

Pygments (Token, text) tuples
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

When you have a list of Pygments <http://pygments.org/>_ (Token, text)
tuples, then these can be printed by wrapping them in a
:class:~prompt_toolkit.formatted_text.PygmentsTokens object.

.. code:: python

text
from pygments.token import Token
from prompt_toolkit import print_formatted_text
from prompt_toolkit.formatted_text import PygmentsTokens

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))

Similarly, it is also possible to print the output of a Pygments lexer:

.. code:: python

text
import pygments
from pygments.token import Token
from pygments.lexers.python import PythonLexer

from prompt_toolkit.formatted_text import PygmentsTokens
from prompt_toolkit import print_formatted_text

# Printing the output of a pygments lexer.
tokens = list(pygments.lex('print("Hello")', lexer=PythonLexer()))
print_formatted_text(PygmentsTokens(tokens))

Prompt_toolkit ships with a default colorscheme which styles it just like
Pygments would do, but if you'd like to change the colors, keep in mind that
Pygments tokens map to classnames like this:

+-----------------------------------+---------------------------------------------+
| pygments.Token | prompt_toolkit classname |
+===================================+=============================================+
| - Token.Keyword | - "class:pygments.keyword" |
| - Token.Punctuation | - "class:pygments.punctuation" |
| - Token.Literal.String.Double | - "class:pygments.literal.string.double"|
| - Token.Text | - "class:pygments.text" |
| - Token | - "class:pygments" |
+-----------------------------------+---------------------------------------------+

A classname like pygments.literal.string.double is actually decomposed in
the following four classnames: pygments, pygments.literal,
pygments.literal.string and pygments.literal.string.double. The final
style is computed by combining the style for these four classnames. So,
changing the style from these Pygments tokens can be done as follows:

.. code:: python

text
from prompt_toolkit.styles import Style

style = Style.from_dict({
    'pygments.keyword': 'underline',
    'pygments.literal.string': 'bg:#00ff00 #ffffff',
})
print_formatted_text(PygmentsTokens(tokens), style=style)

to_formatted_text
^^^^^^^^^^^^^^^^^

A useful function to know about is
:func:~prompt_toolkit.formatted_text.to_formatted_text. This ensures that the
given input is valid formatted text. While doing so, an additional style can be
applied as well.

.. code:: python

text
from prompt_toolkit.formatted_text import to_formatted_text, HTML
from prompt_toolkit import print_formatted_text

html = HTML('<aaa>Hello</aaa> world!')
text = to_formatted_text(html, style='class:my_html bg:#00ff00 italic')

print_formatted_text(text)

Pages Progress Bars (`docs/pages/progress_bars.rst`)

.. _progress_bars:

Progress bars

Prompt_toolkit ships with a high level API for displaying progress bars,
inspired by tqdm <https://github.com/tqdm/tqdm>_

.. warning::

text
The API for the prompt_toolkit progress bars is still very new and can
possibly change in the future. It is usable and tested, but keep this in
mind when upgrading.

Remember that the examples directory <https://github.com/prompt-toolkit/python-prompt-toolkit/tree/master/examples>_
of the prompt_toolkit repository ships with many progress bar examples as well.

Simple progress bar

Creating a new progress bar can be done by calling the
:class:~prompt_toolkit.shortcuts.ProgressBar context manager.

The progress can be displayed for any iterable. This works by wrapping the
iterable (like range) with the
:class:~prompt_toolkit.shortcuts.ProgressBar context manager itself. This
way, the progress bar knows when the next item is consumed by the forloop and
when progress happens.

.. code:: python

text
from prompt_toolkit.shortcuts import ProgressBar
import time


with ProgressBar() as pb:
    for i in pb(range(800)):
        time.sleep(.01)

.. image:: ../images/progress-bars/simple-progress-bar.png

Keep in mind that not all iterables can report their total length. This happens
with a typical generator. In that case, you can still pass the total as follows
in order to make displaying the progress possible:

.. code:: python

text
def some_iterable():
    yield ...

with ProgressBar() as pb:
    for i in pb(some_iterable(), total=1000):
        time.sleep(.01)

Multiple parallel tasks

A prompt_toolkit :class:~prompt_toolkit.shortcuts.ProgressBar can display the
progress of multiple tasks running in parallel. Each task can run in a separate
thread and the :class:~prompt_toolkit.shortcuts.ProgressBar user interface
runs in its own thread.

Notice that we set the "daemon" flag for both threads that run the tasks. This
is because control-c will stop the progress and quit our application. We don't
want the application to wait for the background threads to finish. Whether you
want this depends on the application.

.. code:: python

text
from prompt_toolkit.shortcuts import ProgressBar
import time
import threading


with ProgressBar() as pb:
    # Two parallel tasks.
    def task_1():
        for i in pb(range(100)):
            time.sleep(.05)

    def task_2():
        for i in pb(range(150)):
            time.sleep(.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=.5)

.. image:: ../images/progress-bars/two-tasks.png

Adding a title and label

Each progress bar can have one title, and for each task an individual label.
Both the title and the labels can be :ref:formatted text <formatted_text>.

.. code:: python

text
from prompt_toolkit.shortcuts import ProgressBar
from prompt_toolkit.formatted_text import HTML
import time

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(.01)

.. image:: ../images/progress-bars/colored-title-and-label.png

Formatting the progress bar

The visualization of a :class:~prompt_toolkit.shortcuts.ProgressBar can be
customized by using a different sequence of formatters. The default formatting
looks something like this:

.. code:: python

text
from prompt_toolkit.shortcuts.progress_bar.formatters import *

default_formatting = [
    Label(),
    Text(' '),
    Percentage(),
    Text(' '),
    Bar(),
    Text(' '),
    Progress(),
    Text(' '),
    Text('eta [', style='class:time-left'),
    TimeLeft(),
    Text(']', style='class:time-left'),
    Text(' '),
]

That sequence of
:class:~prompt_toolkit.shortcuts.progress_bar.formatters.Formatter can be
passed to the formatter argument of
:class:~prompt_toolkit.shortcuts.ProgressBar. So, we could change this and
modify the progress bar to look like an apt-get style progress bar:

.. code:: python

text
from prompt_toolkit.shortcuts import ProgressBar
from prompt_toolkit.styles import Style
from prompt_toolkit.shortcuts.progress_bar import formatters
import time

style = Style.from_dict({
    'label': 'bg:#ffff00 #000000',
    'percentage': 'bg:#ffff00 #000000',
    'current': '#448844',
    'bar': '',
})


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(.01)

.. image:: ../images/progress-bars/apt-get.png

Adding key bindings and toolbar

Like other prompt_toolkit applications, we can add custom key bindings, by
passing a :class:~prompt_toolkit.key_binding.KeyBindings object:

.. code:: python

text
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

import os
import time
import signal

bottom_toolbar = HTML(' **[f]** Print "f" **[x]** Abort.')

# Create custom key bindings first.
kb = KeyBindings()
cancel = [False]

@kb.add('f')
def _(event):
    print('You pressed `f`.')

@kb.add('x')
def _(event):
    " Send Abort (control-c) signal. "
    cancel[0] = True
    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(.01)

            # Stop when the cancel flag has been set.
            if cancel[0]:
                break

Notice that we use :func:~prompt_toolkit.patch_stdout.patch_stdout to make
printing text possible while the progress bar is displayed. This ensures that
printing happens above the progress bar.

Further, when "x" is pressed, we set a cancel flag, which stops the progress.
It would also be possible to send SIGINT to the main thread, but that's not
always considered a clean way of cancelling something.

In the example above, we also display a toolbar at the bottom which shows the
key bindings.

.. image:: ../images/progress-bars/custom-key-bindings.png

:ref:Read more about key bindings ...<key_bindings>


Pages Reference (`docs/pages/reference.rst`)

Reference

Application

.. automodule:: prompt_toolkit.application
:members: Application, get_app, get_app_or_none, set_app,
create_app_session, AppSession, get_app_session, DummyApplication,
in_terminal, run_in_terminal,

Formatted text

.. automodule:: prompt_toolkit.formatted_text
:members:

Buffer

.. automodule:: prompt_toolkit.buffer
:members:

Selection

.. automodule:: prompt_toolkit.selection
:members:

Clipboard

.. automodule:: prompt_toolkit.clipboard
:members: Clipboard, ClipboardData, DummyClipboard, DynamicClipboard, InMemoryClipboard

.. automodule:: prompt_toolkit.clipboard.pyperclip
:members:

Auto completion

.. automodule:: prompt_toolkit.completion
:members:

Document

.. automodule:: prompt_toolkit.document
:members:

Enums

.. automodule:: prompt_toolkit.enums
:members:

History

.. automodule:: prompt_toolkit.history
:members:

Keys

.. automodule:: prompt_toolkit.keys
:members:

Style

.. automodule:: prompt_toolkit.styles
:members: Attrs, ANSI_COLOR_NAMES, BaseStyle, DummyStyle, DynamicStyle,
Style, Priority, merge_styles, style_from_pygments_cls,
style_from_pygments_dict, pygments_token_to_classname, NAMED_COLORS,
StyleTransformation, SwapLightAndDarkStyleTransformation,
AdjustBrightnessStyleTransformation, merge_style_transformations,
DummyStyleTransformation, ConditionalStyleTransformation,
DynamicStyleTransformation

Shortcuts

.. automodule:: prompt_toolkit.shortcuts
:members: prompt, PromptSession, confirm, CompleteStyle,
create_confirm_session, clear, clear_title, print_formatted_text,
set_title, ProgressBar, input_dialog, message_dialog, progress_dialog,
radiolist_dialog, yes_no_dialog, button_dialog, choice

.. automodule:: prompt_toolkit.shortcuts.progress_bar.formatters
:members:

Validation

.. automodule:: prompt_toolkit.validation
:members:

Auto suggestion

.. automodule:: prompt_toolkit.auto_suggest
:members:

Renderer

.. automodule:: prompt_toolkit.renderer
:members:

Lexers

.. automodule:: prompt_toolkit.lexers
:members:

Layout

.. automodule:: prompt_toolkit.layout

The layout class itself
^^^^^^^^^^^^^^^^^^^^^^^

.. autoclass:: prompt_toolkit.layout.Layout
:members:

.. autoclass:: prompt_toolkit.layout.InvalidLayoutError
:members:

.. autoclass:: prompt_toolkit.layout.walk
:members:

Containers
^^^^^^^^^^

.. autoclass:: prompt_toolkit.layout.Container
:members:

.. autoclass:: prompt_toolkit.layout.HSplit
:members:

.. autoclass:: prompt_toolkit.layout.VSplit
:members:

.. autoclass:: prompt_toolkit.layout.FloatContainer
:members:

.. autoclass:: prompt_toolkit.layout.Float
:members:

.. autoclass:: prompt_toolkit.layout.Window
:members:

.. autoclass:: prompt_toolkit.layout.WindowAlign
:members:

.. autoclass:: prompt_toolkit.layout.ConditionalContainer
:members:

.. autoclass:: prompt_toolkit.layout.DynamicContainer
:members:

.. autoclass:: prompt_toolkit.layout.ScrollablePane
:members:

.. autoclass:: prompt_toolkit.layout.ScrollOffsets
:members:

.. autoclass:: prompt_toolkit.layout.ColorColumn
:members:

.. autoclass:: prompt_toolkit.layout.to_container
:members:

.. autoclass:: prompt_toolkit.layout.to_window
:members:

.. autoclass:: prompt_toolkit.layout.is_container
:members:

.. autoclass:: prompt_toolkit.layout.HorizontalAlign
:members:

.. autoclass:: prompt_toolkit.layout.VerticalAlign
:members:

Controls
^^^^^^^^

.. autoclass:: prompt_toolkit.layout.BufferControl
:members:

.. autoclass:: prompt_toolkit.layout.SearchBufferControl
:members:

.. autoclass:: prompt_toolkit.layout.DummyControl
:members:

.. autoclass:: prompt_toolkit.layout.FormattedTextControl
:members:

.. autoclass:: prompt_toolkit.layout.UIControl
:members:

.. autoclass:: prompt_toolkit.layout.UIContent
:members:

Other
^^^^^

Sizing
""""""

.. autoclass:: prompt_toolkit.layout.Dimension
:members:

Margins
"""""""

.. autoclass:: prompt_toolkit.layout.Margin
:members:

.. autoclass:: prompt_toolkit.layout.NumberedMargin
:members:

.. autoclass:: prompt_toolkit.layout.ScrollbarMargin
:members:

.. autoclass:: prompt_toolkit.layout.ConditionalMargin
:members:

.. autoclass:: prompt_toolkit.layout.PromptMargin
:members:

Completion Menus
""""""""""""""""

.. autoclass:: prompt_toolkit.layout.CompletionsMenu
:members:

.. autoclass:: prompt_toolkit.layout.MultiColumnCompletionsMenu
:members:

Processors
""""""""""

.. automodule:: prompt_toolkit.layout.processors
:members:

Utils
"""""

.. automodule:: prompt_toolkit.layout.utils
:members:

Screen
""""""

.. automodule:: prompt_toolkit.layout.screen
:members:

Widgets

.. automodule:: prompt_toolkit.widgets
:members: TextArea, Label, Button, Frame, Shadow, Box, VerticalLine,
HorizontalLine, RadioList, Checkbox, ProgressBar, CompletionsToolbar,
FormattedTextToolbar, SearchToolbar, SystemToolbar, ValidationToolbar,
MenuContainer, MenuItem

Filters

.. automodule:: prompt_toolkit.filters
:members:

.. autoclass:: prompt_toolkit.filters.Filter
:members:
:no-index:

.. autoclass:: prompt_toolkit.filters.Condition
:members:
:no-index:

.. automodule:: prompt_toolkit.filters.utils
:members:

.. automodule:: prompt_toolkit.filters.app
:members:

Key binding

.. automodule:: prompt_toolkit.key_binding
:members: KeyBindingsBase, KeyBindings, ConditionalKeyBindings,
merge_key_bindings, DynamicKeyBindings

.. automodule:: prompt_toolkit.key_binding.defaults
:members:

.. automodule:: prompt_toolkit.key_binding.vi_state
:members:

.. automodule:: prompt_toolkit.key_binding.key_processor
:members:

Eventloop

.. automodule:: prompt_toolkit.eventloop
:members: run_in_executor_with_context, call_soon_threadsafe,
get_traceback_from_context

.. automodule:: prompt_toolkit.eventloop.inputhook
:members:

.. automodule:: prompt_toolkit.eventloop.utils
:members:

Input

.. automodule:: prompt_toolkit.input
:members: Input, DummyInput, create_input, create_pipe_input

.. automodule:: prompt_toolkit.input.vt100
:members:

.. automodule:: prompt_toolkit.input.vt100_parser
:members:

.. automodule:: prompt_toolkit.input.ansi_escape_sequences
:members:

.. automodule:: prompt_toolkit.input.win32
:members:

Output

.. automodule:: prompt_toolkit.output
:members: Output, DummyOutput, ColorDepth, create_output

.. automodule:: prompt_toolkit.output.vt100
:members:

.. automodule:: prompt_toolkit.output.win32
:members:

Data structures

.. autoclass:: prompt_toolkit.layout.WindowRenderInfo
:members:

.. autoclass:: prompt_toolkit.data_structures.Point
:members:

.. autoclass:: prompt_toolkit.data_structures.Size
:members:

Patch stdout

.. automodule:: prompt_toolkit.patch_stdout
:members: patch_stdout, StdoutProxy


.. _related_projects:

There are some other Python libraries that provide similar functionality that
are also worth checking out:

  • Urwid <http://urwid.org/>_
  • Textual <https://textual.textualize.io/>_
  • Rich <https://rich.readthedocs.io/>_

Pages Advanced Topics Architecture (`docs/pages/advanced_topics/architecture.rst`)

.. _architecture:

Architecture

TODO: this is a little outdated.

::

text
+---------------------------------------------------------------+
|     InputStream                                               |
|     ===========                                               |
|          - Parses the input stream coming from a VT100        |
|            compatible terminal. Translates it into data input |
|            and control characters. Calls the corresponding    |
|            handlers of the `InputStreamHandler` instance.     |
|                                                               |
|          e.g. Translate '\x1b[6~' into "Keys.PageDown", call  |
|               the `feed_key` method of `InputProcessor`.      |
+---------------------------------------------------------------+
           |
           v
+---------------------------------------------------------------+
|     InputStreamHandler                                        |
|     ==================                                        |
|          - Has a `Registry` of key bindings, it calls the     |
|            bindings according to the received keys and the    |
|            input mode.                                        |
|                                                               |
|         We have Vi and Emacs bindings.
+---------------------------------------------------------------+
           |
           v
+---------------------------------------------------------------+
|     Key bindings                                              |
|     ============                                              |
|          - Every key binding consists of a function that      |
|            receives an `Event` and usually it operates on     |
|            the `Buffer` object. (It could insert data or      |
|            move the cursor for example.)                      |
+---------------------------------------------------------------+
    |
    | Most of the key bindings operate on a `Buffer` object, but
    | they don't have to. They could also change the visibility
    | of a menu for instance, or change the color scheme.
    |
    v
+---------------------------------------------------------------+
|     Buffer                                                    |
|     ======                                                    |
|          - Contains a data structure to hold the current      |
|            input (text and cursor position). This class       |
|            implements all text manipulations and cursor       |
|            movements (Like e.g. cursor_forward, insert_char   |
|            or delete_word.)                                   |
|                                                               |
|            +-----------------------------------------------+  |
|            | Document (text, cursor_position)              |  |
|            | ================================              |  |
|            | Accessed as the `document` property of the    |  |
|            | `Buffer` class. This is a wrapper around the  |  |
|            | text and cursor position, and contains        |  |
|            | methods for querying this data , e.g. to give |  |
|            | the text before the cursor.                   |  |
|            +-----------------------------------------------+  |
+---------------------------------------------------------------+
    |
    |  Normally after every key press, the output will be
    |  rendered again. This happens in the event loop of
    |  the `Application` where `Renderer.render` is called.
    v
+---------------------------------------------------------------+
|     Layout                                                    |
|     ======                                                    |
|          - When the renderer should redraw, the renderer      |
|            asks the layout what the output should look like.  |
|          - The layout operates on a `Screen` object that he   |
|            received from the `Renderer` and will put the      |
|            toolbars, menus, highlighted content and prompt    |
|            in place.                                          |
|                                                               |
|            +-----------------------------------------------+  |
|            | Menus, toolbars, prompt                       |  |
|            | =======================                       |  |
|            |                                               |  |
|            +-----------------------------------------------+  |
+---------------------------------------------------------------+
    |
    v
+---------------------------------------------------------------+
|     Renderer                                                  |
|     ========                                                  |
|          - Calculates the difference between the last output  |
|            and the new one and writes it to the terminal      |
|            output.                                            |
+---------------------------------------------------------------+

Pages Advanced Topics Asyncio (`docs/pages/advanced_topics/asyncio.rst`)

.. _asyncio:

Running on top of the `asyncio` event loop

.. note::

text
New in prompt_toolkit 3.0. (In prompt_toolkit 2.0 this was possible using a
work-around).

Prompt_toolkit 3.0 uses asyncio natively. Calling Application.run() will
automatically run the asyncio event loop.

If however you want to run a prompt_toolkit Application within an asyncio
environment, you have to call the run_async method, like this:

.. code:: python

text
from prompt_toolkit.application import Application

async def main():
    # Define application.
    application = Application(
        ...
    )

    result = await application.run_async()
    print(result)

asyncio.get_event_loop().run_until_complete(main())

Pages Advanced Topics Filters (`docs/pages/advanced_topics/filters.rst`)

.. _filters:

Filters

Many places in prompt_toolkit require a boolean value that can change over
time. For instance:

  • to specify whether a part of the layout needs to be visible or not;
  • or to decide whether a certain key binding needs to be active or not;
  • or the wrap_lines option of
    :class:~prompt_toolkit.layout.BufferControl;
  • etcetera.

These booleans are often dynamic and can change at runtime. For instance, the
search toolbar should only be visible when the user is actually searching (when
the search buffer has the focus). The wrap_lines option could be changed
with a certain key binding. And that key binding could only work when the
default buffer got the focus.

In prompt_toolkit, we decided to reduce the amount of state in the whole
framework, and apply a simple kind of reactive programming to describe the flow
of these booleans as expressions. (It's one-way only: if a key binding needs to
know whether it's active or not, it can follow this flow by evaluating an
expression.)

The (abstract) base class is :class:~prompt_toolkit.filters.Filter, which
wraps an expression that takes no input and evaluates to a boolean. Getting the
state of a filter is done by simply calling it.

An example

The most obvious way to create such a :class:~prompt_toolkit.filters.Filter
instance is by creating a :class:~prompt_toolkit.filters.Condition instance
from a function. For instance, the following condition will evaluate to
True when the user is searching:

.. code:: python

text
from prompt_toolkit.application.current import get_app
from prompt_toolkit.filters import Condition

is_searching = Condition(lambda: get_app().is_searching)

A different way of writing this, is by using the decorator syntax:

.. code:: python

text
from prompt_toolkit.application.current import get_app
from prompt_toolkit.filters import Condition

@Condition
def is_searching():
    return get_app().is_searching

This filter can then be used in a key binding, like in the following snippet:

.. code:: python

text
from prompt_toolkit.key_binding import KeyBindings

kb = KeyBindings()

@kb.add('c-t', filter=is_searching)
def _(event):
    # Do, something, but only when searching.
    pass

If we want to know the boolean value of this filter, we have to call it like a
function:

.. code:: python

text
print(is_searching())

Built-in filters

There are many built-in filters, ready to use. All of them have a lowercase
name, because they represent the wrapped function underneath, and can be called
as a function.

  • :class:~prompt_toolkit.filters.app.has_arg

  • :class:~prompt_toolkit.filters.app.has_completions

  • :class:~prompt_toolkit.filters.app.has_focus

  • :class:~prompt_toolkit.filters.app.buffer_has_focus

  • :class:~prompt_toolkit.filters.app.has_selection

  • :class:~prompt_toolkit.filters.app.has_validation_error

  • :class:~prompt_toolkit.filters.app.is_aborting

  • :class:~prompt_toolkit.filters.app.is_done

  • :class:~prompt_toolkit.filters.app.is_read_only

  • :class:~prompt_toolkit.filters.app.is_multiline

  • :class:~prompt_toolkit.filters.app.renderer_height_is_known

  • :class:~prompt_toolkit.filters.app.in_editing_mode

  • :class:~prompt_toolkit.filters.app.in_paste_mode

  • :class:~prompt_toolkit.filters.app.vi_mode

  • :class:~prompt_toolkit.filters.app.vi_navigation_mode

  • :class:~prompt_toolkit.filters.app.vi_insert_mode

  • :class:~prompt_toolkit.filters.app.vi_insert_multiple_mode

  • :class:~prompt_toolkit.filters.app.vi_replace_mode

  • :class:~prompt_toolkit.filters.app.vi_selection_mode

  • :class:~prompt_toolkit.filters.app.vi_waiting_for_text_object_mode

  • :class:~prompt_toolkit.filters.app.vi_digraph_mode

  • :class:~prompt_toolkit.filters.app.emacs_mode

  • :class:~prompt_toolkit.filters.app.emacs_insert_mode

  • :class:~prompt_toolkit.filters.app.emacs_selection_mode

  • :class:~prompt_toolkit.filters.app.is_searching

  • :class:~prompt_toolkit.filters.app.control_is_searchable

  • :class:~prompt_toolkit.filters.app.vi_search_direction_reversed

Combining filters

Filters can be chained with the & (AND) and | (OR) operators and
negated with the ~ (negation) operator.

Some examples:

.. code:: python

text
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.filters import has_selection, has_selection

kb = KeyBindings()

@kb.add('c-t', filter=~is_searching)
def _(event):
    " Do something, but not while searching. "
    pass

@kb.add('c-t', filter=has_search | has_selection)
def _(event):
    " Do something, but only when searching or when there is a selection. "
    pass

to_filter

Finally, in many situations you want your code to expose an API that is able to
deal with both booleans as well as filters. For instance, when for most users a
boolean works fine because they don't need to change the value over time, while
some advanced users want to be able this value to a certain setting or event
that does changes over time.

In order to handle both use cases, there is a utility called
:func:~prompt_toolkit.filters.utils.to_filter.

This is a function that takes
either a boolean or an actual :class:~prompt_toolkit.filters.Filter
instance, and always returns a :class:~prompt_toolkit.filters.Filter.

.. code:: python

text
from prompt_toolkit.filters.utils import to_filter

# In each of the following three examples, 'f' will be a `Filter`
# instance.
f = to_filter(True)
f = to_filter(False)
f = to_filter(Condition(lambda: True))
f = to_filter(has_search | has_selection)

Pages Advanced Topics Index (`docs/pages/advanced_topics/index.rst`)

.. _advanced_topics:

Advanced topics

.. toctree::
:caption: Contents:
:maxdepth: 1

text
key_bindings
styling
filters
rendering_flow
asyncio
unit_testing
input_hooks
architecture
rendering_pipeline

Pages Advanced Topics Input Hooks (`docs/pages/advanced_topics/input_hooks.rst`)

.. _input_hooks:

Input hooks

Input hooks are a tool for inserting an external event loop into the
prompt_toolkit event loop, so that the other loop can run as long as
prompt_toolkit (actually asyncio) is idle. This is used in applications like
IPython <https://ipython.org/>_, so that GUI toolkits can display their
windows while we wait at the prompt for user input.

As a consequence, we will "trampoline" back and forth between two event loops.

.. note::

text
This will use a :class:`~asyncio.SelectorEventLoop`, not the
:class:`~asyncio.ProactorEventLoop` (on Windows) due to the way the
implementation works (contributions are welcome to make that work).

.. code:: python

text
from prompt_toolkit.eventloop.inputhook import set_eventloop_with_inputhook

def inputhook(inputhook_context):
    # At this point, we run the other loop. This loop is supposed to run
    # until either `inputhook_context.fileno` becomes ready for reading or
    # `inputhook_context.input_is_ready()` returns True.

    # A good way is to register this file descriptor in this other event
    # loop with a callback that stops this loop when this FD becomes ready.
    # There is no need to actually read anything from the FD.

    while True:
        ...

set_eventloop_with_inputhook(inputhook)

# Any asyncio code at this point will now use this new loop, with input
# hook installed.

Pages Advanced Topics Key Bindings (`docs/pages/advanced_topics/key_bindings.rst`)

.. _key_bindings:

More about key bindings

This page contains a few additional notes about key bindings.

Key bindings can be defined as follows by creating a
:class:~prompt_toolkit.key_binding.KeyBindings instance:

.. code:: python

text
from prompt_toolkit.key_binding import KeyBindings

bindings = KeyBindings()

@bindings.add('a')
def _(event):
    " Do something if 'a' has been pressed. "
    ...


@bindings.add('c-t')
def _(event):
    " Do something if Control-T has been pressed. "
    ...

.. note::

text
:kbd:`c-q` (control-q) and :kbd:`c-s` (control-s) are often captured by the
terminal, because they were used traditionally for software flow control.
When this is enabled, the application will automatically freeze when
:kbd:`c-s` is pressed, until :kbd:`c-q` is pressed. It won't be possible to
bind these keys.

In order to disable this, execute the following command in your shell, or even
add it to your `.bashrc`.

.. code::

    stty -ixon

Key bindings can even consist of a sequence of multiple keys. The binding is
only triggered when all the keys in this sequence are pressed.

.. code:: python

text
@bindings.add('a', 'b')
def _(event):
    " Do something if 'a' is pressed and then 'b' is pressed. "
    ...

If the user presses only a, then nothing will happen until either a second
key (like b) has been pressed or until the timeout expires (see later).

List of special keys

Besides literal characters, any of the following keys can be used in a key
binding:

+-------------------+-----------------------------------------+
| Name + Possible keys |
+===================+=========================================+
| Escape | :kbd:escape |
| Shift + escape | :kbd:s-escape |
+-------------------+-----------------------------------------+
| Arrows | :kbd:left, |
| | :kbd:right, |
| | :kbd:up, |
| | :kbd:down |
+-------------------+-----------------------------------------+
| Navigation | :kbd:home, |
| | :kbd:end, |
| | :kbd:delete, |
| | :kbd:pageup, |
| | :kbd:pagedown, |
| | :kbd:insert |
+-------------------+-----------------------------------------+
| Control+letter | :kbd:c-a, :kbd:c-b, :kbd:c-c, |
| | :kbd:c-d, :kbd:c-e, :kbd:c-f, |
| | :kbd:c-g, :kbd:c-h, :kbd:c-i, |
| | :kbd:c-j, :kbd:c-k, :kbd:c-l, |
| | |
| | :kbd:c-m, :kbd:c-n, :kbd:c-o, |
| | :kbd:c-p, :kbd:c-q, :kbd:c-r, |
| | :kbd:c-s, :kbd:c-t, :kbd:c-u, |
| | :kbd:c-v, :kbd:c-w, :kbd:c-x, |
| | |
| | :kbd:c-y, :kbd:c-z |
+-------------------+-----------------------------------------+
| Control + number | :kbd:c-1, :kbd:c-2, :kbd:c-3, |
| | :kbd:c-4, :kbd:c-5, :kbd:c-6, |
| | :kbd:c-7, :kbd:c-8, :kbd:c-9, |
| | :kbd:c-0 |
+-------------------+-----------------------------------------+
| Control + arrow | :kbd:c-left, |
| | :kbd:c-right, |
| | :kbd:c-up, |
| | :kbd:c-down |
+-------------------+-----------------------------------------+
| Other control | :kbd:c-@, |
| keys | :kbd:c-\\, |
| | :kbd:c-], |
| | :kbd:c-^, |
| | :kbd:c-_, |
| | :kbd:c-delete |
+-------------------+-----------------------------------------+
| Shift + arrow | :kbd:s-left, |
| | :kbd:s-right, |
| | :kbd:s-up, |
| | :kbd:s-down |
+-------------------+-----------------------------------------+
| Control + Shift + | :kbd:c-s-left, |
| arrow | :kbd:c-s-right, |
| | :kbd:c-s-up, |
| | :kbd:c-s-down |
+-------------------+-----------------------------------------+
| Other shift | :kbd:s-delete, |
| keys | :kbd:s-tab |
+-------------------+-----------------------------------------+
| F-keys | :kbd:f1, :kbd:f2, :kbd:f3, |
| | :kbd:f4, :kbd:f5, :kbd:f6, |
| | :kbd:f7, :kbd:f8, :kbd:f9, |
| | :kbd:f10, :kbd:f11, :kbd:f12, |
| | |
| | :kbd:f13, :kbd:f14, :kbd:f15, |
| | :kbd:f16, :kbd:f17, :kbd:f18, |
| | :kbd:f19, :kbd:f20, :kbd:f21, |
| | :kbd:f22, :kbd:f23, :kbd:f24 |
+-------------------+-----------------------------------------+

There are a couple of useful aliases as well:

+-------------------+-------------------+
| :kbd:c-h | :kbd:backspace |
+-------------------+-------------------+
| :kbd:c-@ | :kbd:c-space |
+-------------------+-------------------+
| :kbd:c-m | :kbd:enter |
+-------------------+-------------------+
| :kbd:c-i | :kbd:tab |
+-------------------+-------------------+

.. note::

text
Note that the supported keys are limited to what typical VT100 terminals
offer. Binding :kbd:`c-7` (control + number 7) for instance is not
supported.

Binding alt+something, option+something or meta+something

Vt100 terminals translate the alt key into a leading :kbd:escape key.
For instance, in order to handle :kbd:alt-f, we have to handle
:kbd:escape + :kbd:f. Notice that we receive this as two individual keys.
This means that it's exactly the same as first typing :kbd:escape and then
typing :kbd:f. Something this alt-key is also known as option or meta.

In code that looks as follows:

.. code:: python

text
@bindings.add('escape', 'f')
def _(event):
    " Do something if alt-f or meta-f have been pressed. "

Wildcards

Sometimes you want to catch any key that follows after a certain key stroke.
This is possible by binding the '' key:

.. code:: python

text
@bindings.add('a', '<any>')
def _(event):
    ...

This will handle aa, ab, ac, etcetera. The key binding can check the
event object for which keys exactly have been pressed.

Attaching a filter (condition)

In order to enable a key binding according to a certain condition, we have to
pass it a :class:~prompt_toolkit.filters.Filter, usually a
:class:~prompt_toolkit.filters.Condition instance. (:ref:Read more about filters <filters>.)

.. code:: python

text
from prompt_toolkit.filters import Condition

@Condition
def is_active():
    " Only activate key binding on the second half of each minute. "
    return datetime.datetime.now().second > 30

@bindings.add('c-t', filter=is_active)
def _(event):
    # ...
    pass

The key binding will be ignored when this condition is not satisfied.

ConditionalKeyBindings: Disabling a set of key bindings

Sometimes you want to enable or disable a whole set of key bindings according
to a certain condition. This is possible by wrapping it in a
:class:~prompt_toolkit.key_binding.ConditionalKeyBindings object.

.. code:: python

text
from prompt_toolkit.key_binding import ConditionalKeyBindings

@Condition
def is_active():
    " Only activate key binding on the second half of each minute. "
    return datetime.datetime.now().second > 30

 bindings = ConditionalKeyBindings(
     key_bindings=my_bindings,
     filter=is_active)

If the condition is not satisfied, all the key bindings in my_bindings above
will be ignored.

Merging key bindings

Sometimes you have different parts of your application generate a collection of
key bindings. It is possible to merge them together through the
:func:~prompt_toolkit.key_binding.merge_key_bindings function. This is
preferred above passing a :class:~prompt_toolkit.key_binding.KeyBindings
object around and having everyone populate it.

.. code:: python

text
from prompt_toolkit.key_binding import merge_key_bindings

bindings = merge_key_bindings([
    bindings1,
    bindings2,
])

Eager

Usually not required, but if ever you have to override an existing key binding,
the eager flag can be useful.

Suppose that there is already an active binding for ab and you'd like to add
a second binding that only handles a. When the user presses only a,
prompt_toolkit has to wait for the next key press in order to know which
handler to call.

By passing the eager flag to this second binding, we are actually saying that
prompt_toolkit shouldn't wait for longer matches when all the keys in this key
binding are matched. So, if a has been pressed, this second binding will be
called, even if there's an active ab binding.

.. code:: python

text
@bindings.add('a', 'b')
def binding_1(event):
    ...

@bindings.add('a', eager=True)
def binding_2(event):
    ...

This is mainly useful in order to conditionally override another binding.

Asyncio coroutines

Key binding handlers can be asyncio coroutines.

.. code:: python

text
from prompt_toolkit.application import in_terminal

@bindings.add('x')
async def print_hello(event):
    """
    Pressing 'x' will print 5 times "hello" in the background above the
    prompt.
    """
    for i in range(5):
        # Print hello above the current prompt.
        async with in_terminal():
            print('hello')

        # Sleep, but allow further input editing in the meantime.
        await asyncio.sleep(1)

If the user accepts the input on the prompt, while this coroutine is not yet
finished , an asyncio.CancelledError exception will be thrown in this
coroutine.

Timeouts

There are two timeout settings that effect the handling of keys.

  • Application.ttimeoutlen: Like Vim's ttimeoutlen option.
    When to flush the input (For flushing escape keys.) This is important on
    terminals that use vt100 input. We can't distinguish the escape key from for
    instance the left-arrow key, if we don't know what follows after "\x1b". This
    little timer will consider "\x1b" to be escape if nothing did follow in this
    time span. This seems to work like the ttimeoutlen option in Vim.

  • KeyProcessor.timeoutlen: like Vim's timeoutlen option.
    This can be None or a float. For instance, suppose that we have a key
    binding AB and a second key binding A. If the uses presses A and then waits,
    we don't handle this binding yet (unless it was marked 'eager'), because we
    don't know what will follow. This timeout is the maximum amount of time that
    we wait until we call the handlers anyway. Pass None to disable this
    timeout.

Recording macros

Both Emacs and Vi mode allow macro recording. By default, all key presses are
recorded during a macro, but it is possible to exclude certain keys by setting
the record_in_macro parameter to False:

.. code:: python

text
@bindings.add('c-t', record_in_macro=False)
def _(event):
    # ...
    pass

Creating new Vi text objects and operators

We tried very hard to ship prompt_toolkit with as many as possible Vi text
objects and operators, so that text editing feels as natural as possible to Vi
users.

If you wish to create a new text object or key binding, that is actually
possible. Check the custom-vi-operator-and-text-object.py example for more
information.

Handling SIGINT

The SIGINT Unix signal can be handled by binding <sigint>. For instance:

.. code:: python

text
@bindings.add('<sigint>')
def _(event):
    # ...
    pass

This will handle a SIGINT that was sent by an external application into the
process. Handling control-c should be done by binding c-c. (The terminal
input is set to raw mode, which means that a c-c won't be translated into a
SIGINT.)

For a PromptSession, there is a default binding for <sigint> that
corresponds to c-c: it will exit the prompt, raising a
KeyboardInterrupt exception.

Processing `.inputrc`

GNU readline can be configured using an .inputrc configuration file. This file
contains key bindings as well as certain settings. Right now, prompt_toolkit
doesn't support .inputrc, but it should be possible in the future.


Pages Advanced Topics Rendering Flow (`docs/pages/advanced_topics/rendering_flow.rst`)

.. _rendering_flow:

The rendering flow

Understanding the rendering flow is important for understanding how
:class:~prompt_toolkit.layout.Container and
:class:~prompt_toolkit.layout.UIControl objects interact. We will demonstrate
it by explaining the flow around a
:class:~prompt_toolkit.layout.BufferControl.

.. note::

text
A :class:`~prompt_toolkit.layout.BufferControl` is a
:class:`~prompt_toolkit.layout.UIControl` for displaying the content of a
:class:`~prompt_toolkit.buffer.Buffer`. A buffer is the object that holds
any editable region of text. Like all controls, it has to be wrapped into a
:class:`~prompt_toolkit.layout.Window`.

Let's take the following code:

.. code:: python

text
from prompt_toolkit.enums import DEFAULT_BUFFER
from prompt_toolkit.layout.containers import Window
from prompt_toolkit.layout.controls import BufferControl
from prompt_toolkit.buffer import Buffer

b = Buffer(name=DEFAULT_BUFFER)
Window(content=BufferControl(buffer=b))

What happens when a :class:~prompt_toolkit.renderer.Renderer objects wants a
:class:~prompt_toolkit.layout.Container to be rendered on a certain
:class:~prompt_toolkit.layout.screen.Screen?

The visualization happens in several steps:

  1. The :class:~prompt_toolkit.renderer.Renderer calls the
    :meth:~prompt_toolkit.layout.Container.write_to_screen method
    of a :class:~prompt_toolkit.layout.Container.
    This is a request to paint the layout in a rectangle of a certain size.

    The :class:~prompt_toolkit.layout.Window object then requests
    the :class:~prompt_toolkit.layout.UIControl to create a
    :class:~prompt_toolkit.layout.UIContent instance (by calling
    :meth:~prompt_toolkit.layout.UIControl.create_content).
    The user control receives the dimensions of the window, but can still
    decide to create more or less content.

    Inside the :meth:~prompt_toolkit.layout.UIControl.create_content
    method of :class:~prompt_toolkit.layout.UIControl, there are several
    steps:

    1. First, the buffer's text is passed to the
      :meth:~prompt_toolkit.lexers.Lexer.lex_document method of a
      :class:~prompt_toolkit.lexers.Lexer. This returns a function which
      for a given line number, returns a "formatted text list" for that line
      (that's a list of (style_string, text) tuples).

    2. This list is passed through a list of
      :class:~prompt_toolkit.layout.processors.Processor objects.
      Each processor can do a transformation for each line.
      (For instance, they can insert or replace some text, highlight the
      selection or search string, etc...)

    3. The :class:~prompt_toolkit.layout.UIControl returns a
      :class:~prompt_toolkit.layout.UIContent instance which
      generates such a token lists for each lines.

The :class:~prompt_toolkit.layout.Window receives the
:class:~prompt_toolkit.layout.UIContent and then:

  1. It calculates the horizontal and vertical scrolling, if applicable
    (if the content would take more space than what is available).

  2. The content is copied to the correct absolute position
    :class:~prompt_toolkit.layout.screen.Screen, as requested by the
    :class:~prompt_toolkit.renderer.Renderer. While doing this, the
    :class:~prompt_toolkit.layout.Window can possible wrap the
    lines, if line wrapping was configured.

Note that this process is lazy: if a certain line is not displayed in the
:class:~prompt_toolkit.layout.Window, then it is not requested
from the :class:~prompt_toolkit.layout.UIContent. And from there, the line is
not passed through the processors or even asked from the
:class:~prompt_toolkit.lexers.Lexer.


Pages Advanced Topics Rendering Pipeline (`docs/pages/advanced_topics/rendering_pipeline.rst`)

The rendering pipeline

This document is an attempt to describe how prompt_toolkit applications are
rendered. It's a complex but logical process that happens more or less after
every key stroke. We'll go through all the steps from the point where the user
hits a key, until the character appears on the screen.

Waiting for user input

Most of the time when a prompt_toolkit application is running, it is idle. It's
sitting in the event loop, waiting for some I/O to happen. The most important
kind of I/O we're waiting for is user input. So, within the event loop, we have
one file descriptor that represents the input device from where we receive key
presses. The details are a little different between operating systems, but it
comes down to a selector (like select or epoll) which waits for one or more
file descriptor. The event loop is then responsible for calling the appropriate
feedback when one of the file descriptors becomes ready.

It is like that when the user presses a key: the input device becomes ready for
reading, and the appropriate callback is called. This is the read_from_input
function somewhere in application.py. It will read the input from the
:class:~prompt_toolkit.input.Input object, by calling
:meth:~prompt_toolkit.input.Input.read_keys.

Reading the user input

The actual reading is also operating system dependent. For instance, on a Linux
machine with a vt100 terminal, we read the input from the pseudo terminal
device, by calling os.read. This however returns a sequence of bytes. There
are two difficulties:

  • The input could be UTF-8 encoded, and there is always the possibility that we
    receive only a portion of a multi-byte character.
  • vt100 key presses consist of multiple characters. For instance the "left
    arrow" would generate something like \x1b[D. It could be that when we
    read this input stream, that at some point we only get the first part of such
    a key press, and we have to wait for the rest to arrive.

Both problems are implemented using state machines.

  • The UTF-8 problem is solved using codecs.getincrementaldecoder, which is an
    object in which we can feed the incoming bytes, and it will only return the
    complete UTF-8 characters that we have so far. The rest is buffered for the
    next read operation.
  • Vt100 parsing is solved by the
    :class:~prompt_toolkit.input.vt100_parser.Vt100Parser state machine. The
    state machine itself is implemented using a generator. We feed the incoming
    characters to the generator, and it will call the appropriate callback for
    key presses once they arrive. One thing here to keep in mind is that the
    characters for some key presses are a prefix of other key presses, like for
    instance, escape (\x1b) is a prefix of the left arrow key (\x1b[D).
    So for those, we don't know what key is pressed until more data arrives or
    when the input is flushed because of a timeout.

For Windows systems, it's a little different. Here we use Win32 syscalls for
reading the console input.

Processing the key presses

The Key objects that we receive are then passed to the
:class:~prompt_toolkit.key_binding.key_processor.KeyProcessor for matching
against the currently registered and active key bindings.

This is another state machine, because key bindings are linked to a sequence of
key presses. We cannot call the handler until all of these key presses arrive
and until we're sure that this combination is not a prefix of another
combination. For instance, sometimes people bind jj (a double j key
press) to esc in Vi mode. This is convenient, but we want to make sure that
pressing j once only, followed by a different key will still insert the
j character as usual.

Now, there are hundreds of key bindings in prompt_toolkit (in ptpython, right
now we have 585 bindings). This is mainly caused by the way that Vi key
bindings are generated. In order to make this efficient, we keep a cache of
handlers which match certain sequences of keys.

Of course, key bindings also have filters attached for enabling/disabling them.
So, if at some point, we get a list of handlers from that cache, we still have
to discard the inactive bindings. Luckily, many bindings share exactly the same
filter, and we have to check every filter only once.

:ref:Read more about key bindings ...<key_bindings>

The key handlers

Once a key sequence is matched, the handler is called. This can do things like
text manipulation, changing the focus or anything else.

After the handler is called, the user interface is invalidated and rendered
again.

Rendering the user interface

The rendering is pretty complex for several reasons:

  • We have to compute the dimensions of all user interface elements. Sometimes
    they are given, but sometimes this requires calculating the size of
    :class:~prompt_toolkit.layout.UIControl objects.
  • It needs to be very efficient, because it's something that happens on every
    single key stroke.
  • We should output as little as possible on stdout in order to reduce latency
    on slow network connections and older terminals.

Calculating the total UI height
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Unless the application is a full screen application, we have to know how much
vertical space is going to be consumed. The total available width is given, but
the vertical space is more dynamic. We do this by asking the root
:class:~prompt_toolkit.layout.Container object to calculate its preferred
height. If this is a :class:~prompt_toolkit.layout.VSplit or
:class:~prompt_toolkit.layout.HSplit then this involves recursively querying
the child objects for their preferred widths and heights and either summing it
up, or taking maximum values depending on the actual layout.
In the end, we get the preferred height, for which we make sure it's at least
the distance from the cursor position to the bottom of the screen.

Painting to the screen
^^^^^^^^^^^^^^^^^^^^^^

Then we create a :class:~prompt_toolkit.layout.screen.Screen object. This is
like a canvas on which user controls can paint their content. The
:meth:~prompt_toolkit.layout.Container.write_to_screen method of the root
Container is called with the screen dimensions. This will call recursively
:meth:~prompt_toolkit.layout.Container.write_to_screen methods of nested
child containers, each time passing smaller dimensions while we traverse what
is a tree of Container objects.

The most inner containers are :class:~prompt_toolkit.layout.Window objects,
they will do the actual painting of the
:class:~prompt_toolkit.layout.UIControl to the screen. This involves line
wrapping the UIControl's text and maybe scrolling the content horizontally or
vertically.

Rendering to stdout
^^^^^^^^^^^^^^^^^^^

Finally, when we have painted the screen, this needs to be rendered to stdout.
This is done by taking the difference of the previously rendered screen and the
new one. The algorithm that we have is heavily optimized to compute this
difference as quickly as possible, and call the appropriate output functions of
the :class:~prompt_toolkit.output.Output back-end. At the end, it will
position the cursor in the right place.


Pages Advanced Topics Styling (`docs/pages/advanced_topics/styling.rst`)

.. _styling:

More about styling

This page will attempt to explain in more detail how to use styling in
prompt_toolkit.

To some extent, it is very similar to how Pygments <http://pygments.org/>_
styling works.

Style strings

Many user interface controls, like :class:~prompt_toolkit.layout.Window
accept a style argument which can be used to pass the formatting as a
string. For instance, we can select a foreground color:

  • "fg:ansired" (ANSI color palette)
  • "fg:ansiblue" (ANSI color palette)
  • "fg:#ffaa33" (hexadecimal notation)
  • "fg:darkred" (named color)

Or a background color:

  • "bg:ansired" (ANSI color palette)
  • "bg:#ffaa33" (hexadecimal notation)

Or we can add one of the following flags:

  • "bold"
  • "italic"
  • "underline"
  • "blink"
  • "reverse" (reverse foreground and background on the terminal.)
  • "hidden"

Or their negative variants:

  • "nobold"
  • "noitalic"
  • "nounderline"
  • "noblink"
  • "noreverse"
  • "nohidden"

All of these formatting options can be combined as well:

  • "fg:ansiyellow bg:black bold underline"

The style string can be given to any user control directly, or to a
:class:~prompt_toolkit.layout.Container object from where it will propagate
to all its children. A style defined by a parent user control can be overridden
by any of its children. The parent can for instance say style="bold underline" where a child overrides this style partly by specifying
style="nobold bg:ansired".

.. note::

text
These styles are actually compatible with
`Pygments <http://pygments.org/>`_ styles, with additional support for
`reverse` and `blink`. Further, we ignore flags like `roman`, `sans`,
`mono` and `border`.

The following ANSI colors are available (both for foreground and background):

.. code::

text
# Low intensity, dark.  (One or two components 0x80, the other 0x00.)
ansiblack, ansired, ansigreen, ansiyellow, ansiblue
ansimagenta, ansicyan, ansigray

# High intensity, bright.
ansibrightblack, ansibrightred, ansibrightgreen, ansibrightyellow
ansibrightblue, ansibrightmagenta, ansibrightcyan, ansiwhite

In order to know which styles are actually used in an application, it is
possible to call :meth:~Application.get_used_style_strings, when the
application is done.

Class names

Like we do for web design, it is not a good habit to specify all styling
inline. Instead, we can attach class names to UI controls and have a style
sheet that refers to these class names. The
:class:~prompt_toolkit.styles.Style can be passed as an argument to the
:class:~prompt_toolkit.application.Application.

.. code:: python

text
from prompt_toolkit.layout import VSplit, Window
from prompt_toolkit.styles import Style

layout = VSplit([
    Window(BufferControl(...), style='class:left'),
    HSplit([
        Window(BufferControl(...), style='class:top'),
        Window(BufferControl(...), style='class:bottom'),
    ], style='class:right')
])

style = Style([
     ('left', 'bg:ansired'),
     ('top', 'fg:#00aaaa'),
     ('bottom', 'underline bold'),
 ])

It is possible to add multiple class names to an element. That way we'll
combine the styling for these class names. Multiple classes can be passed by
using a comma separated list, or by using the class: prefix twice.

.. code:: python

Window(BufferControl(...), style='class:left,bottom'),
Window(BufferControl(...), style='class:left class:bottom'),

It is possible to combine class names and inline styling. The order in which
the class names and inline styling is specified determines the order of
priority. In the following example for instance, we'll take first the style of
the "header" class, and then override that with a red background color.

.. code:: python

text
Window(BufferControl(...), style='class:header bg:red'),

Dot notation in class names

The dot operator has a special meaning in a class name. If we write:
style="class:a.b.c", then this will actually expand to the following:
style="class:a class:a.b class:a.b.c".

This is mainly added for Pygments <http://pygments.org/>_ lexers, which
specify "Tokens" like this, but it's useful in other situations as well.

Multiple classes in a style sheet

A style sheet can be more complex as well. We can for instance specify two
class names. The following will underline the left part within the header, or
whatever has both the class "left" and the class "header" (the order doesn't
matter).

.. code:: python

text
style = Style([
     ('header left', 'underline'),
 ])

If you have a dotted class, then it's required to specify the whole path in the
style sheet (just typing c or b.c doesn't work if the class is
a.b.c):

.. code:: python

text
style = Style([
     ('a.b.c', 'underline'),
 ])

It is possible to combine this:

.. code:: python

text
style = Style([
     ('header body left.text', 'underline'),
 ])

Evaluation order of rules in a style sheet

The style is determined as follows:

  • First, we concatenate all the style strings from the root control through all
    the parents to the child in one big string. (Things at the right take
    precedence anyway.)

    E.g: class:body bg:#aaaaaa #000000 class:header.focused class:left.text.highlighted underline

  • Then we go through this style from left to right, starting from the default
    style. Inline styling is applied directly.

    If we come across a class name, then we generate all combinations of the
    class names that we collected so far (this one and all class names to the
    left), and for each combination which includes the new class name, we look
    for matching rules in our style sheet. All these rules are then applied
    (later rules have higher priority).

    If we find a dotted class name, this will be expanded in the individual names
    (like class:left class:left.text class:left.text.highlighted), and all
    these are applied like any class names.

  • Then this final style is applied to this user interface element.

Using a dictionary as a style sheet

The order of the rules in a style sheet is meaningful, so typically, we use a
list of tuples to specify the style. But is also possible to use a dictionary
as a style sheet. This makes sense for Python 3.6, where dictionaries remember
their ordering. An OrderedDict works as well.

.. code:: python

text
from prompt_toolkit.styles import Style

style = Style.from_dict({
     'header body left.text': 'underline',
})

Loading a style from Pygments

Pygments <http://pygments.org/>_ has a slightly different notation for
specifying styles, because it maps styling to Pygments "Tokens". A Pygments
style can however be loaded and used as follows:

.. code:: python

text
from prompt_toolkit.styles.pygments import style_from_pygments_cls
from pygments.styles import get_style_by_name

style = style_from_pygments_cls(get_style_by_name('monokai'))

Merging styles together

Multiple :class:~prompt_toolkit.styles.Style objects can be merged together as
follows:

.. code:: python

text
from prompt_toolkit.styles import merge_styles

style = merge_styles([
    style1,
    style2,
    style3
])

Color depths

There are four different levels of color depths available:

+--------+-----------------+-----------------------------+---------------------------------+
| 1 bit | Black and white | ColorDepth.DEPTH_1_BIT | ColorDepth.MONOCHROME |
+--------+-----------------+-----------------------------+---------------------------------+
| 4 bit | ANSI colors | ColorDepth.DEPTH_4_BIT | ColorDepth.ANSI_COLORS_ONLY |
+--------+-----------------+-----------------------------+---------------------------------+
| 8 bit | 256 colors | ColorDepth.DEPTH_8_BIT | ColorDepth.DEFAULT |
+--------+-----------------+-----------------------------+---------------------------------+
| 24 bit | True colors | ColorDepth.DEPTH_24_BIT | ColorDepth.TRUE_COLOR |
+--------+-----------------+-----------------------------+---------------------------------+

By default, 256 colors are used, because this is what most terminals support
these days. If the TERM environment variable is set to linux or
eterm-color, then only ANSI colors are used, because of these terminals. The 24
bit true color output needs to be enabled explicitly. When 4 bit color output
is chosen, all colors will be mapped to the closest ANSI color.

Setting the default color depth for any prompt_toolkit application can be done
by setting the PROMPT_TOOLKIT_COLOR_DEPTH environment variable. You could
for instance copy the following into your .bashrc file.

.. code:: shell

text
# export PROMPT_TOOLKIT_COLOR_DEPTH=DEPTH_1_BIT
export PROMPT_TOOLKIT_COLOR_DEPTH=DEPTH_4_BIT
# export PROMPT_TOOLKIT_COLOR_DEPTH=DEPTH_8_BIT
# export PROMPT_TOOLKIT_COLOR_DEPTH=DEPTH_24_BIT

An application can also decide to set the color depth manually by passing a
:class:~prompt_toolkit.output.ColorDepth value to the
:class:~prompt_toolkit.application.Application object:

.. code:: python

text
from prompt_toolkit.output.color_depth import ColorDepth

app = Application(
    color_depth=ColorDepth.ANSI_COLORS_ONLY,
    # ...
)

Style transformations

Prompt_toolkit supports a way to apply certain transformations to the styles
near the end of the rendering pipeline. This can be used for instance to change
certain colors to improve the rendering in some terminals.

One useful example is the
:class:~prompt_toolkit.styles.AdjustBrightnessStyleTransformation class,
which takes min_brightness and max_brightness as arguments which by default
have 0.0 and 1.0 as values. In the following code snippet, we increase the
minimum brightness to improve rendering on terminals with a dark background.

.. code:: python

text
from prompt_toolkit.styles import AdjustBrightnessStyleTransformation

app = Application(
    style_transformation=AdjustBrightnessStyleTransformation(
        min_brightness=0.5,  # Increase the minimum brightness.
        max_brightness=1.0,
    )
    # ...
)

Pages Advanced Topics Unit Testing (`docs/pages/advanced_topics/unit_testing.rst`)

.. _unit_testing:

Unit testing

Testing user interfaces is not always obvious. Here are a few tricks for
testing prompt_toolkit applications.

`PosixPipeInput` and `DummyOutput`

During the creation of a prompt_toolkit
:class:~prompt_toolkit.application.Application, we can specify what input and
output device to be used. By default, these are output objects that correspond
with sys.stdin and sys.stdout. In unit tests however, we want to replace
these.

  • For the input, we want a "pipe input". This is an input device, in which we
    can programmatically send some input. It can be created with
    :func:~prompt_toolkit.input.create_pipe_input, and that return either a
    :class:~prompt_toolkit.input.posix_pipe.PosixPipeInput or a
    :class:~prompt_toolkit.input.win32_pipe.Win32PipeInput depending on the
    platform.
  • For the output, we want a :class:~prompt_toolkit.output.DummyOutput. This is
    an output device that doesn't render anything. We don't want to render
    anything to sys.stdout in the unit tests.

.. note::

text
Typically, we don't want to test the bytes that are written to
`sys.stdout`, because these can change any time when the rendering
algorithm changes, and are not so meaningful anyway. Instead, we want to
test the return value from the
:class:`~prompt_toolkit.application.Application` or test how data
structures (like text buffers) change over time.

So we programmatically feed some input to the input pipe, have the key
bindings process the input and then test what comes out of it.

In the following example we use a
:class:~prompt_toolkit.shortcuts.PromptSession, but the same works for any
:class:~prompt_toolkit.application.Application.

.. code:: python

text
from prompt_toolkit.shortcuts import PromptSession
from prompt_toolkit.input import create_pipe_input
from prompt_toolkit.output import DummyOutput

def test_prompt_session():
    with create_pipe_input() as inp:
        inp.send_text("hello\n")
        session = PromptSession(
            input=inp,
            output=DummyOutput(),
        )

        result = session.prompt()

    assert result == "hello"

In the above example, don't forget to send the \\n character to accept the
prompt, otherwise the :class:~prompt_toolkit.application.Application will
wait forever for some more input to receive.

Using an :class:`~prompt_toolkit.application.current.AppSession`

Sometimes it's not convenient to pass input or output objects to the
:class:~prompt_toolkit.application.Application, and in some situations it's
not even possible at all.
This happens when these parameters are not passed down the call stack, through
all function calls.

An easy way to specify which input/output to use for all applications, is by
creating an :class:~prompt_toolkit.application.current.AppSession with this
input/output and running all code in that
:class:~prompt_toolkit.application.current.AppSession. This way, we don't
need to inject it into every :class:~prompt_toolkit.application.Application
or :func:~prompt_toolkit.shortcuts.print_formatted_text call.

Here is an example where we use
:func:~prompt_toolkit.application.create_app_session:

.. code:: python

text
from prompt_toolkit.application import create_app_session
from prompt_toolkit.shortcuts import print_formatted_text
from prompt_toolkit.output import DummyOutput

def test_something():
    with create_app_session(output=DummyOutput()):
        ...
        print_formatted_text('Hello world')
        ...

Pytest fixtures

In order to get rid of the boilerplate of creating the input, the
:class:~prompt_toolkit.output.DummyOutput, and the
:class:~prompt_toolkit.application.current.AppSession, we create a
single fixture that does it for every test. Something like this:

.. code:: python

text
import pytest
from prompt_toolkit.application import create_app_session
from prompt_toolkit.input import create_pipe_input
from prompt_toolkit.output import DummyOutput

@pytest.fixture(autouse=True, scope="function")
def mock_input():
    with create_pipe_input() as pipe_input:
        with create_app_session(input=pipe_input, output=DummyOutput()):
            yield pipe_input

For compatibility with pytest's capsys fixture, we have to create a new
:class:~prompt_toolkit.application.current.AppSession for every test. This
can be done in an autouse fixture. Pytest replaces sys.stdout with a new
object in every test that uses capsys and the following will ensure that
the new :class:~prompt_toolkit.application.current.AppSession will each time
refer to the latest output.

.. code:: python

text
from prompt_toolkit.application import create_app_session

@fixture(autouse=True, scope="function")
def _pt_app_session()
    with create_app_session():
        yield

Type checking

Prompt_toolkit 3.0 is fully type annotated. This means that if a
prompt_toolkit application is typed too, it can be verified with mypy. This is
complementary to unit tests, but also great for testing for correctness.


Pages Tutorials Index (`docs/pages/tutorials/index.rst`)

.. _tutorials:

Tutorials

.. toctree::
:caption: Contents:
:maxdepth: 1

text
repl

Pages Tutorials Repl (`docs/pages/tutorials/repl.rst`)

.. _tutorial_repl:

Tutorial: Build an SQLite REPL

The aim of this tutorial is to build an interactive command line interface for
an SQLite database using prompt_toolkit_.

First, install the library using pip, if you haven't done this already.

.. code::

text
pip install prompt_toolkit

Read User Input

Let's start accepting input using the
:func:~prompt_toolkit.shortcuts.prompt() function. This will ask the user for
input, and echo back whatever the user typed. We wrap it in a main()
function as a good practice.

.. code:: python

text
from prompt_toolkit import prompt

def main():
    text = prompt('> ')
    print('You entered:', text)

if __name__ == '__main__':
    main()

.. image:: ../../images/repl/sqlite-1.png

Loop The REPL

Now we want to call the :meth:~prompt_toolkit.shortcuts.PromptSession.prompt
method in a loop. In order to keep the history, the easiest way to do it is to
use a :class:~prompt_toolkit.shortcuts.PromptSession. This uses an
:class:~prompt_toolkit.history.InMemoryHistory underneath that keeps track of
the history, so that if the user presses the up-arrow, they'll see the previous
entries.

The :meth:~prompt_toolkit.shortcuts.PromptSession.prompt method raises
KeyboardInterrupt when ControlC has been pressed and EOFError when
ControlD has been pressed. This is what people use for cancelling commands and
exiting in a REPL. The try/except below handles these error conditions and make
sure that we go to the next iteration of the loop or quit the loop
respectively.

.. code:: python

text
from prompt_toolkit import PromptSession

def main():
    session = PromptSession()

    while True:
        try:
            text = session.prompt('> ')
        except KeyboardInterrupt:
            continue
        except EOFError:
            break
        else:
            print('You entered:', text)
    print('GoodBye!')

if __name__ == '__main__':
    main()

.. image:: ../../images/repl/sqlite-2.png

Syntax Highlighting

This is where things get really interesting. Let's step it up a notch by adding
syntax highlighting to the user input. We know that users will be entering SQL
statements, so we can leverage the Pygments_ library for coloring the input.
The lexer parameter allows us to set the syntax lexer. We're going to use
the SqlLexer from the Pygments_ library for highlighting.

Notice that in order to pass a Pygments lexer to prompt_toolkit, it needs to be
wrapped into a :class:~prompt_toolkit.lexers.PygmentsLexer.

.. code:: python

text
from prompt_toolkit import PromptSession
from prompt_toolkit.lexers import PygmentsLexer
from pygments.lexers.sql import SqlLexer

def main():
    session = PromptSession(lexer=PygmentsLexer(SqlLexer))

    while True:
        try:
            text = session.prompt('> ')
        except KeyboardInterrupt:
            continue
        except EOFError:
            break
        else:
            print('You entered:', text)
    print('GoodBye!')

if __name__ == '__main__':
    main()

.. image:: ../../images/repl/sqlite-3.png

Auto-completion

Now we are going to add auto completion. We'd like to display a drop down menu
of possible keywords <https://www.sqlite.org/lang_keywords.html>_ when the
user starts typing.

We can do this by creating an sql_completer object from the
:class:~prompt_toolkit.completion.WordCompleter class, defining a set of
keywords for the auto-completion.

Like the lexer, this sql_completer instance can be passed to either the
:class:~prompt_toolkit.shortcuts.PromptSession class or the
:meth:~prompt_toolkit.shortcuts.PromptSession.prompt method.

.. code:: python

text
from prompt_toolkit import PromptSession
from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.lexers import PygmentsLexer
from pygments.lexers.sql import SqlLexer

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)

def main():
    session = PromptSession(
        lexer=PygmentsLexer(SqlLexer), completer=sql_completer)

    while True:
        try:
            text = session.prompt('> ')
        except KeyboardInterrupt:
            continue
        except EOFError:
            break
        else:
            print('You entered:', text)
    print('GoodBye!')

if __name__ == '__main__':
    main()

.. image:: ../../images/repl/sqlite-4.png

In about 30 lines of code we got ourselves an auto completing, syntax
highlighting REPL. Let's make it even better.

Styling the menus

If we want, we can now change the colors of the completion menu. This is
possible by creating a :class:~prompt_toolkit.styles.Style instance and
passing it to the :meth:~prompt_toolkit.shortcuts.PromptSession.prompt
function.

.. code:: python

text
from prompt_toolkit import PromptSession
from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.lexers import PygmentsLexer
from prompt_toolkit.styles import Style
from pygments.lexers.sql import SqlLexer

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():
   session = PromptSession(
       lexer=PygmentsLexer(SqlLexer), completer=sql_completer, style=style)

   while True:
       try:
           text = session.prompt('> ')
       except KeyboardInterrupt:
           continue
       except EOFError:
           break
       else:
           print('You entered:', text)
   print('GoodBye!')

if __name__ == '__main__':
    main()

.. image:: ../../images/repl/sqlite-5.png

All that's left is hooking up the sqlite backend, which is left as an exercise
for the reader. Just kidding... Keep reading.

Hook up Sqlite

This step is the final step to make the SQLite REPL actually work. It's time
to relay the input to SQLite.

Obviously I haven't done the due diligence to deal with the errors. But it
gives a good idea of how to get started.

.. code:: python

text
#!/usr/bin/env python
import sys
import sqlite3

from prompt_toolkit import PromptSession
from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.lexers import PygmentsLexer
from prompt_toolkit.styles import Style
from pygments.lexers.sql import SqlLexer

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)

.. image:: ../../images/repl/sqlite-6.png

I hope that gives an idea of how to get started on building command line
interfaces.

The End.

.. _prompt_toolkit: https://github.com/prompt-toolkit/python-prompt-toolkit
.. _Pygments: http://pygments.org/


Pages Upgrading 2.0 (`docs/pages/upgrading/2.0.rst`)

.. _upgrading_2_0:

Upgrading to prompt_toolkit 2.0

Prompt_toolkit 2.0 is not compatible with 1.0, however you probably want to
upgrade your applications. This page explains why we have these differences and
how to upgrade.

If you experience some difficulties or you feel that some information is
missing from this page, don't hesitate to open a GitHub issue for help.

Why all these breaking changes?

After more and more custom prompt_toolkit applications were developed, it
became clear that prompt_toolkit 1.0 was not flexible enough for certain use
cases. Mostly, the development of full screen applications was not really
natural. All the important components, like the rendering, key bindings, input
and output handling were present, but the API was in the first place designed
for simple command line prompts. This was mostly notably in the following two
places:

  • First, there was the focus which was always pointing to a
    :class:~prompt_toolkit.buffer.Buffer (or text input widget), but in full
    screen applications there are other widgets, like menus and buttons which
    can be focused.
  • And secondly, it was impossible to make reusable UI components. All the key
    bindings for the entire applications were stored together in one
    KeyBindings object, and similar, all
    :class:~prompt_toolkit.buffer.Buffer objects were stored together in one
    dictionary. This didn't work well. You want reusable components to define
    their own key bindings and everything. It's the idea of encapsulation.

For simple prompts, the changes wouldn't be that invasive, but given that there
would be some, I took the opportunity to fix a couple of other things. For
instance:

  • In prompt_toolkit 1.0, we translated \\r into \\n during the input
    processing. This was not a good idea, because some people wanted to handle
    these keys individually. This makes sense if you keep in mind that they
    correspond to Control-M and Control-J. However, we couldn't fix this
    without breaking everyone's enter key, which happens to be the most important
    key in prompts.

Given that we were going to break compatibility anyway, we changed a couple of
other important things that effect both simple prompt applications and
full screen applications. These are the most important:

  • We no longer depend on Pygments for styling. While we like Pygments, it was
    not flexible enough to provide all the styling options that we need, and the
    Pygments tokens were not ideal for styling anything besides tokenized text.

    Instead we created something similar to CSS. All UI components can attach
    classnames to themselves, as well as define an inline style. The final style is
    then computed by combining the inline styles, the classnames and the style
    sheet.

    There are still adaptors available for using Pygments lexers as well as for
    Pygments styles.

  • The way that key bindings were defined was too complex.
    KeyBindingsManager was too complex and no longer exists. Every set of key
    bindings is now a
    :class:~prompt_toolkit.key_binding.KeyBindings object and multiple of these
    can be merged together at any time. The runtime performance remains the same,
    but it's now easier for users.

  • The separation between the CommandLineInterface and
    :class:~prompt_toolkit.application.Application class was confusing and in
    the end, didn't really had an advantage. These two are now merged together in
    one :class:~prompt_toolkit.application.Application class.

  • We no longer pass around the active CommandLineInterface. This was one of
    the most annoying things. Key bindings need it in order to change anything
    and filters need it in order to evaluate their state. It was pretty annoying,
    especially because there was usually only one application active at a time.
    So, :class:~prompt_toolkit.application.Application became a TaskLocal.
    That is like a global variable, but scoped in the current coroutine or
    context. The way this works is still not 100% correct, but good enough for
    the projects that need it (like Pymux), and hopefully Python will get support
    for this in the future thanks to PEP521, PEP550 or PEP555.

All of these changes have been tested for many months, and I can say with
confidence that prompt_toolkit 2.0 is a better prompt_toolkit.

Some new features

Apart from the breaking changes above, there are also some exciting new
features.

  • We now support vt100 escape codes for Windows consoles on Windows 10. This
    means much faster rendering, and full color support.

  • We have a concept of formatted text. This is an object that evaluates to
    styled text. Every input that expects some text, like the message in a
    prompt, or the text in a toolbar, can take any kind of formatted text as input.
    This means you can pass in a plain string, but also a list of (style, text) tuples (similar to a Pygments tokenized string), or an
    :class:~prompt_toolkit.formatted_text.HTML object. This simplifies many
    APIs.

  • New utilities were added. We now have function for printing formatted text
    and an experimental module for displaying progress bars.

  • Autocompletion, input validation, and auto suggestion can now either be
    asynchronous or synchronous. By default they are synchronous, but by wrapping
    them in :class:~prompt_toolkit.completion.ThreadedCompleter,
    :class:~prompt_toolkit.validation.ThreadedValidator or
    :class:~prompt_toolkit.auto_suggest.ThreadedAutoSuggest, they will become
    asynchronous by running in a background thread.

    Further, if the autocompletion code runs in a background thread, we will show
    the completions as soon as they arrive. This means that the autocompletion
    algorithm could for instance first yield the most trivial completions and then
    take time to produce the completions that take more time.

Upgrading

More guidelines on how to upgrade will follow.

AbortAction has been removed
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Prompt_toolkit 1.0 had an argument abort_action for both the
Application class as well as for the prompt function. This has been
removed. The recommended way to handle this now is by capturing
KeyboardInterrupt and EOFError manually.

Calling create_eventloop usually not required anymore
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Prompt_toolkit 2.0 will automatically create the appropriate event loop when
it's needed for the first time. There is no need to create one and pass it
around. If you want to run an application on top of asyncio (without using an
executor), it still needs to be activated by calling
:func:~prompt_toolkit.eventloop.use_asyncio_event_loop at the beginning.

Pygments styles and tokens
^^^^^^^^^^^^^^^^^^^^^^^^^^

prompt_toolkit 2.0 no longer depends on Pygments <http://pygments.org/>_, but
that definitely doesn't mean that you can't use any Pygments functionality
anymore. The only difference is that Pygments stuff needs to be wrapped in an
adaptor to make it compatible with the native prompt_toolkit objects.

  • For instance, if you have a list of (pygments.Token, text) tuples for
    formatting, then this needs to be wrapped in a
    :class:~prompt_toolkit.formatted_text.PygmentsTokens object. This is an
    adaptor that turns it into prompt_toolkit "formatted text". Feel free to keep
    using this.

  • Pygments lexers need to be wrapped in a
    :class:~prompt_toolkit.lexers.PygmentsLexer. This will convert the list of
    Pygments tokens into prompt_toolkit formatted text.

  • If you have a Pygments style, then this needs to be converted as well. A
    Pygments style class can be converted in a prompt_toolkit
    :class:~prompt_toolkit.styles.Style with the
    :func:~prompt_toolkit.styles.pygments.style_from_pygments_cls function
    (which used to be called style_from_pygments). A Pygments style
    dictionary can be converted using
    :func:~prompt_toolkit.styles.pygments.style_from_pygments_dict.

    Multiple styles can be merged together using
    :func:~prompt_toolkit.styles.merge_styles.

Wordcompleter
^^^^^^^^^^^^^

WordCompleter was moved from
:class:prompt_toolkit.contrib.completers.base.WordCompleter to
:class:prompt_toolkit.completion.word_completer.WordCompleter.

Asynchronous autocompletion
^^^^^^^^^^^^^^^^^^^^^^^^^^^

By default, prompt_toolkit 2.0 completion is now synchronous. If you still want
asynchronous auto completion (which is often good thing), then you have to wrap
the completer in a :class:~prompt_toolkit.completion.ThreadedCompleter.

Filters
^^^^^^^

We don't distinguish anymore between CLIFilter and SimpleFilter, because the
application object is no longer passed around. This means that all filters are
a Filter from now on.

All filters have been turned into functions. For instance, IsDone became
is_done and HasCompletions became has_completions.

This was done because almost all classes were called without any arguments in
the __init__ causing additional braces everywhere. This means that
HasCompletions() has to be replaced by has_completions (without
parenthesis).

The few filters that took arguments as input, became functions, but still have
to be called with the given arguments.

For new filters, it is recommended to use the @Condition decorator,
rather then inheriting from Filter. For instance:

.. code:: python

text
from prompt_toolkit.filters import Condition

@Condition
def my_filter();
    return True  # Or False

Pages Upgrading 3.0 (`docs/pages/upgrading/3.0.rst`)

.. _upgrading_3_0:

Upgrading to prompt_toolkit 3.0

There are two major changes in 3.0 to be aware of:

  • First, prompt_toolkit uses the asyncio event loop natively, rather then using
    its own implementations of event loops. This means that all coroutines are
    now asyncio coroutines, and all Futures are asyncio futures. Asynchronous
    generators became real asynchronous generators as well.

  • Prompt_toolkit uses type annotations (almost) everywhere. This should not
    break any code, but its very helpful in many ways.

There are some minor breaking changes:

  • The dialogs API had to change (see below).

Detecting the prompt_toolkit version

Detecting whether version 3 is being used can be done as follows:

.. code:: python

text
from prompt_toolkit import __version__ as ptk_version

PTK3 = ptk_version.startswith('3.')

Fixing calls to `get_event_loop`

Every usage of get_event_loop has to be fixed. An easy way to do this is by
changing the imports like this:

.. code:: python

text
if PTK3:
    from asyncio import get_event_loop
else:
    from prompt_toolkit.eventloop import get_event_loop

Notice that for prompt_toolkit 2.0, get_event_loop returns a prompt_toolkit
EventLoop object. This is not an asyncio eventloop, but the API is
similar.

There are some changes to the eventloop API:

+-----------------------------------+--------------------------------------+
| version 2.0 | version 3.0 (asyncio) |
+===================================+======================================+
| loop.run_in_executor(callback) | loop.run_in_executor(None, callback) |
+-----------------------------------+--------------------------------------+
| loop.call_from_executor(callback) | loop.call_soon_threadsafe(callback) |
+-----------------------------------+--------------------------------------+

Running on top of asyncio

For 2.0, you had tell prompt_toolkit to run on top of the asyncio event loop.
Now it's the default. So, you can simply remove the following two lines:

.. code::

text
from prompt_toolkit.eventloop.defaults import use_asyncio_event_loop
use_asyncio_event_loop()

There is a few little breaking changes though. The following:

.. code::

text
# For 2.0
result = await PromptSession().prompt('Say something: ', async_=True)

has to be changed into:

.. code::

text
# For 3.0
result = await PromptSession().prompt_async('Say something: ')

Further, it's impossible to call the prompt() function within an asyncio
application (within a coroutine), because it will try to run the event loop
again. In that case, always use prompt_async().

Changes to the dialog functions

The original way of using dialog boxes looked like this:

.. code:: python

text
from prompt_toolkit.shortcuts import input_dialog

result = input_dialog(title='...', text='...')

Now, the dialog functions return a prompt_toolkit Application object. You have
to call either its run or run_async method to display the dialog. The
async_ parameter has been removed everywhere.

.. code:: python

text
if PTK3:
    result = input_dialog(title='...', text='...').run()
else:
    result = input_dialog(title='...', text='...')

# Or

if PTK3:
    result = await input_dialog(title='...', text='...').run_async()
else:
    result = await input_dialog(title='...', text='...', async_=True)

Pages Upgrading Index (`docs/pages/upgrading/index.rst`)

.. _upgrading:

Upgrading

.. toctree::
:caption: Contents:
:maxdepth: 1

text
2.0
3.0

--- METRICS ---