Пример #1
0
 def comp_height(cli):
     # If there is an autocompletion menu to be shown, make sure that o
     # layout has at least a minimal height in order to display it.
     if not cli.is_done:
         return LayoutDimension(min=size)
     else:
         return LayoutDimension()
Пример #2
0
 def get_height(cli):
     # If there is an autocompletion menu to be shown, make sure that our
     # layout has at least a minimal height in order to display it.
     if reserve_space_for_menu and not cli.is_done:
         return LayoutDimension(min=reserve_space_for_menu)
     else:
         return LayoutDimension()
Пример #3
0
    def get_height(cli):
        # If there is an autocompletion menu to be shown, make sure that our
        # layout has at least a minimal height in order to display it.
        if reserve_space_for_menu and not cli.is_done:
            buff = cli.current_buffer

            # Reserve the space, either when there are completions, or when
            # `complete_while_typing` is true and we expect completions very
            # soon.
            if buff.complete_while_typing() or buff.complete_state is not None:
                return LayoutDimension(min=reserve_space_for_menu)

        return LayoutDimension()
Пример #4
0
def python_sidebar_help(python_input):
    """
    Create the `Layout` for the help text for the current item in the sidebar.
    """
    token = Token.Sidebar.HelpText

    def get_current_description():
        """
        Return the description of the selected option.
        """
        i = 0
        for category in python_input.options:
            for option in category.options:
                if i == python_input.selected_option_index:
                    return option.description
                i += 1
        return ''

    def get_tokens(cli):
        return [(token, get_current_description())]

    return ConditionalContainer(
        content=Window(TokenListControl(get_tokens, Char(token=token)),
                       height=LayoutDimension(min=3)),
        filter=ShowSidebar(python_input)
        & Condition(lambda cli: python_input.show_sidebar_help) & ~IsDone())
Пример #5
0
    def _get_height_dimension(self) -> LayoutDimension:
        """Retrieve the height dimension dynamically.

        Returns:
            :class:`prompt_toolkit.layout.Dimension` instance.
        """
        return LayoutDimension(preferred=self._get_height() + 1)
Пример #6
0
def python_sidebar(python_input):
    """
    Create the `Layout` for the sidebar with the configurable options.
    """
    def get_tokens(cli):
        tokens = []
        T = Token.Sidebar

        def append_category(category):
            tokens.extend([
                (T, '  '),
                (T.Title, '   %-36s' % category.title),
                (T, '\n'),
            ])

        def append(selected, label, status):
            token = T.Selected if selected else T

            tokens.append((T, ' >' if selected else '  '))
            tokens.append((token.Label, '%-24s' % label))
            tokens.append((token.Status, ' '))
            tokens.append((token.Status, '%s' % status))

            if selected:
                tokens.append((Token.SetCursorPosition, ''))

            tokens.append((token.Status, ' ' * (14 - len(status))))
            tokens.append((T, '<' if selected else ''))
            tokens.append((T, '\n'))

        i = 0
        for category in python_input.options:
            append_category(category)

            for option in category.options:
                append(i == python_input.selected_option_index,
                       option.title, '%s' % option.get_current_value())
                i += 1

        tokens.pop()  # Remove last newline.

        return tokens

    class Control(TokenListControl):
        def move_cursor_down(self, cli):
            python_input.selected_option_index += 1

        def move_cursor_up(self, cli):
            python_input.selected_option_index -= 1

    return ConditionalContainer(
        content=Window(
            Control(get_tokens, Char(token=Token.Sidebar),
                has_focus=ShowSidebar(python_input) & ~IsDone()),
            width=LayoutDimension.exact(43),
            height=LayoutDimension(min=3),
            scroll_offsets=ScrollOffsets(top=1, bottom=1)),
        filter=ShowSidebar(python_input) & ~IsDone())
Пример #7
0
    def _get_width_dimension(self) -> LayoutDimension:
        """Retrieve the width dimension dynamically.

        Returns:
            :class:`prompt_toolkit.layout.Dimension` instance.
        """
        width, _ = get_dimension(offset=self._dimension_offset +
                                 (self._padding * 2))
        if self._vertical_mode():
            if self._id == Pane.left:
                width = math.ceil((width - (self._padding * 2)) / 2)
            elif self._id == Pane.right:
                width = math.floor((width - (self._padding * 2)) / 2)
        self._width = width
        return LayoutDimension(preferred=width)
