def signature_toolbar(python_input): """ Return the `Layout` for the signature. """ def get_tokens(cli): result = [] append = result.append Signature = Token.Toolbar.Signature if python_input.signatures: sig = python_input.signatures[0] # Always take the first one. append((Signature, ' ')) try: append((Signature, sig.full_name)) except IndexError: # Workaround for #37: https://github.com/jonathanslenders/python-prompt-toolkit/issues/37 # See also: https://github.com/davidhalter/jedi/issues/490 return [] append((Signature.Operator, '(')) for i, p in enumerate(sig.params): # Workaround for #47: 'p' is None when we hit the '*' in the signature. # and sig has no 'index' attribute. # See: https://github.com/jonathanslenders/ptpython/issues/47 # https://github.com/davidhalter/jedi/issues/598 description = (p.description if p else '*') #or '*' sig_index = getattr(sig, 'index', 0) if i == sig_index: # Note: we use `_Param.description` instead of # `_Param.name`, that way we also get the '*' before args. append((Signature.CurrentName, str(description))) else: append((Signature, str(description))) append((Signature.Operator, ', ')) if sig.params: # Pop last comma result.pop() append((Signature.Operator, ')')) append((Signature, ' ')) return result return ConditionalContainer( content=Window( TokenListControl(get_tokens), height=LayoutDimension.exact(1)), filter= # Show only when there is a signature HasSignature(python_input) & # And there are no completions to be shown. (would cover signature pop-up.) ~(HasCompletions() & (show_completions_menu(python_input) | show_multi_column_completions_menu(python_input))) # Signature needs to be shown. & ShowSignature(python_input) & # Not done yet. ~IsDone())
def __init__(self, editor, buffer_window, buffer_name): def get_scroll_text(): info = buffer_window.render_info if info: if info.full_height_visible: return 'All' elif info.top_visible: return 'Top' elif info.bottom_visible: return 'Bot' else: percentage = info.vertical_scroll_percentage return '%2i%%' % percentage return '' def get_tokens(cli): main_document = cli.buffers[buffer_name].document return [ (Token.Toolbar.Status.CursorPosition, '(%i,%i)' % (main_document.cursor_position_row + 1, main_document.cursor_position_col + 1)), (Token.Toolbar.Status, ' - '), (Token.Toolbar.Status.Percentage, get_scroll_text()), (Token.Toolbar.Status, ' '), ] super(WindowStatusBarRuler, self).__init__( Window( TokenListControl(get_tokens, default_char=Char(' ', Token.Toolbar.Status), align_right=True), height=LayoutDimension.exact(1), ), filter=Condition(lambda cli: editor.show_ruler))
def python_sidebar_navigation(python_input): """ Create the `Layout` showing the navigation information for the sidebar. """ def get_tokens(cli): tokens = [] T = Token.Sidebar # Show navigation info. tokens.extend([ (T.Separator, ' ' * 43 + '\n'), (T, ' '), (T.Key, '[Arrows]'), (T, ' '), (T.Key.Description, 'Navigate'), (T, ' '), (T.Key, '[Enter]'), (T, ' '), (T.Key.Description, 'Hide menu'), ]) return tokens return ConditionalContainer(content=Window( TokenListControl(get_tokens, Char(token=Token.Sidebar)), width=LayoutDimension.exact(43), height=LayoutDimension.exact(2)), filter=ShowSidebar(python_input) & ~IsDone())
def python_sidebar_help(python_input): """ Create the `Layout` for the help text for the current item in the sidebar. """ token = Token.Sidebar.HelpText def get_current_description(): """ Return the description of the selected option. """ i = 0 for category in python_input.options: for option in category.options: if i == python_input.selected_option_index: return option.description i += 1 return '' def get_tokens(cli): return [(token, get_current_description())] return ConditionalContainer( content=Window(TokenListControl(get_tokens, Char(token=token)), height=LayoutDimension(min=3)), filter=ShowSidebar(python_input) & Condition(lambda cli: python_input.show_sidebar_help) & ~IsDone())
def show_sidebar_button_info(python_input): """ Create `Layout` for the information in the right-bottom corner. (The right part of the status bar.) """ @if_mousedown def toggle_sidebar(cli, mouse_event): " Click handler for the menu. " python_input.show_sidebar = not python_input.show_sidebar token = Token.Toolbar.Status version = sys.version_info tokens = [ (token.Key, '[F2]', toggle_sidebar), (token, ' Menu', toggle_sidebar), (token, ' - '), (token.PythonVersion, '%s %i.%i.%i' % (platform.python_implementation(), version[0], version[1], version[2])), (token, ' '), ] width = token_list_width(tokens) def get_tokens(cli): # Python version return tokens return ConditionalContainer( content=Window( TokenListControl(get_tokens, default_char=Char(token=token)), height=LayoutDimension.exact(1), width=LayoutDimension.exact(width)), filter=~IsDone() & RendererHeightIsKnown() & Condition(lambda cli: python_input.show_status_bar and not python_input.show_exit_confirmation))
def create_tutorial_layout(lex): """ layout for example tutorial """ lexer, _, _ = get_lexers(lex, None, None) layout_full = HSplit([ FloatContainer( Window(BufferControl(input_processors=input_processors, lexer=lexer, preview_search=Always()), get_height=get_height), [ Float(xcursor=True, ycursor=True, content=CompletionsMenu( max_height=MAX_COMPLETION, scroll_offset=1, extra_filter=(HasFocus(DEFAULT_BUFFER)))) ]), ConditionalContainer(HSplit([ get_hline(), get_param(lexer), get_hline(), Window(content=BufferControl(buffer_name='example_line', lexer=lexer), ), Window(TokenListControl(get_tutorial_tokens, default_char=Char(' ', Token.Toolbar)), height=D.exact(1)), ]), filter=~IsDone() & RendererHeightIsKnown()) ]) return layout_full
def __init__(self, opt_ns, srv_c, inst_xml): manager = KeyBindingManager() # Start with the `KeyBindingManager`. self.srv_text = ServiceOutput(opt_ns, srv_c, inst_xml) layout = HSplit( [ # One window that holds the BufferControl with the default buffer on the # left. Window( height=D.exact(1), content=TokenListControl( self.get_title_line, default_char=Char(" ", token=Token.String.ICSW.Header) ) ), Window( height=D.exact(1), content=FillControl('-', token=Token.Line) ), # Display the text 'Hello world' on the right. Window( content=TokenListControl( self.get_icsw_output, ) ), ] ) self._updating = False @manager.registry.add_binding(Keys.ControlC, eager=True) @manager.registry.add_binding("q", eager=True) def _handler_data(event): event.cli.set_return_value(0) our_style = style_from_dict(logging_tools.get_icsw_prompt_styles()) application = Application( layout=layout, use_alternate_screen=True, style=our_style, on_input_timeout=self.input_timeout, key_bindings_registry=manager.registry, ) event_loop = create_eventloop() self.application = application self.event_loop = event_loop
def __init__(self): def get_tokens(cli): if cli.input_processor.arg is not None: return [(Token.Arg, ' %i ' % cli.input_processor.arg)] else: return [] super(SimpleArgToolbar, self).__init__( TokenListControl(get_tokens, align_right=True), filter=HasArg()),
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 __init__(self, tosh): self._tosh = tosh self._tabs = [ToshTab(tosh)] self._active_tab = 0 layout = [ Window(TokenListControl( self._get_tabs_tokens, default_char=Char(' ', Token.Tabs), ), height=D(max=1)), self._tabs[0].layout ] super().__init__(layout)
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. if is_password: input_processors = [PasswordProcessor(), DefaultPrompt(message)] else: input_processors = [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), get_height=get_height, ), [ Float(xcursor=True, ycursor=True, content=CompletionsMenu(max_height=16, extra_filter=HasFocus('default'))) ] ), ValidationToolbar(), SystemToolbar(), ] + toolbars)
def setup_layout(self): """docstring for setup_layout""" if bool(egc.TEXT_EDITOR_ENABLE_LEFT_MARGIN) is True: self._left_margin = NumberredMargin(display_tildes=True) if bool(egc.TEXT_EDITOR_ENABLE_RIGHT_MARGIN) is True: self._right_margin = ScrollbarMargin(display_arrows=True) self._buffer_control = BufferControl(buffer_name=self._editor_buffer_name) self._editor_aiml_code_window = Window(content=self._buffer_control, left_margins=[self._left_margin,]) self._vertical_line = FillControl('|', token=Token.Line) self._window_separater = Window(width=D.exact(1), content=self._vertical_line) self._aiml_list = TokenListControl(get_tokens=self.get_aiml_list) self._editor_aiml_list_window = Window(content=self._aiml_list, right_margins=[self._right_margin,]) self._layout = VSplit([ self._editor_aiml_code_window, self._window_separater, self._editor_aiml_list_window, ])
def _factory(): return [ ConditionalContainer( Window( TokenListControl(get_expand_short_tokens), dont_extend_height=True, wrap_lines=True, ), filter=~Expanded() & BufferValid(), ), ConditionalContainer( HSplit( rawlist_window_factory(window_class, control, page_size) () + []), filter=Expanded(), ), ]
def _factory(): return [ window_class( control, height=LayoutDimension(max=page_size), dont_extend_height=True, wrap_lines=True, ), ConditionalContainer( Window( TokenListControl(_get_default_pager_tokens), dont_extend_height=True, wrap_lines=True, ), filter=NeedsScrollTip(page_size) & ~IsDone(), ), ]
def exit_confirmation(python_input, token=Token.ExitConfirmation): """ Create `Layout` for the exit message. """ def get_tokens(cli): # Show "Do you really want to exit?" return [ (token, '\n %s ([y]/n)' % python_input.exit_message), (Token.SetCursorPosition, ''), (token, ' \n'), ] visible = ~IsDone() & Condition(lambda cli: python_input.show_exit_confirmation) return ConditionalContainer( content=Window(TokenListControl( get_tokens, default_char=Char(token=token), has_focus=visible)), filter=visible)
def __init__(self, editor): once_hidden = [False] # Nonlocal def condition(cli): # Get editor buffers buffers = editor.window_arrangement.editor_buffers # Only show when there is only one empty buffer, but once the # welcome message has been hidden, don't show it again. result = (len(buffers) == 1 and buffers[0].buffer.text == '' and buffers[0].location is None and not once_hidden[0]) if not result: once_hidden[0] = True return result super(WelcomeMessageWindow, self).__init__( Window(TokenListControl(lambda cli: WELCOME_MESSAGE_TOKENS)), filter=Condition(condition))
def meta_enter_message(python_input): """ Create the `Layout` for the 'Meta+Enter` message. """ def get_tokens(cli): return [(Token.AcceptMessage, ' [Meta+Enter] Execute ')] def extra_condition(cli): " Only show when... " b = cli.buffers[DEFAULT_BUFFER] return (python_input.show_meta_enter_message and (not b.document.is_cursor_at_the_end or python_input.accept_input_on_enter is None) and b.is_multiline()) visible = ~IsDone() & HasFocus(DEFAULT_BUFFER) & Condition(extra_condition) return ConditionalContainer(content=Window(TokenListControl(get_tokens)), filter=visible)
def _get_layout(self): token_list_window = Window(height=LD.exact(1), content=TokenListControl( self._get_prompt_tokens)) conditional_window = ConditionalContainer(Window( self.controller, width=LD.exact(43), height=LD.exact(len(self.choices)), scroll_offsets=ScrollOffsets(top=1, bottom=1)), filter=~IsDone()) if self.prompt_msg: return HSplit([token_list_window, conditional_window]) else: return HSplit([conditional_window])
def __init__(self): token = Token.Toolbar.Status version = sys.version_info tokens = [ (token, ' [F2] Sidebar'), (token, ' - '), (token.PythonVersion, '%s %i.%i.%i' % (platform.python_implementation(), version[0], version[1], version[2])), (token, ' '), ] width = token_list_width(tokens) def get_tokens(cli): # Python version return tokens super(ShowSidebarButtonInfo, self).__init__( TokenListControl(get_tokens, default_char=Char(token=token)), filter=~IsDone() & RendererHeightIsKnown(), height=LayoutDimension.exact(1), width=LayoutDimension.exact(width))
def question(message, **kwargs): # TODO disabled, dict choices if not 'choices' in kwargs: raise PromptParameterException('choices') choices = kwargs.pop('choices', None) default = kwargs.pop('default', None) qmark = kwargs.pop('qmark', '?') # TODO style defaults on detail level style = kwargs.pop('style', default_style) ic = InquirerControl(choices, default=default) def get_prompt_tokens(cli): tokens = [] tokens.append((Token.QuestionMark, qmark)) tokens.append((Token.Question, ' %s ' % message)) if ic.answered: tokens.append((Token.Answer, ' ' + ic.get_selection()[0])) else: tokens.append((Token.Instruction, ' (Use arrow keys)')) return tokens # assemble layout layout = HSplit([ Window(height=D.exact(1), content=TokenListControl(get_prompt_tokens)), ConditionalContainer(Window(ic), filter=~IsDone()) ]) # key bindings manager = KeyBindingManager.for_prompt() @manager.registry.add_binding(Keys.ControlQ, eager=True) @manager.registry.add_binding(Keys.ControlC, eager=True) def _(event): raise KeyboardInterrupt() # event.cli.set_return_value(None) @manager.registry.add_binding(Keys.Down, eager=True) def move_cursor_down(event): def _next(): ic.selected_option_index = ((ic.selected_option_index + 1) % ic.choice_count) _next() while isinstance(ic.choices[ic.selected_option_index][0], Separator) or\ ic.choices[ic.selected_option_index][2]: _next() @manager.registry.add_binding(Keys.Up, eager=True) def move_cursor_up(event): def _prev(): ic.selected_option_index = ((ic.selected_option_index - 1) % ic.choice_count) _prev() while isinstance(ic.choices[ic.selected_option_index][0], Separator) or \ ic.choices[ic.selected_option_index][2]: _prev() @manager.registry.add_binding(Keys.Enter, eager=True) def set_answer(event): ic.answered = True event.cli.set_return_value(ic.get_selection()[1]) return Application(layout=layout, key_bindings_registry=manager.registry, mouse_support=True, style=style)
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)
def question(message, **kwargs): # TODO add bottom-bar (Move up and down to reveal more choices) # TODO extract common parts for list, checkbox, rawlist, expand # TODO validate if not 'choices' in kwargs: raise PromptParameterException('choices') # this does not implement default, use checked... if 'default' in kwargs: raise ValueError('Checkbox does not implement \'default\' ' 'use \'checked\':True\' in choice!') choices = kwargs.pop('choices', None) validator = setup_simple_validator(kwargs) # TODO style defaults on detail level style = kwargs.pop('style', default_style) pointer_index = kwargs.pop('pointer_index', 0) ic = InquirerControl(choices, pointer_index) qmark = kwargs.pop('qmark', '?') def get_prompt_tokens(cli): tokens = [] tokens.append((Token.QuestionMark, qmark)) tokens.append((Token.Question, ' %s ' % message)) if ic.answered: nbr_selected = len(ic.selected_options) if nbr_selected == 0: tokens.append((Token.Answer, ' done')) elif nbr_selected == 1: tokens.append((Token.Answer, ' [%s]' % ic.selected_options[0])) else: tokens.append( (Token.Answer, ' done (%d selections)' % nbr_selected)) else: tokens.append((Token.Instruction, ' (<up>, <down> to move, <space> to select, <a> ' 'to toggle, <i> to invert)')) return tokens # assemble layout layout = HSplit([ Window(height=D.exact(1), content=TokenListControl(get_prompt_tokens, align_center=False)), ConditionalContainer(Window(ic, width=D.exact(43), height=D(min=3), scroll_offsets=ScrollOffsets(top=1, bottom=1)), filter=~IsDone()) ]) # key bindings manager = KeyBindingManager.for_prompt() @manager.registry.add_binding(Keys.ControlQ, eager=True) @manager.registry.add_binding(Keys.ControlC, eager=True) def _(event): raise KeyboardInterrupt() # event.cli.set_return_value(None) @manager.registry.add_binding(' ', eager=True) def toggle(event): pointed_choice = ic.choices[ic.pointer_index][1] # value if pointed_choice in ic.selected_options: ic.selected_options.remove(pointed_choice) else: ic.selected_options.append(pointed_choice) @manager.registry.add_binding('i', eager=True) def invert(event): inverted_selection = [ c[1] for c in ic.choices if not isinstance(c, Separator) and c[1] not in ic.selected_options and not c[2] ] ic.selected_options = inverted_selection @manager.registry.add_binding('a', eager=True) def all(event): all_selected = True # all choices have been selected for c in ic.choices: if not isinstance(c, Separator) and c[ 1] not in ic.selected_options and not c[2]: # add missing ones ic.selected_options.append(c[1]) all_selected = False if all_selected: ic.selected_options = [] @manager.registry.add_binding(Keys.Down, eager=True) def move_cursor_down(event): def _next(): ic.pointer_index = ((ic.pointer_index + 1) % ic.line_count) _next() while isinstance(ic.choices[ic.pointer_index], Separator) or \ ic.choices[ic.pointer_index][2]: _next() @manager.registry.add_binding(Keys.Up, eager=True) def move_cursor_up(event): def _prev(): ic.pointer_index = ((ic.pointer_index - 1) % ic.line_count) _prev() while isinstance(ic.choices[ic.pointer_index], Separator) or \ ic.choices[ic.pointer_index][2]: _prev() @manager.registry.add_binding(Keys.Enter, eager=True) def set_answer(event): ic.answered = True # TODO use validator event.cli.set_return_value(ic.get_selected_values()) return Application(layout=layout, key_bindings_registry=manager.registry, mouse_support=True, style=style)
def main(): manager = KeyBindingManager(enable_system_prompt=True) D = LayoutDimension layout = HSplit([ VSplit([ Window(width=D(min=15, max=30, preferred=30), content=FillControl('a', token=Token.A)), Window(width=D.exact(1), content=FillControl('|', token=Token.Line)), Window(content=TokenListControl.static([(Token.HelloWorld, lipsum)])), Window(width=D.exact(1), content=FillControl('|', token=Token.Line)), Window(content=BufferControl(lexer=PythonLexer, show_line_numbers=Always(), input_processors=[ DefaultPrompt('python> '), AfterInput.static(' <python', token=Token.AfterInput), ]), ), Window(width=D.exact(1), content=FillControl('|', token=Token.Line)), HSplit([ Window(width=D(max=40), height=D.exact(4), content=FillControl('b', token=Token.B)), Window(width=D(max=40), content=FillControl('f', token=Token.F)), Window(width=D.exact(30), height=D.exact(2), content=FillControl('c', token=Token.C)), ]), #CompletionsMenu(), ]), Window(height=D.exact(1), content=FillControl('-', token=Token.Line)), Window(height=D.exact(3), content=FillControl('d', token=Token.D)), SystemToolbar(), ArgToolbar(), CompletionsToolbar(), SearchToolbar(), ]) layout = FloatContainer( content=layout, floats=[ Float(xcursor=True, ycursor=True, content=VSplit([ Window(width=D.exact(5), content=FillControl('f', token=Token.F)), CompletionsMenu(), ]) ), ] ) eventloop = create_eventloop() cli = CommandLineInterface(eventloop=eventloop, layout=layout, style=TestStyle, key_bindings_registry=manager.registry, buffer=Buffer(is_multiline=Always(), completer=TestCompleter())) cli.read_input() eventloop.close()
def question(message, **kwargs): # TODO need ENTER confirmation default = kwargs.pop('default', True) # TODO style defaults on detail level style = kwargs.pop( 'style', style_from_dict({ Token.QuestionMark: '#5F819D', #Token.Selected: '#FF9D00', # AWS orange Token.Instruction: '', # default Token.Answer: '#FF9D00 bold', # AWS orange Token.Question: 'bold', })) status = {'answer': None} def get_prompt_tokens(cli): tokens = [] T = Token tokens.append((Token.QuestionMark, '?')) tokens.append((Token.Question, ' %s ' % message)) if isinstance(status['answer'], bool): tokens.append( (Token.Answer, ' Yes' if status['answer'] else ' No')) else: if default: instruction = ' (Y/n)' else: instruction = ' (y/N)' tokens.append((Token.Instruction, instruction)) return tokens # assemble layout # TODO this does not work without the HSplit?? layout = HSplit([ Window( height=D.exact(1), content=TokenListControl(get_prompt_tokens, align_center=False), ) ]) # key bindings manager = KeyBindingManager.for_prompt() @manager.registry.add_binding(Keys.ControlQ, eager=True) @manager.registry.add_binding(Keys.ControlC, eager=True) def _(event): raise KeyboardInterrupt() @manager.registry.add_binding('n') @manager.registry.add_binding('N') def key_n(event): status['answer'] = False event.cli.set_return_value(False) @manager.registry.add_binding('y') @manager.registry.add_binding('Y') def key_y(event): status['answer'] = True event.cli.set_return_value(True) @manager.registry.add_binding(Keys.Enter, eager=True) def set_answer(event): status['answer'] = default event.cli.set_return_value(default) return Application( layout=layout, key_bindings_registry=manager.registry, mouse_support=False, style=style, erase_when_done=False, )
def question(message, **kwargs): # TODO extract common parts for list, checkbox, rawlist, expand # TODO up, down navigation if not 'choices' in kwargs: raise PromptParameterException('choices') choices = kwargs.pop('choices', None) default = kwargs.pop('default', None) qmark = kwargs.pop('qmark', '?') # TODO style defaults on detail level style = kwargs.pop('style', default_style) ic = InquirerControl(choices, default) def get_prompt_tokens(cli): tokens = [] T = Token tokens.append((T.QuestionMark, qmark)) tokens.append((T.Question, ' %s ' % message)) if not ic.answered: tokens.append((T.Instruction, ' (%s)' % ''.join( [k[0] for k in ic.choices if not isinstance(k, Separator)]))) else: tokens.append((T.Answer, ' %s' % ic.get_selected_value())) return tokens #@Condition #def is_help_active(cli): # return ic._help_active # assemble layout layout = HSplit([ Window(height=D.exact(1), content=TokenListControl(get_prompt_tokens)), ConditionalContainer( Window(ic), #filter=is_help_active & ~IsDone() # ~ bitwise inverse filter=~IsDone() # ~ bitwise inverse ) ]) # key bindings manager = KeyBindingManager.for_prompt() @manager.registry.add_binding(Keys.ControlQ, eager=True) @manager.registry.add_binding(Keys.ControlC, eager=True) def _(event): raise KeyboardInterrupt() # add key bindings for choices for i, c in enumerate(ic.choices): if not isinstance(c, Separator): def _reg_binding(i, keys): # trick out late evaluation with a "function factory": # http://stackoverflow.com/questions/3431676/creating-functions-in-a-loop @manager.registry.add_binding(keys, eager=True) def select_choice(event): ic.pointer_index = i if c[0] not in ['h', 'H']: _reg_binding(i, c[0]) if c[0].isupper(): _reg_binding(i, c[0].lower()) @manager.registry.add_binding('H', eager=True) @manager.registry.add_binding('h', eager=True) def help_choice(event): ic._help_active = True @manager.registry.add_binding(Keys.Enter, eager=True) def set_answer(event): selected_value = ic.get_selected_value() if selected_value == '__HELP__': ic._help_active = True else: ic.answered = True event.cli.set_return_value(selected_value) return Application(layout=layout, key_bindings_registry=manager.registry, mouse_support=True, style=style)
def main(): manager = KeyBindingManager(enable_system_bindings=Always()) D = LayoutDimension layout = HSplit([ VSplit([ Window(width=D(min=15, max=30, preferred=30), content=FillControl('a', token=Token.A)), Window(width=D.exact(1), content=FillControl('|', token=Token.Line)), Window(content=TokenListControl.static([(Token.HelloWorld, lipsum)])), Window(width=D.exact(1), content=FillControl('|', token=Token.Line)), Window(content=BufferControl( lexer=PygmentsLexer(PythonLexer), margin=NumberredMargin(), input_processors=[ DefaultPrompt.from_message('python> '), AfterInput.static(' <python', token=Token.AfterInput), ]), ), Window(width=D.exact(1), content=FillControl('|', token=Token.Line)), HSplit([ Window(width=D(max=40), height=D.exact(4), content=FillControl('b', token=Token.B)), Window(width=D(max=40), content=FillControl('f', token=Token.F)), Window(width=D.exact(30), height=D.exact(2), content=FillControl('c', token=Token.C)), ]), #CompletionsMenu(), ]), Window(height=D.exact(1), content=FillControl('-', token=Token.Line)), Window(height=D.exact(3), content=FillControl('d', token=Token.D)), SystemToolbar(), ArgToolbar(), CompletionsToolbar(), SearchToolbar(), ]) layout = FloatContainer(content=layout, floats=[ Float(xcursor=True, ycursor=True, content=VSplit([ Window(width=D.exact(5), content=FillControl( 'f', token=Token.F)), CompletionsMenu(), ])), ]) eventloop = create_eventloop() application = Application(layout=layout, style=TestStyle, key_bindings_registry=manager.registry, buffer=Buffer(is_multiline=Always(), completer=TestCompleter())) cli = CommandLineInterface(application=application, eventloop=eventloop) cli.run() eventloop.close()
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 __init__(self, editor): token = Token.BufferList def highlight_location(location, search_string, default_token): """ Return a tokenlist with the `search_string` highlighted. """ result = [(default_token, c) for c in location] # Replace token of matching positions. for m in re.finditer(re.escape(search_string), location): for i in range(m.start(), m.end()): result[i] = (token.SearchMatch, result[i][1]) return result def get_tokens(cli): wa = editor.window_arrangement buffer_infos = wa.list_open_buffers() # Filter infos according to typed text. input_params = cli.buffers[COMMAND_BUFFER].text.lstrip().split(None, 1) search_string = input_params[1] if len(input_params) > 1 else '' if search_string: def matches(info): """ True when we should show this entry. """ # When the input appears in the location. if input_params[1] in (info.editor_buffer.location or ''): return True # When the input matches this buffer his index number. if input_params[1] in str(info.index): return True # When this entry is part of the current completions list. b = cli.buffers[COMMAND_BUFFER] if b.complete_state and any(info.editor_buffer.location in c.display for c in b.complete_state.current_completions if info.editor_buffer.location is not None): return True return False buffer_infos = [info for info in buffer_infos if matches(info)] # Render output. if len(buffer_infos) == 0: return [(token, ' No match found. ')] else: result = [] # Create title. result.append((token, ' ')) result.append((token.Title, 'Open buffers\n')) # Get length of longest location max_location_len = max(len(info.editor_buffer.get_display_name()) for info in buffer_infos) # Show info for each buffer. for info in buffer_infos: eb = info.editor_buffer char = '%' if info.is_active else ' ' char2 = 'a' if info.is_visible else ' ' char3 = ' + ' if info.editor_buffer.has_unsaved_changes else ' ' t = token.Active if info.is_active else token result.extend([ (token, ' '), (t, '%3i ' % info.index), (t, '%s' % char), (t, '%s ' % char2), (t, '%s ' % char3), ]) result.extend(highlight_location(eb.get_display_name(), search_string, t)) result.extend([ (t, ' ' * (max_location_len - len(eb.get_display_name()))), (t.Lineno, ' line %i' % (eb.buffer.document.cursor_position_row + 1)), (t, ' \n') ]) return result super(BufferListOverlay, self).__init__( Window(TokenListControl(get_tokens, default_char=Char(token=token))), filter=bufferlist_overlay_visible_filter)
def question(message, **kwargs): # TODO extract common parts for list, checkbox, rawlist, expand if not 'choices' in kwargs: raise PromptParameterException('choices') # this does not implement default, use checked... # TODO #if 'default' in kwargs: # raise ValueError('rawlist does not implement \'default\' ' # 'use \'checked\':True\' in choice!') qmark = kwargs.pop('qmark', '?') choices = kwargs.pop('choices', None) if len(choices) > 9: raise ValueError('rawlist supports only a maximum of 9 choices!') # TODO style defaults on detail level style = kwargs.pop('style', default_style) ic = InquirerControl(choices) def get_prompt_tokens(cli): tokens = [] T = Token tokens.append((T.QuestionMark, qmark)) tokens.append((T.Question, ' %s ' % message)) if ic.answered: tokens.append((T.Answer, ' %s' % ic.get_selected_value())) return tokens # assemble layout layout = HSplit([ Window(height=D.exact(1), content=TokenListControl(get_prompt_tokens)), ConditionalContainer(Window(ic), filter=~IsDone()) ]) # key bindings manager = KeyBindingManager.for_prompt() @manager.registry.add_binding(Keys.ControlQ, eager=True) @manager.registry.add_binding(Keys.ControlC, eager=True) def _(event): raise KeyboardInterrupt() # add key bindings for choices for i, c in enumerate(ic.choices): if not isinstance(c, Separator): def _reg_binding(i, keys): # trick out late evaluation with a "function factory": # http://stackoverflow.com/questions/3431676/creating-functions-in-a-loop @manager.registry.add_binding(keys, eager=True) def select_choice(event): ic.pointer_index = i _reg_binding(i, '%d' % c[0]) @manager.registry.add_binding(Keys.Enter, eager=True) def set_answer(event): ic.answered = True event.cli.set_return_value(ic.get_selected_value()) return Application(layout=layout, key_bindings_registry=manager.registry, mouse_support=True, style=style)
# Ctrl-R.) It would be really annoying if the search key bindings are handled, # but the user doesn't see any feedback. We will add the search toolbar to the # bottom by using an HSplit. def get_titlebar_tokens(cli): return [ (Token.Title, ' Hello world '), (Token.Title, ' (Press [Ctrl-Q] to quit.)'), ] layout = HSplit([ # The titlebar. Window(height=D.exact(1), content=TokenListControl(get_titlebar_tokens, align_center=True)), # Horizontal separator. Window(height=D.exact(1), content=FillControl('-', token=Token.Line)), # The 'body', like defined above. layout, ]) # 2. Adding key bindings # -------------------- # As a demonstration, we will add just a ControlQ key binding to exit the # application. Key bindings are registered in a # `prompt_toolkit.key_bindings.registry.Registry` instance. We use the # `load_default_key_bindings` utility function to create a registry that
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)), ] )