def __init__(self, values: Sequence[Tuple[_T, AnyFormattedText]]) -> None: assert len(values) > 0 self.values = values # current_values will be used in multiple_selection, # current_value will be used otherwise. self.current_values: List[_T] = [] self.current_value: _T = values[0][0] self._selected_index = 0 # Key bindings. kb = KeyBindings() @kb.add("up") def _(event: E) -> None: self._selected_index = max(0, self._selected_index - 1) @kb.add("down") def _(event: E) -> None: self._selected_index = min(len(self.values) - 1, self._selected_index + 1) @kb.add("pageup") def _(event: E) -> None: w = event.app.layout.current_window self._selected_index = max( 0, self._selected_index - len(w.render_info.displayed_lines) ) @kb.add("pagedown") def _(event: E) -> None: w = event.app.layout.current_window self._selected_index = min( len(self.values) - 1, self._selected_index + len(w.render_info.displayed_lines), ) @kb.add("enter") @kb.add(" ") def _(event: E) -> None: self._handle_enter() @kb.add(Keys.Any) def _(event: E) -> None: # We first check values after the selected value, then all values. for value in self.values[self._selected_index + 1 :] + self.values: if value[1].startswith(event.data): self._selected_index = self.values.index(value) return # Control and window. self.control = FormattedTextControl( self._get_text_fragments, key_bindings=kb, focusable=True ) self.window = Window( content=self.control, style=self.container_style, right_margins=[ScrollbarMargin(display_arrows=True),], dont_extend_height=True, )
def make_app(path_to_checklist, new_session): session = ChecklistSession(path_to_checklist, new_session) checklist = session.load() def status_bar_text(): items = checklist.items() return "{name} : {checked}/{total} done | 'q': quit | 'z': undo | '?' help | <up>/<down> moves | <space> toggles".format( name=checklist.name, checked=len([i for i in items if i.checked]), total=len(items)) checklist_window = Window(ChecklistControl(checklist, session), left_margins=[NumberedMargin()], right_margins=[ ScrollbarMargin(display_arrows=True), ]) status_bar_window = Window(content=FormattedTextControl(status_bar_text), height=1, style='reverse') root_container = FloatContainer( content=HSplit([ checklist_window, status_bar_window, ]), floats=[], ) if session.duplicates: root_container.floats.append( Float(content=DuplicatesWarningDialog(session.duplicates))) return Application(layout=Layout(root_container), full_screen=True, key_bindings=build_key_bindings())
def create(self): from freud.key_bindings import response_kb, header_kb right_margins = [ScrollbarMargin(display_arrows=True)] left_margins = [NumberedMargin()] self.buffer_control = BufferControl( lexer=PygmentsLexer(JsonLexer), search_buffer_control=search_toolbar.control, buffer=response_buffer) header_window = Window( wrap_lines=True, right_margins=right_margins, left_margins=left_margins, height=HEADER_HEIGHT, content=BufferControl(key_bindings=header_kb, search_buffer_control=search_toolbar.control, lexer=PygmentsLexer(HeaderLexer), buffer=header_buffer)) body_window = Window(left_margins=left_margins, right_margins=right_margins, wrap_lines=True, content=self.buffer_control) return HSplit([ header_window, Window(height=1, char='─', style='class:line'), body_window, ], key_bindings=response_kb)
def __init__( self, options: Sequence[Tuple[RadioListType, AnyFormattedText]]) -> None: self.options = options self.current_option: RadioListType = options[0][0] self._selected_index = 0 # Key bindings. kb = KeyBindings() kb.add("up")(self._handle_up) kb.add("down")(self._handle_down) kb.add("enter")(self._handle_enter) kb.add("c-d")(self._handle_exit) kb.add("c-a")(self._handle_home) kb.add("c-e")(self._handle_end) # Control and window. self.control = FormattedTextControl(self._get_text_fragments, key_bindings=kb, focusable=True) self.window = Window( content=self.control, style=self.container_style, right_margins=[ScrollbarMargin(display_arrows=True)], dont_extend_height=True, )
def __init__(self, fm: Filemanager, handler: Callable[[str], None]): self.fm = fm self.values: List[str] = ['../'] self._styles = [FileList.STYLE_DIR] self._selected_index: int = 0 self._file_handler = handler for f in fm.cwd.iterdir(): if f.is_file(): self.values.append(f.name) self._styles.append(FileList.STYLE_FILE) elif f.is_dir(): self.values.append(f.name + '/') self._styles.append(FileList.STYLE_DIR) # elif f.is_symlink(): # self.values.append(f.name + ' -> ' + os.path.realpath(f)) # self._styles.append(FileList.STYLE_SYMLINK) else: self.values.append(f.name + '|') self._styles.append(FileList.STYLE_OTHER) self.input_field = FormattedTextControl( self._get_text_fragments, show_cursor=False, key_bindings=self._get_filemanager_kb(fm), focusable=True) self.window = Window(content=self.input_field, cursorline=True, right_margins=[ ScrollbarMargin(display_arrows=True), ], dont_extend_height=True)
def __init__(self, values): assert isinstance(values, list) assert len(values) > 0 assert all(isinstance(i, tuple) and len(i) == 2 for i in values) self.values = values self.current_value = values[0][0] self._selected_index = 0 # Key bindings. kb = KeyBindings() @kb.add('up') def _(event): self._selected_index = max(0, self._selected_index - 1) @kb.add('down') def _(event): self._selected_index = min( len(self.values) - 1, self._selected_index + 1) @kb.add('pageup') def _(event): w = event.app.layout.current_window self._selected_index = max( 0, self._selected_index - len(w.render_info.displayed_lines)) @kb.add('pagedown') def _(event): w = event.app.layout.current_window self._selected_index = min( len(self.values) - 1, self._selected_index + len(w.render_info.displayed_lines)) @kb.add('enter') @kb.add(' ') def _(event): self.current_value = self.values[self._selected_index][0] @kb.add(Keys.Any) def _(event): # We first check values after the selected value, then all values. for value in self.values[self._selected_index + 1:] + self.values: if value[1].startswith(event.data): self._selected_index = self.values.index(value) return # Control and window. self.control = FormattedTextControl(self._get_text_fragments, key_bindings=kb, focusable=True) self.window = Window(content=self.control, style='class:radio-list', right_margins=[ ScrollbarMargin(display_arrows=True), ], dont_extend_height=True)
def make_exchange_container(e_key): exchange = {} exchange['name'] = allowed_exchanges[e_key]['name'] exchange['title'] = FormattedTextControl() exchange['title'].text = HTML('awaiting connection') exchange['book_buffer'] = FormattedTextControl() exchange['trades_buffer'] = Buffer_() exchange['summary'] = FormattedTextControl() exchange['summary'].text = get_summary_text() exchange['container'] = HSplit([ Window(BufferControl(Buffer_()), height=0), Window( height=1, content=exchange['title'], align=WindowAlign.LEFT, left_margins=[ScrollbarMargin()], ), Window(height=1, char="-", style="class:line"), VSplit([ Window( height=5, width=45, content=exchange['summary'], align=WindowAlign.LEFT, left_margins=[ScrollbarMargin()], ), Window(width=1, char=".", style="class:mbline"), Window(height=1, content=exchange['book_buffer'], align=WindowAlign.LEFT) ]), Window(height=1, char="-", style="class:line"), Window( BufferControl(exchange['trades_buffer'], input_processors=[FormatText()], include_default_input_processors=True), # right_margins=[ScrollbarMargin(), ScrollbarMargin()], ), ]) return exchange
def _gen_layout(self): stat_windows = [] for stat_group in statinfo.groups: for stat in stat_group: stat_windows.append(make_stat_window(stat)) stat_windows.append(vpad(1)) stat_windows.append( Window(content=BufferControl(buffer_name='REROLLS_STAT_BUFFER'), **stat_args)) stat_windows.append(vpad(1)) @Condition def scroll_cond(cli): if self.info_window.render_info is None: return True try: l = self.buffers['INFO_BUFFER'].document.line_count return self.info_window.render_info.window_height < l except: return True self.info_window = Window( content=BufferControl(buffer_name='INFO_BUFFER'), dont_extend_width=True, wrap_lines=True, always_hide_cursor=True, right_margins=[ ConditionalMargin(ScrollbarMargin(display_arrows=True), scroll_cond) ]) return HSplit([ hpad(1), VSplit([ vpad(1), HSplit(stat_windows), vpad(2), # idk why there's an extra space on the stats self.info_window, vpad(1) ]), hpad(1), Window(content=BufferControl(buffer_name='MSG_BUFFER'), height=D.exact(3), wrap_lines=True), Window(content=BufferControl(buffer_name=DEFAULT_BUFFER), height=D.exact(1), always_hide_cursor=True) ])
def __init__(self): self.selected_line = 0 self.container = Window( content=FormattedTextControl( text=self._get_formatted_text, focusable=True, key_bindings=self._get_key_bindings(), ), style="class:select-box", cursorline=True, right_margins=[ ScrollbarMargin(display_arrows=True), ], width=20, always_hide_cursor=True, )
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, buffer, title): self._title = title self._buffer = buffer self.buffer_control = BufferControl( buffer=self._buffer, lexer=PygmentsLexer(MarkdownLexer), ) self.window = Frame( body=Window( content=self.buffer_control, right_margins=[ScrollbarMargin(display_arrows=True)], scroll_offsets=ScrollOffsets(top=2, bottom=2), ), title=self._title, )
def setup_layout(self): """docstring for setup_layout""" if bool(egc.TEXT_EDITOR_ENABLE_LEFT_MARGIN) is True: self._left_margin = NumberredMargin(display_tildes=True) if bool(egc.TEXT_EDITOR_ENABLE_RIGHT_MARGIN) is True: self._right_margin = ScrollbarMargin(display_arrows=True) self._buffer_control = BufferControl(buffer_name=self._editor_buffer_name) self._editor_aiml_code_window = Window(content=self._buffer_control, left_margins=[self._left_margin,]) self._vertical_line = FillControl('|', token=Token.Line) self._window_separater = Window(width=D.exact(1), content=self._vertical_line) self._aiml_list = TokenListControl(get_tokens=self.get_aiml_list) self._editor_aiml_list_window = Window(content=self._aiml_list, right_margins=[self._right_margin,]) self._layout = VSplit([ self._editor_aiml_code_window, self._window_separater, self._editor_aiml_list_window, ])
def __init__(self, buffer): self.buffer_control = BufferControl( buffer=buffer, focusable=True, key_bindings=self._get_key_bindings(), focus_on_click=True, ) self.window = Window( content=self.buffer_control, right_margins=[ScrollbarMargin(display_arrows=True)], ) self.window = Frame(body=Box( self.window, padding_left=2, padding_right=2, padding_top=0, padding_bottom=0, ))
def __init__(self, title: AnyFormattedText = "", style: str = "", width: AnyDimension = None, height: AnyDimension = None, key_bindings: Optional[KeyBindings] = None, modal: bool = False): buffer = Buffer(read_only=True, name='diff') self._search = SearchToolbar(vi_mode=True) self.control = DiffControl(buffer, self._search.control) body = HSplit([ Window(self.control, right_margins=[ScrollbarMargin(display_arrows=True)]), self._search ]) super().__init__(body=body, title=title, style=style, width=width, height=height, key_bindings=key_bindings, modal=modal)
def __init__(self, values): assert isinstance(values, list) assert len(values) > 0 assert all(isinstance(i, tuple) and len(i) == 2 for i in values) self.values = values self.current_value = values[0][0] self._selected_index = 0 # Key bindings. kb = KeyBindings() @kb.add('up') def _(event): self._selected_index = max(0, self._selected_index - 1) @kb.add('down') def _(event): self._selected_index = min( len(self.values) - 1, self._selected_index + 1) @kb.add('enter') @kb.add(' ') def _(event): self.current_value = self.values[self._selected_index][0] # Control and window. self.control = FormattedTextControl(self._get_text_fragments, key_bindings=kb, focusable=True) self.window = Window(content=self.control, style='class:radio-list', right_margins=[ ScrollbarMargin(display_arrows=True), ], dont_extend_height=True)
def create_layout(python_input, history_mapping): """ Create and return a `Container` instance for the history application. """ processors = [ HighlightSearchProcessor(preview_search=True), HighlightSelectionProcessor() ] help_window = create_popup_window( title='History Help', body=Window(content=BufferControl(buffer_name=HELP_BUFFER, default_char=Char(token=Token), lexer=PygmentsLexer(RstLexer), input_processors=processors), right_margins=[ScrollbarMargin()], scroll_offsets=ScrollOffsets(top=2, bottom=2))) return HSplit([ # Top title bar. TokenListToolbar(get_tokens=_get_top_toolbar_tokens, align_center=True, default_char=Char(' ', Token.Toolbar.Status)), FloatContainer( content=VSplit([ # Left side: history. Window(content=BufferControl(buffer_name=HISTORY_BUFFER, lexer=PygmentsLexer(PythonLexer), input_processors=processors), wrap_lines=False, left_margins=[HistoryMargin(history_mapping)], scroll_offsets=ScrollOffsets(top=2, bottom=2)), # Separator. Window(width=D.exact(1), content=FillControl(BORDER.LIGHT_VERTICAL, token=Token.Separator)), # Right side: result. Window( content=BufferControl(buffer_name=DEFAULT_BUFFER, input_processors=processors + [GrayExistingText(history_mapping)], lexer=PygmentsLexer(PythonLexer)), wrap_lines=False, left_margins=[ResultMargin(history_mapping)], scroll_offsets=ScrollOffsets(top=2, bottom=2)), ]), floats=[ # Help text as a float. Float( width=60, top=3, bottom=2, content=ConditionalContainer( # (We use InFocusStack, because it's possible to search # through the help text as well, and at that point the search # buffer has the focus.) content=help_window, filter=InFocusStack(HELP_BUFFER))), ]), # Bottom toolbars. ArgToolbar(), SearchToolbar(), TokenListToolbar(get_tokens=partial(_get_bottom_toolbar_tokens, python_input=python_input), default_char=Char(' ', Token.Toolbar.Status)), ])
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 __init__(self): self.command_parser = BrewPiCommandParser(self) self.buffers = { DEFAULT_BUFFER: Buffer(completer=command_completer, enable_history_search=True, history=InMemoryHistory(), accept_action=AcceptAction(self.command_parser.parse)), 'MESSAGES': Buffer(), 'RESULT': Buffer(), 'STATE': Buffer(), } self.registry = load_key_bindings() self.registry.add_binding(Keys.ControlC, eager=True)(self._on_request_shutdown) self.registry.add_binding(Keys.ControlQ, eager=True)(self._on_request_shutdown) self.layout = HSplit([ # One window that holds the BufferControl with the default buffer on the # left. VSplit([ HSplit([ Window(content=TokenListControl(get_tokens=lambda cli: [( Token.Title, 'Command Result')]), height=D.exact(1)), Window(content=BufferControl(buffer_name='RESULT'), wrap_lines=True, left_margins=[ScrollbarMargin()]), ]), Window(width=D.exact(1), content=FillControl('|', token=Token.Line)), HSplit([ Window(content=TokenListControl(get_tokens=lambda cli: [( Token.Title, 'Raw Protocol Messages')]), height=D.exact(1)), Window( content=BufferControl(buffer_name='MESSAGES', lexer=PygmentsLexer(JsonLexer)), wrap_lines=True, left_margins=[NumberredMargin()], right_margins=[ScrollbarMargin()]) ]) ]), VSplit([ Window(content=TokenListControl( get_tokens=self.get_prompt_tokens), height=D.exact(1), dont_extend_width=True), Window(content=BufferControl(buffer_name=DEFAULT_BUFFER), height=D.exact(1), dont_extend_height=True), ]), Window(content=BufferControl(buffer_name='STATE'), height=D.exact(1), dont_extend_height=True) ]) super().__init__( layout=self.layout, buffers=self.buffers, key_bindings_registry=self.registry, mouse_support=True, style=style_from_pygments( get_style_by_name('emacs'), style_dict={ Token.Toolbar: '#ffffff bg:#333333', Token.Title: '#ffffff bg:#000088', # User input. Token: '#ff0066', # Prompt. Token.Name: '#884444 italic', Token.At: '#00aa00', Token.Colon: '#00aa00', Token.Pound: '#00aa00', Token.Host: '#000088 bg:#aaaaff', Token.Path: '#884444 underline', # Make a selection reverse/underlined. # (Use Control-Space to select.) Token.SelectedText: 'reverse underline', }), use_alternate_screen=True) # BrewPi Stuff self.controller_manager = BrewPiControllerManager() self.msg_decoder = RawMessageDecoder() self.controller = None
def __init__(self, text='', multiline=True, password=False, lexer=None, completer=None, accept_handler=None, focusable=True, wrap_lines=True, read_only=False, width=None, height=None, dont_extend_height=False, dont_extend_width=False, line_numbers=False, scrollbar=False, style='', input_processor=None, search_field=None, preview_search=True, prompt=''): assert isinstance(text, six.text_type) assert search_field is None or isinstance(search_field, SearchToolbar) if search_field is None: search_control = None elif isinstance(search_field, SearchToolbar): search_control = search_field.control self.buffer = Buffer( document=Document(text, 0), multiline=multiline, read_only=read_only, completer=completer, complete_while_typing=True, accept_handler=lambda buff: accept_handler and accept_handler()) self.control = BufferControl( buffer=self.buffer, lexer=lexer, input_processor=merge_processors([ ConditionalProcessor(processor=PasswordProcessor(), filter=to_filter(password)), HighlightSearchProcessor(preview_search=preview_search), HighlightSelectionProcessor(), DisplayMultipleCursors(), BeforeInput(prompt, style='class:text-area.prompt'), ]), search_buffer_control=search_control, preview_search=preview_search, focusable=focusable) if multiline: if scrollbar: right_margins = [ScrollbarMargin(display_arrows=True)] else: right_margins = [] if line_numbers: left_margins = [NumberedMargin()] else: left_margins = [] else: wrap_lines = False # Never wrap for single line input. 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=wrap_lines, left_margins=left_margins, right_margins=right_margins)
def __init__(self, debugger): self._filename = None self.sources = {} self.debugger = debugger self.debugger.events.on_stop += self.on_stop self.current_address_margin = CurrentAddressMargin() kb = KeyBindings() self.locals_processor = DisplayVariablesProcessor() self.source_buffer = Buffer(multiline=True) self.bar_buffer = Buffer(multiline=True) self.register_buffer = Buffer(multiline=True) self.logs_buffer = Buffer(multiline=True) @kb.add(Keys.F10, eager=True) def quit_(event): event.app.exit() @kb.add(Keys.F8) def clear_breakpoint_(event): if self.has_source(): filename, row = self.get_current_location() self.debugger.clear_breakpoint(filename, row) @kb.add(Keys.F7) def set_breakpoint_(event): if self.has_source(): filename, row = self.get_current_location() self.debugger.set_breakpoint(filename, row) @kb.add(Keys.F6) def step_(event): self.debugger.step() @kb.add(Keys.F5) def run_(event): self.debugger.run() @kb.add(Keys.F4) def stop_(event): self.debugger.stop() @kb.add(Keys.PageUp) def scroll_up_(event): self.source_buffer.cursor_up(count=15) @kb.add(Keys.PageDown) def scroll_down_(event): self.source_buffer.cursor_down(count=15) src_lexer = PygmentsLexer(CLexer) source_code_window = Window( content=BufferControl( buffer=self.source_buffer, lexer=src_lexer, input_processors=[self.locals_processor], ), left_margins=[self.current_address_margin, NumberedMargin()], right_margins=[ScrollbarMargin(display_arrows=True)], cursorline=True, ) register_window = Window( content=BufferControl(buffer=self.register_buffer), width=20) title_text = "Welcome to the ppci debugger version {} running in prompt_toolkit {}".format( ppci_version, ptk_version) help_text = ("F4=stop F5=run F6=step F7=set breakpoint" + " F8=clear breakpoint F10=exit") # Application layout: body = HSplit([ Window(content=FormattedTextControl(text=title_text), height=1), VSplit([ HSplit([ Frame( body=source_code_window, title="source-code", ), Window( content=BufferControl(buffer=self.logs_buffer), height=2, ), ]), Frame(body=register_window, title="registers"), ]), Window( content=FormattedTextControl(self.get_status_tokens), height=1, ), Window(content=FormattedTextControl(help_text), height=1), ]) layout = Layout(body) style = style_from_pygments_cls(get_style_by_name("vim")) log_handler = MyHandler(self.logs_buffer) fmt = logging.Formatter(fmt=logformat) log_handler.setFormatter(fmt) log_handler.setLevel(logging.DEBUG) logging.getLogger().setLevel(logging.DEBUG) logging.getLogger().addHandler(log_handler) self._event_loop = get_event_loop() self.application = Application(layout=layout, style=style, key_bindings=kb, full_screen=True)
WINDOW_VISIBILITY = { 'history': True, 'diff': False, } @Condition def diff_visible() -> bool: global WINDOW_VISIBILITY return WINDOW_VISIBILITY['diff'] MARGINS = [ ScrollbarMargin(display_arrows=True), ConditionalMargin(MyMargin(), filter=diff_visible) ] DIFF_CONTAINER = ConditionalContainer(DiffView(key_bindings=KD), filter=diff_visible) HISTORY_CONTAINER = HistoryContainer(KB, ARGUMENTS, right_margins=MARGINS) def get_container(): width = screen_width() if width >= 160: return VSplit([HISTORY_CONTAINER, DIFF_CONTAINER]) return HSplit([HISTORY_CONTAINER, DIFF_CONTAINER])
def sql_sidebar(my_app: "sqlApp") -> Window: """ Create the `Layout` for the sidebar with the configurable objects. """ @if_mousedown def expand_item(obj: "myDBObject") -> None: obj.expand() def tokenize_obj(obj: "myDBObject") -> StyleAndTextTuples: " Recursively build the token list " tokens: StyleAndTextTuples = [] selected = obj is my_app.selected_object expanded = obj.children is not None connected = obj.otype == "Connection" and obj.conn.connected() active = my_app.active_conn is not None and my_app.active_conn is obj.conn and obj.level == 0 act = ",active" if active else "" sel = ",selected" if selected else "" if len(obj.name) > 24 - 2 * obj.level: name_trim = obj.name[:24 - 2 * obj.level - 3] + "..." else: name_trim = ("%-" + str(24 - 2 * obj.level) + "s") % obj.name tokens.append(("class:sidebar.label" + sel + act, " >" if connected else " ")) tokens.append( ("class:sidebar.label" + sel, " " * 2 * obj.level, expand_item) ) tokens.append( ("class:sidebar.label" + sel + act, name_trim, expand_item) ) tokens.append(("class:sidebar.status" + sel + act, " ", expand_item)) tokens.append(("class:sidebar.status" + sel + act, "%+12s" % obj.otype, expand_item)) if selected: tokens.append(("[SetCursorPosition]", "")) if expanded: tokens.append(("class:sidebar.status" + sel + act, "\/")) else: tokens.append(("class:sidebar.status" + sel + act, " <" if selected else " ")) # Expand past the edge of the visible buffer to get an even panel tokens.append(("class:sidebar.status" + sel + act, " " * 10)) return tokens search_buffer = Buffer(name = "sidebarsearchbuffer") search_field = SearchToolbar( search_buffer = search_buffer, ignore_case = True ) def _buffer_pos_changed(buff): """ This callback gets executed after cursor position changes. Most of the time we register a key-press (up / down), we change the selected object and as a result of that the cursor changes. By that time we don't need to updat the selected object (cursor changed as a result of the selected object being updated). The one exception is when searching the sidebar buffer. When this happens the cursor moves ahead of the selected object. When that happens, here we update the selected object to follow suit. """ if buff.document.cursor_position_row != my_app.selected_object_idx[0]: my_app.select(buff.document.cursor_position_row) sidebar_buffer = Buffer( name = "sidebarbuffer", read_only = True, on_cursor_position_changed = _buffer_pos_changed ) class myLexer(Lexer): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._obj_list = [] def add_objects(self, objects: List): self._obj_list = objects def lex_document(self, document: Document) -> Callable[[int], StyleAndTextTuples]: def get_line(lineno: int) -> StyleAndTextTuples: # TODO: raise out-of-range exception return tokenize_obj(self._obj_list[lineno]) return get_line sidebar_lexer = myLexer() class myControl(BufferControl): def move_cursor_down(self): my_app.select_next() # Need to figure out what do do here # AFAICT these are only called for the mouse handler # when events are otherwise not handled def move_cursor_up(self): my_app.select_previous() def mouse_handler(self, mouse_event: MouseEvent) -> "NotImplementedOrNone": """ There is an intricate relationship between the cursor position in the sidebar document and which object is market as 'selected' in the linked list. Let's not muck that up by allowing the user to change the cursor position in the sidebar document with the mouse. """ return NotImplemented def create_content(self, width: int, height: Optional[int]) -> UIContent: # Only traverse the obj_list if it has been expanded / collapsed if not my_app.obj_list_changed: self.buffer.cursor_position = my_app.selected_object_idx[1] return super().create_content(width, height) res = [] obj = my_app.obj_list[0] res.append(obj) while obj.next_object is not my_app.obj_list[0]: res.append(obj.next_object) obj = obj.next_object self.lexer.add_objects(res) self.buffer.set_document(Document( text = "\n".join([a.name for a in res]), cursor_position = my_app.selected_object_idx[1]), True) # Reset obj_list_changed flag, now that we have had a chance to # regenerate the sidebar document content my_app.obj_list_changed = False return super().create_content(width, height) sidebar_control = myControl( buffer = sidebar_buffer, lexer = sidebar_lexer, search_buffer_control = search_field.control, focusable = True, ) return HSplit([ search_field, Window( sidebar_control, right_margins = [ScrollbarMargin(display_arrows = True)], style = "class:sidebar", width = Dimension.exact( 45 ), height = Dimension(min = 7, preferred = 33), scroll_offsets = ScrollOffsets(top = 1, bottom = 1)), Window( height = Dimension.exact(1), char = "\u2500", style = "class:sidebar,separator", ), expanding_object_notification(my_app), sql_sidebar_navigation()])
def __init__(self, config, out_queue, state=TaskState()): self.config = config tui_config = config['tui'] self.tui_config = tui_config self.out_queue = out_queue def commandHandler(buffer): #check incoming command cmdString = buffer.text #executeCommand(cmdString) pass def commandPrompt(line_number, wrap_count): return "command> " ######################################################################## kb = KeyBindings() @kb.add('c-d') def exit_(event): """ Pressing Esc will exit the user interface. Setting a return value means: quit the event loop that drives the user interface and return this value from the `CommandLineInterface.run()` call. """ event.app.exit() @kb.add('tab') def tab_(event): focus_next(event) @kb.add('s-tab') def stab_(event): focus_previous(event) @kb.add('s-right') def next_tab(event): state.next_tab() event.app.invalidate() @kb.add('s-left') def next_tab(event): state.prev_tab() event.app.invalidate() orders_kb = KeyBindings() @orders_kb.add('f5') def _(event): #command = ('refresh', something...) #self.out_queue.put_nowait(command) pass ######################################################################## outputArea = TextArea( text="", multiline=True, wrap_lines=False, #lexer=lexer.OutputAreaLexer(), #scrollbar=enableScrollbar, style='class:output-field', read_only=True) content_container = Frame(outputArea, title="Output") log_container = Frame( Window( BufferControl( buffer=Buffer(name='logger_buffer', read_only=True), input_processors=[FormatTextHTML()], ), right_margins=[ScrollbarMargin(display_arrows=True) ], # low-level scrollbar ), title='Log', height=8, ) command_container = TextArea(text="", multiline=False, accept_handler=commandHandler, get_line_prefix=commandPrompt) commandWindowFrame = Frame( command_container, title= "TuiTerminal (Ctrl-D to exit, Tab to switch focus and refresh UI, 'help' for help)", height=4) root_container = HSplit( [content_container, log_container, commandWindowFrame]) layout = Layout(root_container, focused_element=command_container) style = Style.from_dict({ 'output-field': 'bg:#101010', 'frame.border': 'SteelBlue', 'frame.label': 'PowderBlue', }) application = Application( layout=layout, key_bindings=kb, style=style, full_screen=tui_config.getboolean('full_screen'), mouse_support=tui_config.getboolean('mouse_support'), #after_render=after_render, ) self.application = application
def __init__(self) -> None: self._selected_index = 0 # Key bindings. kb = KeyBindings() @kb.add("up") def _up(event: E) -> None: self._selected_index = max(0, self._selected_index - 1) @kb.add("down") def _down(event: E) -> None: self._selected_index = min( len(self.values) - 1, self._selected_index + 1) @kb.add("pageup") def _pageup(event: E) -> None: w = event.app.layout.current_window if w.render_info: self._selected_index = max( 0, self._selected_index - len(w.render_info.displayed_lines)) @kb.add("pagedown") def _pagedown(event: E) -> None: w = event.app.layout.current_window if w.render_info: self._selected_index = min( len(self.values) - 1, self._selected_index + len(w.render_info.displayed_lines), ) @kb.add("enter") @kb.add(" ") def _click(event: E) -> None: self._handle_enter() @kb.add(Keys.Any) def _find(event: E) -> None: # We first check values after the selected value, then all values. values = list(self.values) for value in values[self._selected_index + 1:] + values: text = fragment_list_to_text(to_formatted_text( value[1])).lower() if text.startswith(event.data.lower()): self._selected_index = self.values.index(value) return # Control and window. self.control = FormattedTextControl(self._get_text_fragments, key_bindings=kb, focusable=True) self.window = Window( content=self.control, style=self.container_style, right_margins=[ ConditionalMargin( margin=ScrollbarMargin(display_arrows=True), filter=Condition(lambda: self.show_scrollbar), ), ], dont_extend_height=True, )
# 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()], ), ]) # 2. Key bindings kb = KeyBindings() @kb.add('q') @kb.add('c-c') def _(event): " Quit application. " event.app.exit()
def sql_sidebar(my_app: "sqlApp") -> Window: """ Create the `Layout` for the sidebar with the configurable objects. """ @if_mousedown def expand_item(obj: "myDBObject") -> None: obj.expand() def tokenize_obj(obj: "myDBObject") -> StyleAndTextTuples: " Recursively build the token list " tokens: StyleAndTextTuples = [] selected = obj is my_app.selected_object expanded = obj.children is not None connected = obj.otype == "Connection" and obj.conn.connected() active = my_app.active_conn is not None and my_app.active_conn is obj.conn and obj.level == 0 act = ",active" if active else "" sel = ",selected" if selected else "" if len(obj.name) > 24 - 2 * obj.level: name_trim = obj.name[:24 - 2 * obj.level - 3] + "..." else: name_trim = ("%-" + str(24 - 2 * obj.level) + "s") % obj.name tokens.append( ("class:sidebar.label" + sel + act, " >" if connected else " ")) tokens.append( ("class:sidebar.label" + sel, " " * 2 * obj.level, expand_item)) tokens.append( ("class:sidebar.label" + sel + act, name_trim, expand_item)) tokens.append(("class:sidebar.status" + sel + act, " ", expand_item)) tokens.append(("class:sidebar.status" + sel + act, "%+12s" % obj.otype, expand_item)) if selected: tokens.append(("[SetCursorPosition]", "")) if expanded: tokens.append(("class:sidebar.status" + sel + act, "\/")) else: tokens.append(("class:sidebar.status" + sel + act, " <" if selected else " ")) # Expand past the edge of the visible buffer to get an even panel tokens.append(("class:sidebar.status" + sel + act, " " * 10)) return tokens def _buffer_pos_changed(buff): """ When the cursor changes in the sidebar buffer, make sure the appropriate database object is market as selected """ # Only when this buffer has the focus. try: line_no = buff.document.cursor_position_row if line_no < 0: # When the cursor is above the inserted region. raise IndexError idx = 0 obj = my_app.obj_list[0] while idx < line_no: if not obj.next_object: raise IndexError idx += 1 obj = obj.next_object my_app.selected_object = obj except IndexError: pass search_buffer = Buffer(name="sidebarsearchbuffer") search_field = SearchToolbar(search_buffer=search_buffer, ignore_case=True) sidebar_buffer = Buffer(name="sidebarbuffer", read_only=True, on_cursor_position_changed=_buffer_pos_changed) class myLexer(Lexer): def __init__(self, token_list=None, *args, **kwargs): super().__init__(*args, **kwargs) self.token_list = token_list def lex_document( self, document: Document) -> Callable[[int], StyleAndTextTuples]: def get_line(lineno: int) -> StyleAndTextTuples: # TODO: raise out-of-range exception return self.token_list[lineno] return get_line def reset_tokens(self, tokens: [StyleAndTextTuples]): self.token_list = tokens sidebar_lexer = myLexer() class myControl(BufferControl): def move_cursor_down(self): my_app.select_next() # Need to figure out what do do here # AFAICT thse are only called for the mouse handler # when events are otherwise not handled def move_cursor_up(self): my_app.select_previous() def mouse_handler(self, mouse_event: MouseEvent) -> "NotImplementedOrNone": """ There is an intricate relationship between the cursor position in the sidebar document and which object is market as 'selected' in the linked list. Let's not muck that up by allowing the user to change the cursor position in the sidebar document with the mouse. """ return NotImplemented def create_content(self, width: int, height: Optional[int]) -> UIContent: res = [] res_tokens = [] count = 0 obj = my_app.obj_list[0] res.append(obj.name) res_tokens.append(tokenize_obj(obj)) found_selected = obj is my_app.selected_object idx = 0 while obj.next_object is not my_app.obj_list[0]: res.append(obj.next_object.name) res_tokens.append(tokenize_obj(obj.next_object)) if obj is not my_app.selected_object and not found_selected: count += 1 idx += len(obj.name) + 1 # Newline character else: found_selected = True obj = obj.next_object self.buffer.set_document( Document(text="\n".join(res), cursor_position=idx), True) self.lexer.reset_tokens(res_tokens) return super().create_content(width, height) sidebar_control = myControl( buffer=sidebar_buffer, lexer=sidebar_lexer, search_buffer_control=search_field.control, focusable=True, ) return HSplit([ search_field, Window(sidebar_control, right_margins=[ScrollbarMargin(display_arrows=True)], style="class:sidebar", width=Dimension.exact(45), height=Dimension(min=7, preferred=33), scroll_offsets=ScrollOffsets(top=1, bottom=1)), Window( height=Dimension.exact(1), char="\u2500", style="class:sidebar,separator", ), expanding_object_notification(my_app), sql_sidebar_navigation() ])
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, values: Sequence[Tuple[_T, AnyFormattedText]], current_values: Optional[_T] = undefined, current_value: Optional[_T] = undefined) -> None: self.values = values # current_values will be used in multiple_selection, # current_value will be used otherwise. self.current_values: List[_T] = [] self.current_value: _T = undefined self._selected_index = 0 if current_values != undefined: indexes = [i for i, (v, _) in enumerate(values) if v in current_values] if indexes: self._selected_index = indexes[0] self.current_values = [values[i][0] for i in indexes] if current_value != undefined: self._selected_index = [i for i, (v, _) in enumerate(values) if v == current_value][0] self.current_value = values[self._selected_index][0] # Key bindings. kb = KeyBindings() @kb.add("up") def _up(event: E) -> None: if self._selected_index == 0: focus_previous(event) return self._selected_index = max(0, self._selected_index - 1) @kb.add("down") def _down(event: E) -> None: if self._selected_index == len(self.values) - 1: focus_next(event) return self._selected_index = min(len(self.values) - 1, self._selected_index + 1) @kb.add("pageup") def _pageup(event: E) -> None: w = event.app.layout.current_window if w.render_info: self._selected_index = max( 0, self._selected_index - len(w.render_info.displayed_lines) ) @kb.add("pagedown") def _pagedown(event: E) -> None: w = event.app.layout.current_window if w.render_info: self._selected_index = min( len(self.values) - 1, self._selected_index + len(w.render_info.displayed_lines), ) @kb.add("enter") @kb.add(" ") def _click(event: E) -> None: self._handle_enter() if not self.multiple_selection: get_app().exit(result=self.current_value) @kb.add(Keys.Any) def _find(event: E) -> None: # We first check values after the selected value, then all values. values = list(self.values) for value in values[self._selected_index + 1 :] + values: text = fragment_list_to_text(to_formatted_text(value[1])).lower() if text.startswith(event.data.lower()): self._selected_index = self.values.index(value) return # Control and window. self.control = FormattedTextControl( self._get_text_fragments, key_bindings=kb, focusable=True ) self.window = Window( content=self.control, style=self.container_style, right_margins=[ ConditionalMargin( margin=ScrollbarMargin(display_arrows=True), filter=Condition(lambda: self.show_scrollbar), ), ], dont_extend_height=True, )
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, max_line_count=1000, initial_text="", align=WindowAlign.LEFT): assert isinstance(text, six.text_type) assert search_field is None or isinstance(search_field, SearchToolbar) 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.max_line_count = max_line_count self.buffer = CustomBuffer( 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: 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, align=align) self.log_lines: Deque[str] = deque() self.log(initial_text)
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())