Пример #8
0
 def _factory():
     return [
         window_class(
             control,
             height=LayoutDimension(max=page_size),
             dont_extend_height=True,
             wrap_lines=True,
         ),
         ConditionalContainer(
             Window(
                 TokenListControl(_get_default_pager_tokens),
                 dont_extend_height=True,
                 wrap_lines=True,
             ),
             filter=NeedsScrollTip(page_size) & ~IsDone(),
         ),
     ]
Пример #9
0
def get_height(cli):
    """ gets the height of the cli """
    if not cli.is_done:
        return LayoutDimension(min=8)
    return None
Пример #10
0
def create_default_layout(app,
                          message='',
                          lexer=None,
                          is_password=False,
                          reserve_space_for_menu=False,
                          get_prompt_tokens=None,
                          get_bottom_toolbar_tokens=None,
                          display_completions_in_columns=False,
                          extra_input_processors=None,
                          multiline=False):
    """
    Generate default layout.

    Returns a ``Layout`` instance.

    :param message: Text to be used as prompt.
    :param lexer: Lexer to be used for the highlighting.
    :param is_password: `bool` or `CLIFilter`. When True, display input as '*'.
    :param reserve_space_for_menu: When True, make sure that a minimal height
        is allocated in the terminal, in order to display the completion menu.
    :param get_prompt_tokens: An optional callable that returns the tokens to
        be shown in the menu. (To be used instead of a `message`.)
    :param get_bottom_toolbar_tokens: An optional callable that returns the
        tokens for a toolbar at the bottom.
    :param display_completions_in_columns: `bool` or `CLIFilter`. Display the
        completions in multiple columns.
    :param multiline: `bool` or `CLIFilter`. When True, prefer a layout that is
        more adapted for multiline input. Text after newlines is automatically
        indented, and search/arg input is shown below the input, instead of
        replacing the prompt.
    """
    assert isinstance(message, text_type)
    assert (get_bottom_toolbar_tokens is None
            or callable(get_bottom_toolbar_tokens))
    assert get_prompt_tokens is None or callable(get_prompt_tokens)
    assert not (message and get_prompt_tokens)

    display_completions_in_columns = to_cli_filter(
        display_completions_in_columns)
    multiline = to_cli_filter(multiline)

    if get_prompt_tokens is None:
        get_prompt_tokens = lambda _: [(Token.Prompt, message)]

    get_prompt_tokens_1, get_prompt_tokens_2 = _split_multiline_prompt(
        get_prompt_tokens)

    # `lexer` is supposed to be a `Lexer` instance. But if a Pygments lexer
    # class is given, turn it into a PygmentsLexer. (Important for
    # backwards-compatibility.)
    try:
        if issubclass(lexer, Lexer):
            lexer = PygmentsLexer(lexer)
    except TypeError:
        # Happens when lexer is `None` or an instance of something else.
        pass

    # Create processors list.
    # (DefaultPrompt should always be at the end.)
    input_processors = [
        ConditionalProcessor(
            # By default, only highlight search when the search
            # input has the focus. (Note that this doesn't mean
            # there is no search: the Vi 'n' binding for instance
            # still allows to jump to the next match in
            # navigation mode.)
            HighlightSearchProcessor(preview_search=Always()),
            HasFocus(SEARCH_BUFFER)),
        HighlightSelectionProcessor(),
        ConditionalProcessor(AppendAutoSuggestion(),
                             HasFocus(DEFAULT_BUFFER) & ~IsDone()),
        ConditionalProcessor(PasswordProcessor(), is_password)
    ]

    if extra_input_processors:
        input_processors.extend(extra_input_processors)

    # Show the prompt before the input (using the DefaultPrompt processor.
    # This also replaces it with reverse-i-search and 'arg' when required.
    # (Only for single line mode.)
    input_processors.append(
        ConditionalProcessor(DefaultPrompt(get_prompt_tokens), ~multiline))

    # Create bottom toolbar.
    if get_bottom_toolbar_tokens:
        toolbars = [
            ConditionalContainer(Window(TokenListControl(
                get_bottom_toolbar_tokens,
                default_char=Char(' ', Token.Toolbar)),
                                        height=LayoutDimension.exact(1)),
                                 filter=~IsDone() & RendererHeightIsKnown())
        ]
    else:
        toolbars = []

    def get_height(cli):
        # If there is an autocompletion menu to be shown, make sure that our
        # layout has at least a minimal height in order to display it.
        if reserve_space_for_menu and not cli.is_done:
            return LayoutDimension(min=8)
        else:
            return LayoutDimension()

    def separator():
        return ConditionalContainer(content=Window(
            height=LayoutDimension.exact(1),
            content=FillControl(u'\u2500', token=Token.Separator)),
                                    filter=HasDocumentation(app) & ~IsDone())

    # Create and return Layout instance.
    return HSplit([
        ConditionalContainer(
            Window(TokenListControl(get_prompt_tokens_1),
                   dont_extend_height=True),
            filter=multiline,
        ),
        VSplit([
            # In multiline mode, the prompt is displayed in a left pane.
            ConditionalContainer(
                Window(
                    TokenListControl(get_prompt_tokens_2),
                    dont_extend_width=True,
                ),
                filter=multiline,
            ),
            # The main input, with completion menus floating on top of it.
            FloatContainer(
                Window(
                    BufferControl(
                        input_processors=input_processors,
                        lexer=lexer,
                        # Enable preview_search, we want to have immediate
                        # feedback in reverse-i-search mode.
                        preview_search=Always(),
                        focus_on_click=True,
                    ),
                    get_height=get_height,
                ),
                [
                    Float(xcursor=True,
                          ycursor=True,
                          content=CompletionsMenu(
                              max_height=16,
                              scroll_offset=1,
                              extra_filter=(HasFocus(DEFAULT_BUFFER)
                                            & ~display_completions_in_columns
                                            ))),  # noqa E501
                    Float(xcursor=True,
                          ycursor=True,
                          content=MultiColumnCompletionsMenu(
                              extra_filter=(HasFocus(DEFAULT_BUFFER)
                                            & display_completions_in_columns),
                              show_meta=Always()))
                ]),
        ]),
        separator(),
        ConditionalContainer(
            content=Window(BufferControl(
                focus_on_click=True,
                buffer_name=u'clidocs',
            ),
                           height=LayoutDimension(max=15)),
            filter=HasDocumentation(app) & ~IsDone(),
        ),
        separator(),
        ValidationToolbar(),
        SystemToolbar(),

        # In multiline mode, we use two toolbars for 'arg' and 'search'.
        ConditionalContainer(ArgToolbar(), multiline),
        ConditionalContainer(SearchToolbar(), multiline),
    ] + toolbars)
