def __init__(self, inpipe): self.inpipe = inpipe self.tempfile = tempfile.NamedTemporaryFile(mode="w", delete=True) self.initialize_nodes() root = VSplit( [ # Input buffer and status line HSplit( [ self.first_line, Window( content=BufferControl( buffer=self.input_buffer, # This lexer is disabled for now because # I don't want to mess with colourschemes # lexer=PygmentsLexer(PythonLexer), ) ), self.error_output, ], width=Dimension(), ), Window(width=1, char="|"), # Output display area Window(ignore_content_width=True, content=self.output, wrap_lines=True), ], width=Dimension(), ) layout = Layout(root) self.app = Application(layout=layout, key_bindings=kb, full_screen=True)
def setup_logging_containers(repl): j = KosmosShellConfig.j panel_line_count = j.core.myenv.config.get("LOGGER_PANEL_NRLINES", 12) parent_container = get_ptpython_parent_container(repl) parent_container.children.extend( [ ConditionalContainer( content=Window(height=Dimension.exact(1), char="\u2500", style="class:separator"), filter=HasLogs(repl) & ~is_done, ), ConditionalContainer( content=Window( BufferControl( buffer=LogPane.Buffer, input_processors=[FormatANSIText(), HighlightIncrementalSearchProcessor()], focusable=False, preview_search=True, ), wrap_lines=True, height=Dimension.exact(panel_line_count), ), filter=HasLogs(repl) & ~is_done, ), ] )
def show_sidebar_button_info(python_input): """ Create `Layout` for the information in the right-bottom corner. (The right part of the status bar.) """ @if_mousedown def toggle_sidebar(mouse_event): " Click handler for the menu. " python_input.show_sidebar = not python_input.show_sidebar version = sys.version_info tokens = [ ('class:status-toolbar.key', '[F2]', toggle_sidebar), ('class:status-toolbar', ' Menu', toggle_sidebar), ('class:status-toolbar', ' - '), ('class:status-toolbar.python-version', '%s %i.%i.%i' % (platform.python_implementation(), version[0], version[1], version[2])), ('class:status-toolbar', ' '), ] width = fragment_list_width(tokens) def get_text_fragments(): # Python version return tokens return ConditionalContainer( content=Window( FormattedTextControl(get_text_fragments), style='class:status-toolbar', height=Dimension.exact(1), width=Dimension.exact(width)), filter=~is_done & renderer_height_is_known & Condition(lambda: python_input.show_status_bar and not python_input.show_exit_confirmation))
def python_sidebar_navigation(python_input): """ Create the `Layout` showing the navigation information for the sidebar. """ def get_text_fragments(): tokens = [] # Show navigation info. tokens.extend([ ('class:sidebar', ' '), ('class:sidebar.key', '[Arrows]'), ('class:sidebar', ' '), ('class:sidebar.description', 'Navigate'), ('class:sidebar', ' '), ('class:sidebar.key', '[Enter]'), ('class:sidebar', ' '), ('class:sidebar.description', 'Hide menu'), ]) return tokens return Window( FormattedTextControl(get_text_fragments), style='class:sidebar', width=Dimension.exact(43), height=Dimension.exact(1))
def preferred_dimensions(self, width): dimensions = [[]] * self.columns for row in self.children: assert isinstance(row, _Row) j = 0 for cell in row.children: assert isinstance(cell, _Cell) if cell.merge != 1: dimensions[j].append(cell.preferred_width(width)) j += cell.merge for i, c in enumerate(dimensions): yield D.exact(1) try: w = self.column_widths[i] except IndexError: w = self.column_width if w is None: # fitted yield max_layout_dimensions(c) else: # fixed or weighted yield to_dimension(w) yield D.exact(1)
def show_sidebar_button_info(python_input): """ Create `Layout` for the information in the right-bottom corner. (The right part of the status bar.) """ @if_mousedown def toggle_sidebar(mouse_event): " Click handler for the menu. " python_input.show_sidebar = not python_input.show_sidebar version = sys.version_info tokens = [ ('class:status-toolbar.key', '[F2]', toggle_sidebar), ('class:status-toolbar', ' Menu', toggle_sidebar), ('class:status-toolbar', ' - '), ('class:status-toolbar.python-version', '%s %i.%i.%i' % (platform.python_implementation(), version[0], version[1], version[2])), ('class:status-toolbar', ' '), ] width = fragment_list_width(tokens) def get_text_fragments(): # Python version return tokens return ConditionalContainer( content=Window(FormattedTextControl(get_text_fragments), style='class:status-toolbar', height=Dimension.exact(1), width=Dimension.exact(width)), filter=~is_done & renderer_height_is_known & Condition(lambda: python_input.show_status_bar and not python_input. show_exit_confirmation))
def sql_sidebar_navigation(): """ Create the `Layout` showing the navigation information for the sidebar. """ def get_text_fragments(): # Show navigation info. return [ ("class:sidebar.navigation", " "), ("class:sidebar.navigation.key", "[Up/Dn]"), ("class:sidebar.navigation", " "), ("class:sidebar.navigation.description", "Navigate"), ("class:sidebar.navigation", " "), ("class:sidebar.navigation.key", "[L/R]"), ("class:sidebar.navigation", " "), ("class:sidebar.navigation.description", "Expand/Collapse"), ("class:sidebar.navigation", "\n "), ("class:sidebar.navigation.key", "[Enter]"), ("class:sidebar.navigation", " "), ("class:sidebar.navigation.description", "Connect/Preview"), ] return Window( FormattedTextControl(get_text_fragments), style = "class:sidebar.navigation", width=Dimension.exact( 45 ), height=Dimension(max = 2), )
def python_sidebar_navigation(python_input): """ Create the `Layout` showing the navigation information for the sidebar. """ def get_text_fragments(): tokens = [] # Show navigation info. tokens.extend([ ('class:sidebar', ' '), ('class:sidebar.key', '[Arrows]'), ('class:sidebar', ' '), ('class:sidebar.description', 'Navigate'), ('class:sidebar', ' '), ('class:sidebar.key', '[Enter]'), ('class:sidebar', ' '), ('class:sidebar.description', 'Hide menu'), ]) return tokens return Window(FormattedTextControl(get_text_fragments), style='class:sidebar', width=Dimension.exact(43), height=Dimension.exact(1))
def get_root_container(self) -> FloatContainer: buttons = [ *self._game_buttons.keys(), HorizontalLine(), Button("Quit", width=MENU_BUTTON_WIDTH, handler=self._exit), ] menu_keybindings = _create_menu_keybindings(buttons) game_buttons_container = Frame( HSplit( buttons, width=Dimension(min=MENU_BUTTON_WIDTH, max=40), height=Dimension(), ), title="Games", key_bindings=menu_keybindings, ) game_description_container = Frame( Box( Label( text=self._get_game_description, dont_extend_height=False, width=Dimension(min=40), ), padding=0, padding_left=1, ), ) return FloatContainer(VSplit([ game_buttons_container, game_description_container, ]), floats=[])
def __init__(self, title="", label_text="", completer=None): self.future = Future() def accept_text(buf): app.layout.focus(ok_button) buf.complete_state = None return True def accept(): self.future.set_result(self.text_area.text) def cancel(): self.future.set_result(None) self.text_area = TextArea( completer=completer, multiline=False, width=Dimension(preferred=40), accept_handler=accept_text, ) ok_button = Button(text="OK", handler=accept) cancel_button = Button(text="Cancel", handler=cancel) self.dialog = Dialog( title=title, body=HSplit([Label(text=label_text), self.text_area]), buttons=[ok_button, cancel_button], width=Dimension(preferred=80), modal=True, )
def show_sidebar_button_info(my_app: "sqlApp") -> Container: """ Create `Layout` for the information in the right-bottom corner. (The right part of the status bar.) """ @if_mousedown def toggle_sidebar(mouse_event: MouseEvent) -> None: " Click handler for the menu. " my_app.show_sidebar = not my_app.show_sidebar # TO DO: app version rather than python version = sys.version_info tokens: StyleAndTextTuples = [ ("class:status-toolbar.key", "[C-t]", toggle_sidebar), ("class:status-toolbar", " Object Browser", toggle_sidebar), ("class:status-toolbar", " - "), ("class:status-toolbar.cli-version", "odbcli %s" % __version__), ("class:status-toolbar", " "), ] width = fragment_list_width(tokens) def get_text_fragments() -> StyleAndTextTuples: # Python version return tokens return ConditionalContainer( content=Window( FormattedTextControl(get_text_fragments), style="class:status-toolbar", height=Dimension.exact(1), width=Dimension.exact(width), ), filter=~is_done & Condition(lambda: not my_app.show_exit_confirmation) & renderer_height_is_known)
def get_default_buffer_control_height(): # 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. space = self.reserve_space_for_menu if space and not get_app().is_done: buff = default_buffer if buff.complete_while_typing() or buff.complete_state is not None: return Dimension(min=space) return Dimension()
def _get_buffer_control_height(buf): # 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 get_app().is_done: buff = 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 Dimension(min=reserve_space_for_menu) return Dimension()
def _create_layout(self): has_before_fragments, get_prompt_text_1, get_prompt_text_2 = \ _split_multiline_prompt(self._get_prompt) default_buffer = self.default_buffer default_buffer_control = BufferControl( buffer=default_buffer, search_buffer_control=None, input_processors=[], include_default_input_processors=False) prompt_window = Window(FormattedTextControl(get_prompt_text_1), dont_extend_height=True) default_buffer_window = Window( default_buffer_control, dont_extend_height=True, get_line_prefix=partial(self._get_line_prefix, get_prompt_text_2=get_prompt_text_2)) divider = Window(char='_', height=1, style='fg:gray bg:black') search_window = Window(content=SearchControl(), style='') bottom_toolbar = ConditionalContainer( Window(FormattedTextControl(lambda: self.bottom_toolbar), dont_extend_height=True, height=Dimension(min=1)), filter=~is_done & renderer_height_is_known & Condition(lambda: self.bottom_toolbar is not None)) layout = HSplit([ prompt_window, default_buffer_window, divider, search_window, bottom_toolbar ]) return Layout(layout, default_buffer_window)
def __init__(self, text: str, handler: Optional[Callable[[], None]] = None, width: int = None) -> None: self.text = text self.handler = handler self.width = width if width is None: self.width = max(12, len(text) + 2) self.control = FormattedTextControl( self._get_text_fragments, key_bindings=self._get_key_bindings(), focusable=True, ) def get_style() -> str: if get_app().layout.has_focus(self): return "class:button.focused" else: return "class:button" self.window = Window( self.control, align=WindowAlign.CENTER, height=1, width=Dimension(preferred=self.width, max=self.width), style=get_style, dont_extend_width=True, dont_extend_height=True, always_hide_cursor=True # Stops curser from showing when selected )
def InputDialog(on_ok, on_cancel, title="", prompt="", ok_text="OK", cancel_text="Cancel", is_text_valid=lambda text: True) -> Dialog: """Returns a Dialogue component displaying a text input box""" def on_accept(buf): if is_text_valid(textfield.text): get_app().layout.focus(ok_button) return True # Keep text. def on_ok_clicked(): if is_text_valid(textfield.text): on_ok(textfield.text) ok_button = Button(text=ok_text, handler=on_ok_clicked) exit_button = Button(text=cancel_text, handler=on_cancel) textfield = TextArea(multiline=False, accept_handler=on_accept) dialog = Dialog( title=title, body=HSplit( [Label(text=prompt, dont_extend_height=True), textfield], padding=Dimension(preferred=1, max=1), ), buttons=[ok_button, exit_button], with_background=True) return dialog
def MenuScreen(controller): def on_start_click(): new_state = PlayingScreenState(username=controller.state.username, choice_history=[root_branch], choice_index=0, start_time=time()) controller.set_state(new_state) def on_help_click(): new_state = HelpScreenState(username=controller.state.username, previous_state=controller.state) controller.set_state(new_state) buttons = [ Button('start', handler=on_start_click), Button('help', handler=on_help_click), Button('quit', handler=exit_current_app) ] kb = create_vertical_button_list_kbs(buttons) body = Box( VSplit([ HSplit(children=buttons, padding=Dimension(preferred=1, max=1), key_bindings=kb) ])) toolbar_content = Window(content=FormattedTextControl( 'Hello %s. I wish you the best of luck...' % controller.state.username), align=WindowAlign.CENTER, height=1) return ToolbarFrame(body, toolbar_content)
def __init__(self, text: AnyFormattedText, style: str = '', **kw) -> None: # Note: The style needs to be applied to the toolbar as a whole, not # just the `FormattedTextControl`. super().__init__(FormattedTextControl(text, **kw), style=style, dont_extend_height=True, height=Dimension(min=1))
def python_sidebar_help(python_input): """ Create the `Layout` for the help text for the current item in the sidebar. """ token = 'class: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_help_text(): return [(token, get_current_description())] return ConditionalContainer( content=Window(FormattedTextControl(get_help_text), style=token, height=Dimension(min=3)), filter=ShowSidebar(python_input) & Condition(lambda: python_input.show_sidebar_help) & ~is_done)
def sql_sidebar_help(my_app: "sqlApp"): """ Create the `Layout` for the help text for the current item in the sidebar. """ token = "class:sidebar.helptext" def get_current_description(): """ Return the description of the selected option. """ obj = my_app.selected_object if obj is not None: return obj.name return "" def get_help_text(): return [(token, get_current_description())] return ConditionalContainer( content=Window( FormattedTextControl(get_help_text), style=token, height=Dimension(min=3) ), filter = ~is_done & ShowSidebar(my_app) & Condition( lambda: not my_app.show_exit_confirmation ))
def __init__(self, row, table, borders, window_too_small=None, align=HorizontalAlign.JUSTIFY, padding=D.exact(0), padding_char=None, padding_style='', width=None, height=None, z_index=None, modal=False, key_bindings=None, style=''): self.table = table self.borders = borders # ensure the row is iterable (has cells) if not isinstance(row, list): row = [row] children = [] for c in row: m = 1 if isinstance(c, Merge): c, m = c elif isinstance(c, dict): c, m = Merge(**c) children.append(_Cell(cell=c, table=table, row=self, merge=m)) super().__init__( children=children, window_too_small=window_too_small, align=align, padding=padding, padding_char=padding_char, padding_style=padding_style, width=width, height=height, z_index=z_index, modal=modal, key_bindings=key_bindings, style=style)
def __init__(self, prev, next, table, borders, window_too_small=None, align=HorizontalAlign.JUSTIFY, padding=D.exact(0), padding_char=None, padding_style='', width=None, height=None, z_index=None, modal=False, key_bindings=None, style=''): assert prev or next self.prev = prev self.next = next self.table = table self.borders = borders children = [_HorizontalBorder(borders=borders)] * self.columns super().__init__( children=children, window_too_small=window_too_small, align=align, padding=padding, padding_char=padding_char, padding_style=padding_style, width=width, height=height or 1, z_index=z_index, modal=modal, key_bindings=key_bindings, style=style)
def get_width(self, progress_bar: "ProgressBar") -> AnyDimension: width = 5 for counter in progress_bar.counters: if counter.items_completed >= 1000: width = 6 break return Dimension.exact(width)
def select_menu(items, display_format=None, max_height=10): """ Presents a list of options and allows the user to select one. This presents a static list of options and prompts the user to select one. This is similar to a completion menu but is different in that it does not allow a user to type and the returned value is always a member of the list. :type items: list :param list: The list of items to be selected from. If this list contains elements that are not strings the display_format option must be specified. :type display_format: Callable[[Any], str] :param display_format: A callable that takes a single element from the items list as input and returns a string used to represent the item in the menu. :type max_height: int :param max_height: The max number of items to show in the list at a time. :returns: The selected element from the items list. """ app_bindings = KeyBindings() @app_bindings.add('c-c') def exit_app(event): event.app.exit(exception=KeyboardInterrupt, style='class:aborting') min_height = min(max_height, len(items)) menu_window = Window( SelectionMenuControl(items, display_format=display_format), always_hide_cursor=False, height=Dimension(min=min_height, max=min_height), scroll_offsets=ScrollOffsets(), right_margins=[ScrollbarMargin()], ) # Using a FloatContainer was the only way I was able to succesfully # limit the height and width of the window. content = FloatContainer( Window(height=Dimension(min=min_height, max=min_height)), [Float(menu_window, top=0, left=0)]) app = Application( layout=Layout(content), key_bindings=app_bindings, erase_when_done=True, ) return app.run()
def __init__(self, text='', style=''): self.percent = 0 self.container = VSplit( children=[ Window( style='class:info.progressbar.progress', width=lambda: Dimension(weight=int(self.percent)), height=1, ), Window( style='class:info.progressbar', width=lambda: Dimension(weight=int(100 - self.percent)), height=1, ), ], style=style, )
def expanding_object_notification(my_app: "sqlApp"): """ Create the `Layout` for the 'Expanding object' notification. """ def get_text_fragments(): # Show navigation info. return [("fg:red", "Expanding object ...")] return ConditionalContainer( content=Window( FormattedTextControl(get_text_fragments), style="class:sidebar", width=Dimension.exact(45), height=Dimension(max=1), ), filter=~is_done & ShowSidebar(my_app) & Condition(lambda: my_app.show_expanding_object))
def setup_docstring_containers(repl): parent_container = get_ptpython_parent_container(repl) # the same as ptpython containers, but without signature checking parent_container.children.extend( [ ConditionalContainer( content=Window(height=Dimension.exact(1), char="\u2500", style="class:separator"), filter=HasDocString(repl) & ShowDocstring(repl) & ~is_done, ), ConditionalContainer( content=Window( BufferControl(buffer=repl.docstring_buffer, lexer=PygmentsLexer(PythonLexer)), height=Dimension(max=12), ), filter=HasDocString(repl) & ShowDocstring(repl) & ~is_done, ), ] )
def render(self): choices_len = len(self._choices) buttons = [ Button('[%s] %s' % (i, label) if choices_len > 1 else label, handler=self._create_handler(sub_component)) for ((label, sub_component), i) in zip(self._choices, range( 1, choices_len + 1)) # this is still a loop even if it is inline.. ] self._first_button = buttons[0] global global__default_target_focus global__default_target_focus = self._first_button kb = create_vertical_button_list_kbs(buttons) is_first_selected = has_focus(buttons[0]) kb.add('up', filter=is_first_selected)(lambda e: focus_first_element()) return Box( HSplit( [ TextArea( text=self._label.format( name=self._controller.state.username) + '\n', read_only=True, focusable=False, scrollbar=True, # push buttons to bottom of screen height=Dimension(preferred=100000, max=100000)), HSplit([ VSplit(children=[button], align=HorizontalAlign.CENTER) for button in buttons ], padding=1, key_bindings=kb) ], padding=Dimension(preferred=2, max=2), width=Dimension(), align=VerticalAlign.TOP), padding=1)
def progress_dialog( title: AnyFormattedText = "", text: AnyFormattedText = "", run_callback: Callable[[Callable[[int], None], Callable[[str], None]], None] = ( lambda *a: None ), style: Optional[BaseStyle] = None, ) -> Application[None]: """ :param run_callback: A function that receives as input a `set_percentage` function and it does the work. """ loop = get_event_loop() progressbar = ProgressBar() text_area = TextArea( focusable=False, # Prefer this text area as big as possible, to avoid having a window # that keeps resizing when we add text to it. height=D(preferred=10 ** 10), ) dialog = Dialog( body=HSplit( [ Box(Label(text=text)), Box(text_area, padding=D.exact(1)), progressbar, ] ), title=title, with_background=True, ) app = _create_app(dialog, style) def set_percentage(value: int) -> None: progressbar.percentage = int(value) app.invalidate() def log_text(text: str) -> None: loop.call_soon_threadsafe(text_area.buffer.insert_text, text) app.invalidate() # Run the callback in the executor. When done, set a return value for the # UI, so that it quits. def start() -> None: try: run_callback(set_percentage, log_text) finally: app.exit() def pre_run() -> None: run_in_executor_with_context(start) app.pre_run_callables.append(pre_run) return app
def show_sidebar_button_info(python_input: "PythonInput") -> Container: """ Create `Layout` for the information in the right-bottom corner. (The right part of the status bar.) """ @if_mousedown def toggle_sidebar(mouse_event: MouseEvent) -> None: " Click handler for the menu. " python_input.show_sidebar = not python_input.show_sidebar version = sys.version_info tokens: StyleAndTextTuples = [ ("class:status-toolbar.key", "[F2]", toggle_sidebar), ("class:status-toolbar", " Menu", toggle_sidebar), ("class:status-toolbar", " - "), ( "class:status-toolbar.python-version", "%s %i.%i.%i" % (platform.python_implementation(), version[0], version[1], version[2]), ), ("class:status-toolbar", " "), ] width = fragment_list_width(tokens) def get_text_fragments() -> StyleAndTextTuples: # Python version return tokens return ConditionalContainer( content=Window( FormattedTextControl(get_text_fragments), style="class:status-toolbar", height=Dimension.exact(1), width=Dimension.exact(width), ), filter=~is_done & renderer_height_is_known & Condition( lambda: python_input.show_status_bar and not python_input.show_exit_confirmation ), )
def _get_default_buffer_control_height(self): # 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 (self.completer is not None and self.complete_style != CompleteStyle.READLINE_LIKE): space = self.reserve_space_for_menu else: space = 0 if space and not get_app().is_done: buff = self.default_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 Dimension(min=space) return Dimension()
def __init__(self, text, **kw): # The style needs to be applied to the toolbar as a whole, not just the # `FormattedTextControl`. style = kw.pop('style', '') super(FormattedTextToolbar, self).__init__(FormattedTextControl(text, **kw), style=style, dont_extend_height=True, height=Dimension(min=1))
def progress_dialog( title: AnyFormattedText = '', text: AnyFormattedText = '', run_callback: Callable[[Callable[[int], None], Callable[[str], None]], None] = (lambda *a: None), style: Optional[BaseStyle] = None) -> Application[None]: """ :param run_callback: A function that receives as input a `set_percentage` function and it does the work. """ loop = get_event_loop() progressbar = ProgressBar() text_area = TextArea( focusable=False, # Prefer this text area as big as possible, to avoid having a window # that keeps resizing when we add text to it. height=D(preferred=10**10)) dialog = Dialog( body=HSplit([ Box(Label(text=text)), Box(text_area, padding=D.exact(1)), progressbar, ]), title=title, with_background=True) app = _create_app(dialog, style) def set_percentage(value: int) -> None: progressbar.percentage = int(value) app.invalidate() def log_text(text: str) -> None: loop.call_soon_threadsafe(text_area.buffer.insert_text, text) app.invalidate() # Run the callback in the executor. When done, set a return value for the # UI, so that it quits. def start() -> None: try: run_callback(set_percentage, log_text) finally: app.exit() def pre_run() -> None: run_in_executor_with_context(start) app.pre_run_callables.append(pre_run) return app
def progress_dialog(title='', text='', run_callback=None, style=None, async_=False): """ :param run_callback: A function that receives as input a `set_percentage` function and it does the work. """ assert callable(run_callback) progressbar = ProgressBar() text_area = TextArea( focusable=False, # Prefer this text area as big as possible, to avoid having a window # that keeps resizing when we add text to it. height=D(preferred=10**10)) dialog = Dialog( body=HSplit([ Box(Label(text=text)), Box(text_area, padding=D.exact(1)), progressbar, ]), title=title, with_background=True) app = _create_app(dialog, style) def set_percentage(value): progressbar.percentage = int(value) app.invalidate() def log_text(text): text_area.buffer.insert_text(text) app.invalidate() # Run the callback in the executor. When done, set a return value for the # UI, so that it quits. def start(): try: run_callback(set_percentage, log_text) finally: app.exit() run_in_executor(start) if async_: return app.run_async() else: return app.run()
def preferred_width(self, max_available_width): return D.exact(BigClock.WIDTH)
def preferred_width(self, max_available_width): # Enough to display all the digits. return Dimension.exact(6 * len('%s' % self._get_index()) - 1)
def preferred_height(self, width, max_available_height): return Dimension.exact(self.HEIGHT)
def __init__(self, history): search_toolbar = SearchToolbar() self.help_buffer_control = BufferControl( buffer=history.help_buffer, lexer=PygmentsLexer(RstLexer)) help_window = _create_popup_window( title='History Help', body=Window( content=self.help_buffer_control, right_margins=[ScrollbarMargin(display_arrows=True)], scroll_offsets=ScrollOffsets(top=2, bottom=2))) self.default_buffer_control = BufferControl( buffer=history.default_buffer, input_processors=[GrayExistingText(history.history_mapping)], lexer=PygmentsLexer(PythonLexer)) self.history_buffer_control = BufferControl( buffer=history.history_buffer, lexer=PygmentsLexer(PythonLexer), search_buffer_control=search_toolbar.control, preview_search=True) history_window = Window( content=self.history_buffer_control, wrap_lines=False, left_margins=[HistoryMargin(history)], scroll_offsets=ScrollOffsets(top=2, bottom=2)) self.root_container = HSplit([ # Top title bar. Window( content=FormattedTextControl(_get_top_toolbar_fragments), align=WindowAlign.CENTER, style='class:status-toolbar'), FloatContainer( content=VSplit([ # Left side: history. history_window, # Separator. Window(width=D.exact(1), char=BORDER.LIGHT_VERTICAL, style='class:separator'), # Right side: result. Window( content=self.default_buffer_control, wrap_lines=False, left_margins=[ResultMargin(history)], scroll_offsets=ScrollOffsets(top=2, bottom=2)), ]), floats=[ # Help text as a float. Float(width=60, top=3, bottom=2, content=ConditionalContainer( content=help_window, filter=has_focus(history.help_buffer))), ] ), # Bottom toolbars. ArgToolbar(), search_toolbar, Window( content=FormattedTextControl( partial(_get_bottom_toolbar_fragments, history=history)), style='class:status-toolbar'), ]) self.layout = Layout(self.root_container, history_window)
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)
def signature_toolbar(python_input): """ Return the `Layout` for the signature. """ def get_text_fragments(): result = [] append = result.append Signature = 'class:signature-toolbar' if python_input.signatures: sig = python_input.signatures[0] # Always take the first one. append((Signature, ' ')) try: append((Signature, sig.full_name)) except IndexError: # Workaround for #37: https://github.com/jonathanslenders/python-prompt-toolkit/issues/37 # See also: https://github.com/davidhalter/jedi/issues/490 return [] append((Signature + ',operator', '(')) try: enumerated_params = enumerate(sig.params) except AttributeError: # Workaround for #136: https://github.com/jonathanslenders/ptpython/issues/136 # AttributeError: 'Lambda' object has no attribute 'get_subscope_by_name' return [] for i, p in enumerated_params: # Workaround for #47: 'p' is None when we hit the '*' in the signature. # and sig has no 'index' attribute. # See: https://github.com/jonathanslenders/ptpython/issues/47 # https://github.com/davidhalter/jedi/issues/598 description = (p.description if p else '*') #or '*' sig_index = getattr(sig, 'index', 0) if i == sig_index: # Note: we use `_Param.description` instead of # `_Param.name`, that way we also get the '*' before args. append((Signature + ',current-name', str(description))) else: append((Signature, str(description))) append((Signature + ',operator', ', ')) if sig.params: # Pop last comma result.pop() append((Signature + ',operator', ')')) append((Signature, ' ')) return result return ConditionalContainer( content=Window( FormattedTextControl(get_text_fragments), height=Dimension.exact(1)), filter= # Show only when there is a signature HasSignature(python_input) & # And there are no completions to be shown. (would cover signature pop-up.) ~(has_completions & (show_completions_menu(python_input) | show_multi_column_completions_menu(python_input))) # Signature needs to be shown. & ShowSignature(python_input) & # Not done yet. ~is_done)
def python_sidebar(python_input): """ Create the `Layout` for the sidebar with the configurable options. """ def get_text_fragments(): tokens = [] def append_category(category): tokens.extend([ ('class:sidebar', ' '), ('class:sidebar.title', ' %-36s' % category.title), ('class:sidebar', '\n'), ]) def append(index, label, status): selected = index == python_input.selected_option_index @if_mousedown def select_item(mouse_event): python_input.selected_option_index = index @if_mousedown def goto_next(mouse_event): " Select item and go to next value. " python_input.selected_option_index = index option = python_input.selected_option option.activate_next() sel = ',selected' if selected else '' tokens.append(('class:sidebar' + sel, ' >' if selected else ' ')) tokens.append(('class:sidebar.label' + sel, '%-24s' % label, select_item)) tokens.append(('class:sidebar.status' + sel, ' ', select_item)) tokens.append(('class:sidebar.status' + sel, '%s' % status, goto_next)) if selected: tokens.append(('[SetCursorPosition]', '')) tokens.append(('class:sidebar.status' + sel, ' ' * (13 - len(status)), goto_next)) tokens.append(('class:sidebar', '<' if selected else '')) tokens.append(('class:sidebar', '\n')) i = 0 for category in python_input.options: append_category(category) for option in category.options: append(i, option.title, '%s' % option.get_current_value()) i += 1 tokens.pop() # Remove last newline. return tokens class Control(FormattedTextControl): def move_cursor_down(self): python_input.selected_option_index += 1 def move_cursor_up(self): python_input.selected_option_index -= 1 return Window( Control(get_text_fragments), style='class:sidebar', width=Dimension.exact(43), height=Dimension(min=3), scroll_offsets=ScrollOffsets(top=1, bottom=1))
def preferred_height(self, width, max_available_height): return D.exact(BigClock.HEIGHT)
def __init__(self, text='', multiline=True, password=False, lexer=None, auto_suggest=None, completer=None, complete_while_typing=True, accept_handler=None, history=None, focusable=True, focus_on_click=False, wrap_lines=True, read_only=False, width=None, height=None, dont_extend_height=False, dont_extend_width=False, line_numbers=False, get_line_prefix=None, scrollbar=False, style='', search_field=None, preview_search=True, prompt='', input_processors=None): # assert isinstance(text, six.text_type) if search_field is None: search_control = None 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)