def create_buffer_window(source_info): """ Window for the main content. """ pager = source_info.pager input_processors = [ ConditionalProcessor( processor=_EscapeProcessor(source_info), filter=Condition(lambda: not bool(source_info.source.lexer)), ), TabsProcessor(), ConditionalProcessor( processor=HighlightSearchProcessor(), filter=Condition(lambda: pager.highlight_search), ), ConditionalProcessor( processor=HighlightIncrementalSearchProcessor(), filter=Condition(lambda: pager.highlight_search), ), HighlightSelectionProcessor(), HighlightMatchingBracketProcessor(), ] return Window( always_hide_cursor=True, content=BufferControl( buffer=source_info.buffer, lexer=source_info.source.lexer, input_processors=input_processors, include_default_input_processors=False, preview_search=True, search_buffer_control=pager.layout.search_toolbar.control))
def create_python_input_window(): def menu_position(cli): """ When there is no autocompletion menu to be shown, and we have a signature, set the pop-up position at `bracket_start`. """ b = cli.buffers['default'] if b.complete_state is None and settings.signatures: row, col = settings.signatures[0].bracket_start index = b.document.translate_row_col_to_index(row - 1, col) return index return Window( BufferControl( buffer_name=DEFAULT_BUFFER, lexer=lexer, show_line_numbers=ShowLineNumbersFilter(settings, 'default'), input_processors=[ # Show matching parentheses, but only while editing. ConditionalProcessor( processor=HighlightMatchingBracketProcessor(chars='[](){}'), filter=HasFocus(DEFAULT_BUFFER) & ~IsDone()), HighlightSearchProcessor(preview_search=Always()), HighlightSelectionProcessor()] + extra_buffer_processors, menu_position=menu_position, # Make sure that we always see the result of an reverse-i-search: preview_search=Always(), ), # As long as we're editing, prefer a minimal height of 6. get_height=(lambda cli: (None if cli.is_done else D(min=6))), )
def get_buffer_window(self): " Return the Container object according to which Buffer/Source is visible. " source = self.pager.source if source not in self._bodies: input_processors = [ ConditionalProcessor( processor=_EscapeProcessor(self.pager), filter=Condition( lambda cli: not bool(self.pager.source.lexer)), ), TabsProcessor(), HighlightSelectionProcessor(), ConditionalProcessor( processor=HighlightSearchProcessor(preview_search=True), filter=Condition(lambda cli: self.pager.highlight_search), ), HighlightMatchingBracketProcessor(), ] buffer_window = Window( always_hide_cursor=True, content=BufferControl( buffer_name=self.pager.source_info[source].buffer_name, lexer=source.lexer, input_processors=input_processors)) self._bodies[source] = buffer_window return self._bodies[source]
def create_python_input_window(): def menu_position(): """ When there is no autocompletion menu to be shown, and we have a signature, set the pop-up position at `bracket_start`. """ b = python_input.default_buffer if b.complete_state is None and python_input.signatures: row, col = python_input.signatures[0].bracket_start index = b.document.translate_row_col_to_index(row - 1, col) return index return Window( BufferControl( buffer=python_input.default_buffer, search_buffer_control=search_toolbar.control, lexer=lexer, include_default_input_processors=False, input_processors=[ ConditionalProcessor( processor=HighlightIncrementalSearchProcessor(), filter=has_focus(SEARCH_BUFFER) | has_focus(search_toolbar.control), ), HighlightSelectionProcessor(), DisplayMultipleCursors(), # Show matching parentheses, but only while editing. ConditionalProcessor( processor=HighlightMatchingBracketProcessor(chars="[](){}"), filter=has_focus(DEFAULT_BUFFER) & ~is_done & Condition( lambda: python_input.highlight_matching_parenthesis ), ), ConditionalProcessor( processor=AppendAutoSuggestion(), filter=~is_done ), ] + extra_buffer_processors, menu_position=menu_position, # Make sure that we always see the result of an reverse-i-search: preview_search=True, ), left_margins=[PythonPromptMargin(python_input)], # Scroll offsets. The 1 at the bottom is important to make sure # the cursor is never below the "Press [Meta+Enter]" message # which is a float. scroll_offsets=ScrollOffsets(bottom=1, left=4, right=4), # As long as we're editing, prefer a minimal height of 6. height=( lambda: ( None if get_app().is_done or python_input.show_exit_confirmation else input_buffer_height ) ), wrap_lines=Condition(lambda: python_input.wrap_lines), )
def create_default_layout(message='', lexer=None, is_password=False, reserve_space_for_menu=False, get_bottom_toolbar_tokens=None): """ Generate default layout. """ assert get_bottom_toolbar_tokens is None or callable(get_bottom_toolbar_tokens) # Create processors list. input_processors = [HighlightSearchProcessor(), HighlightSelectionProcessor()] if is_password: input_processors.extend([PasswordProcessor(), DefaultPrompt(message)]) else: input_processors.append(DefaultPrompt(message)) # Create bottom toolbar. if get_bottom_toolbar_tokens: toolbars = [Window(TokenListControl(get_bottom_toolbar_tokens, default_char=Char(' ', Token.Toolbar)), height=LayoutDimension.exact(1), filter=~IsDone())] 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() # Create and return Layout instance. return HSplit([ 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()), get_height=get_height, ), [ Float(xcursor=True, ycursor=True, content=CompletionsMenu(max_height=16, extra_filter=HasFocus(DEFAULT_BUFFER))) ] ), ValidationToolbar(), SystemToolbar(), ] + toolbars)
def create_python_input_window(): def menu_position(cli): """ When there is no autocompletion menu to be shown, and we have a signature, set the pop-up position at `bracket_start`. """ b = cli.buffers[DEFAULT_BUFFER] if b.complete_state is None and python_input.signatures: row, col = python_input.signatures[0].bracket_start index = b.document.translate_row_col_to_index(row - 1, col) return index return Window( BufferControl( buffer_name=DEFAULT_BUFFER, lexer=lexer, input_processors=[ ConditionalProcessor( processor=HighlightSearchProcessor( preview_search=True), filter=HasFocus(SEARCH_BUFFER), ), HighlightSelectionProcessor(), # Show matching parentheses, but only while editing. ConditionalProcessor( processor=HighlightMatchingBracketProcessor( chars='[](){}'), filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() & Condition(lambda cli: python_input. highlight_matching_parenthesis)), ConditionalProcessor(processor=AppendAutoSuggestion(), filter=~IsDone()) ] + extra_buffer_processors, menu_position=menu_position, # Make sure that we always see the result of an reverse-i-search: preview_search=True, ), left_margins=[PythonPromptMargin(python_input)], # Scroll offsets. The 1 at the bottom is important to make sure the # cursor is never below the "Press [Meta+Enter]" message which is a float. scroll_offsets=ScrollOffsets(bottom=1, left=4, right=4), # As long as we're editing, prefer a minimal height of 6. get_height=(lambda cli: (None if cli.is_done or python_input. show_exit_confirmation else input_buffer_height)), wrap_lines=Condition(lambda cli: python_input.wrap_lines), )
def _create_buffer_control(self, editor_buffer): """ Create a new BufferControl for a given location. """ @Condition def preview_search(): return self.editor.incsearch input_processors = [ # Processor for visualising spaces. (should come before the # selection processor, otherwise, we won't see these spaces # selected.) ConditionalProcessor( ShowTrailingWhiteSpaceProcessor(), Condition(lambda: self.editor.display_unprintable_characters)), # Replace tabs by spaces. TabsProcessor( tabstop=(lambda: self.editor.tabstop), char1=(lambda: '|' if self.editor.display_unprintable_characters else ' '), char2=(lambda: _try_char('\u2508', '.', get_app().output.encoding()) if self.editor.display_unprintable_characters else ' '), ), # Reporting of errors, for Pyflakes. ReportingProcessor(editor_buffer), HighlightSelectionProcessor(), ConditionalProcessor( HighlightSearchProcessor(), Condition(lambda: self.editor.highlight_search)), ConditionalProcessor( HighlightIncrementalSearchProcessor(), Condition(lambda: self.editor.highlight_search) & preview_search), HighlightMatchingBracketProcessor(), DisplayMultipleCursors(), ] return BufferControl(lexer=DocumentLexer(editor_buffer), include_default_input_processors=False, input_processors=input_processors, buffer=editor_buffer.buffer, preview_search=preview_search, search_buffer_control=self.search_control, focus_on_click=True)
def __init__( self, text="", focusable=False, wrap_lines=True, width=None, height=None, scrollbar=False, dont_extend_height=True, dont_extend_width=False, read_only=True, ): self.read_only = read_only formatted_text = to_formatted_text(text) plain_text = fragment_list_to_text(formatted_text) self.buffer = Buffer( document=Document(plain_text, 0), read_only=Condition(lambda: self.read_only), ) self.control = FormattedBufferControl( buffer=self.buffer, formatted_text=formatted_text, input_processors=[ FormatTextProcessor(), HighlightSelectionProcessor() ], include_default_input_processors=False, focusable=focusable, focus_on_click=focusable, ) self.scrollbar = scrollbar right_margins = [ ConditionalMargin( ScrollbarMargin(display_arrows=True), filter=Condition(lambda: self.scrollbar), ), ] self.window = Window( content=self.control, width=width, height=height, wrap_lines=wrap_lines, right_margins=right_margins, dont_extend_height=dont_extend_height, dont_extend_width=dont_extend_width, )
def _create_buffer_control(self, editor_buffer): """ Create a new BufferControl for a given filename. """ filename = editor_buffer.filename buffer_name = editor_buffer.buffer_name @Condition def preview_search(cli): return self.editor.incsearch input_processors = [ # Highlighting of the search. ConditionalProcessor( HighlightSearchProcessor(preview_search=preview_search), Condition(lambda cli: self.editor.highlight_search)), # Processor for visualising spaces. (should come before the # selection processor, otherwise, we won't see these spaces # selected.) ConditionalProcessor( ShowTrailingWhiteSpaceProcessor(), Condition( lambda cli: self.editor.display_unprintable_characters)), # Highlight selection. HighlightSelectionProcessor(), # Highlight matching parentheses. HighlightMatchingBracketProcessor(), # Reporting of errors, for Pyflakes. ReportingProcessor(editor_buffer), # Replace tabs by spaces. TabsProcessor(self.editor) ] return BufferControl(show_line_numbers=Condition( lambda cli: self.editor.show_line_numbers), lexer=DocumentLexer(editor_buffer), input_processors=input_processors, buffer_name=buffer_name, preview_search=preview_search)
def _create_buffer_control(self, editor_buffer): """ Create a new BufferControl for a given location. """ buffer_name = editor_buffer.buffer_name @Condition def preview_search(cli): return self.editor.incsearch input_processors = [ # Processor for visualising spaces. (should come before the # selection processor, otherwise, we won't see these spaces # selected.) ConditionalProcessor( ShowTrailingWhiteSpaceProcessor(), Condition( lambda cli: self.editor.display_unprintable_characters)), # Replace tabs by spaces. TabsProcessor( tabstop=Integer.from_callable(lambda: self.editor.tabstop), get_char1=( lambda cli: '|' if self.editor.display_unprintable_characters else ' '), get_char2=( lambda cli: '\u2508' if self.editor.display_unprintable_characters else ' '), ), # Reporting of errors, for Pyflakes. ReportingProcessor(editor_buffer), HighlightSelectionProcessor(), ConditionalProcessor( HighlightSearchProcessor(preview_search=preview_search), Condition(lambda cli: self.editor.highlight_search)), HighlightMatchingBracketProcessor(), ] return BufferControl(lexer=DocumentLexer(editor_buffer), input_processors=input_processors, buffer_name=buffer_name, preview_search=preview_search, focus_on_click=True)
def __init__(self, shell_ctx): self.shell_ctx = shell_ctx @Condition def show_default(_): return self.shell_ctx.is_showing_default @Condition def show_symbol(_): return self.shell_ctx.is_symbols @Condition def show_progress(_): progress = get_progress_message() done = get_done() return progress != '' and not done @Condition def has_default_scope(_): return self.shell_ctx.default_command == '' self.has_default_scope = has_default_scope self.show_default = show_default self.show_symbol = show_symbol self.show_progress = show_progress # TODO fix this somehow self.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) & self.has_default_scope) ]
def preview_element(my_app: "sqlApp"): help_text = """ Press Enter in the input box to page through the table. Alternatively, enter a filtering SQL statement and then press Enter to page through the results. """ formatter = TabularOutputFormatter() input_buffer = Buffer(name="previewbuffer", tempfile_suffix=".sql", multiline=False) input_control = BufferControl(buffer=input_buffer, include_default_input_processors=False, preview_search=False) input_window = Window(input_control, ) search_buffer = Buffer(name="previewsearchbuffer") search_field = SearchToolbar(search_buffer) output_field = TextArea( style="class:preview-output-field", text=help_text, height=D(preferred=50), search_field=search_field, wrap_lines=False, focusable=True, read_only=True, preview_search=True, input_processors=[ ConditionalProcessor( processor=HighlightIncrementalSearchProcessor(), filter=has_focus("previewsearchbuffer") | has_focus(search_field.control), ), HighlightSelectionProcessor(), ]) def refresh_results(window_height) -> bool: sql_conn = my_app.selected_object.conn if sql_conn.execution_status == executionStatus.FAIL: # Let's display the error message to the user output = sql_conn.execution_err else: crsr = sql_conn.cursor if crsr.description: cols = [col.name for col in crsr.description] else: cols = [] if len(cols): sql_conn.status = connStatus.FETCHING res = sql_conn.async_fetchmany(size=window_height - 4) output = formatter.format_output(res, cols, format_name="psql") output = "\n".join(output) else: sql_conn.status = connStatus.IDLE output = "No rows returned\n" # Add text to output buffer. output_field.buffer.set_document( Document(text=output, cursor_position=0), True) return True def accept(buff: Buffer) -> bool: obj = my_app.selected_object sql_conn = obj.conn catalog = None schema = None # TODO: Verify connected if obj.parent is not None: if type(obj.parent).__name__ == "myDBSchema": schema = obj.parent.name elif type(obj.parent).__name__ == "myDBCatalog": catalog = obj.parent.name if obj.parent.parent is not None: if type(obj.parent.parent).__name__ == "myDBCatalog": catalog = obj.parent.parent.name if catalog: catalog = (sql_conn.quotechar + "%s" + sql_conn.quotechar) % catalog if schema: schema = (sql_conn.quotechar + "%s" + sql_conn.quotechar) % schema name = (sql_conn.quotechar + "%s" + sql_conn.quotechar) % obj.name identifier = ".".join(list(filter(None, [catalog, schema, obj.name]))) query = sql_conn.preview_query(table=identifier, filter_query=buff.text, limit=my_app.preview_limit_rows) func = partial( refresh_results, window_height=output_field.window.render_info.window_height) # If status is IDLE, this is the first time we are executing. if sql_conn.query != query or sql_conn.status == connStatus.IDLE: # Exit the app to execute the query my_app.application.exit(result=["preview", query]) my_app.application.pre_run_callables.append(func) else: # No need to exit let's just go and fetch func() return True # Keep filter text input_buffer.accept_handler = accept def cancel_handler() -> None: sql_conn = my_app.selected_object.conn sql_conn.close_cursor() sql_conn.status = connStatus.IDLE input_buffer.text = "" output_field.buffer.set_document( Document(text=help_text, cursor_position=0), True) my_app.show_preview = False my_app.show_sidebar = True my_app.application.layout.focus(input_buffer) my_app.application.layout.focus("sidebarbuffer") return None cancel_button = Button(text="Done", handler=cancel_handler) container = HSplit([ Box(body=VSplit([input_window, cancel_button], padding=1), padding=1, style="class:preview-input-field"), Window(height=1, char="-", style="class:preview-divider-line"), output_field, search_field, ]) frame = Shadow(body=Frame(title="Table Preview", body=container, style="class:dialog.body", width=D(preferred=180, min=30), modal=True)) return ConditionalContainer(content=frame, filter=ShowPreview(my_app) & ~is_done)
def _create_layout(self): """ Generate the main prompt_toolkit layout. """ waits_for_confirmation = WaitsForConfirmation(self.pymux) waits_for_prompt = WaitsForPrompt(self.pymux) in_command_mode = InCommandMode(self.pymux) return FloatContainer( content=HSplit([ # The main window. HighlightBorders( self, self.pymux, FloatContainer(Background(), floats=[ Float(get_width=lambda cli: self.pymux. get_window_size(cli).columns, get_height=lambda cli: self.pymux. get_window_size(cli).rows, content=TraceBodyWritePosition( self.pymux, DynamicBody(self.pymux))) ])), # Status bar. ConditionalContainer( content=VSplit([ # Left. Window(height=D.exact(1), get_width=(lambda cli: D(max=self.pymux. status_left_length)), dont_extend_width=True, content=TokenListControl( self._get_status_left_tokens, default_char=Char(' ', Token.StatusBar))), # List of windows in the middle. Window(height=D.exact(1), content=TokenListControl( self._get_status_tokens, align_right=Condition( self._status_align_right), align_center=Condition( self._status_align_center), default_char=Char(' ', Token.StatusBar))), # Right. Window(height=D.exact(1), get_width=(lambda cli: D(max=self.pymux. status_right_length)), dont_extend_width=True, content=TokenListControl( self._get_status_right_tokens, align_right=True, default_char=Char(' ', Token.StatusBar))) ]), filter=Condition(lambda cli: self.pymux.enable_status), ) ]), floats=[ Float(bottom=1, left=0, content=MessageToolbar(self.pymux)), Float( left=0, right=0, bottom=0, content=HSplit([ # Wait for confirmation toolbar. ConditionalContainer( content=Window( height=D.exact(1), content=ConfirmationToolbar(self.pymux), ), filter=waits_for_confirmation, ), # ':' prompt toolbar. ConditionalContainer( content=Window( height=D( min=1 ), # Can be more if the command is multiline. dont_extend_height=True, content=BufferControl( buffer_name=COMMAND, default_char=Char(' ', Token.CommandLine), lexer=SimpleLexer(Token.CommandLine), preview_search=True, input_processors=[ AppendAutoSuggestion(), DefaultPrompt(lambda cli: [( Token.CommandLine.Prompt, ':')]), HighlightSelectionProcessor(), ])), filter=in_command_mode, ), # Other command-prompt commands toolbar. ConditionalContainer( content=Window( height=D.exact(1), content=BufferControl( buffer_name=PROMPT, default_char=Char(' ', Token.CommandLine), lexer=SimpleLexer(Token.CommandLine), input_processors=[ BeforeInput( self._before_prompt_command_tokens ), AppendAutoSuggestion(), HighlightSelectionProcessor(), ])), filter=waits_for_prompt, ), ])), Float(xcursor=True, ycursor=True, content=CompletionsMenu(max_height=12)), ])
def __init__(self, command=['/bin/bash'], before_exec_func=None, bell_func=None, style='', width=None, height=None, done_callback=None): self.terminal_control = _TerminalControl( command=command, before_exec_func=before_exec_func, bell_func=bell_func, done_callback=done_callback) self.terminal_window = _Window(terminal_control=self.terminal_control, content=self.terminal_control, wrap_lines=False) # Key bindigns for copy buffer. kb = KeyBindings() @kb.add('c-c') def _(event): self.exit_copy_mode() @kb.add('space') def _(event): " Reset selection. " event.current_buffer.start_selection() @kb.add('enter', filter=has_selection) def _(event): " Reset selection. " data = event.current_buffer.copy_selection() event.app.clipboard.set_data(data) self.search_toolbar = SearchToolbar( forward_search_prompt='Search down: ', backward_search_prompt='Search up: ') self.copy_buffer = Buffer(read_only=True) self.copy_buffer_control = BufferControl( buffer=self.copy_buffer, search_buffer_control=self.search_toolbar.control, include_default_input_processors=False, input_processors=[ _UseStyledTextProcessor(self), HighlightSelectionProcessor(), HighlightSearchProcessor(), HighlightIncrementalSearchProcessor(), ], preview_search= True, # XXX: not sure why we need twice preview_search. key_bindings=kb) self.copy_window = Window(content=self.copy_buffer_control, wrap_lines=False) self.is_copying = False self.styled_copy_lines = [ ] # List of lists of (style, text) tuples, for each line. @Condition def is_copying(): return self.is_copying self.container = FloatContainer( content=HSplit( [ # Either show terminal window or copy buffer. VSplit([ # XXX: this nested VSplit should not have been necessary, # but the ConditionalContainer which width can become # zero will collapse the other elements. ConditionalContainer(self.terminal_window, filter=~is_copying), ConditionalContainer(self.copy_window, filter=is_copying), ]), ConditionalContainer(self.search_toolbar, filter=is_copying), ], style=style, width=width, height=height), floats=[ Float(top=0, right=0, height=1, content=ConditionalContainer(Window( content=FormattedTextControl( text=self._copy_position_formatted_text), style='class:copy-mode-cursor-position'), filter=is_copying)) ])
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 _create_layout(self): """ Generate the main prompt_toolkit layout. """ waits_for_confirmation = WaitsForConfirmation(self.pymux) return FloatContainer( content=HSplit([ # The main window. FloatContainer( Background(), floats=[ Float( width=lambda: self.pymux.get_window_size().columns, height=lambda: self.pymux.get_window_size().rows, content=DynamicBody(self.pymux)) ]), # Status bar. ConditionalContainer( content=VSplit( [ # Left. Window(height=1, width=(lambda: D(max=self.pymux. status_left_length)), dont_extend_width=True, content=FormattedTextControl( self._get_status_left_tokens)), # List of windows in the middle. Window(height=1, char=' ', align=self._get_align, content=FormattedTextControl( self._get_status_tokens)), # Right. Window(height=1, width=(lambda: D(max=self.pymux. status_right_length)), dont_extend_width=True, align=WindowAlign.RIGHT, content=FormattedTextControl( self._get_status_right_tokens)) ], z_index=Z_INDEX.STATUS_BAR, style='class:statusbar'), filter=Condition(lambda: self.pymux.enable_status), ) ]), floats=[ Float(bottom=1, left=0, z_index=Z_INDEX.MESSAGE_TOOLBAR, content=MessageToolbar(self.client_state)), Float( left=0, right=0, bottom=0, content=HSplit([ # Wait for confirmation toolbar. ConditionalContainer( content=Window( height=1, content=ConfirmationToolbar( self.pymux, self.client_state), z_index=Z_INDEX.COMMAND_LINE, ), filter=waits_for_confirmation, ), # ':' prompt toolbar. ConditionalContainer( content=Window( height=D( min=1 ), # Can be more if the command is multiline. style='class:commandline', dont_extend_height=True, content=BufferControl( buffer=self.client_state.command_buffer, preview_search=True, input_processors=[ AppendAutoSuggestion(), BeforeInput( ':', style='class:commandline-prompt'), ShowArg(), HighlightSelectionProcessor(), ]), z_index=Z_INDEX.COMMAND_LINE, ), filter=has_focus(self.client_state.command_buffer), ), # Other command-prompt commands toolbar. ConditionalContainer( content=Window( height=1, style='class:commandline', content=BufferControl( buffer=self.client_state.prompt_buffer, input_processors=[ BeforeInput( self._before_prompt_command_tokens ), AppendAutoSuggestion(), HighlightSelectionProcessor(), ]), z_index=Z_INDEX.COMMAND_LINE, ), filter=has_focus(self.client_state.prompt_buffer), ), ])), # Keys pop-up. Float( content=ConditionalContainer( content=self.popup_dialog, filter=Condition( lambda: self.client_state.display_popup), ), left=3, right=3, top=5, bottom=5, z_index=Z_INDEX.POPUP, ), Float(xcursor=True, ycursor=True, content=CompletionsMenu(max_height=12)), ])
def __init__( self, entries, preview_callback=None, input_callback=None, input_completions=None, ): if not entries or len(entries) == 0: raise RuntimeError("Entries cannot be empty.") self.entries = entries self.input_callback = input_callback self.preview_callback = preview_callback self.ansi_escape_8bit = re.compile( r"(?:\x1B[@-Z\\-_]|[\x80-\x9A\x9C-\x9F]|(?:\x1B\[|\x9B)[0-?]*[ -/]*[@-~])" ) self.current_lineno = 1 self.max_entry_width = min( max( map( lambda x: len(x) + 1, self.ansi_escape_8bit.sub("", entries).split("\n") ) ), 48, ) entries_text = ANSI(self.entries) entries_formatted_text = to_formatted_text(entries_text) entries_plain_text = fragment_list_to_text(entries_formatted_text) self.entries_control = FormattedBufferControl( buffer=Buffer( document=Document(entries_plain_text, 0), name="entries", on_cursor_position_changed=self.update_entries, read_only=True, ), focusable=True, formatted_text=entries_formatted_text, include_default_input_processors=False, input_processors=[FormatTextProcessor(), HighlightSelectionProcessor()], ) if self.preview_callback: self.preview_text = ANSI(self.preview_callback(self.current_lineno)) formatted_text = to_formatted_text(self.preview_text) plain_text = fragment_list_to_text(formatted_text) self.preview_control = FormattedBufferControl( buffer=Buffer( document=Document(plain_text, 0), name="preview", on_cursor_position_changed=self.update_preview, read_only=True, ), focusable=True, formatted_text=formatted_text, include_default_input_processors=False, input_processors=[FormatTextProcessor(), HighlightSelectionProcessor()], ) # Alternative (not scrollable): # self.preview_control = FormattedTextControl( # focusable=True, # show_cursor=True, # text=ANSI(self.preview_callback(self.current_lineno)), # ) entries_container = VSplit( [ Window( content=self.entries_control, width=self.max_entry_width, wrap_lines=True, ), Window(width=3, char=" | "), Window(content=self.preview_control, wrap_lines=True), ] ) else: entries_container = Window( content=self.entries_control, width=self.max_entry_width, wrap_lines=True, ) if self.input_callback: self.search_field = SearchToolbar() self.input_field = TextArea( accept_handler=self.input_accept, completer=FuzzyWordCompleter(list(input_completions)), complete_while_typing=True, height=1, multiline=False, prompt="> ", search_field=self.search_field, wrap_lines=False, ) self.root_container = FloatContainer( content=HSplit( [entries_container, Window(height=1, char="-"), self.input_field,] ), floats=[ Float( content=CompletionsMenu(max_height=16, scroll_offset=1), xcursor=True, ycursor=True, ) ], ) else: self.root_container = entries_container self.layout = Layout(self.root_container) self.app = Application(full_screen=True, key_bindings=kb, layout=self.layout)
def main(self, data): fr = FileReader(data) bc = BufferCache() all_input_processors = [ ConditionalProcessor(HighlightSearchProcessor(), ~is_searching), HighlightIncrementalSearchProcessor(), HighlightSelectionProcessor(), DisplayMultipleCursors(), ] search_toolbar = SearchToolbar(vi_mode=True) lst_window = Window( BufferControl( Buffer( name="file_list", document=Document(fr.get_list_text(), cursor_position=0), read_only=True, ), search_buffer_control=search_toolbar.control, preview_search=True, include_default_input_processors=False, input_processors=all_input_processors, ), cursorline=True, ) txt_window = Window( BufferControl( bc.current_buffer, search_buffer_control=search_toolbar.control, preview_search=True, include_default_input_processors=False, input_processors=all_input_processors, ), wrap_lines=False, ) toolbar = FormattedTextToolbar(text="hello world!", style="class:buf_name") body = HSplit([lst_window]) # Key bind kb = KeyBindings() kb.add(Keys.ControlD)(scroll_half_page_down) kb.add(Keys.ControlU)(scroll_half_page_up) @kb.add(Keys.ControlQ) def _(event): event.app.exit() @kb.add(Keys.Enter, filter=has_focus("file_list")) def _(event): idx = event.current_buffer.document.cursor_position_row path = str(fr.get_path(idx)) origin_data = str(fr.get_relative_path(idx)) origin_data2 = origin_data.split("|")[0] number = origin_data2.split(":")[-1] command = "vim " + "+" + number + " " + path res = subprocess.call(command.split()) @kb.add("k") def _(event): event.current_buffer.cursor_up() idx = event.current_buffer.document.cursor_position_row path = str(fr.get_relative_path(idx)) try: set_buffer_txt_window(bc.get_or_append_buffer(path, "AAAAA")) set_text_toolbar(bc.current_buffer_name) except: pass @kb.add("j") def _(event): event.current_buffer.cursor_down() idx = event.current_buffer.document.cursor_position_row path = str(fr.get_relative_path(idx)) set_buffer_txt_window(bc.get_or_append_buffer(path, "AAAAA")) set_text_toolbar(bc.current_buffer_name) def set_buffer_txt_window(buf): txt_window.content.buffer = buf def set_text_toolbar(text): toolbar.content.text = text @Condition def search_buffer_is_empty(): return get_app().current_buffer.text == "" style = Style([ ("buf_name", "fg:#dddddd bg:#8a2be2"), ("incsearch", "fg:ansibrightyellow reverse"), ]) app = Application(layout=Layout(body), key_bindings=kb, full_screen=True, style=style) app.run()
def create_default_layout(message='', lexer=None, is_password=False, reserve_space_for_menu=False, get_prompt_tokens=None, get_bottom_toolbar_tokens=None, extra_input_processors=None): """ Generate default layout. Returns a ``Layout`` instance. :param message: Text to be used as prompt. :param lexer: Pygments lexer to be used for the highlighting. :param is_password: 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. """ 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) # Create processors list. # (DefaultPrompt should always be at the end.) input_processors = [ HighlightSearchProcessor(preview_search=Always()), HighlightSelectionProcessor() ] if is_password: input_processors.append(PasswordProcessor()) if extra_input_processors: input_processors.extend(extra_input_processors) if message: input_processors.append(DefaultPrompt.from_message(message)) else: input_processors.append(DefaultPrompt(get_prompt_tokens)) # Create bottom toolbar. if get_bottom_toolbar_tokens: toolbars = [ 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() # Create and return Layout instance. return HSplit([ 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()), get_height=get_height, ), [ Float(xcursor=True, ycursor=True, content=CompletionsMenu(max_height=16, extra_filter=HasFocus( DEFAULT_BUFFER))) ]), ValidationToolbar(), SystemToolbar(), ] + toolbars)
def _create_application(self, editing_mode, erase_when_done): def dyncond(attr_name): """ Dynamically take this setting from this 'Prompt' class. `attr_name` represents an attribute name of this class. Its value can either be a boolean or a `Filter`. This returns something that can be used as either a `Filter` or `Filter`. """ @Condition def dynamic(): value = getattr(self, attr_name) return to_filter(value)() return dynamic # Create functions that will dynamically split the prompt. (If we have # a multiline prompt.) has_before_fragments, get_prompt_text_1, get_prompt_text_2 = \ _split_multiline_prompt(self._get_prompt) # Create buffers list. def accept(buff): """ Accept the content of the default buffer. This is called when the validation succeeds. """ self.app.set_result(buff.document.text) # Reset content before running again. self.app.pre_run_callables.append(buff.reset) default_buffer = Buffer( name=DEFAULT_BUFFER, # Make sure that complete_while_typing is disabled when # enable_history_search is enabled. (First convert to Filter, # to avoid doing bitwise operations on bool objects.) complete_while_typing=Condition( lambda: _true(self.complete_while_typing) and not _true( self.enable_history_search) and not self.complete_style == CompleteStyle.READLINE_LIKE), validate_while_typing=dyncond('validate_while_typing'), enable_history_search=dyncond('enable_history_search'), validator=DynamicValidator(lambda: self.validator), completer=ThreadedCompleter( completer=DynamicCompleter(lambda: self.completer), in_thread=dyncond('complete_in_thread'), ), history=DynamicHistory(lambda: self.history), auto_suggest=DynamicAutoSuggest(lambda: self.auto_suggest), accept_handler=accept, get_tempfile_suffix=lambda: self.tempfile_suffix) search_buffer = Buffer(name=SEARCH_BUFFER) # Create processors list. input_processor = merge_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=True), has_focus(search_buffer)), HighlightSelectionProcessor(), ConditionalProcessor(AppendAutoSuggestion(), has_focus(default_buffer) & ~is_done), ConditionalProcessor(PasswordProcessor(), dyncond('is_password')), DisplayMultipleCursors(), # Users can insert processors here. DynamicProcessor(lambda: self.extra_input_processor), # For single line mode, show the prompt before the input. ConditionalProcessor( merge_processors([ BeforeInput(get_prompt_text_2), ShowArg(), ]), ~dyncond('multiline')) ]) # Create bottom toolbars. bottom_toolbar = ConditionalContainer( Window(FormattedTextControl(lambda: self.bottom_toolbar, style='class:bottom-toolbar.text'), style='class: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)) search_toolbar = SearchToolbar( search_buffer, get_search_state=lambda: default_buffer_control.get_search_state()) search_buffer_control = BufferControl(buffer=search_buffer, input_processor=merge_processors( [ ReverseSearchProcessor(), ShowArg(), ])) system_toolbar = SystemToolbar() def get_search_buffer_control(): " Return the UIControl to be focused when searching start. " if _true(self.multiline): return search_toolbar.control else: return search_buffer_control default_buffer_control = BufferControl( buffer=default_buffer, get_search_buffer_control=get_search_buffer_control, input_processor=input_processor, lexer=DynamicLexer(lambda: self.lexer), preview_search=True) default_buffer_window = Window( default_buffer_control, height=self._get_default_buffer_control_height, left_margins=[ # In multiline mode, use the window margin to display # the prompt and continuation fragments. ConditionalMargin( PromptMargin(get_prompt_text_2, self._get_continuation), filter=dyncond('multiline'), ) ], wrap_lines=dyncond('wrap_lines')) @Condition def multi_column_complete_style(): return self.complete_style == CompleteStyle.MULTI_COLUMN # Build the layout. layout = HSplit([ # The main input, with completion menus floating on top of it. FloatContainer( HSplit([ ConditionalContainer( Window(FormattedTextControl(get_prompt_text_1), dont_extend_height=True), Condition(has_before_fragments)), ConditionalContainer( default_buffer_window, Condition(lambda: get_app().layout.current_control != search_buffer_control), ), ConditionalContainer( Window(search_buffer_control), Condition(lambda: get_app().layout.current_control == search_buffer_control), ), ]), [ # Completion menus. Float(xcursor=True, ycursor=True, content=CompletionsMenu( max_height=16, scroll_offset=1, extra_filter=has_focus(default_buffer) & ~multi_column_complete_style)), Float(xcursor=True, ycursor=True, content=MultiColumnCompletionsMenu( show_meta=True, extra_filter=has_focus(default_buffer) & multi_column_complete_style)), # The right prompt. Float(right=0, top=0, hide_when_covering_content=True, content=_RPrompt(lambda: self.rprompt)), ]), ConditionalContainer(ValidationToolbar(), filter=~is_done), ConditionalContainer(system_toolbar, dyncond('enable_system_prompt') & ~is_done), # In multiline mode, we use two toolbars for 'arg' and 'search'. ConditionalContainer( Window(FormattedTextControl(self._get_arg_text), height=1), dyncond('multiline') & has_arg), ConditionalContainer(search_toolbar, dyncond('multiline') & ~is_done), bottom_toolbar, ]) # Default key bindings. auto_suggest_bindings = load_auto_suggest_bindings() open_in_editor_bindings = load_open_in_editor_bindings() prompt_bindings = self._create_prompt_bindings() # Create application application = Application( layout=Layout(layout, default_buffer_window), style=DynamicStyle(lambda: self.style), include_default_pygments_style=dyncond( 'include_default_pygments_style'), clipboard=DynamicClipboard(lambda: self.clipboard), key_bindings=merge_key_bindings([ merge_key_bindings([ auto_suggest_bindings, ConditionalKeyBindings( open_in_editor_bindings, dyncond('enable_open_in_editor') & has_focus(DEFAULT_BUFFER)), prompt_bindings ]), ConditionalKeyBindings( system_toolbar.get_global_key_bindings(), dyncond('enable_system_prompt')), DynamicKeyBindings(lambda: self.extra_key_bindings), ]), mouse_support=dyncond('mouse_support'), editing_mode=editing_mode, erase_when_done=erase_when_done, reverse_vi_search_direction=True, # I/O. input=self.input, output=self.output) # During render time, make sure that we focus the right search control # (if we are searching). - This could be useful if people make the # 'multiline' property dynamic. ''' def on_render(app): multiline = _true(self.multiline) current_control = app.layout.current_control if multiline: if current_control == search_buffer_control: app.layout.current_control = search_toolbar.control app.invalidate() else: if current_control == search_toolbar.control: app.layout.current_control = search_buffer_control app.invalidate() app.on_render += on_render ''' return application, default_buffer, default_buffer_control
def create_layout(self): # Create functions that will dynamically split the prompt. (If we have # a multiline prompt.) has_before_fragments, get_prompt_text_1, get_prompt_text_2 = \ _split_multiline_prompt(self.formatted_message) default_buffer = ModalBuffer( name=DEFAULT_BUFFER, complete_while_typing=Condition( lambda: self.complete_while_typing), completer=DynamicCompleter(lambda: self.completer), history=self.history, get_tempfile_suffix=lambda: self.tempfile_suffix) search_buffer = Buffer(name=SEARCH_BUFFER) search_toolbar = SearchToolbar(search_buffer) input_processor = merge_processors([ ConditionalProcessor(HighlightSearchProcessor(preview_search=True), has_focus(search_buffer)), HighlightSelectionProcessor(), HighlightMatchingBracketProcessor(), DisplayMultipleCursors() ]) default_buffer_control = BufferControl( buffer=default_buffer, search_buffer_control=search_toolbar.control, input_processor=input_processor, lexer=DynamicLexer(lambda: self.lexer), preview_search=True) 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_continuation(width): prompt_continuation = self.prompt_continuation if callable(prompt_continuation): prompt_continuation = prompt_continuation(width) return to_formatted_text(prompt_continuation, style='class:prompt-continuation') default_buffer_window = Window( default_buffer_control, height=get_default_buffer_control_height, left_margins=[PromptMargin(get_prompt_text_2, get_continuation)], wrap_lines=True) def get_arg_text(): arg = self.app.key_processor.arg if arg == '-': arg = '-1' return [('class:arg-toolbar', 'Repeat: '), ('class:arg-toolbar.text', arg)] # Build the layout. layout = HSplit([ # The main input, with completion menus floating on top of it. FloatContainer( HSplit([ ConditionalContainer( Window(FormattedTextControl(get_prompt_text_1), dont_extend_height=True), Condition(has_before_fragments)), default_buffer_window, ]), [ # Completion menus. Float(xcursor=True, ycursor=True, content=MultiColumnCompletionsMenu( show_meta=True, extra_filter=has_focus(default_buffer))) ]), ConditionalContainer( Window(FormattedTextControl(get_arg_text), height=1), has_arg), search_toolbar ]) return Layout(layout, default_buffer_window)
""" if there is a scope on the input """ def __call__(self, *a, **kw): return DEFAULT_COMMAND == "" # TODO fix this somehow 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) & HasDefaultScope()), ] # pylint: disable=too-few-public-methods class ShowDefault(Filter): """ toggle on and off seeing the default """ def __init__(self, shell_ctx): self.shell_ctx = shell_ctx def __call__(self, *a, **kw): return self.shell_ctx.is_showing_default
def _create_container_for_process(pymux, arrangement_pane, zoom=False): """ Create a `Container` with a titlebar for a process. """ assert isinstance(arrangement_pane, arrangement.Pane) process = arrangement_pane.process def has_focus(cli): return pymux.arrangement.get_active_pane(cli) == arrangement_pane def get_titlebar_token(cli): return Token.TitleBar.Focussed if has_focus(cli) else Token.TitleBar def get_titlebar_name_token(cli): return Token.TitleBar.Name.Focussed if has_focus( cli) else Token.TitleBar.Name def get_title_tokens(cli): token = get_titlebar_token(cli) name_token = get_titlebar_name_token(cli) result = [] if zoom: result.append((Token.TitleBar.Zoom, ' Z ')) if process.is_terminated: result.append((Token.Terminated, ' Terminated ')) # Scroll buffer info. if arrangement_pane.display_scroll_buffer: result.append((token.CopyMode, ' %s ' % arrangement_pane.scroll_buffer_title)) # Cursor position. document = arrangement_pane.scroll_buffer.document result.append( (token.CopyMode.Position, ' %i,%i ' % (document.cursor_position_row, document.cursor_position_col))) if arrangement_pane.name: result.append((name_token, ' %s ' % arrangement_pane.name)) result.append((token, ' ')) return result + [ (token.Title, format_pymux_string(pymux, cli, ' #T ', pane=arrangement_pane) ) # XXX: Make configurable. ] def get_pane_index(cli): token = get_titlebar_token(cli) try: w = pymux.arrangement.get_active_window(cli) index = w.get_pane_index(arrangement_pane) except ValueError: index = '/' return [(token.PaneIndex, '%3s ' % index)] def on_click(cli): " Click handler for the clock. When clicked, select this pane. " arrangement_pane.clock_mode = False pymux.arrangement.get_active_window(cli).active_pane = arrangement_pane pymux.invalidate() def set_focus(cli): pymux.arrangement.get_active_window(cli).active_pane = arrangement_pane pymux.invalidate() clock_is_visible = Condition(lambda cli: arrangement_pane.clock_mode) pane_numbers_are_visible = Condition( lambda cli: pymux.display_pane_numbers) return TracePaneWritePosition( pymux, arrangement_pane, content=HSplit([ # The title bar. VSplit([ Window(height=D.exact(1), content=TokenListControl( get_title_tokens, get_default_char=lambda cli: Char( ' ', get_titlebar_token(cli)))), Window(height=D.exact(1), width=D.exact(4), content=TokenListControl(get_pane_index)) ]), # The pane content. FloatContainer( content=HSplit([ # The 'screen' of the pseudo terminal. ConditionalContainer( content=Vt100Window( process=process, has_focus=Condition(lambda cli: ( cli.current_buffer_name != COMMAND and pymux. arrangement.get_active_pane(cli) == arrangement_pane)), set_focus=set_focus, ), filter=~clock_is_visible & Condition(lambda cli: not arrangement_pane. display_scroll_buffer)), # The copy/paste buffer. ConditionalContainer(content=Window( BufferControl( buffer_name='pane-%i' % arrangement_pane.pane_id, focus_on_click=True, default_char=Char(token=Token), preview_search=True, get_search_state=lambda cli: arrangement_pane. search_state, search_buffer_name='search-%i' % arrangement_pane.pane_id, input_processors=[ _UseCopyTokenListProcessor(arrangement_pane), HighlightSearchProcessor( search_buffer_name='search-%i' % arrangement_pane.pane_id, get_search_state=lambda cli: arrangement_pane.search_state, preview_search=True, ), HighlightSelectionProcessor(), ], ), wrap_lines=False, ), filter=~clock_is_visible & Condition(lambda cli: arrangement_pane .display_scroll_buffer)), # Search toolbar. (Displayed when this pane has the focus, and searching.) ConditionalContainer( content=SearchWindow(pymux, arrangement_pane), filter=~clock_is_visible & Condition(lambda cli: arrangement_pane.is_searching)), # The clock. ConditionalContainer( # Add a dummy VSplit/HSplit around the BigClock in order to center it. # (Using a FloatContainer to do the centering doesn't work well, because # the boundaries are not clipped when the parent is smaller.) content=VSplit( [ Window(_FillControl(on_click)), HSplit([ Window(_FillControl(on_click)), BigClock(on_click), Window(_FillControl(on_click)), ]), Window(_FillControl(on_click)), ], get_dimensions=lambda cli: [None, D.exact(BigClock.WIDTH), None]), filter=clock_is_visible, ), ]), # Pane numbers. (Centered.) floats=[ Float(content=ConditionalContainer( content=PaneNumber(pymux, arrangement_pane), filter=pane_numbers_are_visible)), ]) ]))
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())
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)
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 _create_layout(self, message='', lexer=None, is_password=False, reserve_space_for_menu=8, get_prompt_tokens=None, get_continuation_tokens=None, get_rprompt_tokens=None, get_bottom_toolbar_tokens=None, get_url_tokens=None, display_completions_in_columns=False, extra_input_processors=None, multiline=False, wrap_lines=True): """ Create a :class:`.Container` instance for a prompt. :param message: Text to be used as prompt. :param lexer: :class:`~prompt_toolkit.layout.lexers.Lexer` to be used for the highlighting. :param is_password: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`. When True, display input as '*'. :param reserve_space_for_menu: Space to be reserved for the menu. When >0, 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_continuation_tokens: An optional callable that takes a CommandLineInterface and width as input and returns a list of (Token, text) tuples to be used for the continuation. :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 :class:`~prompt_toolkit.filters.CLIFilter`. Display the completions in multiple columns. :param multiline: `bool` or :class:`~prompt_toolkit.filters.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. :param wrap_lines: `bool` or :class:`~prompt_toolkit.filters.CLIFilter`. When True (the default), automatically wrap long lines instead of scrolling horizontally. """ 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 get_rprompt_tokens is None or callable(get_rprompt_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)] has_before_tokens, 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 pygments_Lexer and issubclass(lexer, pygments_Lexer): lexer = PygmentsLexer(lexer, sync_from_start=True) except TypeError: # Happens when lexer is `None` or an instance of something else. pass # Create processors list. 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=True), HasFocus(SEARCH_BUFFER)), HighlightSelectionProcessor(), ConditionalProcessor(AppendAutoSuggestion(), HasFocus(DEFAULT_BUFFER) & ~IsDone()), ConditionalProcessor(PasswordProcessor(), is_password), DisplayMultipleCursors(DEFAULT_BUFFER), ] 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( ConditionalProcessor(DefaultPrompt(get_prompt_tokens_2), ~multiline)) # Create bottom toolbar. if get_bottom_toolbar_tokens: toolbars = [ ConditionalContainer(VSplit([ Window(TokenListControl(get_url_tokens, default_char=Char( ' ', Token.Toolbar)), height=LayoutDimension.exact(1)), Window(TokenListControl(get_bottom_toolbar_tokens, default_char=Char( ' ', Token.Toolbar), align_right=True), 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: 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() # Create and return Container instance. return HSplit([ # The main input, with completion menus floating on top of it. FloatContainer( HSplit([ ConditionalContainer( Window(TokenListControl(get_prompt_tokens_1), dont_extend_height=True), Condition(has_before_tokens)), Window( 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=get_height, left_margins=[ # In multiline mode, use the window margin to display # the prompt and continuation tokens. ConditionalMargin(PromptMargin( get_prompt_tokens_2, get_continuation_tokens), filter=multiline) ], wrap_lines=wrap_lines, ), ]), [ # Completion menus. Float(xcursor=True, ycursor=True, content=CompletionsMenu( max_height=16, scroll_offset=1, extra_filter=HasFocus(DEFAULT_BUFFER) & ~display_completions_in_columns)), Float(xcursor=True, ycursor=True, content=MultiColumnCompletionsMenu( extra_filter=HasFocus(DEFAULT_BUFFER) & display_completions_in_columns, show_meta=True)), # The right prompt. Float(right=0, top=0, hide_when_covering_content=True, content=_RPrompt(get_rprompt_tokens)), ]), ValidationToolbar(), SystemToolbar(), # In multiline mode, we use two toolbars for 'arg' and 'search'. ConditionalContainer(ArgToolbar(), multiline), ConditionalContainer(SearchToolbar(), multiline), ] + toolbars)
def _create_layout(self): """ Create `Layout` for this prompt. """ dyncond = self._dyncond # Create functions that will dynamically split the prompt. (If we have # a multiline prompt.) has_before_fragments, get_prompt_text_1, get_prompt_text_2 = \ _split_multiline_prompt(self._get_prompt) default_buffer = self.default_buffer search_buffer = self.search_buffer # Create processors list. all_input_processors = [ HighlightIncrementalSearchProcessor(), HighlightSelectionProcessor(), ConditionalProcessor(AppendAutoSuggestion(), has_focus(default_buffer) & ~is_done), ConditionalProcessor(PasswordProcessor(), dyncond('is_password')), DisplayMultipleCursors(), # Users can insert processors here. DynamicProcessor( lambda: merge_processors(self.input_processors or [])), # For single line mode, show the prompt before the input. ConditionalProcessor( merge_processors([ BeforeInput(get_prompt_text_2), ShowArg(), ]), ~dyncond('multiline')) ] # Create bottom toolbars. bottom_toolbar = ConditionalContainer( Window(FormattedTextControl(lambda: self.bottom_toolbar, style='class:bottom-toolbar.text'), style='class: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)) search_toolbar = SearchToolbar( search_buffer, ignore_case=dyncond('search_ignore_case')) search_buffer_control = SearchBufferControl( buffer=search_buffer, input_processors=[ ReverseSearchProcessor(), ShowArg(), ], ignore_case=dyncond('search_ignore_case')) system_toolbar = SystemToolbar( enable_global_bindings=dyncond('enable_system_prompt')) def get_search_buffer_control(): " Return the UIControl to be focused when searching start. " if _true(self.multiline): return search_toolbar.control else: return search_buffer_control default_buffer_control = BufferControl( buffer=default_buffer, search_buffer_control=get_search_buffer_control, input_processors=all_input_processors, include_default_input_processors=False, lexer=DynamicLexer(lambda: self.lexer), preview_search=True) default_buffer_window = Window( default_buffer_control, height=self._get_default_buffer_control_height, left_margins=[ # In multiline mode, use the window margin to display # the prompt and continuation fragments. ConditionalMargin( PromptMargin(get_prompt_text_2, self._get_continuation), filter=dyncond('multiline'), ) ], wrap_lines=dyncond('wrap_lines')) @Condition def multi_column_complete_style(): return self.complete_style == CompleteStyle.MULTI_COLUMN # Build the layout. layout = HSplit([ # The main input, with completion menus floating on top of it. FloatContainer( HSplit([ ConditionalContainer( Window(FormattedTextControl(get_prompt_text_1), dont_extend_height=True), Condition(has_before_fragments)), ConditionalContainer( default_buffer_window, Condition(lambda: get_app().layout.current_control != search_buffer_control), ), ConditionalContainer( Window(search_buffer_control), Condition(lambda: get_app().layout.current_control == search_buffer_control), ), ]), [ # Completion menus. Float(xcursor=True, ycursor=True, content=CompletionsMenu( max_height=16, scroll_offset=1, extra_filter=has_focus(default_buffer) & ~multi_column_complete_style)), Float(xcursor=True, ycursor=True, content=MultiColumnCompletionsMenu( show_meta=True, extra_filter=has_focus(default_buffer) & multi_column_complete_style)), # The right prompt. Float(right=0, top=0, hide_when_covering_content=True, content=_RPrompt(lambda: self.rprompt)), ]), ConditionalContainer(ValidationToolbar(), filter=~is_done), ConditionalContainer(system_toolbar, dyncond('enable_system_prompt') & ~is_done), # In multiline mode, we use two toolbars for 'arg' and 'search'. ConditionalContainer( Window(FormattedTextControl(self._get_arg_text), height=1), dyncond('multiline') & has_arg), ConditionalContainer(search_toolbar, dyncond('multiline') & ~is_done), bottom_toolbar, ]) return Layout(layout, default_buffer_window)
def __init__(self, my_app: "sqlApp"): self.my_app = my_app help_text = """ Press Enter in the input box to page through the table. Alternatively, enter a filtering SQL statement and then press Enter to page through the results. """ self.formatter = TabularOutputFormatter() self.completer = PreviewCompleter( my_app=self.my_app, completer=MssqlCompleter( smart_completion=True, get_conn=lambda: self.my_app.selected_object.conn)) history_file = config_location() + 'preview_history' ensure_dir_exists(history_file) hist = PreviewHistory(my_app=self.my_app, filename=expanduser(history_file)) self.input_buffer = PreviewBuffer( name="previewbuffer", tempfile_suffix=".sql", history=ThreadedHistory(hist), auto_suggest=ThreadedAutoSuggest( PreviewSuggestFromHistory(my_app)), completer=ThreadedCompleter(self.completer), # history = hist, # auto_suggest = PreviewSuggestFromHistory(my_app), # completer = self.completer, complete_while_typing=Condition( lambda: self.my_app.selected_object is not None and self.my_app .selected_object.conn.connected()), multiline=False) input_control = BufferControl( buffer=self.input_buffer, include_default_input_processors=False, input_processors=[AppendAutoSuggestion()], preview_search=False) self.input_window = Window(input_control) search_buffer = Buffer(name="previewsearchbuffer") self.search_field = SearchToolbar(search_buffer) self.output_field = TextArea( style="class:preview-output-field", text=help_text, height=D(preferred=50), search_field=self.search_field, wrap_lines=False, focusable=True, read_only=True, preview_search=True, input_processors=[ ConditionalProcessor( processor=HighlightIncrementalSearchProcessor(), filter=has_focus("previewsearchbuffer") | has_focus(self.search_field.control), ), HighlightSelectionProcessor(), ]) def refresh_results(window_height) -> bool: """ This method gets called when the app restarts after exiting for execution of preview query. It populates the output buffer with results from the fetch/query. """ sql_conn = self.my_app.selected_object.conn if sql_conn.execution_status == executionStatus.FAIL: # Let's display the error message to the user output = sql_conn.execution_err else: crsr = sql_conn.cursor if crsr.description: cols = [col.name for col in crsr.description] else: cols = [] if len(cols): res = sql_conn.fetch_from_cache(size=window_height - 4, wait=True) output = self.formatter.format_output(res, cols, format_name="psql") output = "\n".join(output) else: output = "No rows returned\n" # Add text to output buffer. self.output_field.buffer.set_document( Document(text=output, cursor_position=0), True) return True def accept(buff: Buffer) -> bool: """ This method gets called when the user presses enter/return in the filter box. It is interpreted as either 'execute query' or 'fetch next page of results' if filter query hasn't changed. """ obj = self.my_app.selected_object sql_conn = obj.conn identifier = object_to_identifier(obj) query = sql_conn.preview_query( name=identifier, obj_type=obj.otype, filter_query=buff.text, limit=self.my_app.preview_limit_rows) if query is None: return True func = partial(refresh_results, window_height=self.output_field.window.render_info. window_height) if sql_conn.query != query: # Exit the app to execute the query self.my_app.application.exit(result=["preview", query]) self.my_app.application.pre_run_callables.append(func) else: # No need to exit let's just go and fetch func() return True # Keep filter text def cancel_handler() -> None: sql_conn = self.my_app.selected_object.conn sql_conn.close_cursor() self.input_buffer.text = "" self.output_field.buffer.set_document( Document(text=help_text, cursor_position=0), True) self.my_app.show_preview = False self.my_app.show_sidebar = True self.my_app.application.layout.focus(self.input_buffer) self.my_app.application.layout.focus("sidebarbuffer") return None self.input_buffer.accept_handler = accept self.cancel_button = Button(text="Done", handler=cancel_handler)