def _create_more_session(message='--MORE--'): """ Create a `PromptSession` object for displaying the "--MORE--". """ from polymorph.deps.prompt_toolkit.shortcuts import PromptSession bindings = KeyBindings() @bindings.add(' ') @bindings.add('y') @bindings.add('Y') @bindings.add(Keys.ControlJ) @bindings.add(Keys.ControlM) @bindings.add(Keys.ControlI) # Tab. def _(event): event.app.exit(result=True) @bindings.add('n') @bindings.add('N') @bindings.add('q') @bindings.add('Q') @bindings.add(Keys.ControlC) def _(event): event.app.exit(result=False) @bindings.add(Keys.Any) def _(event): " Disable inserting of text. " session = PromptSession(message, key_bindings=bindings, erase_when_done=True) return session
def create_confirm_session(message): """ Create a `PromptSession` object for the 'confirm' function. """ assert isinstance(message, text_type) bindings = KeyBindings() @bindings.add('y') @bindings.add('Y') def yes(event): session.default_buffer.text = 'y' event.app.exit(result=True) @bindings.add('n') @bindings.add('N') @bindings.add('c-c') def no(event): session.default_buffer.text = 'n' event.app.exit(result=False) @bindings.add(Keys.Any) def _(event): " Disallow inserting other text. " pass session = PromptSession(message, key_bindings=bindings) return session
def _create_prompt_bindings(self): """ Create the KeyBindings for a prompt application. """ kb = KeyBindings() handle = kb.add default_focused = has_focus(DEFAULT_BUFFER) @Condition def do_accept(): return (not _true(self.multiline) and self.app.layout.has_focus(DEFAULT_BUFFER)) @handle('enter', filter=do_accept & default_focused) def _(event): " Accept input when enter has been pressed. " self.default_buffer.validate_and_handle() @Condition def readline_complete_style(): return self.complete_style == CompleteStyle.READLINE_LIKE @handle('tab', filter=readline_complete_style & default_focused) def _(event): " Display completions (like Readline). " display_completions_like_readline(event) @handle('c-c', filter=default_focused) def _(event): " Abort when Control-C has been pressed. " event.app.exit(exception=KeyboardInterrupt, style='class:aborting') @Condition def ctrl_d_condition(): """ Ctrl-D binding is only active when the default buffer is selected and empty. """ app = get_app() return (app.current_buffer.name == DEFAULT_BUFFER and not app.current_buffer.text) @handle('c-d', filter=ctrl_d_condition & default_focused) def _(event): " Exit when Control-D has been pressed. " event.app.exit(exception=EOFError, style='class:exiting') suspend_supported = Condition(suspend_to_background_supported) @Condition def enable_suspend(): return to_filter(self.enable_suspend)() @handle('c-z', filter=suspend_supported & enable_suspend) def _(event): """ Suspend process to background. """ event.app.suspend_to_background() return kb
def _get_key_bindings(self): " Key bindings for the Button. " kb = KeyBindings() @kb.add(' ') @kb.add('enter') def _(event): if self.handler is not None: self.handler() return kb
def get_key_bindings(self): """ Expose key bindings that handle the left/right arrow keys when the menu is displayed. """ from polymorph.deps.prompt_toolkit.key_binding.key_bindings import KeyBindings kb = KeyBindings() @Condition def filter(): " Only handle key bindings if this menu is visible. " app = get_app() complete_state = app.current_buffer.complete_state # There need to be completions, and one needs to be selected. if complete_state is None or complete_state.complete_index is None: return False # This menu needs to be visible. return any(window.content == self for window in app.layout.visible_windows) def move(right=False): buff = get_app().current_buffer complete_state = buff.complete_state if complete_state is not None and \ buff.complete_state.complete_index is not None: # Calculate new complete index. new_index = buff.complete_state.complete_index if right: new_index += self._rendered_rows else: new_index -= self._rendered_rows if 0 <= new_index < len(complete_state.completions): buff.go_to_completion(new_index) # NOTE: the is_global is required because the completion menu will # never be focussed. @kb.add('left', is_global=True, filter=filter) def _(event): move() @kb.add('right', is_global=True, filter=filter) def _(event): move(True) return kb
def load_emacs_page_navigation_bindings(): """ Key bindings, for scrolling up and down through pages. This are separate bindings, because GNU readline doesn't have them. """ key_bindings = KeyBindings() handle = key_bindings.add handle('c-v')(scroll_page_down) handle('pagedown')(scroll_page_down) handle('escape', 'v')(scroll_page_up) handle('pageup')(scroll_page_up) return ConditionalKeyBindings(key_bindings, emacs_mode)
def load_vi_page_navigation_bindings(): """ Key bindings, for scrolling up and down through pages. This are separate bindings, because GNU readline doesn't have them. """ key_bindings = KeyBindings() handle = key_bindings.add handle('c-f')(scroll_forward) handle('c-b')(scroll_backward) handle('c-d')(scroll_half_page_down) handle('c-u')(scroll_half_page_up) handle('c-e')(scroll_one_line_down) handle('c-y')(scroll_one_line_up) handle('pagedown')(scroll_page_down) handle('pageup')(scroll_page_up) return ConditionalKeyBindings(key_bindings, vi_mode)
def load_auto_suggest_bindings(): """ Key bindings for accepting auto suggestion text. (This has to come after the Vi bindings, because they also have an implementation for the "right arrow", but we really want the suggestion binding when a suggestion is available.) """ key_bindings = KeyBindings() handle = key_bindings.add @Condition def suggestion_available(): app = get_app() return (app.current_buffer.suggestion is not None and app.current_buffer.document.is_cursor_at_the_end) @handle('c-f', filter=suggestion_available) @handle('c-e', filter=suggestion_available) @handle('right', filter=suggestion_available) def _(event): " Accept suggestion. " b = event.current_buffer suggestion = b.suggestion if suggestion: b.insert_text(suggestion.text) @handle('escape', 'f', filter=suggestion_available & emacs_mode) def _(event): " Fill partial suggestion. " b = event.current_buffer suggestion = b.suggestion if suggestion: t = re.split(r'(\S+\s+)', suggestion.text) b.insert_text(next(x for x in t if x)) return key_bindings
def _do_wait_for_enter(wait_text): """ Create a sub application to wait for the enter key press. This has two advantages over using 'input'/'raw_input': - This will share the same input/output I/O. - This doesn't block the event loop. """ from polymorph.deps.prompt_toolkit.shortcuts import PromptSession key_bindings = KeyBindings() @key_bindings.add('enter') def _(event): event.app.exit() @key_bindings.add(Keys.Any) def _(event): " Disallow typing. " pass session = PromptSession(message=wait_text, key_bindings=key_bindings) yield From(session.app.run_async())
def __init__(self, text=''): assert is_formatted_text(text) self.checked = True kb = KeyBindings() @kb.add(' ') @kb.add('enter') def _(event): self.checked = not self.checked self.control = FormattedTextControl(self._get_text_fragments, key_bindings=kb, focusable=True) self.window = Window(width=3, content=self.control, height=1) self.container = VSplit( [self.window, Label(text=Template(' {}').format(text))], style='class:checkbox')
def __init__(self, values): assert isinstance(values, list) assert len(values) > 0 assert all(isinstance(i, tuple) and len(i) == 2 for i in values) self.values = values self.current_value = values[0][0] self._selected_index = 0 # Key bindings. kb = KeyBindings() @kb.add('up') def _(event): self._selected_index = max(0, self._selected_index - 1) @kb.add('down') def _(event): self._selected_index = min( len(self.values) - 1, self._selected_index + 1) @kb.add('enter') @kb.add(' ') def _(event): self.current_value = self.values[self._selected_index][0] # Control and window. self.control = FormattedTextControl(self._get_text_fragments, key_bindings=kb, focusable=True) self.window = Window(content=self.control, style='class:radio-list', right_margins=[ ScrollbarMargin(display_arrows=True), ], dont_extend_height=True)
def _build_key_bindings(self): focused = has_focus(self.system_buffer) # Emacs emacs_bindings = KeyBindings() handle = emacs_bindings.add @handle('escape', filter=focused) @handle('c-g', filter=focused) @handle('c-c', filter=focused) def _(event): " Hide system prompt. " self.system_buffer.reset() event.app.layout.focus_last() @handle('enter', filter=focused) def _(event): " Run system command. " event.app.run_system_command( self.system_buffer.text, display_before_text=self._get_display_before_text()) self.system_buffer.reset(append_to_history=True) event.app.layout.focus_last() # Vi. vi_bindings = KeyBindings() handle = vi_bindings.add @handle('escape', filter=focused) @handle('c-c', filter=focused) def _(event): " Hide system prompt. " event.app.vi_state.input_mode = InputMode.NAVIGATION self.system_buffer.reset() event.app.layout.focus_last() @handle('enter', filter=focused) def _(event): " Run system command. " event.app.vi_state.input_mode = InputMode.NAVIGATION event.app.run_system_command( self.system_buffer.text, display_before_text=self._get_display_before_text()) self.system_buffer.reset(append_to_history=True) event.app.layout.focus_last() # Global bindings. (Listen to these bindings, even when this widget is # not focussed.) global_bindings = KeyBindings() handle = global_bindings.add @handle(Keys.Escape, '!', filter=~focused & emacs_mode, is_global=True) def _(event): " M-'!' will focus this user control. " event.app.layout.focus(self.window) @handle('!', filter=~focused & vi_mode & vi_navigation_mode, is_global=True) def _(event): " Focus. " event.app.vi_state.input_mode = InputMode.INSERT event.app.layout.focus(self.window) return merge_key_bindings([ ConditionalKeyBindings(emacs_bindings, emacs_mode), ConditionalKeyBindings(vi_bindings, vi_mode), ConditionalKeyBindings(global_bindings, self.enable_global_bindings), ])
def __init__(self, body, title='', buttons=None, modal=True, width=None, with_background=False): assert is_formatted_text(title) assert buttons is None or isinstance(buttons, list) buttons = buttons or [] # When a button is selected, handle left/right key bindings. buttons_kb = KeyBindings() if len(buttons) > 1: first_selected = has_focus(buttons[0]) last_selected = has_focus(buttons[-1]) buttons_kb.add('left', filter=~first_selected)(focus_previous) buttons_kb.add('right', filter=~last_selected)(focus_next) if buttons: frame_body = HSplit([ # Add optional padding around the body. Box(body=body, padding=D(preferred=1, max=1), padding_bottom=0), # The buttons. Box(body=VSplit(buttons, padding=1, key_bindings=buttons_kb), height=D(min=1, max=3, preferred=3)) ]) else: frame_body = body # Key bindings for whole dialog. kb = KeyBindings() kb.add('tab', filter=~has_completions)(focus_next) kb.add('s-tab', filter=~has_completions)(focus_previous) frame = Shadow(body=Frame( title=title, body=frame_body, style='class:dialog.body', width=(None if with_background is None else width), key_bindings=kb, modal=modal, )) if with_background: self.container = Box(body=frame, style='class:dialog', width=width) else: self.container = frame
def __init__(self, body, menu_items=None, floats=None, key_bindings=None): assert isinstance(menu_items, list) and \ all(isinstance(i, MenuItem) for i in menu_items) assert floats is None or all(isinstance(f, Float) for f in floats) self.body = body self.menu_items = menu_items self.selected_menu = [0] # Key bindings. kb = KeyBindings() @Condition def in_main_menu(): return len(self.selected_menu) == 1 @Condition def in_sub_menu(): return len(self.selected_menu) > 1 # Navigation through the main menu. @kb.add('left', filter=in_main_menu) def _(event): self.selected_menu[0] = max(0, self.selected_menu[0] - 1) @kb.add('right', filter=in_main_menu) def _(event): self.selected_menu[0] = min( len(self.menu_items) - 1, self.selected_menu[0] + 1) @kb.add('down', filter=in_main_menu) def _(event): self.selected_menu.append(0) @kb.add('c-c', filter=in_main_menu) @kb.add('c-g', filter=in_main_menu) def _(event): " Leave menu. " event.app.layout.focus_last() # Sub menu navigation. @kb.add('left', filter=in_sub_menu) @kb.add('c-g', filter=in_sub_menu) @kb.add('c-c', filter=in_sub_menu) def _(event): " Go back to parent menu. " if len(self.selected_menu) > 1: self.selected_menu.pop() @kb.add('right', filter=in_sub_menu) def _(event): " go into sub menu. " if self._get_menu(len(self.selected_menu) - 1).children: self.selected_menu.append(0) # If This item does not have a sub menu. Go up in the parent menu. elif len(self.selected_menu) == 2 and self.selected_menu[0] < len( self.menu_items) - 1: self.selected_menu = [ min(len(self.menu_items) - 1, self.selected_menu[0] + 1) ] if self.menu_items[self.selected_menu[0]].children: self.selected_menu.append(0) @kb.add('up', filter=in_sub_menu) def _(event): " Select previous (enabled) menu item or return to main menu. " # Look for previous enabled items in this sub menu. menu = self._get_menu(len(self.selected_menu) - 2) index = self.selected_menu[-1] previous_indexes = [ i for i, item in enumerate(menu.children) if i < index and not item.disabled ] if previous_indexes: self.selected_menu[-1] = previous_indexes[-1] elif len(self.selected_menu) == 2: # Return to main menu. self.selected_menu.pop() @kb.add('down', filter=in_sub_menu) def _(event): " Select next (enabled) menu item. " menu = self._get_menu(len(self.selected_menu) - 2) index = self.selected_menu[-1] next_indexes = [ i for i, item in enumerate(menu.children) if i > index and not item.disabled ] if next_indexes: self.selected_menu[-1] = next_indexes[0] @kb.add('enter') def _(event): " Click the selected menu item. " item = self._get_menu(len(self.selected_menu) - 1) if item.handler: event.app.layout.focus_last() item.handler() # Controls. self.control = FormattedTextControl(self._get_menu_fragments, key_bindings=kb, focusable=True, show_cursor=False) self.window = Window(height=1, content=self.control, style='class:menu-bar') submenu = self._submenu(0) submenu2 = self._submenu(1) submenu3 = self._submenu(2) @Condition def has_focus(): return get_app().layout.current_window == self.window self.container = FloatContainer( content=HSplit([ # The titlebar. self.window, # The 'body', like defined above. body, ]), floats=[ Float(xcursor=self.window, ycursor=self.window, content=ConditionalContainer( content=Shadow(body=submenu), filter=has_focus)), Float(attach_to_window=submenu, xcursor=True, ycursor=True, allow_cover_cursor=True, content=ConditionalContainer( content=Shadow(body=submenu2), filter=has_focus & Condition(lambda: len(self.selected_menu) >= 1))), Float(attach_to_window=submenu2, xcursor=True, ycursor=True, allow_cover_cursor=True, content=ConditionalContainer( content=Shadow(body=submenu3), filter=has_focus & Condition(lambda: len(self.selected_menu) >= 2))), # -- ] + (floats or []), key_bindings=key_bindings, )