Пример #11
0
    def __init__(self):
        pdb.Pdb.__init__(self)

        # Cache for the grammar.
        self._grammar_cache = None  # (current_pdb_commands, grammar) tuple.

        self.completer = None
        self.validator = None
        self.lexer = None

        self._source_code_window = Window(BufferControl(
            buffer_name='source_code',
            lexer=PygmentsLexer(PythonLexer),
            input_processors=[
                HighlightSearchProcessor(preview_search=True),
                HighlightSelectionProcessor(),
            ],
        ),
                                          left_margins=[
                                              SourceCodeMargin(self),
                                              NumberredMargin(),
                                          ],
                                          right_margins=[ScrollbarMargin()],
                                          scroll_offsets=ScrollOffsets(
                                              top=2, bottom=2),
                                          height=LayoutDimension(preferred=10))

        # Callstack window.
        callstack = CallStack(weakref.ref(self))
        self.callstack_focussed = False  # When True, show cursor there, and allow navigation through it.
        self.callstack_selected_frame = 0  # Top frame.

        show_pdb_content_filter = ~IsDone() & Condition(
            lambda cli: not self.python_input.show_exit_confirmation)

        self.python_input = PythonInput(
            get_locals=lambda: self.curframe.f_locals,
            get_globals=lambda: self.curframe.f_globals,
            _completer=DynamicCompleter(lambda: self.completer),
            _validator=DynamicValidator(lambda: self.validator),
            _accept_action=self._create_accept_action(),
            _extra_buffers={'source_code': Buffer(read_only=True)},
            _input_buffer_height=LayoutDimension(min=2, max=4),
            _lexer=PdbLexer(),
            _extra_buffer_processors=[
                ConditionalProcessor(processor=CompletionHint(),
                                     filter=~IsDone())
            ],
            _extra_layout_body=ConditionalContainer(
                HSplit([
                    VSplit([
                        HSplit([
                            SourceTitlebar(weakref.ref(self)),
                            FloatContainer(
                                content=self._source_code_window,
                                floats=[
                                    Float(right=0,
                                          bottom=0,
                                          content=BreakPointInfoToolbar(
                                              weakref.ref(self)))
                                ]),
                        ]),
                        HSplit([
                            Window(width=LayoutDimension.exact(1),
                                   height=LayoutDimension.exact(1),
                                   content=FillControl(
                                       '\u252c', token=Token.Toolbar.Title)),
                            Window(width=LayoutDimension.exact(1),
                                   content=FillControl('\u2502',
                                                       token=Token.Separator)),
                        ]),
                        HSplit([
                            StackTitlebar(weakref.ref(self)),
                            Window(callstack,
                                   scroll_offsets=ScrollOffsets(top=2,
                                                                bottom=2),
                                   right_margins=[ScrollbarMargin()],
                                   height=LayoutDimension(preferred=10)),
                        ]),
                    ]),
                ]),
                filter=show_pdb_content_filter),
            _extra_toolbars=[
                ConditionalContainer(PdbShortcutsToolbar(weakref.ref(self)),
                                     show_pdb_content_filter)
            ],
            history_filename=os.path.expanduser('~/.ptpdb_history'),
        )

        # Override prompt style.
        self.python_input.all_prompt_styles['pdb'] = PdbPromptStyle(
            self._get_current_pdb_commands())
        self.python_input.prompt_style = 'pdb'

        # Override exit message.
        self.python_input.exit_message = 'Do you want to quit BDB? This raises BdbQuit.'

        # Set UI styles.
        self.python_input.ui_styles = {
            'ptpdb': get_ui_style(),
        }
        self.python_input.use_ui_colorscheme('ptpdb')

        # Set autocompletion style. (Multi-column works nicer.)
        self.python_input.completion_visualisation = CompletionVisualisation.MULTI_COLUMN

        # Load additional key bindings.
        load_custom_pdb_key_bindings(self,
                                     self.python_input.key_bindings_registry)

        self.cli = CommandLineInterface(
            eventloop=create_eventloop(),
            application=self.python_input.create_application())
