summaryrefslogtreecommitdiffstats
path: root/docs/pages/upgrading/2.0.rst
blob: 60670578fcfc36d38ac66bc1234c6d276f9f786e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
.. _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

    from prompt_toolkit.filters import Condition

    @Condition
    def my_filter();
        return True  # Or False