Exemplo n.º 1
0
    def __init__(self,
                 prompt: AnyFormattedText = 'Shell command: ',
                 enable_global_bindings: FilterOrBool = True) -> None:

        self.prompt = prompt
        self.enable_global_bindings = to_filter(enable_global_bindings)

        self.system_buffer = Buffer(name=SYSTEM_BUFFER)

        self._bindings = self._build_key_bindings()

        self.buffer_control = BufferControl(
            buffer=self.system_buffer,
            lexer=SimpleLexer(style='class:system-toolbar.text'),
            input_processors=[
                BeforeInput(lambda: self.prompt, style='class:system-toolbar')
            ],
            key_bindings=self._bindings)

        self.window = Window(self.buffer_control,
                             height=1,
                             style='class:system-toolbar')

        self.container = ConditionalContainer(content=self.window,
                                              filter=has_focus(
                                                  self.system_buffer))
Exemplo n.º 2
0
    def current_buffer(self) -> Buffer:
        """
        The currently focused :class:`~.Buffer`.

        (This returns a dummy :class:`.Buffer` when none of the actual buffers
        has the focus. In this case, it's really not practical to check for
        `None` values or catch exceptions every time.)
        """
        return self.layout.current_buffer or Buffer(
            name='dummy-buffer')  # Dummy buffer.
Exemplo n.º 3
0
    def __init__(self,
                 buffer: Optional[Buffer] = None,
                 input_processors: Optional[List[Processor]] = None,
                 include_default_input_processors: bool = True,
                 lexer: Optional[Lexer] = None,
                 preview_search: FilterOrBool = False,
                 focusable: FilterOrBool = True,
                 search_buffer_control: Union[
                     None, 'SearchBufferControl',
                     Callable[[], 'SearchBufferControl']] = None,
                 menu_position: Optional[Callable] = None,
                 focus_on_click: FilterOrBool = False,
                 key_bindings: Optional['KeyBindingsBase'] = None):

        self.input_processors = input_processors
        self.include_default_input_processors = include_default_input_processors

        self.default_input_processors = [
            HighlightSearchProcessor(),
            HighlightIncrementalSearchProcessor(),
            HighlightSelectionProcessor(),
            DisplayMultipleCursors(),
        ]

        self.preview_search = to_filter(preview_search)
        self.focusable = to_filter(focusable)
        self.focus_on_click = to_filter(focus_on_click)

        self.buffer = buffer or Buffer()
        self.menu_position = menu_position
        self.lexer = lexer or SimpleLexer()
        self.key_bindings = key_bindings
        self._search_buffer_control = search_buffer_control

        #: Cache for the lexer.
        #: Often, due to cursor movement, undo/redo and window resizing
        #: operations, it happens that a short time, the same document has to be
        #: lexed. This is a fairly easy way to cache such an expensive operation.
        self._fragment_cache: SimpleCache[Hashable, Callable[[int], StyleAndTextTuples]] = \
            SimpleCache(maxsize=8)

        self._last_click_timestamp: Optional[float] = None
        self._last_get_processed_line: Optional[Callable[
            [int], _ProcessedLine]] = None
Exemplo n.º 4
0
    def __init__(
            self,
            search_buffer: Optional[Buffer] = None,
            vi_mode: bool = False,
            text_if_not_searching: AnyFormattedText = '',
            forward_search_prompt: AnyFormattedText = 'I-search: ',
            backward_search_prompt: AnyFormattedText = 'I-search backward: ',
            ignore_case: FilterOrBool = False) -> None:

        if search_buffer is None:
            search_buffer = Buffer()

        @Condition
        def is_searching() -> bool:
            return self.control in get_app().layout.search_links

        def get_before_input() -> AnyFormattedText:
            if not is_searching():
                return text_if_not_searching
            elif self.control.searcher_search_state.direction == SearchDirection.BACKWARD:
                return ('?' if vi_mode else backward_search_prompt)
            else:
                return ('/' if vi_mode else forward_search_prompt)

        self.search_buffer = search_buffer

        self.control = SearchBufferControl(
            buffer=search_buffer,
            input_processors=[
                BeforeInput(get_before_input,
                            style='class:search-toolbar.prompt')
            ],
            lexer=SimpleLexer(style='class:search-toolbar.text'),
            ignore_case=ignore_case)

        self.container = ConditionalContainer(content=Window(
            self.control, height=1, style='class:search-toolbar'),
                                              filter=is_searching)
