summaryrefslogtreecommitdiffstats
path: root/docs/pages/advanced_topics/rendering_flow.rst
blob: 0cd12c707e1bcc9eda099ee7c3ea77a75eb75049 (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
.. _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`.