Пример #12
0
 def preferred_height(self, cli, width, max_available_height):
     return LayoutDimension()
Пример #13
0
 def preferred_width(self, cli, max_available_width):
     return LayoutDimension()
Пример #14
0
def CreatePromptLayout(message='',
                       lexer=None,
                       is_password=False,
                       reserve_space_for_menu=5,
                       get_prompt_tokens=None,
                       get_continuation_tokens=None,
                       get_bottom_toolbar_tokens=None,
                       display_completions_in_columns=False,
                       extra_input_processors=None,
                       multiline=False,
                       wrap_lines=True,
                       get_help_tokens=None,
                       show_help=True):
  """Create a container instance for the prompt."""
  assert isinstance(message, unicode), 'Please provide a unicode string.'
  assert get_bottom_toolbar_tokens is None or callable(
      get_bottom_toolbar_tokens)
  assert get_prompt_tokens is None or callable(get_prompt_tokens)
  assert not (message and get_prompt_tokens)

  display_completions_in_columns = filters.to_cli_filter(
      display_completions_in_columns)
  multiline = filters.to_cli_filter(multiline)

  if get_prompt_tokens is None:
    get_prompt_tokens = lambda _: [(Token.Prompt, message)]

  has_before_tokens, get_prompt_tokens_1, get_prompt_tokens_2 = (
      shortcuts._split_multiline_prompt(get_prompt_tokens))  # pylint: disable=protected-access
  # TODO(b/35347840): reimplement _split_multiline_prompt to remove
  #                   protected-access.

  # Create processors list.
  input_processors = [
      processors.ConditionalProcessor(
          # By default, only highlight search when the search
          # input has the focus. (Note that this doesn't mean
          # there is no search: the Vi 'n' binding for instance
          # still allows to jump to the next match in
          # navigation mode.)
          processors.HighlightSearchProcessor(preview_search=True),
          filters.HasFocus(enums.SEARCH_BUFFER)),
      processors.HighlightSelectionProcessor(),
      processors.ConditionalProcessor(processors.AppendAutoSuggestion(),
                                      filters.HasFocus(enums.DEFAULT_BUFFER)
                                      & ~filters.IsDone()),
      processors.ConditionalProcessor(processors.PasswordProcessor(),
                                      is_password),
  ]

  if extra_input_processors:
    input_processors.extend(extra_input_processors)

  # Show the prompt before the input (using the DefaultPrompt processor.
  # This also replaces it with reverse-i-search and 'arg' when required.
  # (Only for single line mode.)
  # (DefaultPrompt should always be at the end of the processors.)
  input_processors.append(
      processors.ConditionalProcessor(
          DefaultPrompt(get_prompt_tokens_2), ~multiline))

  # Create toolbars
  toolbars = []
  if get_help_tokens:
    toolbars.append(
        containers.ConditionalContainer(
            layout.HSplit([
                layout.Window(
                    controls.FillControl(char=Char('-', Token.HSep)),
                    height=LayoutDimension.exact(1)),
                layout.Window(
                    controls.TokenListControl(
                        get_help_tokens,
                        default_char=Char(' ', Token.Toolbar)),
                    height=LayoutDimension(preferred=10, max=10)),
            ]),
            filter=(show_help & UserTypingFilter & ~filters.IsDone() &
                    filters.RendererHeightIsKnown())))
  if get_bottom_toolbar_tokens:
    toolbars.append(
        containers.ConditionalContainer(
            layout.HSplit([
                layout.Window(
                    controls.FillControl(char=Char('-', Token.HSep)),
                    height=LayoutDimension.exact(1)),
                layout.Window(
                    controls.TokenListControl(
                        get_bottom_toolbar_tokens,
                        default_char=Char(' ', Token.Toolbar)),
                    height=LayoutDimension.exact(1)),
            ]),
            filter=~filters.IsDone() & filters.RendererHeightIsKnown()))

  def GetHeight(cli):
    """Determine the height for the input buffer."""
    # If there is an autocompletion menu to be shown, make sure that our
    # layout has at least a minimal height in order to display it.
    if reserve_space_for_menu and not cli.is_done:
      buff = cli.current_buffer

      # Reserve the space, either when there are completions, or when
      # `complete_while_typing` is true and we expect completions very
      # soon.
      if UserTypingFilter(cli) or buff.complete_state is not None:
        return LayoutDimension(min=reserve_space_for_menu)

    return LayoutDimension()

  # Create and return Container instance.
  return layout.HSplit([
      # The main input, with completion menus floating on top of it.
      containers.FloatContainer(
          layout.HSplit([
              containers.ConditionalContainer(
                  layout.Window(
                      controls.TokenListControl(get_prompt_tokens_1),
                      dont_extend_height=True),
                  filters.Condition(has_before_tokens)),
              layout.Window(
                  controls.BufferControl(
                      input_processors=input_processors,
                      lexer=lexer,
                      # Enable preview_search, we want to have immediate
                      # feedback in reverse-i-search mode.
                      preview_search=True),
                  get_height=GetHeight,
                  left_margins=[
                      # In multiline mode, use the window margin to display
                      # the prompt and continuation tokens.
                      margins.ConditionalMargin(
                          margins.PromptMargin(get_prompt_tokens_2,
                                               get_continuation_tokens),
                          filter=multiline)
                  ],
                  wrap_lines=wrap_lines,),
          ]),
          [
              # Completion menus.
              layout.Float(
                  xcursor=True,
                  ycursor=True,
                  content=menus.CompletionsMenu(
                      max_height=16,
                      scroll_offset=1,
                      extra_filter=filters.HasFocus(enums.DEFAULT_BUFFER) &
                      ~display_completions_in_columns)),
              layout.Float(
                  xcursor=True,
                  ycursor=True,
                  content=menus.MultiColumnCompletionsMenu(
                      extra_filter=filters.HasFocus(enums.DEFAULT_BUFFER) &
                      display_completions_in_columns,
                      show_meta=True)),
          ]),
      pt_toolbars.ValidationToolbar(),
      pt_toolbars.SystemToolbar(),

      # In multiline mode, we use two toolbars for 'arg' and 'search'.
      containers.ConditionalContainer(pt_toolbars.ArgToolbar(), multiline),
      containers.ConditionalContainer(pt_toolbars.SearchToolbar(), multiline),
  ] + toolbars)
