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 @Condition def wrap_lines(cli): return self.editor.wrap_lines 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)), # Reporting of errors, for Pyflakes. ReportingProcessor(editor_buffer), # Replace tabs by spaces. TabsProcessor(self.editor) ] highlighters = [ # Highlighting of the selection. SelectionHighlighter(), # Highlighting of the search. ConditionalHighlighter( SearchHighlighter(preview_search=preview_search), Condition(lambda cli: self.editor.highlight_search)), # Highlight matching parentheses. MatchingBracketHighlighter(), ] return BufferControl(lexer=DocumentLexer(editor_buffer), input_processors=input_processors, highlighters=highlighters, buffer_name=buffer_name, preview_search=preview_search, wrap_lines=wrap_lines, focus_on_click=True)
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, highlighters=[ # Show matching parentheses, but only while editing. ConditionalHighlighter( highlighter=MatchingBracketHighlighter(chars='[](){}'), filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() & Condition(lambda cli: python_input. highlight_matching_parenthesis)), ConditionalHighlighter( highlighter=SearchHighlighter(preview_search=Always()), filter=HasFocus(SEARCH_BUFFER)), SelectionHighlighter(), ], input_processors=[ ConditionalProcessor(processor=AppendAutoSuggestion(), filter=~IsDone()) ] + extra_buffer_processors, menu_position=menu_position, wrap_lines=Condition(lambda cli: python_input.wrap_lines), # Make sure that we always see the result of an reverse-i-search: preview_search=Always(), ), left_margins=[PromptMargin(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)), )
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. " 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=PaneWindow(pymux, arrangement_pane, process), 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, wrap_lines=False, 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)], highlighters=[ SearchHighlighter( search_buffer_name='search-%i' % arrangement_pane.pane_id, get_search_state=lambda cli: arrangement_pane.search_state, preview_search=True), SelectionHighlighter(), ], )), 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 clipt when the parent is smaller.) content=VSplit([ Window(_FillControl(on_click)), HSplit([ Window(_FillControl(on_click)), Window(BigClock(on_click), height=D.exact(BigClock.HEIGHT)), 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=Window(PaneNumber(pymux, arrangement_pane, on_click)), filter=pane_numbers_are_visible)), ] ) ]) )
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, highlighters=[SelectionHighlighter()], input_processors=[ AppendAutoSuggestion(), DefaultPrompt(lambda cli:[(Token.CommandLine.Prompt, ':')]), ]) ), 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), highlighters=[SelectionHighlighter()], input_processors=[ BeforeInput(self._before_prompt_command_tokens), AppendAutoSuggestion(), ]) ), filter=waits_for_prompt, ), ])), Float(xcursor=True, ycursor=True, content=CompletionsMenu(max_height=12)), ] )
def create_prompt_layout(self, message='', lexer=None, is_password=False, reserve_space_for_menu=8, get_prompt_tokens=None, get_bottom_toolbar_tokens=None, display_completions_in_columns=False, extra_input_processors=None, multiline=False, wrap_lines=True): """Create a Container instance for a prompt. Parameters ---------- message : Text to be used as prompt. lexer : ~prompt_toolkit.layout.lexers.Lexer to be used for the highlighting. is_password : bool or ~prompt_toolkit.filters.CLIFilter. When True, display input as '*'. 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. get_prompt_tokens : An optional callable that returns the tokens to be shown in the menu. (To be used instead of a `message`.) get_bottom_toolbar_tokens : An optional callable that returns the tokens for a toolbar at the bottom. display_completions_in_columns : `bool` or :class:`~prompt_toolkit.filters.CLIFilter`. Display the completions in multiple columns. 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. wrap_lines : `bool` or :class:`~prompt_toolkit.filters.CLIFilter`. When True (the default), automatically wrap long lines instead of scrolling horizontally. Notes ----- This method was forked from the mainline prompt-toolkit repo. Copyright (c) 2014, Jonathan Slenders, All rights reserved. WARNING; This method is due for removal once prompt-toolkit >v0.54 is released. """ assert isinstance(message, str) 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, pygments.lexer.Lexer): lexer = PygmentsLexer(lexer) except TypeError: # Happens when lexer is `None` or an instance of something else. pass # Create highlighters and processors list. if ConditionalHighlighter is None: highlighters = None highlighters_kwargs = {} else: highlighters = [ ConditionalHighlighter( # 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.) SearchHighlighter(preview_search=True), HasFocus(SEARCH_BUFFER)), SelectionHighlighter() ] highlighters_kwargs = {'highlighters': highlighters} input_processors = [ 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.) # (DefaultPrompt should always be at the end of the processors.) 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=reserve_space_for_menu) else: return LayoutDimension() # Create and return Container 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, wrap_lines=wrap_lines, # Enable preview_search, we want to have immediate feedback # in reverse-i-search mode. preview_search=True, **highlighters_kwargs), 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)), Float(xcursor=True, ycursor=True, content=MultiColumnCompletionsMenu( extra_filter=HasFocus(DEFAULT_BUFFER) & display_completions_in_columns, show_meta=True)) ]), ]), ValidationToolbar(), SystemToolbar(), # In multiline mode, we use two toolbars for 'arg' and 'search'. ConditionalContainer(ArgToolbar(), multiline), ConditionalContainer(SearchToolbar(), multiline), ] + toolbars)