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 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(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 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(), DisplayMultipleCursors(DEFAULT_BUFFER), # 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 _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 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='', 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)
# pylint: disable=too-few-public-methods class HasDefaultScope(Filter): """ 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_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)
def create_layout(buffer, lexer=None, reserve_space_for_menu=8, get_prompt_tokens=None, get_bottom_toolbar_tokens=None, extra_input_processors=None, multiline=False, wrap_lines=True): """ Creates a custom `Layout` for the Crash input REPL This layout includes: * a bottom left-aligned session toolbar container * a bottom right-aligned side-bar container +-------------------------------------------+ | cr> select 1; | | | | | +-------------------------------------------+ | bottom_toolbar_tokens sidebar_tokens | +-------------------------------------------+ """ input_processors = [ ConditionalProcessor( # Highlight the reverse-i-search buffer HighlightSearchProcessor(), has_focus(SEARCH_BUFFER)), ] + (extra_input_processors or []) lexer = PygmentsLexer(lexer, sync_from_start=True) sidebar_token = [ ('class:status-toolbar', "[ctrl+d]"), ('class:status-toolbar.text', " Exit") ] def _get_buffer_control_height(buf): # If there is an autocompletion menu to be shown, make sure that our # layout has at least a minimal height in order to display it. if reserve_space_for_menu and not get_app().is_done: buff = buffer # Reserve the space, either when there are completions, or when # `complete_while_typing` is true and we expect completions very # soon. if buff.complete_while_typing() or buff.complete_state is not None: return Dimension(min=reserve_space_for_menu) return Dimension() search_toolbar = SearchToolbar() buf_ctrl_window = Window( BufferControl( buffer=buffer, search_buffer_control=search_toolbar.control, input_processors=input_processors, lexer=lexer, preview_search=True ), height=lambda: _get_buffer_control_height(buffer), wrap_lines=wrap_lines, left_margins=[ ConditionalMargin( PromptMargin(get_prompt_tokens), filter=multiline ) ] ) in_out_area = VSplit([ HSplit([ FloatContainer( HSplit([buf_ctrl_window]), [ Float( xcursor=True, ycursor=True, content=CompletionsMenu( max_height=16, scroll_offset=1, extra_filter=has_focus(DEFAULT_BUFFER) ) ), ] ), # reverse-i-search toolbar (ctrl+r) search_toolbar, ]) ]) bottom_toolbar = VSplit([ ConditionalContainer( Window( FormattedTextControl(get_bottom_toolbar_tokens), height=Dimension.exact(1) ), filter=~is_done & renderer_height_is_known ), ConditionalContainer( Window( FormattedTextControl(lambda: sidebar_token), height=Dimension.exact(1), align=WindowAlign.RIGHT ), filter=~is_done & renderer_height_is_known ) ]) return Layout(HSplit([in_out_area, bottom_toolbar]))
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_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 __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 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 __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 _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 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(message='', lexer=None, reserve_space_for_menu=8, get_prompt_tokens=None, get_bottom_toolbar_tokens=None, extra_input_processors=None, multiline=False, wrap_lines=True): # Create processors list. input_processors = [ ConditionalProcessor( # Highlight the reverse-i-search buffer HighlightSearchProcessor(preview_search=True), HasFocus(SEARCH_BUFFER)), ] if extra_input_processors: input_processors.extend(extra_input_processors) lexer = PygmentsLexer(lexer, sync_from_start=True) multiline = to_cli_filter(multiline) sidebar_token = [(Token.Toolbar.Status.Key, "[ctrl+d]"), (Token.Toolbar.Status, " Exit")] sidebar_width = token_list_width(sidebar_token) get_prompt_tokens = lambda _: [(Token.Prompt, message)] get_sidebar_tokens = lambda _: sidebar_token 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([ VSplit([ HSplit([ # The main input, with completion menus floating on top of it. FloatContainer( HSplit([ Window( BufferControl( input_processors=input_processors, lexer=lexer, # enable preview search for reverse-i-search preview_search=True), get_height=get_height, wrap_lines=wrap_lines, left_margins=[ # In multiline mode, use the window margin to display # the prompt and continuation tokens. ConditionalMargin(PromptMargin( get_prompt_tokens), filter=multiline) ], ), ]), [ # Completion menu Float(xcursor=True, ycursor=True, content=CompletionsMenu(max_height=16, scroll_offset=1, extra_filter=HasFocus( DEFAULT_BUFFER))), ]), # reverse-i-search toolbar (ctrl+r) ConditionalContainer(SearchToolbar(), multiline), ]) ]), ] + [ VSplit([ # Left-Aligned Session Toolbar ConditionalContainer(Window(TokenListControl( get_bottom_toolbar_tokens), height=LayoutDimension.exact(1)), filter=~IsDone() & RendererHeightIsKnown()), # Right-Aligned Container ConditionalContainer(Window(TokenListControl(get_sidebar_tokens), height=LayoutDimension.exact(1), width=LayoutDimension.exact( sidebar_width)), filter=~IsDone() & RendererHeightIsKnown()) ]) ])