Skip to content

Latest commit

 

History

History
86 lines (66 loc) · 3.63 KB

rendering_flow.rst

File metadata and controls

86 lines (66 loc) · 3.63 KB

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:

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 visualisation 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`.