def create_application(self): """ Create an `Application` instance for use in a `CommandLineInterface`. """ buffers = { 'docstring': Buffer(read_only=True), 'realtime_display': Buffer(read_only=True), 'vars': Buffer(read_only=True), 'parenthesizer_buffer': Buffer(read_only=True), } for key in r_iterm_comm.python_input_buffers: buffers[key] = Buffer(read_only=True) buffers.update(self._extra_buffers or {}) return Application( layout=create_layout( self, lexer=self._lexer, input_buffer_height=self._input_buffer_height, extra_buffer_processors=self._extra_buffer_processors, extra_body=self._extra_layout_body, extra_toolbars=self._extra_toolbars), buffer=self._create_buffer(), buffers=buffers, key_bindings_registry=self.key_bindings_registry, paste_mode=Condition(lambda cli: self.paste_mode), mouse_support=Condition(lambda cli: self.enable_mouse_support), on_abort=AbortAction.RETRY, on_exit=self._on_exit, style=DynamicStyle(lambda: self._current_style), get_title=lambda: self.terminal_title, reverse_vi_search_direction=True, on_initialize=self._on_cli_initialize, on_start=self._on_start, on_input_timeout=self._on_input_timeout)
def _create_buffer(self): """ Create the `Buffer` for the Python input. """ def is_buffer_multiline(): return (self.paste_mode or self.accept_input_on_enter is None or document_is_multiline_python(python_buffer.document)) python_buffer = Buffer( is_multiline=Condition(is_buffer_multiline), complete_while_typing=Condition( lambda: self.complete_while_typing), enable_history_search=Condition( lambda: self.enable_history_search), tempfile_suffix='.py', history=self.history, completer=self._completer, validator=ConditionalValidator( self._validator, Condition(lambda: self.enable_input_validation)), auto_suggest=ConditionalAutoSuggest( AutoSuggestFromHistory(), Condition(lambda cli: self.enable_auto_suggest)), accept_action=self._accept_action) return python_buffer
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 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 add_key_binding(self): """ Shortcut for adding new key bindings. (Mostly useful for a .ptpython/config.py file, that receives a PythonInput/Repl instance as input.) :: @python_input.add_key_binding(Keys.ControlX, filter=...) def handler(event): ... """ # Extra key bindings should not be active when the sidebar is visible. sidebar_visible = Condition(lambda cli: self.show_sidebar) def add_binding_decorator(*keys, **kw): # Pop default filter keyword argument. filter = kw.pop('filter', Always()) assert not kw return self.key_bindings_registry.add_binding(*keys, filter=filter & ~sidebar_visible) return add_binding_decorator
def __init__(self, min_rows=3, suggested_max_column_width=30, show_meta=True, extra_filter=True): show_meta = to_cli_filter(show_meta) extra_filter = to_cli_filter(extra_filter) # Display filter: show when there are completions but not at the point # we are returning the input. full_filter = HasCompletions() & ~IsDone() & extra_filter any_completion_has_meta = Condition(lambda cli: any(c.display_meta for c in cli.current_buffer.complete_state.current_completions)) # Create child windows. completions_window = ConditionalContainer( content=Window( content=MultiColumnCompletionMenuControl( min_rows=min_rows, suggested_max_column_width=suggested_max_column_width), width=LayoutDimension(min=8), height=LayoutDimension(min=1)), filter=full_filter) meta_window = ConditionalContainer( content=Window(content=_SelectedCompletionMetaControl()), filter=show_meta & full_filter & any_completion_has_meta) # Initialise split. super(MultiColumnCompletionsMenu, self).__init__([ completions_window, meta_window ])
def __init__(self, python_input): self.python_input = python_input def get_prompt_style(): return python_input.all_prompt_styles[python_input.prompt_style] def get_prompt(cli): return get_prompt_style().in_tokens(cli) def get_continuation_prompt(cli, width): return get_prompt_style().in2_tokens(cli, width) super(PythonPromptMargin, self).__init__( get_prompt, get_continuation_prompt, show_numbers=Condition(lambda cli: python_input.show_line_numbers))
def load_basic_system_bindings(): """ Basic system bindings (For both Emacs and Vi mode.) """ registry = Registry() suspend_supported = Condition( lambda cli: suspend_to_background_supported()) @registry.add_binding(Keys.ControlZ, filter=suspend_supported) def _(event): """ Suspend process to background. """ event.cli.suspend_to_background() return registry
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 import datetime remove_beginning_zero = lambda x: x[1:] if x[0] == '0' else x import rp get_tokens = lambda cli: [ (token.BatteryPluggedIn if rp.battery_plugged_in() else token.BatteryNotPluggedIn, "🔋 " * 0 + str(rp.battery_percentage()) + '%'), # put the time here (token, ' '), (token, (remove_beginning_zero(datetime.datetime.now().strftime( "%I:%M%p")).lower())), # put the time here (token, ' '), (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(get_tokens(None)) # 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 __init__(self, eventloop=None, python_input=None, input=None, output=None): assert python_input is None or isinstance(python_input, PythonInput) python_input = python_input or PythonInput() # Make sure that the rp.prompt_toolkit 'renderer' knows about the # 'true_color' property of PythonInput. if output is None: output = create_output( true_color=Condition(lambda: python_input.true_color)) super(PythonCommandLineInterface, self).__init__(application=python_input.create_application(), eventloop=eventloop, input=input, output=output)
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 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 load_auto_suggestion_bindings(): """ Key bindings for accepting auto suggestion text. """ registry = Registry() handle = registry.add_binding suggestion_available = Condition( lambda cli: cli.current_buffer.suggestion is not None and cli. current_buffer.document.is_cursor_at_the_end) @handle(Keys.ControlF, filter=suggestion_available) @handle(Keys.ControlE, filter=suggestion_available) @handle(Keys.Right, filter=suggestion_available) def _(event): " Accept suggestion. " b = event.current_buffer suggestion = b.suggestion if suggestion: b.insert_text(suggestion.text) return registry
def status_bar(python_input): """ Create the `Layout` for the status bar. """ TB = Token.Toolbar.Status @if_mousedown def toggle_mouse_support(cli, mouse_event): python_input.enable_mouse_support = not python_input.enable_mouse_support @if_mousedown def toggle_paste_mode(cli, mouse_event): python_input.paste_mode = not python_input.paste_mode @if_mousedown def enter_history(cli, mouse_event): python_input.enter_history(cli) def get_tokens(cli): python_buffer = cli.buffers[DEFAULT_BUFFER] result = [] append = result.append append((TB, ' ')) result.extend(get_inputmode_tokens(cli, python_input)) # Position in history. append((TB, '%i/%i ' % (python_buffer.working_index + 1, len(python_buffer._working_lines)))) # Shortcuts. if not python_input.vi_mode and cli.current_buffer_name == SEARCH_BUFFER: append((TB, '[Ctrl-G] Cancel search [Enter] Go to this position.')) elif bool(cli.current_buffer.selection_state ) and not python_input.vi_mode: # Emacs cut/copy keys. append( (TB, '[Ctrl-W] Cut [Meta-W] Copy [Ctrl-Y] Paste [Ctrl-G] Cancel')) else: result.extend([ (TB.Key, '[F3]', enter_history), (TB, 'History ', enter_history), (TB.Key, '[F6]', toggle_paste_mode), # (TB, ' ', toggle_paste_mode), ]) if python_input.paste_mode: append((TB.PasteModeOn, 'Paste:On ', toggle_paste_mode)) else: append((TB, 'Paste:Off ', toggle_paste_mode)) result.extend([ (TB.Key, '[F1]', toggle_mouse_support), ]) if python_input.enable_mouse_support: append((TB.PasteModeOn, 'Mouse:On ', toggle_mouse_support)) else: append((TB, 'Mouse:Off ', toggle_mouse_support)) #region RYAN BURGERT CODE GOES HERE FOR PSEUDOTERMINAL STUFF append((TB, ' ')) @if_mousedown def testytest(cli, mouse_event): # python_input.enter_history(cli) pass import rp.r_iterm_comm append((TB.PseudoTerminalCurrentVariable, repr(rp.r_iterm_comm.last_assignable_comm), testytest)) append((TB, ' ')) return result return TokenListToolbar( get_tokens, default_char=Char(token=TB), filter=~IsDone() & RendererHeightIsKnown() & Condition(lambda cli: python_input.show_status_bar and not python_input.show_exit_confirmation))
def show_completions_menu(python_input): return Condition(lambda cli: python_input.completion_visualisation == CompletionVisualisation.POP_UP)
def load_basic_bindings(): registry = Registry() insert_mode = ViInsertMode() | EmacsInsertMode() handle = registry.add_binding has_selection = HasSelection() @handle(Keys.ControlA) @handle(Keys.ControlB) @handle(Keys.ControlC) @handle(Keys.ControlD) @handle(Keys.ControlE) @handle(Keys.ControlF) @handle(Keys.ControlG) @handle(Keys.ControlH) @handle(Keys.ControlI) @handle(Keys.ControlJ) @handle(Keys.ControlK) @handle(Keys.ControlL) @handle(Keys.ControlM) @handle(Keys.ControlN) @handle(Keys.ControlO) @handle(Keys.ControlP) @handle(Keys.ControlQ) @handle(Keys.ControlR) @handle(Keys.ControlS) @handle(Keys.ControlT) @handle(Keys.ControlU) @handle(Keys.ControlV) @handle(Keys.ControlW) @handle(Keys.ControlX) @handle(Keys.ControlY) @handle(Keys.ControlZ) @handle(Keys.F1) @handle(Keys.F2) @handle(Keys.F3) @handle(Keys.F4) @handle(Keys.F5) @handle(Keys.F6) @handle(Keys.F7) @handle(Keys.F8) @handle(Keys.F9) @handle(Keys.F10) @handle(Keys.F11) @handle(Keys.F12) @handle(Keys.F13) @handle(Keys.F14) @handle(Keys.F15) @handle(Keys.F16) @handle(Keys.F17) @handle(Keys.F18) @handle(Keys.F19) @handle(Keys.F20) @handle(Keys.ControlSpace) @handle(Keys.ControlBackslash) @handle(Keys.ControlSquareClose) @handle(Keys.ControlCircumflex) @handle(Keys.ControlUnderscore) @handle(Keys.Backspace) @handle(Keys.Up) @handle(Keys.Down) @handle(Keys.Right) @handle(Keys.Left) @handle(Keys.ShiftUp) @handle(Keys.ShiftDown) @handle(Keys.ShiftRight) @handle(Keys.ShiftLeft) @handle(Keys.Home) @handle(Keys.End) @handle(Keys.Delete) @handle(Keys.ShiftDelete) @handle(Keys.ControlDelete) @handle(Keys.PageUp) @handle(Keys.PageDown) @handle(Keys.BackTab) @handle(Keys.Tab) @handle(Keys.ControlLeft) @handle(Keys.ControlRight) @handle(Keys.ControlUp) @handle(Keys.ControlDown) @handle(Keys.Insert) @handle(Keys.Ignore) def _(event): """ First, for any of these keys, Don't do anything by default. Also don't catch them in the 'Any' handler which will insert them as data. If people want to insert these characters as a literal, they can always do by doing a quoted insert. (ControlQ in emacs mode, ControlV in Vi mode.) """ pass # Readline-style bindings. handle(Keys.Home)(get_by_name('beginning-of-line')) handle(Keys.End)(get_by_name('end-of-line')) handle(Keys.Left)(get_by_name('backward-char')) handle(Keys.Right)(get_by_name('forward-char')) handle(Keys.ControlUp)(get_by_name('previous-history')) handle(Keys.ControlDown)(get_by_name('next-history')) handle(Keys.ControlL)(get_by_name('clear-screen')) handle(Keys.ControlK, filter=insert_mode)(get_by_name('kill-line')) handle(Keys.ControlU, filter=insert_mode)(get_by_name('unix-line-discard')) handle(Keys.ControlH, filter=insert_mode, save_before=if_no_repeat)(get_by_name('backward-delete-char')) handle(Keys.Backspace, filter=insert_mode, save_before=if_no_repeat)(get_by_name('backward-delete-char')) handle(Keys.Delete, filter=insert_mode, save_before=if_no_repeat)(get_by_name('delete-char')) handle(Keys.ShiftDelete, filter=insert_mode, save_before=if_no_repeat)(get_by_name('delete-char')) handle(Keys.Any, filter=insert_mode, save_before=if_no_repeat)(get_by_name('self-insert')) handle(Keys.ControlT, filter=insert_mode)(get_by_name('transpose-chars')) handle(Keys.ControlW, filter=insert_mode)(get_by_name('unix-word-rubout')) handle(Keys.ControlI, filter=insert_mode)(get_by_name('menu-complete')) handle(Keys.BackTab, filter=insert_mode)(get_by_name('menu-complete-backward')) handle(Keys.PageUp, filter=~has_selection)(get_by_name('previous-history')) handle(Keys.PageDown, filter=~has_selection)(get_by_name('next-history')) # CTRL keys. text_before_cursor = Condition(lambda cli: cli.current_buffer.text) handle(Keys.ControlD, filter=text_before_cursor & insert_mode)(get_by_name('delete-char')) is_multiline = Condition(lambda cli: cli.current_buffer.is_multiline()) is_returnable = Condition( lambda cli: cli.current_buffer.accept_action.is_returnable) @handle(Keys.ControlJ, filter=is_multiline & insert_mode) def _(event): " Newline (in case of multiline input. " event.current_buffer.newline(copy_margin=not event.cli.in_paste_mode) @handle(Keys.ControlJ, filter=~is_multiline & is_returnable) def _(event): " Enter, accept input. " buff = event.current_buffer buff.accept_action.validate_and_handle(event.cli, buff) # Delete the word before the cursor. @handle(Keys.Up) def _(event): event.current_buffer.auto_up(count=event.arg) @handle(Keys.Down) def _(event): event.current_buffer.auto_down(count=event.arg) @handle(Keys.Delete, filter=has_selection) def _(event): data = event.current_buffer.cut_selection() event.cli.clipboard.set_data(data) # Global bindings. @handle(Keys.ControlZ) def _(event): """ By default, control-Z should literally insert Ctrl-Z. (Ansi Ctrl-Z, code 26 in MSDOS means End-Of-File. In a Python REPL for instance, it's possible to type Control-Z followed by enter to quit.) When the system bindings are loaded and suspend-to-background is supported, that will override this binding. """ event.current_buffer.insert_text(event.data) @handle(Keys.CPRResponse, save_before=lambda e: False) def _(event): """ Handle incoming Cursor-Position-Request response. """ # The incoming data looks like u'\x1b[35;1R' # Parse row/col information. row, col = map(int, event.data[2:-1].split(';')) # Report absolute cursor position to the renderer. event.cli.renderer.report_absolute_cursor_row(row) @handle(Keys.BracketedPaste) def _(event): " Pasting from clipboard. " data = event.data # Be sure to use \n as line ending. # Some terminals (Like iTerm2) seem to paste \r\n line endings in a # bracketed paste. See: https://github.com/ipython/ipython/issues/9737 data = data.replace('\r\n', '\n') data = data.replace('\r', '\n') event.current_buffer.insert_text(data) @handle(Keys.Any, filter=Condition(lambda cli: cli.quoted_insert), eager=True) def _(event): """ Handle quoted insert. """ event.current_buffer.insert_text(event.data, overwrite=False) event.cli.quoted_insert = False return registry
def show_completions_toolbar(python_input): return Condition(lambda cli: python_input.completion_visualisation == CompletionVisualisation.TOOLBAR)
def load_emacs_bindings(): """ Some e-macs extensions. """ # Overview of Readline emacs commands: # http://www.catonmat.net/download/readline-emacs-editing-mode-cheat-sheet.pdf registry = ConditionalRegistry(Registry(), EmacsMode()) handle = registry.add_binding insert_mode = EmacsInsertMode() has_selection = HasSelection() @handle(Keys.Escape) def _(event): """ By default, ignore escape key. (If we don't put this here, and Esc is followed by a key which sequence is not handled, we'll insert an Escape character in the input stream. Something we don't want and happens to easily in emacs mode. Further, people can always use ControlQ to do a quoted insert.) """ pass handle(Keys.ControlA)(get_by_name('beginning-of-line')) handle(Keys.ControlB)(get_by_name('backward-char')) handle(Keys.ControlDelete, filter=insert_mode)(get_by_name('kill-word')) handle(Keys.ControlE)(get_by_name('end-of-line')) handle(Keys.ControlF)(get_by_name('forward-char')) handle(Keys.ControlLeft)(get_by_name('backward-word')) handle(Keys.ControlRight)(get_by_name('forward-word')) handle(Keys.ControlX, 'r', 'y', filter=insert_mode)(get_by_name('yank')) handle(Keys.ControlY, filter=insert_mode)(get_by_name('yank')) handle(Keys.Escape, 'b')(get_by_name('backward-word')) handle(Keys.Escape, 'c', filter=insert_mode)(get_by_name('capitalize-word')) handle(Keys.Escape, 'd', filter=insert_mode)(get_by_name('kill-word')) handle(Keys.Escape, 'f')(get_by_name('forward-word')) handle(Keys.Escape, 'l', filter=insert_mode)(get_by_name('downcase-word')) handle(Keys.Escape, 'u', filter=insert_mode)(get_by_name('uppercase-word')) handle(Keys.Escape, 'y', filter=insert_mode)(get_by_name('yank-pop')) handle(Keys.Escape, Keys.ControlH, filter=insert_mode)(get_by_name('backward-kill-word')) handle(Keys.Escape, Keys.Backspace, filter=insert_mode)(get_by_name('backward-kill-word')) handle(Keys.Escape, '\\', filter=insert_mode)(get_by_name('delete-horizontal-space')) handle(Keys.ControlUnderscore, save_before=(lambda e: False), filter=insert_mode)(get_by_name('undo')) handle(Keys.ControlX, Keys.ControlU, save_before=(lambda e: False), filter=insert_mode)(get_by_name('undo')) handle(Keys.Escape, '<', filter=~has_selection)(get_by_name('beginning-of-history')) handle(Keys.Escape, '>', filter=~has_selection)(get_by_name('end-of-history')) handle(Keys.Escape, '.', filter=insert_mode)(get_by_name('yank-last-arg')) handle(Keys.Escape, '_', filter=insert_mode)(get_by_name('yank-last-arg')) handle(Keys.Escape, Keys.ControlY, filter=insert_mode)(get_by_name('yank-nth-arg')) handle(Keys.Escape, '#', filter=insert_mode)(get_by_name('insert-comment')) handle(Keys.ControlO)(get_by_name('operate-and-get-next')) # ControlQ does a quoted insert. Not that for vt100 terminals, you have to # disable flow control by running ``stty -ixon``, otherwise Ctrl-Q and # Ctrl-S are captured by the terminal. handle(Keys.ControlQ, filter=~has_selection)(get_by_name('quoted-insert')) handle(Keys.ControlX, '(')(get_by_name('start-kbd-macro')) handle(Keys.ControlX, ')')(get_by_name('end-kbd-macro')) handle(Keys.ControlX, 'e')(get_by_name('call-last-kbd-macro')) @handle(Keys.ControlN) def _(event): " Next line. " event.current_buffer.auto_down() @handle(Keys.ControlP) def _(event): " Previous line. " event.current_buffer.auto_up(count=event.arg) def handle_digit(c): """ Handle input of arguments. The first number needs to be preceeded by escape. """ @handle(c, filter=HasArg()) @handle(Keys.Escape, c) def _(event): event.append_to_arg_count(c) for c in '0123456789': handle_digit(c) @handle(Keys.Escape, '-', filter=~HasArg()) def _(event): """ """ if event._arg is None: event.append_to_arg_count('-') @handle('-', filter=Condition(lambda cli: cli.input_processor.arg == '-')) def _(event): """ When '-' is typed again, after exactly '-' has been given as an argument, ignore this. """ event.cli.input_processor.arg = '-' is_returnable = Condition( lambda cli: cli.current_buffer.accept_action.is_returnable) # Meta + Newline: always accept input. handle(Keys.Escape, Keys.ControlJ, filter=insert_mode & is_returnable)(get_by_name('accept-line')) def character_search(buff, char, count): if count < 0: match = buff.document.find_backwards(char, in_current_line=True, count=-count) else: match = buff.document.find(char, in_current_line=True, count=count) if match is not None: buff.cursor_position += match @handle(Keys.ControlSquareClose, Keys.Any) def _(event): " When Ctl-] + a character is pressed. go to that character. " # Also named 'character-search' character_search(event.current_buffer, event.data, event.arg) @handle(Keys.Escape, Keys.ControlSquareClose, Keys.Any) def _(event): " Like Ctl-], but backwards. " # Also named 'character-search-backward' character_search(event.current_buffer, event.data, -event.arg) @handle(Keys.Escape, 'a') def _(event): " Previous sentence. " # TODO: @handle(Keys.Escape, 'e') def _(event): " Move to end of sentence. " # TODO: @handle(Keys.Escape, 't', filter=insert_mode) def _(event): """ Swap the last two words before the cursor. """ # TODO @handle(Keys.Escape, '*', filter=insert_mode) def _(event): """ `meta-*`: Insert all possible completions of the preceding text. """ buff = event.current_buffer # List all completions. complete_event = CompleteEvent(text_inserted=False, completion_requested=True) completions = list( buff.completer.get_completions(buff.document, complete_event)) # Insert them. text_to_insert = ' '.join(c.text for c in completions) buff.insert_text(text_to_insert) @handle(Keys.ControlX, Keys.ControlX) def _(event): """ Move cursor back and forth between the start and end of the current line. """ buffer = event.current_buffer if buffer.document.is_cursor_at_the_end_of_line: buffer.cursor_position += buffer.document.get_start_of_line_position( after_whitespace=False) else: buffer.cursor_position += buffer.document.get_end_of_line_position( ) @handle(Keys.ControlSpace) def _(event): """ Start of the selection (if the current buffer is not empty). """ # Take the current cursor position as the start of this selection. buff = event.current_buffer if buff.text: buff.start_selection(selection_type=SelectionType.CHARACTERS) @handle(Keys.ControlG, filter=~has_selection) def _(event): """ Control + G: Cancel completion menu and validation state. """ event.current_buffer.complete_state = None event.current_buffer.validation_error = None @handle(Keys.ControlG, filter=has_selection) def _(event): """ Cancel selection. """ event.current_buffer.exit_selection() @handle(Keys.ControlW, filter=has_selection) @handle(Keys.ControlX, 'r', 'k', filter=has_selection) def _(event): """ Cut selected text. """ data = event.current_buffer.cut_selection() event.cli.clipboard.set_data(data) @handle(Keys.Escape, 'w', filter=has_selection) def _(event): """ Copy selected text. """ data = event.current_buffer.copy_selection() event.cli.clipboard.set_data(data) @handle(Keys.Escape, Keys.Left) def _(event): """ Cursor to start of previous word. """ buffer = event.current_buffer buffer.cursor_position += buffer.document.find_previous_word_beginning( count=event.arg) or 0 @handle(Keys.Escape, Keys.Right) def _(event): """ Cursor to start of next word. """ buffer = event.current_buffer buffer.cursor_position += buffer.document.find_next_word_beginning(count=event.arg) or \ buffer.document.get_end_of_document_position() @handle(Keys.Escape, '/', filter=insert_mode) def _(event): """ M-/: Complete. """ b = event.current_buffer if b.complete_state: b.complete_next() else: event.cli.start_completion(select_first=True) @handle(Keys.ControlC, '>', filter=has_selection) def _(event): """ Indent selected text. """ buffer = event.current_buffer buffer.cursor_position += buffer.document.get_start_of_line_position( after_whitespace=True) from_, to = buffer.document.selection_range() from_, _ = buffer.document.translate_index_to_position(from_) to, _ = buffer.document.translate_index_to_position(to) indent(buffer, from_, to + 1, count=event.arg) @handle(Keys.ControlC, '<', filter=has_selection) def _(event): """ Unindent selected text. """ buffer = event.current_buffer from_, to = buffer.document.selection_range() from_, _ = buffer.document.translate_index_to_position(from_) to, _ = buffer.document.translate_index_to_position(to) unindent(buffer, from_, to + 1, count=event.arg) return registry
def create_history_application(python_input, original_document): """ Create an `Application` for the history screen. This has to be run as a sub application of `python_input`. When this application runs and returns, it retuns the selected lines. """ history_mapping = HistoryMapping(python_input.history, original_document) def default_buffer_pos_changed(_): """ When the cursor changes in the default buffer. Synchronize with history buffer. """ # Only when this buffer has the focus. if buffer_mapping.focus_stack[-1] == DEFAULT_BUFFER: try: line_no = default_buffer.document.cursor_position_row - \ history_mapping.result_line_offset if line_no < 0: # When the cursor is above the inserted region. raise IndexError history_lineno = sorted( history_mapping.selected_lines)[line_no] except IndexError: pass else: history_buffer.cursor_position = \ history_buffer.document.translate_row_col_to_index(history_lineno, 0) def history_buffer_pos_changed(_): """ When the cursor changes in the history buffer. Synchronize. """ # Only when this buffer has the focus. if buffer_mapping.focus_stack[-1] == HISTORY_BUFFER: line_no = history_buffer.document.cursor_position_row if line_no in history_mapping.selected_lines: default_lineno = sorted(history_mapping.selected_lines).index(line_no) + \ history_mapping.result_line_offset default_buffer.cursor_position = \ default_buffer.document.translate_row_col_to_index(default_lineno, 0) history_buffer = Buffer( initial_document=Document(history_mapping.concatenated_history), on_cursor_position_changed=history_buffer_pos_changed, accept_action=AcceptAction( lambda cli, buffer: cli.set_return_value(default_buffer.document)), read_only=True) default_buffer = Buffer( initial_document=history_mapping.get_new_document(), on_cursor_position_changed=default_buffer_pos_changed, read_only=True) help_buffer = Buffer(initial_document=Document(HELP_TEXT, 0), accept_action=AcceptAction.IGNORE, read_only=True) buffer_mapping = BufferMapping( { HISTORY_BUFFER: history_buffer, DEFAULT_BUFFER: default_buffer, HELP_BUFFER: help_buffer, }, initial=HISTORY_BUFFER) application = Application( layout=create_layout(python_input, history_mapping), use_alternate_screen=True, buffers=buffer_mapping, style=python_input._current_style, mouse_support=Condition(lambda cli: python_input.enable_mouse_support), key_bindings_registry=create_key_bindings(python_input, history_mapping)) return application
def __init__( self, get_globals=None, get_locals=None, history_filename=None, vi_mode=False, # For internal use. _completer=None, _validator=None, _lexer=None, _extra_buffers=None, _extra_buffer_processors=None, _on_start=None, _extra_layout_body=None, _extra_toolbars=None, _input_buffer_height=None, _accept_action=AcceptAction.RETURN_DOCUMENT, _on_exit=AbortAction.RAISE_EXCEPTION): self.get_globals = get_globals or (lambda: {}) self.get_locals = get_locals or self.get_globals self.show_parenthesis_automator = False self._completer = _completer or PythonCompleter( self.get_globals, self.get_locals) self._validator = _validator or PythonValidator( self.get_compiler_flags) self.history = FileHistory( history_filename) if history_filename else InMemoryHistory() self._lexer = _lexer or PygmentsLexer(PythonLexer) self._extra_buffers = _extra_buffers self._accept_action = _accept_action self._on_exit = _on_exit self._on_start = _on_start self._input_buffer_height = _input_buffer_height self._extra_layout_body = _extra_layout_body or [] self._extra_toolbars = _extra_toolbars or [] self._extra_buffer_processors = _extra_buffer_processors or [] # Settings. self.show_signature = False self.show_docstring = False self.show_realtime_input = False self.show_vars = False self.show_meta_enter_message = True self.completion_visualisation = CompletionVisualisation.MULTI_COLUMN self.completion_menu_scroll_offset = 1 self.show_line_numbers = False self.show_status_bar = True self.wrap_lines = True self.complete_while_typing = True self.vi_mode = vi_mode self.paste_mode = False # When True, don't insert whitespace after newline. self.confirm_exit = True # Ask for confirmation when Control-D is pressed. self.accept_input_on_enter = 2 # Accept when pressing Enter 'n' times. # 'None' means that meta-enter is always required. self.enable_open_in_editor = True self.enable_system_bindings = True self.enable_input_validation = True self.enable_auto_suggest = False self.enable_mouse_support = False self.enable_history_search = False # When True, like readline, going # back in history will filter the # history on the records starting # with the current input. self.highlight_matching_parenthesis = False self.show_sidebar = False # Currently show the sidebar. self.show_sidebar_help = True # When the sidebar is visible, also show the help text. self.show_exit_confirmation = False # Currently show 'Do you really want to exit?' self.terminal_title = None # The title to be displayed in the terminal. (None or string.) self.exit_message = 'Do you really want to exit?' self.insert_blank_line_after_output = True # (For the REPL.) # Tokens to be shown at the prompt. self.prompt_style = 'classic' # The currently active style. self.all_prompt_styles={ # Styles selectable from the menu. 'ipython':IPythonPrompt(self), 'classic':ClassicPrompt(), } self.get_input_prompt_tokens=lambda cli: \ self.all_prompt_styles[self.prompt_style].in_tokens(cli) self.get_output_prompt_tokens=lambda cli: \ self.all_prompt_styles[self.prompt_style].out_tokens(cli) #: Load styles. self.code_styles = get_all_code_styles() self.ui_styles = get_all_ui_styles() self._current_code_style_name = 'default' self._current_ui_style_name = 'default' if is_windows(): self._current_code_style_name = 'win32' self._current_style = self._generate_style() self.true_color = False # Options to be configurable from the sidebar. self.options = self._create_options() self.selected_option_index = 0 #: Incremeting integer counting the current statement. self.current_statement_index = 1 # Code signatures. (This is set asynchronously after a timeout.) self.signatures = [] self.waa = True # RYAN BURGERT STUFF self.sand_creature = 'dust ball' # Create a Registry for the key bindings. self.key_bindings_registry = MergedRegistry([ ConditionalRegistry( registry=load_key_bindings_for_prompt( enable_abort_and_exit_bindings=True, enable_search=True, enable_open_in_editor=Condition( lambda cli: self.enable_open_in_editor), enable_system_bindings=Condition( lambda cli: self.enable_system_bindings), enable_auto_suggest_bindings=Condition( lambda cli: self.enable_auto_suggest)), # Disable all default key bindings when the sidebar or the exit confirmation # are shown. filter=Condition(lambda cli: not (self.show_sidebar or self. show_exit_confirmation))), load_mouse_bindings(), load_python_bindings(self), load_sidebar_bindings(self), load_confirm_exit_bindings(self), ]) # Boolean indicating whether we have a signatures thread running. # (Never run more than one at the same time.) self._get_signatures_thread_running = False
def show_multi_column_completions_menu(python_input): return Condition(lambda cli: python_input.completion_visualisation == CompletionVisualisation.MULTI_COLUMN)
def create_key_bindings(python_input, history_mapping): """ Key bindings. """ registry = load_key_bindings(enable_search=True, enable_extra_page_navigation=True) handle = registry.add_binding @handle(' ', filter=HasFocus(HISTORY_BUFFER)) def _(event): """ Space: select/deselect line from history pane. """ b = event.current_buffer line_no = b.document.cursor_position_row if line_no in history_mapping.selected_lines: # Remove line. history_mapping.selected_lines.remove(line_no) history_mapping.update_default_buffer(event.cli) else: # Add line. history_mapping.selected_lines.add(line_no) history_mapping.update_default_buffer(event.cli) # Update cursor position default_buffer = event.cli.buffers[DEFAULT_BUFFER] default_lineno = sorted(history_mapping.selected_lines).index(line_no) + \ history_mapping.result_line_offset default_buffer.cursor_position = \ default_buffer.document.translate_row_col_to_index(default_lineno, 0) # Also move the cursor to the next line. (This way they can hold # space to select a region.) b.cursor_position = b.document.translate_row_col_to_index( line_no + 1, 0) @handle(' ', filter=HasFocus(DEFAULT_BUFFER)) @handle(Keys.Delete, filter=HasFocus(DEFAULT_BUFFER)) @handle(Keys.ControlH, filter=HasFocus(DEFAULT_BUFFER)) def _(event): """ Space: remove line from default pane. """ b = event.current_buffer line_no = b.document.cursor_position_row - history_mapping.result_line_offset if line_no >= 0: try: history_lineno = sorted( history_mapping.selected_lines)[line_no] except IndexError: pass # When `selected_lines` is an empty set. else: history_mapping.selected_lines.remove(history_lineno) history_mapping.update_default_buffer(event.cli) help_focussed = HasFocus(HELP_BUFFER) main_buffer_focussed = HasFocus(HISTORY_BUFFER) | HasFocus(DEFAULT_BUFFER) @handle(Keys.Tab, filter=main_buffer_focussed) @handle(Keys.ControlX, filter=main_buffer_focussed, eager=True) # Eager: ignore the Emacs [Ctrl-X Ctrl-X] binding. @handle(Keys.ControlW, filter=main_buffer_focussed) def _(event): " Select other window. " _select_other_window(event.cli) @handle(Keys.F4) def _(event): " Switch between Emacs/Vi mode. " python_input.vi_mode = not python_input.vi_mode @handle(Keys.F1) def _(event): " Display/hide help. " _toggle_help(event.cli) @handle(Keys.ControlJ, filter=help_focussed) @handle(Keys.ControlC, filter=help_focussed) @handle(Keys.ControlG, filter=help_focussed) @handle(Keys.Escape, filter=help_focussed) def _(event): " Leave help. " event.cli.pop_focus() @handle('q', filter=main_buffer_focussed) @handle(Keys.F3, filter=main_buffer_focussed) @handle(Keys.ControlC, filter=main_buffer_focussed) @handle(Keys.ControlG, filter=main_buffer_focussed) def _(event): " Cancel and go back. " event.cli.set_return_value(None) enable_system_bindings = Condition( lambda cli: python_input.enable_system_bindings) @handle(Keys.ControlZ, filter=enable_system_bindings) def _(event): " Suspend to background. " event.cli.suspend_to_background() return registry