Exemplo n.º 5
0
LIPSUM = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit.  Maecenas
quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est bibendum
mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
dignissim placerat. In vel dictum ex, vulputate accumsan mi. Donec ut quam
placerat massa tempor elementum. Sed tristique mauris ac suscipit euismod. Ut
tempus vehicula augue non venenatis. Mauris aliquam velit turpis, nec congue
risus aliquam sit amet. Pellentesque blandit scelerisque felis, faucibus
consequat ante. Curabitur tempor tortor a imperdiet tincidunt. Nam sed justo
sit amet odio bibendum congue. Quisque varius ligula nec ligula gravida, sed
convallis augue faucibus. Nunc ornare pharetra bibendum. Praesent blandit ex
quis sodales maximus.""" * 40

# Create text buffers. The margins will update if you scroll up or down.

buff = Buffer()
buff.text = LIPSUM

# 1. The layout
body = HSplit([
    Window(FormattedTextControl('Press "q" to quit.'),
           height=1,
           style='reverse'),
    Window(
        BufferControl(buffer=buff),

        # Add margins.
        left_margins=[NumberedMargin(), ScrollbarMargin()],
        right_margins=[ScrollbarMargin(), ScrollbarMargin()],
    ),
])
Exemplo n.º 6
0
def get_line_prefix(lineno, wrap_count):
    if wrap_count == 0:
        return HTML(
            '[%s] <style bg="orange" fg="black">--&gt;</style> ') % lineno

    text = str(lineno) + '-' + '*' * (lineno // 2) + ': '
    return HTML('[%s.%s] <style bg="ansigreen" fg="ansiblack">%s</style>') % (
        lineno, wrap_count, text)


# Global wrap lines flag.
wrap_lines = True

# The layout
buff = Buffer(complete_while_typing=True)
buff.text = LIPSUM

body = FloatContainer(content=HSplit([
    Window(FormattedTextControl(
        'Press "q" to quit. Press "w" to enable/disable wrapping.'),
           height=1,
           style='reverse'),
    Window(BufferControl(buffer=buff),
           get_line_prefix=get_line_prefix,
           wrap_lines=Condition(lambda: wrap_lines)),
]),
                      floats=[
                          Float(xcursor=True,
                                ycursor=True,
                                content=CompletionsMenu(max_height=16,
Exemplo n.º 7
0
    def __init__(self,
                 text: str = '',
                 multiline: FilterOrBool = True,
                 password: FilterOrBool = False,
                 lexer: Optional[Lexer] = None,
                 auto_suggest: Optional[AutoSuggest] = None,
                 completer: Optional[Completer] = None,
                 complete_while_typing: FilterOrBool = True,
                 accept_handler: Optional[BufferAcceptHandler] = None,
                 history: Optional[History] = None,
                 focusable: FilterOrBool = True,
                 focus_on_click: FilterOrBool = False,
                 wrap_lines: FilterOrBool = True,
                 read_only: FilterOrBool = False,
                 width: AnyDimension = None,
                 height: AnyDimension = None,
                 dont_extend_height: FilterOrBool = False,
                 dont_extend_width: FilterOrBool = False,
                 line_numbers: bool = False,
                 get_line_prefix: Optional[GetLinePrefixCallable] = None,
                 scrollbar: bool = False,
                 style: str = '',
                 search_field: Optional[SearchToolbar] = None,
                 preview_search: FilterOrBool = True,
                 prompt: AnyFormattedText = '',
                 input_processors: Optional[List[Processor]] = None) -> None:

        if search_field is None:
            search_control = None
        elif isinstance(search_field, SearchToolbar):
            search_control = search_field.control

        if input_processors is None:
            input_processors = []

        # Writeable attributes.
        self.completer = completer
        self.complete_while_typing = complete_while_typing
        self.lexer = lexer
        self.auto_suggest = auto_suggest
        self.read_only = read_only
        self.wrap_lines = wrap_lines

        self.buffer = Buffer(
            document=Document(text, 0),
            multiline=multiline,
            read_only=Condition(lambda: is_true(self.read_only)),
            completer=DynamicCompleter(lambda: self.completer),
            complete_while_typing=Condition(
                lambda: is_true(self.complete_while_typing)),
            auto_suggest=DynamicAutoSuggest(lambda: self.auto_suggest),
            accept_handler=accept_handler,
            history=history)

        self.control = BufferControl(
            buffer=self.buffer,
            lexer=DynamicLexer(lambda: self.lexer),
            input_processors=[
                ConditionalProcessor(AppendAutoSuggestion(),
                                     has_focus(self.buffer) & ~is_done),
                ConditionalProcessor(processor=PasswordProcessor(),
                                     filter=to_filter(password)),
                BeforeInput(prompt, style='class:text-area.prompt'),
            ] + input_processors,
            search_buffer_control=search_control,
            preview_search=preview_search,
            focusable=focusable,
            focus_on_click=focus_on_click)

        if multiline:
            if scrollbar:
                right_margins = [ScrollbarMargin(display_arrows=True)]
            else:
                right_margins = []
            if line_numbers:
                left_margins = [NumberedMargin()]
            else:
                left_margins = []
        else:
            height = D.exact(1)
            left_margins = []
            right_margins = []

        style = 'class:text-area ' + style

        self.window = Window(
            height=height,
            width=width,
            dont_extend_height=dont_extend_height,
            dont_extend_width=dont_extend_width,
            content=self.control,
            style=style,
            wrap_lines=Condition(lambda: is_true(self.wrap_lines)),
            left_margins=left_margins,
            right_margins=right_margins,
            get_line_prefix=get_line_prefix)
Exemplo n.º 8
0
    "[q] Quit [a] Focus left top [b] Right top [c] Left bottom [d] Right bottom."
)

LIPSUM = """Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas quis interdum enim. Nam viverra, mauris et blandit malesuada, ante est
bibendum mauris, ac dignissim dui tellus quis ligula. Aenean condimentum leo at
dignissim placerat. In vel dictum ex, vulputate accumsan mi. Donec ut quam
placerat massa tempor elementum. Sed tristique mauris ac suscipit euismod. Ut
tempus vehicula augue non venenatis. Mauris aliquam velit turpis, nec congue
risus aliquam sit amet. Pellentesque blandit scelerisque felis, faucibus
consequat ante. Curabitur tempor tortor a imperdiet tincidunt. Nam sed justo
sit amet odio bibendum congue. Quisque varius ligula nec ligula gravida, sed
convallis augue faucibus. Nunc ornare pharetra bibendum. Praesent blandit ex
quis sodales maximus. """

left_top = Window(BufferControl(Buffer(document=Document(LIPSUM))))
left_bottom = Window(BufferControl(Buffer(document=Document(LIPSUM))))
right_top = Window(BufferControl(Buffer(document=Document(LIPSUM))))
right_bottom = Window(BufferControl(Buffer(document=Document(LIPSUM))))

body = HSplit([
    Window(FormattedTextControl(top_text), height=2, style='reverse'),
    Window(height=1, char='-'),  # Horizontal line in the middle.
    VSplit([left_top, Window(width=1, char='|'), right_top]),
    Window(height=1, char='-'),  # Horizontal line in the middle.
    VSplit([left_bottom, Window(width=1, char='|'), right_bottom]),
])

# 2. Key bindings
kb = KeyBindings()
Exemplo n.º 9
0
def test_repeated_search(_history):
    buff = Buffer(history=_history)
    buff.yank_last_arg()
    buff.yank_last_arg()
    assert buff.document.current_line == 'delta'
Exemplo n.º 10
0
def test_simple_search_with_arg_out_of_bounds(_history):
    buff = Buffer(history=_history)
    buff.yank_last_arg(n=8)
    assert buff.document.current_line == ''
Exemplo n.º 11
0
def test_simple_search_with_arg(_history):
    buff = Buffer(history=_history)
    buff.yank_last_arg(n=2)
    assert buff.document.current_line == 'three'
Exemplo n.º 12
0
def test_simple_search_with_quotes(_history):
    _history.append_string("""one two "three 'x' four"\n""")
    buff = Buffer(history=_history)
    buff.yank_last_arg()
    assert buff.document.current_line == '''"three 'x' four"'''
Exemplo n.º 13
0
def test_simple_search(_history):
    buff = Buffer(history=_history)
    buff.yank_last_arg()
    assert buff.document.current_line == 'four'
Exemplo n.º 14
0
def test_empty_history():
    buf = Buffer()
    buf.yank_last_arg()
    assert buf.document.current_line == ''
Exemplo n.º 15
0
    'gorilla',
    'kangaroo',
    'leopard',
    'lion',
    'mouse',
    'rabbit',
    'rat',
    'snake',
    'spider',
    'turkey',
    'turtle',
],
                                 ignore_case=True)

# The layout
buff = Buffer(completer=animal_completer, complete_while_typing=True)

body = FloatContainer(content=HSplit([
    Window(FormattedTextControl('Press "q" to quit.'),
           height=1,
           style='reverse'),
    Window(BufferControl(buffer=buff)),
]),
                      floats=[
                          Float(xcursor=True,
                                ycursor=True,
                                content=CompletionsMenu(max_height=16,
                                                        scroll_offset=1))
                      ])

# Key bindings
Exemplo n.º 16
0
class SystemToolbar:
    """
    Toolbar for a system prompt.

    :param prompt: Prompt to be displayed to the user.
    """
    def __init__(self,
                 prompt: AnyFormattedText = 'Shell command: ',
                 enable_global_bindings: FilterOrBool = True) -> None:

        self.prompt = prompt
        self.enable_global_bindings = to_filter(enable_global_bindings)

        self.system_buffer = Buffer(name=SYSTEM_BUFFER)

        self._bindings = self._build_key_bindings()

        self.buffer_control = BufferControl(
            buffer=self.system_buffer,
            lexer=SimpleLexer(style='class:system-toolbar.text'),
            input_processors=[
                BeforeInput(lambda: self.prompt, style='class:system-toolbar')
            ],
            key_bindings=self._bindings)

        self.window = Window(self.buffer_control,
                             height=1,
                             style='class:system-toolbar')

        self.container = ConditionalContainer(content=self.window,
                                              filter=has_focus(
                                                  self.system_buffer))

    def _get_display_before_text(self) -> StyleAndTextTuples:
        return [
            ('class:system-toolbar', 'Shell command: '),
            ('class:system-toolbar.text', self.system_buffer.text),
            ('', '\n'),
        ]

    def _build_key_bindings(self) -> KeyBindingsBase:
        focused = has_focus(self.system_buffer)

        # Emacs
        emacs_bindings = KeyBindings()
        handle = emacs_bindings.add

        @handle('escape', filter=focused)
        @handle('c-g', filter=focused)
        @handle('c-c', filter=focused)
        def _(event: E) -> None:
            " Hide system prompt. "
            self.system_buffer.reset()
            event.app.layout.focus_last()

        @handle('enter', filter=focused)
        def _(event: E) -> None:
            " Run system command. "
            event.app.run_system_command(
                self.system_buffer.text,
                display_before_text=self._get_display_before_text())
            self.system_buffer.reset(append_to_history=True)
            event.app.layout.focus_last()

        # Vi.
        vi_bindings = KeyBindings()
        handle = vi_bindings.add

        @handle('escape', filter=focused)
        @handle('c-c', filter=focused)
        def _(event: E) -> None:
            " Hide system prompt. "
            event.app.vi_state.input_mode = InputMode.NAVIGATION
            self.system_buffer.reset()
            event.app.layout.focus_last()

        @handle('enter', filter=focused)
        def _(event: E) -> None:
            " Run system command. "
            event.app.vi_state.input_mode = InputMode.NAVIGATION
            event.app.run_system_command(
                self.system_buffer.text,
                display_before_text=self._get_display_before_text())
            self.system_buffer.reset(append_to_history=True)
            event.app.layout.focus_last()

        # Global bindings. (Listen to these bindings, even when this widget is
        # not focussed.)
        global_bindings = KeyBindings()
        handle = global_bindings.add

        @handle(Keys.Escape, '!', filter=~focused & emacs_mode, is_global=True)
        def _(event: E) -> None:
            " M-'!' will focus this user control. "
            event.app.layout.focus(self.window)

        @handle('!',
                filter=~focused & vi_mode & vi_navigation_mode,
                is_global=True)
        def _(event: E) -> None:
            " Focus. "
            event.app.vi_state.input_mode = InputMode.INSERT
            event.app.layout.focus(self.window)

        return merge_key_bindings([
            ConditionalKeyBindings(emacs_bindings, emacs_mode),
            ConditionalKeyBindings(vi_bindings, vi_mode),
            ConditionalKeyBindings(global_bindings,
                                   self.enable_global_bindings),
        ])

    def __pt_container__(self) -> Container:
        return self.container
Exemplo n.º 17
0
def test_repeated_search_with_wraparound(_history):
    buff = Buffer(history=_history)
    buff.yank_last_arg()
    buff.yank_last_arg()
    buff.yank_last_arg()
    assert buff.document.current_line == 'four'
Exemplo n.º 18
0
def test_repeated_yank_nth_arg(_history):
    buff = Buffer(history=_history)
    buff.yank_nth_arg()
    buff.yank_nth_arg()
    assert buff.document.current_line == 'beta'
Exemplo n.º 19
0
class TextArea:
    """
    A simple input field.

    This is a higher level abstraction on top of several other classes with
    sane defaults.

    This widget does have the most common options, but it does not intend to
    cover every single use case. For more configurations options, you can
    always build a text area manually, using a
    :class:`~prompt_toolkit_dev.buffer.Buffer`,
    :class:`~prompt_toolkit_dev.layout.BufferControl` and
    :class:`~prompt_toolkit_dev.layout.Window`.

    Buffer attributes:

    :param text: The initial text.
    :param multiline: If True, allow multiline input.
    :param completer: :class:`~prompt_toolkit_dev.completion.Completer` instance
        for auto completion.
    :param complete_while_typing: Boolean.
    :param accept_handler: Called when `Enter` is pressed (This should be a
        callable that takes a buffer as input).
    :param history: :class:`~prompt_toolkit_dev.history.History` instance.
    :param auto_suggest: :class:`~prompt_toolkit_dev.auto_suggest.AutoSuggest`
        instance for input suggestions.

    BufferControl attributes:

    :param password: When `True`, display using asterisks.
    :param focusable: When `True`, allow this widget to receive the focus.
    :param focus_on_click: When `True`, focus after mouse click.
    :param input_processors: `None` or a list of
        :class:`~prompt_toolkit_dev.layout.Processor` objects.

    Window attributes:

    :param lexer: :class:`~prompt_toolkit_dev.lexers.Lexer` instance for syntax
        highlighting.
    :param wrap_lines: When `True`, don't scroll horizontally, but wrap lines.
    :param width: Window width. (:class:`~prompt_toolkit_dev.layout.Dimension` object.)
    :param height: Window height. (:class:`~prompt_toolkit_dev.layout.Dimension` object.)
    :param scrollbar: When `True`, display a scroll bar.
    :param style: A style string.
    :param dont_extend_width: When `True`, don't take up more width then the
                              preferred width reported by the control.
    :param dont_extend_height: When `True`, don't take up more width then the
                               preferred height reported by the control.
    :param get_line_prefix: None or a callable that returns formatted text to
        be inserted before a line. It takes a line number (int) and a
        wrap_count and returns formatted text. This can be used for
        implementation of line continuations, things like Vim "breakindent" and
        so on.

    Other attributes:

    :param search_field: An optional `SearchToolbar` object.
    """
    def __init__(self,
                 text: str = '',
                 multiline: FilterOrBool = True,
                 password: FilterOrBool = False,
                 lexer: Optional[Lexer] = None,
                 auto_suggest: Optional[AutoSuggest] = None,
                 completer: Optional[Completer] = None,
                 complete_while_typing: FilterOrBool = True,
                 accept_handler: Optional[BufferAcceptHandler] = None,
                 history: Optional[History] = None,
                 focusable: FilterOrBool = True,
                 focus_on_click: FilterOrBool = False,
                 wrap_lines: FilterOrBool = True,
                 read_only: FilterOrBool = False,
                 width: AnyDimension = None,
                 height: AnyDimension = None,
                 dont_extend_height: FilterOrBool = False,
                 dont_extend_width: FilterOrBool = False,
                 line_numbers: bool = False,
                 get_line_prefix: Optional[GetLinePrefixCallable] = None,
                 scrollbar: bool = False,
                 style: str = '',
                 search_field: Optional[SearchToolbar] = None,
                 preview_search: FilterOrBool = True,
                 prompt: AnyFormattedText = '',
                 input_processors: Optional[List[Processor]] = None) -> None:

        if search_field is None:
            search_control = None
        elif isinstance(search_field, SearchToolbar):
            search_control = search_field.control

        if input_processors is None:
            input_processors = []

        # Writeable attributes.
        self.completer = completer
        self.complete_while_typing = complete_while_typing
        self.lexer = lexer
        self.auto_suggest = auto_suggest
        self.read_only = read_only
        self.wrap_lines = wrap_lines

        self.buffer = Buffer(
            document=Document(text, 0),
            multiline=multiline,
            read_only=Condition(lambda: is_true(self.read_only)),
            completer=DynamicCompleter(lambda: self.completer),
            complete_while_typing=Condition(
                lambda: is_true(self.complete_while_typing)),
            auto_suggest=DynamicAutoSuggest(lambda: self.auto_suggest),
            accept_handler=accept_handler,
            history=history)

        self.control = BufferControl(
            buffer=self.buffer,
            lexer=DynamicLexer(lambda: self.lexer),
            input_processors=[
                ConditionalProcessor(AppendAutoSuggestion(),
                                     has_focus(self.buffer) & ~is_done),
                ConditionalProcessor(processor=PasswordProcessor(),
                                     filter=to_filter(password)),
                BeforeInput(prompt, style='class:text-area.prompt'),
            ] + input_processors,
            search_buffer_control=search_control,
            preview_search=preview_search,
            focusable=focusable,
            focus_on_click=focus_on_click)

        if multiline:
            if scrollbar:
                right_margins = [ScrollbarMargin(display_arrows=True)]
            else:
                right_margins = []
            if line_numbers:
                left_margins = [NumberedMargin()]
            else:
                left_margins = []
        else:
            height = D.exact(1)
            left_margins = []
            right_margins = []

        style = 'class:text-area ' + style

        self.window = Window(
            height=height,
            width=width,
            dont_extend_height=dont_extend_height,
            dont_extend_width=dont_extend_width,
            content=self.control,
            style=style,
            wrap_lines=Condition(lambda: is_true(self.wrap_lines)),
            left_margins=left_margins,
            right_margins=right_margins,
            get_line_prefix=get_line_prefix)

    @property
    def text(self) -> str:
        """
        The `Buffer` text.
        """
        return self.buffer.text

    @text.setter
    def text(self, value: str) -> None:
        self.buffer.set_document(Document(value, 0), bypass_readonly=True)

    @property
    def document(self) -> Document:
        """
        The `Buffer` document (text + cursor position).
        """
        return self.buffer.document

    @document.setter
    def document(self, value: Document) -> None:
        self.buffer.document = value

    @property
    def accept_handler(self) -> Optional[BufferAcceptHandler]:
        """
        The accept handler. Called when the user accepts the input.
        """
        return self.buffer.accept_handler

    @accept_handler.setter
    def accept_handler(self, value: BufferAcceptHandler) -> None:
        self.buffer.accept_handler = value

    def __pt_container__(self) -> Container:
        return self.window
Exemplo n.º 20
0
def test_yank_nth_arg_with_arg(_history):
    buff = Buffer(history=_history)
    buff.yank_nth_arg(n=2)
    assert buff.document.current_line == 'three'
Exemplo n.º 21
0
def _buffer():
    buff = Buffer()
    return buff
Exemplo n.º 22
0
from prompt_toolkit_dev.application import Application
from prompt_toolkit_dev.buffer import Buffer
from prompt_toolkit_dev.key_binding import KeyBindings
from prompt_toolkit_dev.layout.containers import (
    HSplit,
    VSplit,
    Window,
    WindowAlign,
)
from prompt_toolkit_dev.layout.controls import BufferControl, FormattedTextControl
from prompt_toolkit_dev.layout.layout import Layout

# 3. Create the buffers
#    ------------------

left_buffer = Buffer()
right_buffer = Buffer()

# 1. First we create the layout
#    --------------------------

left_window = Window(BufferControl(buffer=left_buffer))
right_window = Window(BufferControl(buffer=right_buffer))


body = VSplit([
    left_window,

    # A vertical line in the middle. We explicitly specify the width, to make
    # sure that the layout engine will not try to divide the whole width by
    # three for all these windows.