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
|
.. _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::
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
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:
2. 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).
3. 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...)
4. 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:
5. It calculates the horizontal and vertical scrolling, if applicable
(if the content would take more space than what is available).
6. 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`.
|