summaryrefslogtreecommitdiffstats
path: root/docs/pages/asking_for_input.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/pages/asking_for_input.rst')
-rw-r--r--docs/pages/asking_for_input.rst1034
1 files changed, 1034 insertions, 0 deletions
diff --git a/docs/pages/asking_for_input.rst b/docs/pages/asking_for_input.rst
new file mode 100644
index 0000000..20619ac
--- /dev/null
+++ b/docs/pages/asking_for_input.rst
@@ -0,0 +1,1034 @@
+.. _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
+
+ from prompt_toolkit import prompt
+
+ text = prompt('Give me some input: ')
+ print('You said: %s' % 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
+
+ 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
+
+ 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('You said: %s' % 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
+
+ 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('You said: %s' % 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
+
+ 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
+
+ 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
+
+ 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
+
+ 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
+
+ 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
+
+ from prompt_toolkit import prompt
+ from prompt_toolkit.completion import WordCompleter
+
+ html_completer = WordCompleter(['<html>', '<body>', '<head>', '<title>'])
+ text = prompt('Enter HTML: ', completer=html_completer)
+ print('You said: %s' % 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::
+
+ 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
+
+ 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('You said: %s' % 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
+
+ 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
+
+ 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
+
+
+ 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('<b>completion</b><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 = 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 = 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
+
+ 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('You said: %i' % 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
+
+ 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
+
+ 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('You said: %i' % 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::
+
+ 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
+
+ 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('You said: %s' % 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
+
+ from prompt_toolkit import prompt
+ from prompt_toolkit.formatted_text import HTML
+
+ def bottom_toolbar():
+ return HTML('This is a <b><style bg="ansired">Toolbar</style></b>!')
+
+ text = prompt('> ', bottom_toolbar=bottom_toolbar)
+ print('You said: %s' % text)
+
+.. image:: ../images/bottom-toolbar.png
+
+Similar, we could use a list of style/text tuples.
+
+.. code:: python
+
+ 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('You said: %s' % 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
+
+ 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
+
+ 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
+
+ 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('You said: %s' % 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
+
+ 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
+
+ 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
+
+ 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
+
+ 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
+
+ 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
+
+ from prompt_toolkit import prompt
+ import getpass
+
+ prompt('What is your name: ', default='%s' % 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
+
+ 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
+
+ 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
+
+ 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
+
+ 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())
+
+
+Prompt in an `asyncio` application
+----------------------------------
+
+.. note::
+
+ 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
+
+ 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('You said: %s' % 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
+
+ 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.