Пример #15
0
def setup_app(gdb):
    def codeview_line_prefix(line_number, wrap_count):
        try:
            if False: pass
            elif line_number + 1 == get_app().my.gdb.lineno:
                return [('class:text-area.pfx,selected', '>')]
            elif get_app().my.gdb.sourcefile in get_app(
            ).my.gdb.breakpoints and line_number + 1 in get_app(
            ).my.gdb.breakpoints[get_app().my.gdb.sourcefile]:
                return [('class:text-area.pfx.bp', 'o')]
        except:
            pass
        return [('class:text-area.pfx', ' ')]

    controls = {}

    controls['header'] = Label(
        text=u'',
        style=u'class:header_label',
    )
    controls['codeview'] = TextArea(
        text=u'',
        read_only=True,
        scrollbar=True,
        line_numbers=True,
        wrap_lines=True,
        get_line_prefix=codeview_line_prefix,
        lexer=PygmentsLexer(CLexer),
        style=u'class:codeview',
        focusable=True,
        focus_on_click=True,
    )
    controls['gdbout'] = TextArea(
        text=u'',
        read_only=True,
        scrollbar=True,
        wrap_lines=True,
        style=u'class:gdbout',
        height=LayoutDimension(4, 16, preferred=8),
        focusable=True,
        focus_on_click=True,
    )
    controls['inferiorout'] = TextArea(
        text=u'',
        read_only=True,
        scrollbar=True,
        wrap_lines=False,
        style=u'class:inferiorout',
        height=LayoutDimension(1, 16, preferred=1),
        focusable=True,
        focus_on_click=True,
    )
    controls['locals'] = sidebar('locals', lambda: get_app().my.locals)
    controls['exprs'] = sidebar('exprs', lambda: get_app().my.exprs)
    controls['args'] = sidebar('args', lambda: get_app().my.args)
    controls['input_label'] = Label(
        text=u'(gdb) ',
        style=u'class:input_label',
        width=LayoutDimension.exact(6),
    )
    controls['input'] = Window(
        content=BufferControl(
            buffer=Buffer(
                read_only=False,
                multiline=False,
                history=InMemoryHistory(),
            ),
            focusable=True,
            focus_on_click=True,
        ),
        height=LayoutDimension.exact(1),
        dont_extend_height=True,
        style=u'class:input',
    )
    controls['vardetails'] = TextArea(
        height=LayoutDimension(1, 4),
        wrap_lines=True,
        read_only=True,
        style=u'class:vardetails',
    )

    def up_():
        val = get_app().my.locals.get_value_by_index( \
         get_app().my.controls['locals'].selected_option_index)
        text = get_app().my.controls['vardetails'].text
        if val is None and text != '':
            get_app().my.controls['vardetails'].text = '<out of scope>'
        elif text != '':
            get_app().my.controls['vardetails'].text = val[1]

    controls['vardetails'].update = up_

    def need_vardetails():
        return get_app().my.controls['vardetails'].text != ''

    controls['sidebar'] = HSplit([
        controls['exprs'],
        controls['args'],
        controls['locals'],
    ])
    controls['sidebar']._remaining_space_window.style = 'class:sidebar'

    controls['root_container'] = HSplit([
        controls['header'],
        ConditionalContainer(controls['vardetails'],
                             Condition(need_vardetails)),
        VSplit([
            HSplit([
                controls['codeview'],
                controls['inferiorout'],
                controls['gdbout'],
                VSplit([
                    controls['input_label'],
                    controls['input'],
                ]),
            ]),
            controls['sidebar'],
        ]),
    ])

    def do_exit():
        get_app().exit(result=True)

    def do_cont():
        run_gdb_cmd(get_app(), 'c')

    def do_step_into():
        run_gdb_cmd(get_app(), 's')

    def do_step_over():
        run_gdb_cmd(get_app(), 'n')

    def do_set_bp():
        if get_app().my.focused_control == 'codeview':
            c = get_app().my.controls['codeview']
            line, col = c.document.translate_index_to_position(
                c.document.cursor_position)
            line += 1
            run_gdb_cmd(get_app(),
                        'b %s:%d' % (get_app().my.gdb.sourcefile, line))

    def do_toggle_prompt():
        get_app().my.input_gdb = not get_app().my.input_gdb
        get_app().my.controls['input_label'].text = '(gdb) ' if get_app(
        ).my.input_gdb else '>>> '

    def do_toggle_mouse():
        # we need to have the ability to turn mouse off to use the X11
        # clipboard (selection needs to be handled by X11, not the app)
        get_app().my.mouse_enabled = not get_app().my.mouse_enabled

    controls['root_container'] = MenuContainer(
        body=controls['root_container'],
        menu_items=[
            MenuItem('File',
                     children=[
                         MenuItem('Load config', handler=load_config),
                         MenuItem('Save config', handler=save_config),
                         MenuItem('-', disabled=True),
                         MenuItem('Exit', handler=do_exit),
                     ]),
            MenuItem('Debug',
                     children=[
                         MenuItem('Continue  (F5)', handler=do_cont),
                         MenuItem('Step Into (F7)', handler=do_step_into),
                         MenuItem('Step Over (F8)', handler=do_step_over),
                         MenuItem('Set Breakpoint (CTRL-b)',
                                  handler=do_set_bp),
                     ]),
            MenuItem('Extra',
                     children=[
                         MenuItem('Toggle python prompt  (F1)',
                                  handler=do_toggle_prompt),
                         MenuItem('Toggle mouse support  (F2)',
                                  handler=do_toggle_mouse),
                     ]),
        ],
        floats=[])

    kb = KeyBindings()

    @kb.add(u'escape', 'f')
    def _focus_menu(event):
        get_app().layout.focus(get_app().my.controls['root_container'].window)

    @kb.add(u'c-q')
    def exit_(event):
        do_exit()

    @kb.add(u'f1')
    def eff_one_(event):
        do_toggle_prompt()

    @kb.add(u'enter')
    def enter_(event):
        def add_expr(name, expr):
            get_app().my.exprs_dict[name] = expr

        def del_expr(name):
            if name in get_app().my.exprs_dict:
                del get_app().my.exprs_dict[name]

        if event.app.my.focused_control != 'input':
            event.app.my.set_focus('input')
            return
        text = event.app.my.controls['input'].content.buffer.text
        if len(text) and text[0] == ':':
            # direct command
            command, rest = text.split(' ', 1)
            if command == ':expr':
                command, rest = rest.split(' ', 1)
                if command == 'add':
                    name, expr = rest.split(' ', 1)
                    add_expr(name, expr)
                elif command == 'del':
                    del_expr(rest)
        elif event.app.my.input_gdb:
            cmd = text
            if not len(cmd): cmd = event.app.my.last_gdb_cmd
            else: event.app.my.last_gdb_cmd = cmd
            run_gdb_cmd(event.app, cmd)
            if text == 'q':
                event.app.exit()
        else:
            try:
                app.my.console.runsource(text)
            except Exception as e:
                import traceback
                add_gdbview_text(event.app, traceback.format_exc())
        event.app.my.controls['input'].content.buffer.reset(
            append_to_history=True)

    @kb.add(u'tab')
    def enter_(event):
        for i in xrange(len(event.app.my.focus_list)):
            if event.app.my.focus_list[i] == event.app.my.focused_control:
                next_focus = i + 1
                if next_focus >= len(event.app.my.focus_list):
                    next_focus = 0
                event.app.my.set_focus(event.app.my.focus_list[next_focus])
                break

    @kb.add(u'c-b')
    def cb_(event):
        do_set_bp()

    @kb.add(u'f5')
    def eff_five_(event):
        do_cont()

    @kb.add(u'f7')
    def _(event):
        do_step_into()

    @kb.add(u'f8')
    def _(event):
        do_step_over()

    @kb.add(u'f2')
    def _(event):
        do_toggle_mouse()

    styledict = {
        'gdbout': 'bg:#000000 #888888',
        'inferiorout': 'bg:#330000 #888888',
        'input': 'bg:#000000 #8888ff underline',
        'input_label': 'bg:#000000 #8888ff underline',
        'header_label': 'bg:#9999ff #000000 underline',
        'vardetails': 'bg:#000000 #8888ff',
        'text-area.pfx': 'bg:#aaaaaa #ff0000',
        'text-area.pfx.selected': 'bg:#ff0000 #ffffff',
        'sidebar': 'bg:#bbbbbb #000000',
        'sidebar.title': 'bg:#668866 #ffffff',
        'sidebar.title focused': 'bg:#000000 #ffffff bold',
        'sidebar.label': 'bg:#bbbbbb #222222',
        'sidebar.status': 'bg:#dddddd #000011',
        'sidebar.labelodd': 'bg:#bbbb00 #222222',
        'sidebar.statusodd': 'bg:#dddd00 #000011',
        'sidebar.label selected': 'bg:#222222 #eeeeee',
        'sidebar.status selected': 'bg:#444444 #ffffff bold',
        'sidebar.status changed': 'bg:#dddddd #ff0000 bold',
        'sidebar.statusodd changed': 'bg:#dddd00 #ff0000 bold',
    }

    pyg_style = style_from_pygments_cls(CodeviewStyle)

    style = merge_styles([
        Style.from_dict(styledict),
        pyg_style,
    ])

    @Condition
    def _is_mouse_active():
        return get_app().my.mouse_enabled

    app = Application(
        layout=Layout(
            controls['root_container'],
            focused_element=controls['input'],
        ),
        style=style,
        full_screen=True,
        key_bindings=merge_key_bindings([
            kb,
            load_sidebar_bindings('locals'),
            load_inputbar_bindings(),
        ]),
        mouse_support=_is_mouse_active,
    )

    class My():
        pass

    app.my = My()
    app.my.saved_config = {}
    app.my.mouse_enabled = True
    app.my.controls = controls
    app.my.control_to_name_mapping = {}
    for name in controls:
        app.my.control_to_name_mapping[controls[name]] = name
        if isinstance(controls[name], TextArea) or 'control' in vars(
                controls[name]):
            app.my.control_to_name_mapping[controls[name].control] = name
        elif 'content' in vars(controls[name]):
            app.my.control_to_name_mapping[controls[name].content] = name

    app.my.locals = OrderedDict()
    app.my.args = OrderedDict()
    app.my.exprs = OrderedDict()
    app.my.exprs_dict = dict()
    app.my.gdb = gdb
    app.my.last_gdb_cmd = ''
    app.my.input_gdb = True
    app.my.focus_list = [
        'input', 'codeview', 'inferiorout', 'gdbout', 'args', 'locals', 'exprs'
    ]
    app.my.focused_control = 'input'

    def _set_focus(ctrl_or_name):
        if isinstance(ctrl_or_name, six.text_type):
            ctrl = get_app().my.controls[ctrl_or_name]
            name = ctrl_or_name
        else:
            ctrl = ctrl_or_name
            name = get_app().my.control_to_name_mapping[ctrl]
        get_app().layout.focus(ctrl)
        get_app().my.focused_control = name

    app.my.set_focus = _set_focus

    def _has_focus(ctrl_or_name):
        ctrl = get_app().my.controls[ctrl_or_name] if isinstance(
            ctrl_or_name, str) else ctrl_or_name
        return get_app().layout.has_focus(ctrl)

    app.my.has_focus = _has_focus
    app_console_writefunc = lambda x: add_gdbview_text(get_app(), x)
    app.my.console = py_console.Shell(locals=globals(),
                                      writefunc=app_console_writefunc)

    def my_mouse_handler(self, mouse_event):
        # loosely based on prompt_toolkit/layout/controls.py:716
        #if self.focus_on_click() and mouse_event.event_type == MouseEventType.MOUSE_DOWN:
        if mouse_event.event_type == MouseEventType.MOUSE_DOWN:
            get_app().my.set_focus(self)
            processed_line = self._last_get_processed_line(
                mouse_event.position.y)
            xpos = processed_line.display_to_source(mouse_event.position.x)
            index = self.buffer.document.translate_row_col_to_index(
                mouse_event.position.y, xpos)
            self.buffer.cursor_position = index
        else:
            return NotImplemented

    for x in app.my.focus_list:
        if isinstance(app.my.controls[x], Window) and isinstance(
                app.my.controls[x].content, SidebarControl):
            continue  #don't override custom mouse handler
        if isinstance(app.my.controls[x], TextArea):
            app.my.controls[
                x].control.mouse_handler = my_mouse_handler.__get__(
                    app.my.controls[x].control)
        else:
            app.my.controls[
                x].content.mouse_handler = my_mouse_handler.__get__(
                    app.my.controls[x].content)

    return app