def __init__(self, pymux): self.pymux = pymux def get_search_state(cli): " Return the currently active SearchState. (The one for the focussed pane.) " return pymux.arrangement.get_active_pane(cli).search_state # Start from this KeyBindingManager from prompt_toolkit, to have basic # editing functionality for the command line. These key binding are # however only active when the following `enable_all` condition is met. self.registry = MergedRegistry([ ConditionalRegistry( registry=load_key_bindings( enable_auto_suggest_bindings=True, enable_search=False, # We have our own search bindings, that support multiple panes. enable_extra_page_navigation=True, get_search_state=get_search_state), filter=(HasFocus(COMMAND) | HasFocus(PROMPT) | InScrollBuffer(pymux)) & ~HasPrefix(pymux), ), load_mouse_bindings(), self._load_builtins(), _load_search_bindings(pymux), ]) self._prefix = (Keys.ControlB, ) self._prefix_binding = None # Load initial bindings. self._load_prefix_binding() # Custom user configured key bindings. # { (needs_prefix, key) -> (command, handler) } self.custom_bindings = {}
def choose_version(assets): '''choose a version from assets list''' versions = list(map(lambda item: item['version'], assets)) # print(versions) values = list(map(lambda item: (item, item), versions)) rdo = NewRadioList(values) def do_exit(event): # get_app().exit() event.app.exit(result=rdo.current_value) def do_up_down(event): print(event) pass bindings = KeyBindings() bindings.add('enter')(do_exit) app_bindings = merge_key_bindings([load_key_bindings(), bindings]) selected = Application(layout=Layout(rdo), key_bindings=app_bindings).run() if selected in versions: print('your choice is:', end=' ') # refer: https://github.com/jonathanslenders/python-prompt-toolkit/blob/master/examples/print-text/ansi.py print_formatted_text(ANSI('\x1b[91m{0}'.format(selected))) return selected else: print('canceled')
def __init__(self, pymux): self.pymux = pymux def get_search_state(cli): " Return the currently active SearchState. (The one for the focussed pane.) " return pymux.arrangement.get_active_pane(cli).search_state # Start from this KeyBindingManager from prompt_toolkit, to have basic # editing functionality for the command line. These key binding are # however only active when the following `enable_all` condition is met. self.registry = MergedRegistry([ ConditionalRegistry( registry=load_key_bindings( enable_auto_suggest_bindings=True, enable_search= False, # We have our own search bindings, that support multiple panes. enable_extra_page_navigation=True, get_search_state=get_search_state), filter=(HasFocus(COMMAND) | HasFocus(PROMPT) | InScrollBuffer(pymux)) & ~HasPrefix(pymux), ), load_mouse_bindings(), self._load_builtins(), _load_search_bindings(pymux), ]) self._prefix = (Keys.ControlB, ) self._prefix_binding = None # Load initial bindings. self._load_prefix_binding() # Custom user configured key bindings. # { (needs_prefix, key) -> (command, handler) } self.custom_bindings = {}
def repl(parser, interpreter, style_name='default'): registry = load_key_bindings() @registry.add_binding(Keys.Escape, Keys.Enter) # meta-enter/alt-enter def _(event): '''Evaluate the buffer ''' code = buffers[DEFAULT_BUFFER].text try: ast = parser.parse(code) except (UnexpectedToken, UnexpectedInput) as e: toolbar_value = str(e) return try: start_eval_time = time.time() retval = interpreter.eval(ast) except Exception as e: toolbar_value = "Error: %s" % e.args return else: buffers['RESULT'].text = str(retval) toolbar_value = "Time: {:0.4f}, Value: {}".format( time.time() - start_eval_time, str(retval)) @registry.add_binding(Keys.ControlC, eager=True) @registry.add_binding(Keys.ControlQ, eager=True) def _(event): '''Exit the REPL ''' event.cli.set_return_value(None) buffers = { DEFAULT_BUFFER: Buffer(is_multiline=True), 'RESULT': Buffer(is_multiline=True), } style = style_from_pygments(get_style_by_name(style_name)) application = Application(layout=layout, buffers=buffers, mouse_support=True, style=style, use_alternate_screen=True, key_bindings_registry=registry) eventloop = create_eventloop() try: cli = CommandLineInterface(application=application, eventloop=eventloop) cli.run() finally: eventloop.close()
def _create_app(dialog: AnyContainer, style: Optional[BaseStyle]) -> Application[Any]: # Key bindings. bindings = KeyBindings() bindings.add("tab")(focus_next) bindings.add("s-tab")(focus_previous) return Application( layout=Layout(dialog), key_bindings=merge_key_bindings([load_key_bindings(), bindings]), mouse_support=True, style=style, full_screen=True, )
def main(): style = Style([ ('terminal focused', 'bg:#aaaaaa'), ('title', 'bg:#000044 #ffffff underline'), ]) term1 = Terminal() text_area = TextArea(text='Press Control-W to switch focus.\n' 'Then you can edit this text area.\n' 'Press Control-X to exit') kb = KeyBindings() @kb.add('c-w') def _(event): switch_focus() @kb.add('c-x', eager=True) def _(event): event.app.exit() def switch_focus(): " Change focus when Control-W is pressed." if application.layout.has_focus(term1): application.layout.focus(text_area) else: application.layout.focus(term1) application = Application( layout=Layout(container=HSplit([ Window(height=1, style='class:title', content=FormattedTextControl( ' Press Control-W to switch focus.')), VSplit([ term1, Window(style='bg:#aaaaff', width=1), text_area, ]), ]), focused_element=term1), style=style, key_bindings=merge_key_bindings([ load_key_bindings(), kb, ]), full_screen=True, mouse_support=True, ) application.run()
def _create_app(dialog, style): # Key bindings. bindings = KeyBindings() bindings.add('tab')(focus_next) bindings.add('s-tab')(focus_previous) return Application(layout=Layout(dialog), key_bindings=merge_key_bindings([ load_key_bindings(), bindings, ]), mouse_support=True, style=style, full_screen=True)
def get_app(self): bindings = KeyBindings() @bindings.add(Keys.ControlC) def _ctrl_c(event): get_app().exit(exception=KeyboardInterrupt) @bindings.add(Keys.Enter) def _enter(event): get_app().exit(result=self.get_answer()) return Application(layout=Layout(self.get_layout()), key_bindings=merge_key_bindings( [load_key_bindings(), bindings]), style=get_theme_manager().get_current_style())
def _create_app(dialog: AnyContainer, style: Optional[BaseStyle]) -> Application[Any]: # Key bindings. bindings = KeyBindings() bindings.add('tab')(focus_next) bindings.add('s-tab')(focus_previous) return Application( layout=Layout(dialog), key_bindings=merge_key_bindings([ load_key_bindings(), bindings, ]), mouse_support=True, style=style, full_screen=True)
def _create_app(dialog, style): # Key bindings. bindings = KeyBindings() bindings.add('tab')(focus_next) bindings.add('s-tab')(focus_previous) return Application( layout=Layout(dialog), key_bindings=merge_key_bindings([ load_key_bindings(), bindings, ]), mouse_support=True, style=style, full_screen=True)
def show_error_dialog(messages): texts = [] for message in messages: texts.append( Label(message, style='class:error', dont_extend_height=True)) dialog = Dialog(title='Some inputs are invalid', body=HSplit(texts, padding=1), buttons=[ Button(text='Ok', handler=lambda: get_app().exit()), ], with_background=True) app = Application(layout=Layout(dialog), key_bindings=load_key_bindings(), mouse_support=True, style=for_dialog(), full_screen=True) app.run()
def __init__(self, title="", label_text="", completer=None): self.future = Future() def accept_text(buf) -> bool: """ Change focus to OK button after user pressed enter on text field. """ get_app().layout.focus(ok_button) buf.complete_state = None return True def accept(): """ Set future result to text from text field if user pressed OK button. """ self.future.set_result(self.text_area.text) def cancel(): """ Set future result to None if user pressed cancel button. """ self.future.set_result(None) self.text_area = TextEditor( completer=completer, multiline=False, width=D(preferred=40), accept_handler=accept_text, key_bindings=load_key_bindings(), ) ok_button = Button(text="OK", handler=accept) cancel_button = Button(text="Cancel", handler=cancel) self.dialog = Dialog( title=title, body=HSplit([Label(text=label_text), self.text_area]), buttons=[ok_button, cancel_button], width=D(preferred=80), modal=True, )
def radiolist_dialog(title='', values=None, style=None, async_=False): # Add exit key binding. bindings = KeyBindings() @bindings.add('c-d') def exit_(event): """ Pressing Ctrl-d will exit the user interface. """ event.app.exit() radio_list = RadioListFast(values) application = Application( layout=Layout(HSplit([Label(title), radio_list])), key_bindings=merge_key_bindings([load_key_bindings(), bindings]), mouse_support=True, style=style, full_screen=False) if async_: return application.run_async() else: return application.run()
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
def __init__( self, layout=None, style=None, key_bindings=None, clipboard=None, full_screen=False, mouse_support=False, enable_page_navigation_bindings=False, paste_mode=False, editing_mode=EditingMode.EMACS, erase_when_done=False, reverse_vi_search_direction=False, min_redraw_interval=None, max_render_postpone_time=0, on_reset=None, on_render=None, on_invalidate=None, # I/O. input=None, output=None): paste_mode = to_filter(paste_mode) mouse_support = to_filter(mouse_support) reverse_vi_search_direction = to_filter(reverse_vi_search_direction) enable_page_navigation_bindings = to_filter( enable_page_navigation_bindings) assert layout is None or isinstance(layout, Layout) assert key_bindings is None or isinstance(key_bindings, KeyBindingsBase) assert clipboard is None or isinstance(clipboard, Clipboard) assert isinstance(full_screen, bool) assert isinstance(editing_mode, six.string_types) assert style is None or isinstance(style, BaseStyle) assert isinstance(erase_when_done, bool) assert min_redraw_interval is None or isinstance( min_redraw_interval, (float, int)) assert max_render_postpone_time is None or isinstance( max_render_postpone_time, (float, int)) assert on_reset is None or callable(on_reset) assert on_render is None or callable(on_render) assert on_invalidate is None or callable(on_invalidate) assert output is None or isinstance(output, Output) assert input is None or isinstance(input, Input) self.style = style if layout is None: layout = create_dummy_layout() # Key bindings. self.key_bindings = key_bindings self._default_bindings = load_key_bindings() self._page_navigation_bindings = load_page_navigation_bindings() self.layout = layout self.clipboard = clipboard or InMemoryClipboard() self.full_screen = full_screen self.mouse_support = mouse_support self.paste_mode = paste_mode self.editing_mode = editing_mode self.erase_when_done = erase_when_done self.reverse_vi_search_direction = reverse_vi_search_direction self.enable_page_navigation_bindings = enable_page_navigation_bindings self.min_redraw_interval = min_redraw_interval self.max_render_postpone_time = max_render_postpone_time # Events. self.on_invalidate = Event(self, on_invalidate) self.on_render = Event(self, on_render) self.on_reset = Event(self, on_reset) # I/O. self.output = output or get_default_output() self.input = input or get_default_input() # List of 'extra' functions to execute before a Application.run. self.pre_run_callables = [] self._is_running = False self.future = None #: Quoted insert. This flag is set if we go into quoted insert mode. self.quoted_insert = False #: Vi state. (For Vi key bindings.) self.vi_state = ViState() #: When to flush the input (For flushing escape keys.) This is important #: on terminals that use vt100 input. We can't distinguish the escape #: key from for instance the left-arrow key, if we don't know what follows #: after "\x1b". This little timer will consider "\x1b" to be escape if #: nothing did follow in this time span. #: This seems to work like the `ttimeoutlen` option in Vim. self.input_timeout = .5 #: The `Renderer` instance. # Make sure that the same stdout is used, when a custom renderer has been passed. self._merged_style = merge_styles([ default_style(), DynamicStyle(lambda: self.style), ]) self.renderer = Renderer( self._merged_style, self.output, full_screen=full_screen, mouse_support=mouse_support, cpr_not_supported_callback=self.cpr_not_supported_callback) #: Render counter. This one is increased every time the UI is rendered. #: It can be used as a key for caching certain information during one #: rendering. self.render_counter = 0 # Invalidate flag. When 'True', a repaint has been scheduled. self._invalidated = False self._invalidate_events = [ ] # Collection of 'invalidate' Event objects. self._last_redraw_time = 0 # Unix timestamp of last redraw. Used when # `min_redraw_interval` is given. #: The `InputProcessor` instance. self.key_processor = KeyProcessor(_CombinedRegistry(self)) # If `run_in_terminal` was called. This will point to a `Future` what will be # set at the point whene the previous run finishes. self._running_in_terminal = False self._running_in_terminal_f = None # Trigger initialize callback. self.reset()
def __init__(self, layout: Optional[Layout] = None, style: Optional[BaseStyle] = None, include_default_pygments_style: FilterOrBool = True, style_transformation: Optional[StyleTransformation] = None, key_bindings: Optional[KeyBindingsBase] = None, clipboard: Optional[Clipboard] = None, full_screen: bool = False, color_depth: Union[ColorDepth, Callable[[], Union[ColorDepth, None]], None] = None, mouse_support: FilterOrBool = False, enable_page_navigation_bindings: Optional[FilterOrBool] = None, # Can be None, True or False. paste_mode: FilterOrBool = False, editing_mode: EditingMode = EditingMode.EMACS, erase_when_done: bool = False, reverse_vi_search_direction: FilterOrBool = False, min_redraw_interval: Union[float, int, None] = None, max_render_postpone_time: Union[float, int, None] = .01, on_reset: Optional[ApplicationEventHandler] = None, on_invalidate: Optional[ApplicationEventHandler] = None, before_render: Optional[ApplicationEventHandler] = None, after_render: Optional[ApplicationEventHandler] = None, # I/O. input: Optional[Input] = None, output: Optional[Output] = None): # If `enable_page_navigation_bindings` is not specified, enable it in # case of full screen applications only. This can be overridden by the user. if enable_page_navigation_bindings is None: enable_page_navigation_bindings = Condition(lambda: self.full_screen) paste_mode = to_filter(paste_mode) mouse_support = to_filter(mouse_support) reverse_vi_search_direction = to_filter(reverse_vi_search_direction) enable_page_navigation_bindings = to_filter(enable_page_navigation_bindings) include_default_pygments_style = to_filter(include_default_pygments_style) if layout is None: layout = create_dummy_layout() if style_transformation is None: style_transformation = DummyStyleTransformation() self.style = style self.style_transformation = style_transformation # Key bindings. self.key_bindings = key_bindings self._default_bindings = load_key_bindings() self._page_navigation_bindings = load_page_navigation_bindings() self.layout = layout self.clipboard = clipboard or InMemoryClipboard() self.full_screen: bool = full_screen self._color_depth = color_depth self.mouse_support = mouse_support self.paste_mode = paste_mode self.editing_mode = editing_mode self.erase_when_done = erase_when_done self.reverse_vi_search_direction = reverse_vi_search_direction self.enable_page_navigation_bindings = enable_page_navigation_bindings self.min_redraw_interval = min_redraw_interval self.max_render_postpone_time = max_render_postpone_time # Events. self.on_invalidate = Event(self, on_invalidate) self.on_reset = Event(self, on_reset) self.before_render = Event(self, before_render) self.after_render = Event(self, after_render) # I/O. session = get_app_session() self.output = output or session.output self.input = input or session.input # List of 'extra' functions to execute before a Application.run. self.pre_run_callables: List[Callable[[], None]] = [] self._is_running = False self.future: Optional[Future[_AppResult]] = None self.loop: Optional[AbstractEventLoop] = None self.context: Optional[contextvars.Context] = None #: Quoted insert. This flag is set if we go into quoted insert mode. self.quoted_insert = False #: Vi state. (For Vi key bindings.) self.vi_state = ViState() self.emacs_state = EmacsState() #: When to flush the input (For flushing escape keys.) This is important #: on terminals that use vt100 input. We can't distinguish the escape #: key from for instance the left-arrow key, if we don't know what follows #: after "\x1b". This little timer will consider "\x1b" to be escape if #: nothing did follow in this time span. #: This seems to work like the `ttimeoutlen` option in Vim. self.ttimeoutlen = .5 # Seconds. #: Like Vim's `timeoutlen` option. This can be `None` or a float. For #: instance, suppose that we have a key binding AB and a second key #: binding A. If the uses presses A and then waits, we don't handle #: this binding yet (unless it was marked 'eager'), because we don't #: know what will follow. This timeout is the maximum amount of time #: that we wait until we call the handlers anyway. Pass `None` to #: disable this timeout. self.timeoutlen = 1.0 #: The `Renderer` instance. # Make sure that the same stdout is used, when a custom renderer has been passed. self._merged_style = self._create_merged_style(include_default_pygments_style) self.renderer = Renderer( self._merged_style, self.output, self.input, full_screen=full_screen, mouse_support=mouse_support, cpr_not_supported_callback=self.cpr_not_supported_callback) #: Render counter. This one is increased every time the UI is rendered. #: It can be used as a key for caching certain information during one #: rendering. self.render_counter = 0 # Invalidate flag. When 'True', a repaint has been scheduled. self._invalidated = False self._invalidate_events: List[Event[object]] = [] # Collection of 'invalidate' Event objects. self._last_redraw_time = 0.0 # Unix timestamp of last redraw. Used when # `min_redraw_interval` is given. #: The `InputProcessor` instance. self.key_processor = KeyProcessor(_CombinedRegistry(self)) # If `run_in_terminal` was called. This will point to a `Future` what will be # set at the point when the previous run finishes. self._running_in_terminal = False self._running_in_terminal_f: Optional[Future[None]] = None # Trigger initialize callback. self.reset()
def _get_key_bindings(self): kb = KeyBindings() @kb.add('c-up') def _(event): self.console.enter_copy_mode() @kb.add('c-x', 'a', eager=True) def _(event): self._hide_tui() self.app.invalidate() @kb.add('c-x', '1', eager=True) def _(event): self._hide_tui() self.source.show = True self.app.invalidate() @kb.add('c-x', '2', eager=True) def _(event): self._hide_tui() self.source.show = True self.disassembly.show = True @kb.add('c-x', 's', eager=True) def _(event): self.source.toggle_show() self.app.invalidate() @kb.add('c-x', 'd', eager=True) def _(event): self.disassembly.toggle_show() self.app.invalidate() @kb.add('c-x', 'c', eager=True) def _(event): self.callstack.toggle_show() self.app.invalidate() @kb.add('c-x', 'v', eager=True) def _(event): self.argsnlocals.toggle_show() self.app.invalidate() @kb.add('c-x', 'b', eager=True) def _(event): self.breakpoints.toggle_show() self.app.invalidate() @kb.add('c-x', 'r', eager=True) def _(event): self.registers.toggle_show() self.app.invalidate() @kb.add('c-x', 't', eager=True) def _(event): self.threads.toggle_show() @kb.add('c-s', eager=True) def _(event): self._next_style() @kb.add('c-l') def _(event): pass @kb.add('c-x') def _(event): pass @kb.add('s-right') def _(event): self.layout.focus_next() @kb.add('s-left') def _(event): self.layout.focus_previous() kb = merge_key_bindings([load_key_bindings(), kb]) return kb
from prompt_toolkit.key_binding.defaults import load_key_bindings from prompt_toolkit.keys import Keys animal_completer = WordCompleter([ 'alligator', 'ant', 'ape', 'bat', 'bear', 'beaver', 'bee', 'bison', 'butterfly', 'cat', 'chicken', 'crocodile', 'dinosaur', 'dog', 'dolphine', 'dove', 'duck', 'eagle', 'elephant', 'fish', 'goat', 'gorilla', 'kangoroo', 'leopard', 'lion', 'mouse', 'rabbit', 'rat', 'snake', 'spider', 'turkey', 'turtle', ], ignore_case=True) # Create key bindings registry with a custom binding for the Tab key that # displays completions like GNU readline. registry = load_key_bindings() registry.add_binding(Keys.ControlI)(display_completions_like_readline) def main(): text = prompt('Give some animals: ', completer=animal_completer, key_bindings_registry=registry, # Important: for this to work: `complete_while_typing` needs # to be False. complete_while_typing=False) print('You said: %s' % text) if __name__ == '__main__': main()
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
def load_bindings(self): bindings = load_key_bindings(enable_abort_and_exit_bindings=True, enable_system_bindings=True) @bindings.add_binding('j', filter=~self.editing) def down(event): if self.lock: self.scroll(1, None) else: self.move_cursor(1) @bindings.add_binding('k', filter=~self.editing) def up(event): if self.lock: self.scroll(-1, None) else: self.move_cursor(-1) @bindings.add_binding('g', filter=~self.editing) def c_d(event): self.scroll(-self.model.line_count(), None) @bindings.add_binding('G', filter=~self.editing) def c_d(event): self.scroll(self.model.line_count(), None) @bindings.add_binding('d', filter=~self.editing) def c_d(event): self.scroll(1, True) @bindings.add_binding('f', filter=~self.editing) def c_d(event): self.scroll(1, False) @bindings.add_binding('u', filter=~self.editing) def c_u(event): self.scroll(-1, True) @bindings.add_binding('b', filter=~self.editing) def c_u(event): self.scroll(-1, False) @bindings.add_binding('w', filter=~self.editing) def toggle_wrap(event): self.model.wrap = not self.model.wrap @bindings.add_binding('n', filter=~self.editing) def toggle_numbers(event): self.model.numbers = not self.model.numbers @bindings.add_binding('q', filter=~self.editing) def end_loop(event): event.cli.set_return_value(None) @bindings.add_binding('/', filter=~self.editing) def start_edit(event): self.edit = True @bindings.add_binding(Keys.ControlC) def end_edit(event): self.edit = False @bindings.add_binding('l', filter=~self.editing) def _(event): self.lock = not self.lock return bindings
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 # already contains the default key bindings. registry = load_key_bindings() # Now add the Ctrl-Q binding. We have to pass `eager=True` here. The reason is # that there is another key *sequence* that starts with Ctrl-Q as well. Yes, a # key binding is linked to a sequence of keys, not necessarily one key. So, # what happens if there is a key binding for the letter 'a' and a key binding # for 'ab'. When 'a' has been pressed, nothing will happen yet. Because the # next key could be a 'b', but it could as well be anything else. If it's a 'c' # for instance, we'll handle the key binding for 'a' and then look for a key # binding for 'c'. So, when there's a common prefix in a key binding sequence, # prompt-toolkit will wait calling a handler, until we have enough information. # Now, There is an Emacs key binding for the [Ctrl-Q Any] sequence by default. # Pressing Ctrl-Q followed by any other key will do a quoted insert. So to be # sure that we won't wait for that key binding to match, but instead execute # Ctrl-Q immediately, we can pass eager=True. (Don't make a habbit of adding
def create_key_bindings(editor): """ Create custom key bindings. This starts with the key bindings, defined by `prompt-toolkit`, but adds the ones which are specific for the editor. """ # Create new Key binding manager. registry = load_key_bindings( enable_search=True, enable_extra_page_navigation=True, enable_system_bindings=True) # Filters. vi_buffer_focussed = Condition(lambda cli: cli.current_buffer_name.startswith('buffer-')) in_insert_mode = ViInsertMode() & vi_buffer_focussed in_navigation_mode = ViNavigationMode() & vi_buffer_focussed handle = registry.add_binding @handle(Keys.ControlT) def _(event): """ Override default behaviour of prompt-toolkit. (Control-T will swap the last two characters before the cursor, because that's what readline does.) """ pass @handle(Keys.ControlT, filter=in_insert_mode) def indent_line(event): """ Indent current line. """ b = event.cli.current_buffer # Move to start of line. pos = b.document.get_start_of_line_position(after_whitespace=True) b.cursor_position += pos # Insert tab. if editor.expand_tab: b.insert_text(' ') else: b.insert_text('\t') # Restore cursor. b.cursor_position -= pos @handle(Keys.ControlR, filter=in_navigation_mode, save_before=(lambda e: False)) def redo(event): """ Redo. """ event.cli.current_buffer.redo() @handle(':', filter=in_navigation_mode) def enter_command_mode(event): """ Entering command mode. """ editor.enter_command_mode() @handle(Keys.Tab, filter=ViInsertMode() & ~HasFocus(COMMAND_BUFFER) & WhitespaceBeforeCursorOnLine()) def autocomplete_or_indent(event): """ When the 'tab' key is pressed with only whitespace character before the cursor, do autocompletion. Otherwise, insert indentation. """ b = event.cli.current_buffer if editor.expand_tab: b.insert_text(' ') else: b.insert_text('\t') @handle(Keys.Escape, filter=HasFocus(COMMAND_BUFFER)) @handle(Keys.ControlC, filter=HasFocus(COMMAND_BUFFER)) @handle( Keys.Backspace, filter=HasFocus(COMMAND_BUFFER) & Condition(lambda cli: cli.buffers[COMMAND_BUFFER].text == '')) def leave_command_mode(event): """ Leaving command mode. """ editor.leave_command_mode() @handle(Keys.ControlW, Keys.ControlW, filter=in_navigation_mode) def focus_next_window(event): editor.window_arrangement.cycle_focus() editor.sync_with_prompt_toolkit() @handle(Keys.ControlW, 'n', filter=in_navigation_mode) def horizontal_split(event): """ Split horizontally. """ editor.window_arrangement.hsplit(None) editor.sync_with_prompt_toolkit() @handle(Keys.ControlW, 'v', filter=in_navigation_mode) def vertical_split(event): """ Split vertically. """ editor.window_arrangement.vsplit(None) editor.sync_with_prompt_toolkit() @handle('g', 't', filter=in_navigation_mode) def focus_next_tab(event): editor.window_arrangement.go_to_next_tab() editor.sync_with_prompt_toolkit() @handle('g', 'T', filter=in_navigation_mode) def focus_previous_tab(event): editor.window_arrangement.go_to_previous_tab() editor.sync_with_prompt_toolkit() @handle(Keys.ControlJ, filter=in_navigation_mode) def goto_line_beginning_or_open_file(event): """ Enter in navigation mode should move to the start of the next line. Enter in directory mode should open the directory or file under the cursor. """ if editor.file_explorer: b = event.current_buffer i0 = b.cursor_position + b.document.get_start_of_line_position() i1 = b.cursor_position + b.document.get_end_of_line_position() name_under_cursor = b.text[i0:i1] editor.file_explorer = os.path.normpath(os.path.join(editor.file_explorer, name_under_cursor)) editor.window_arrangement.open_buffer(editor.file_explorer, show_in_current_window=True) editor.sync_with_prompt_toolkit() else: b = event.current_buffer b.cursor_down(count=event.arg) b.cursor_position += b.document.get_start_of_line_position(after_whitespace=True) @handle(Keys.F1) def show_help(event): editor.show_help() return registry
def show_dialog(questions, title, confirm, cancel): handlers = [] for q in questions: handler = get_handlers_registry().get_handler(q, questions, None, mode=Mode.DIALOG) handlers.append(handler) def ok_handler(): result = dict() for handler in handlers: result.update(handler.get_answer()) get_app().exit(result=result) dialog = Dialog(title=title, body=HSplit([h.get_layout() for h in handlers], padding=1), buttons=[ Button(text=confirm, handler=ok_handler), Button(text=cancel, handler=lambda: get_app().exit()), ], with_background=True) # Key bindings. bindings = KeyBindings() bindings.add('tab')(focus_next) bindings.add('s-tab')(focus_previous) app = Application(layout=Layout(dialog), key_bindings=merge_key_bindings([ load_key_bindings(), bindings, ]), mouse_support=True, style=get_theme_manager().get_current_style(), full_screen=True) size = app.renderer.output.get_size() container = app.layout.container height = container.preferred_height(size.columns, size.rows).preferred if height > size.rows: message_dialog(title='Too many questions', text='Cannot render a {} rows dialog in a ' '{} rows screen: too many questions!'.format( height, size.rows), ok_text='Got it!') return while True: validation_errors = [] answers = app.run() if answers is None: return for handler in handlers: for msg in handler.apply_validators(): validation_errors.append('{}: {}'.format( handler.get_variable_name(), msg)) if not validation_errors: return answers show_error_dialog(validation_errors)
def create_key_bindings(pager): registry = load_key_bindings(enable_search=True, enable_extra_page_navigation=True, enable_system_bindings=True) handle = registry.add_binding @Condition def has_colon(cli): return pager.in_colon_mode @Condition def default_focus(cli): return (cli.current_buffer_name.startswith('source') and not pager.in_colon_mode) @Condition def displaying_help(cli): return pager.displaying_help for c in '01234556789': @handle(c, filter=default_focus) def _(event, c=c): event.append_to_arg_count(c) @handle('q', filter=default_focus | has_colon) @handle('Q', filter=default_focus | has_colon) @handle('Z', 'Z', filter=default_focus) def _(event): " Quit. " if pager.displaying_help: pager.quit_help() else: event.cli.set_return_value(None) @handle(' ', filter=default_focus) @handle('f', filter=default_focus) @handle(Keys.ControlF, filter=default_focus) @handle(Keys.ControlV, filter=default_focus) def _(event): " Page down." scroll_page_down(event) @handle('b', filter=default_focus) @handle(Keys.ControlB, filter=default_focus) @handle(Keys.Escape, 'v', filter=default_focus) def _(event): " Page up." scroll_page_up(event) @handle('d', filter=default_focus) @handle(Keys.ControlD, filter=default_focus) def _(event): " Half page down." scroll_half_page_down(event) @handle('u', filter=default_focus) @handle(Keys.ControlU, filter=default_focus) def _(event): " Half page up." scroll_half_page_up(event) @handle('e', filter=default_focus) @handle('j', filter=default_focus) @handle(Keys.ControlE, filter=default_focus) @handle(Keys.ControlN, filter=default_focus) @handle(Keys.ControlJ, filter=default_focus) @handle(Keys.ControlM, filter=default_focus) @handle(Keys.Down, filter=default_focus) def _(event): " Scoll one line down." if event.arg > 1: # When an argument is given, go this amount of lines down. event.current_buffer.auto_down(count=event.arg) else: scroll_one_line_down(event) @handle('y', filter=default_focus) @handle('k', filter=default_focus) @handle(Keys.ControlY, filter=default_focus) @handle(Keys.ControlK, filter=default_focus) @handle(Keys.ControlP, filter=default_focus) @handle(Keys.Up, filter=default_focus) def _(event): " Scoll one line up." if event.arg > 1: event.current_buffer.auto_up(count=event.arg) else: scroll_one_line_up(event) @handle('/', filter=default_focus) def _(event): " Start searching forward. " event.cli.search_state.direction = IncrementalSearchDirection.FORWARD event.cli.vi_state.input_mode = InputMode.INSERT event.cli.push_focus(SEARCH_BUFFER) @handle('?', filter=default_focus) def _(event): " Start searching backwards. " event.cli.search_state.direction = IncrementalSearchDirection.BACKWARD event.cli.vi_state.input_mode = InputMode.INSERT event.cli.push_focus(SEARCH_BUFFER) @handle('n', filter=default_focus) def _(event): " Search next. " event.current_buffer.apply_search(event.cli.search_state, include_current_position=False, count=event.arg) @handle('N', filter=default_focus) def _(event): " Search previous. " event.current_buffer.apply_search(~event.cli.search_state, include_current_position=False, count=event.arg) @handle(Keys.Escape, 'u') def _(event): " Toggle search highlighting. " pager.highlight_search = not pager.highlight_search @handle('=', filter=default_focus) @handle(Keys.ControlG, filter=default_focus) @handle('f', filter=has_colon) def _(event): " Print the current file name. " pager.message = ' {} '.format(pager.source.get_name()) @handle('h', filter=default_focus & ~displaying_help) @handle('H', filter=default_focus & ~displaying_help) def _(event): " Display Help. " pager.display_help() @handle('g', filter=default_focus) @handle('<', filter=default_focus) @handle(Keys.Escape, '<', filter=default_focus) def _(event): " Go to the first line of the file. " event.current_buffer.cursor_position = 0 @handle('G', filter=default_focus) @handle('>', filter=default_focus) @handle(Keys.Escape, '>', filter=default_focus) def _(event): " Go to the last line of the file. " b = event.current_buffer b.cursor_position = len(b.text) @handle('m', Keys.Any, filter=default_focus) def _(event): " Mark current position. " pager.marks[event.data] = (event.current_buffer.cursor_position, pager.layout.buffer_window.vertical_scroll) @handle("'", Keys.Any, filter=default_focus) def _(event): " Go to a previously marked position. " go_to_mark(event, event.data) @handle(Keys.ControlX, Keys.ControlX, filter=default_focus) def _(event): " Same as '. " go_to_mark(event, '.') def go_to_mark(event, mark): b = event.current_buffer try: if mark == '^': # Start of file. cursor_pos, vertical_scroll = 0, 0 elif mark == '$': # End of file - mark. cursor_pos, vertical_scroll = len(b.text), 0 else: # Custom mark. cursor_pos, vertical_scroll = pager.marks[mark] except KeyError: pass # TODO: show warning. else: b.cursor_position = cursor_pos pager.layout.buffer_window.vertical_scroll = vertical_scroll @handle('F', filter=default_focus) def _(event): " Forward forever, like 'tail -f'. " pager.forward_forever = True @handle(Keys.ControlR, filter=default_focus) @handle('r', filter=default_focus) @handle('R', filter=default_focus) def _(event): event.cli.renderer.clear() def search_buffer_is_empty(cli): " Returns True when the search buffer is empty. " return cli.buffers[SEARCH_BUFFER].text == '' @handle(Keys.Backspace, filter=HasFocus(SEARCH_BUFFER) & Condition(search_buffer_is_empty)) def _(event): " Cancel search when backspace is pressed. " event.cli.vi_state.input_mode = InputMode.NAVIGATION event.cli.pop_focus() event.cli.buffers[SEARCH_BUFFER].reset() @handle(Keys.Left, filter=default_focus) @handle(Keys.Escape, '(', filter=default_focus) def _(event): " Scroll half page to the left. " w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name) b = event.cli.current_buffer if w and w.render_info: info = w.render_info amount = info.window_width // 2 # Move cursor horizontally. value = b.cursor_position - min( amount, len(b.document.current_line_before_cursor)) b.cursor_position = value # Scroll. w.horizontal_scroll = max(0, w.horizontal_scroll - amount) @handle(Keys.Right, filter=default_focus) @handle(Keys.Escape, ')', filter=default_focus) def _(event): " Scroll half page to the right. " w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name) b = event.cli.current_buffer if w and w.render_info: info = w.render_info amount = info.window_width // 2 # Move the cursor first to a visible line that is long enough to # have the cursor visible after scrolling. (Otherwise, the Window # will scroll back.) xpos = w.horizontal_scroll + amount for line in info.displayed_lines: if len(b.document.lines[line]) >= xpos: b.cursor_position = b.document.translate_row_col_to_index( line, xpos) break # Scroll. w.horizontal_scroll = max(0, w.horizontal_scroll + amount) @handle(':', filter=default_focus & ~displaying_help) def _(event): pager.in_colon_mode = True @handle('n', filter=has_colon) def _(event): " Go to next file. " pager.focus_next_source() @handle('p', filter=has_colon) def _(event): " Go to previous file. " pager.focus_previous_source() @handle('e', filter=has_colon) @handle(Keys.ControlX, Keys.ControlV, filter=default_focus) def _(event): pager.buffers.focus(event.cli, 'EXAMINE') pager.in_colon_mode = False @handle('d', filter=has_colon) def _(event): pager.remove_current_source() @handle(Keys.Any, filter=has_colon) @handle(Keys.Backspace, filter=has_colon) def _(event): pager.in_colon_mode = False pager.message = 'No command.' @handle(Keys.ControlC, filter=HasFocus('EXAMINE')) @handle(Keys.ControlG, filter=HasFocus('EXAMINE')) def _(event): " Cancel 'Examine' input. " pager.buffers.focus(event.cli, pager.source_info[pager.source].buffer_name) @handle(Keys.ControlZ, filter=Condition(lambda cli: suspend_to_background_supported())) def _(event): " Suspend to bakground. " event.cli.suspend_to_background() return registry
def __init__( self, layout: Optional[Layout] = None, style: Optional[BaseStyle] = None, include_default_pygments_style: FilterOrBool = True, style_transformation: Optional[StyleTransformation] = None, key_bindings: Optional[KeyBindingsBase] = None, clipboard: Optional[Clipboard] = None, full_screen: bool = False, color_depth: Union[ColorDepth, Callable[[], Union[ColorDepth, None]], None] = None, mouse_support: FilterOrBool = False, enable_page_navigation_bindings: Optional[ FilterOrBool] = None, # Can be None, True or False. paste_mode: FilterOrBool = False, editing_mode: EditingMode = EditingMode.EMACS, erase_when_done: bool = False, reverse_vi_search_direction: FilterOrBool = False, min_redraw_interval: Union[float, int, None] = None, max_render_postpone_time: Union[float, int, None] = 0.01, refresh_interval: Optional[float] = None, on_reset: Optional[ApplicationEventHandler] = None, on_invalidate: Optional[ApplicationEventHandler] = None, before_render: Optional[ApplicationEventHandler] = None, after_render: Optional[ApplicationEventHandler] = None, # I/O. input: Optional[Input] = None, output: Optional[Output] = None, ): # If `enable_page_navigation_bindings` is not specified, enable it in # case of full screen applications only. This can be overridden by the user. if enable_page_navigation_bindings is None: enable_page_navigation_bindings = Condition( lambda: self.full_screen) paste_mode = to_filter(paste_mode) mouse_support = to_filter(mouse_support) reverse_vi_search_direction = to_filter(reverse_vi_search_direction) enable_page_navigation_bindings = to_filter( enable_page_navigation_bindings) include_default_pygments_style = to_filter( include_default_pygments_style) if layout is None: layout = create_dummy_layout() if style_transformation is None: style_transformation = DummyStyleTransformation() self.style = style self.style_transformation = style_transformation # Key bindings. self.key_bindings = key_bindings self._default_bindings = load_key_bindings() self._page_navigation_bindings = load_page_navigation_bindings() self.layout = layout self.clipboard = clipboard or InMemoryClipboard() self.full_screen: bool = full_screen self._color_depth = color_depth self.mouse_support = mouse_support self.paste_mode = paste_mode self.editing_mode = editing_mode self.erase_when_done = erase_when_done self.reverse_vi_search_direction = reverse_vi_search_direction self.enable_page_navigation_bindings = enable_page_navigation_bindings self.min_redraw_interval = min_redraw_interval self.max_render_postpone_time = max_render_postpone_time self.refresh_interval = refresh_interval # Events. self.on_invalidate = Event(self, on_invalidate) self.on_reset = Event(self, on_reset) self.before_render = Event(self, before_render) self.after_render = Event(self, after_render) # I/O. session = get_app_session() self.output = output or session.output self.input = input or session.input # List of 'extra' functions to execute before a Application.run. self.pre_run_callables: List[Callable[[], None]] = [] self._is_running = False self.future: Optional[Future[_AppResult]] = None self.loop: Optional[AbstractEventLoop] = None self.context: Optional[contextvars.Context] = None #: Quoted insert. This flag is set if we go into quoted insert mode. self.quoted_insert = False #: Vi state. (For Vi key bindings.) self.vi_state = ViState() self.emacs_state = EmacsState() #: When to flush the input (For flushing escape keys.) This is important #: on terminals that use vt100 input. We can't distinguish the escape #: key from for instance the left-arrow key, if we don't know what follows #: after "\x1b". This little timer will consider "\x1b" to be escape if #: nothing did follow in this time span. #: This seems to work like the `ttimeoutlen` option in Vim. self.ttimeoutlen = 0.5 # Seconds. #: Like Vim's `timeoutlen` option. This can be `None` or a float. For #: instance, suppose that we have a key binding AB and a second key #: binding A. If the uses presses A and then waits, we don't handle #: this binding yet (unless it was marked 'eager'), because we don't #: know what will follow. This timeout is the maximum amount of time #: that we wait until we call the handlers anyway. Pass `None` to #: disable this timeout. self.timeoutlen = 1.0 #: The `Renderer` instance. # Make sure that the same stdout is used, when a custom renderer has been passed. self._merged_style = self._create_merged_style( include_default_pygments_style) self.renderer = Renderer( self._merged_style, self.output, self.input, full_screen=full_screen, mouse_support=mouse_support, cpr_not_supported_callback=self.cpr_not_supported_callback, ) #: Render counter. This one is increased every time the UI is rendered. #: It can be used as a key for caching certain information during one #: rendering. self.render_counter = 0 # Invalidate flag. When 'True', a repaint has been scheduled. self._invalidated = False self._invalidate_events: List[Event[object]] = [ ] # Collection of 'invalidate' Event objects. self._last_redraw_time = 0.0 # Unix timestamp of last redraw. Used when # `min_redraw_interval` is given. #: The `InputProcessor` instance. self.key_processor = KeyProcessor(_CombinedRegistry(self)) # If `run_in_terminal` was called. This will point to a `Future` what will be # set at the point when the previous run finishes. self._running_in_terminal = False self._running_in_terminal_f: Optional[Future[None]] = None # Trigger initialize callback. self.reset()
def interrogatio(questions, theme='default'): """ Prompts user for inputs as defined in the questions parameter and returns a dictionary with the answers. :param questions: a list of questions. :type questions: list :param theme: the name of the theme to use. :type theme: string :return: a dictionary with the answers. :rtype: dict :raise InvalidQuestionError: if there is an error in the question definition. :raise ThemeNotFoundError: if the specified theme does not exists. Usage: .. code-block:: python from interrogatio import interrogatio questions = [ { 'name': 'name', 'type': 'input', 'message': 'What is your name' }, { 'name': 'favorite_pet', 'type': 'input', 'message': 'What is your favorite pet' } ] answers = interrogatio(questions, theme='purple') """ set_theme(theme) answers = {} validate_questions(questions) for q in questions: handler = get_instance(q) handler.set_context(answers) layout = handler.get_layout() layout.align = HorizontalAlign.LEFT bindings = [load_key_bindings()] handler_bindings = handler.get_keybindings() if handler_bindings: # pragma: no branch bindings.append(handler_bindings) app = Application( layout=Layout(layout), key_bindings=merge_key_bindings(bindings), style=for_prompt(), ) while True: result = app.run() if not result: return if handler.is_valid(answers): answers.update(handler.get_answer()) break else: print_formatted_text( FormattedText([('class:error', handler.errors[0])]), style=for_prompt(), ) return answers
def __init__(self): self.command_parser = BrewPiCommandParser(self) self.buffers = { DEFAULT_BUFFER: Buffer(completer=command_completer, enable_history_search=True, history=InMemoryHistory(), accept_action=AcceptAction(self.command_parser.parse)), 'MESSAGES': Buffer(), 'RESULT': Buffer(), 'STATE': Buffer(), } self.registry = load_key_bindings() self.registry.add_binding(Keys.ControlC, eager=True)(self._on_request_shutdown) self.registry.add_binding(Keys.ControlQ, eager=True)(self._on_request_shutdown) self.layout = HSplit([ # One window that holds the BufferControl with the default buffer on the # left. VSplit([ HSplit([ Window(content=TokenListControl(get_tokens=lambda cli: [( Token.Title, 'Command Result')]), height=D.exact(1)), Window(content=BufferControl(buffer_name='RESULT'), wrap_lines=True, left_margins=[ScrollbarMargin()]), ]), Window(width=D.exact(1), content=FillControl('|', token=Token.Line)), HSplit([ Window(content=TokenListControl(get_tokens=lambda cli: [( Token.Title, 'Raw Protocol Messages')]), height=D.exact(1)), Window( content=BufferControl(buffer_name='MESSAGES', lexer=PygmentsLexer(JsonLexer)), wrap_lines=True, left_margins=[NumberredMargin()], right_margins=[ScrollbarMargin()]) ]) ]), VSplit([ Window(content=TokenListControl( get_tokens=self.get_prompt_tokens), height=D.exact(1), dont_extend_width=True), Window(content=BufferControl(buffer_name=DEFAULT_BUFFER), height=D.exact(1), dont_extend_height=True), ]), Window(content=BufferControl(buffer_name='STATE'), height=D.exact(1), dont_extend_height=True) ]) super().__init__( layout=self.layout, buffers=self.buffers, key_bindings_registry=self.registry, mouse_support=True, style=style_from_pygments( get_style_by_name('emacs'), style_dict={ Token.Toolbar: '#ffffff bg:#333333', Token.Title: '#ffffff bg:#000088', # User input. Token: '#ff0066', # Prompt. Token.Name: '#884444 italic', Token.At: '#00aa00', Token.Colon: '#00aa00', Token.Pound: '#00aa00', Token.Host: '#000088 bg:#aaaaff', Token.Path: '#884444 underline', # Make a selection reverse/underlined. # (Use Control-Space to select.) Token.SelectedText: 'reverse underline', }), use_alternate_screen=True) # BrewPi Stuff self.controller_manager = BrewPiControllerManager() self.msg_decoder = RawMessageDecoder() self.controller = None
def __init__(self, project=None, extra_locals=None): """ Launch the Brownie console. Arguments --------- project : `Project`, optional Active Brownie project to include in the console's local namespace. extra_locals: dict, optional Additional variables to add to the console namespace. """ console_settings = CONFIG.settings["console"] locals_dict = dict((i, getattr(brownie, i)) for i in brownie.__all__) locals_dict.update(_dir=dir, dir=self._dir, exit=_Quitter("exit"), quit=_Quitter("quit"), _console=self) if project: project._update_and_register(locals_dict) # only make GUI available if Tkinter is installed try: Gui = importlib.import_module("brownie._gui").Gui locals_dict["Gui"] = Gui except ModuleNotFoundError: pass if extra_locals: locals_dict.update(extra_locals) # create prompt session object history_file = str(_get_data_folder().joinpath(".history").absolute()) kwargs = {} if console_settings["show_colors"]: kwargs.update( lexer=PygmentsLexer(PythonLexer), style=style_from_pygments_cls( get_style_by_name(console_settings["color_style"])), include_default_pygments_style=False, ) if console_settings["auto_suggest"]: kwargs["auto_suggest"] = ConsoleAutoSuggest(self, locals_dict) if console_settings["completions"]: kwargs["completer"] = ConsoleCompleter(self, locals_dict) self.compile_mode = "single" self.prompt_session = PromptSession( history=SanitizedFileHistory(history_file, locals_dict), input=self.prompt_input, key_bindings=KeyBindings(), **kwargs, ) # add custom bindings key_bindings = self.prompt_session.key_bindings key_bindings.add(Keys.BracketedPaste)(self.paste_event) key_bindings.add("c-i")(self.tab_event) key_bindings.get_bindings_for_keys( ("c-i", ))[-1].filter = lambda: not self.tab_filter() # modify default bindings key_bindings = load_key_bindings() key_bindings.get_bindings_for_keys( ("c-i", ))[-1].filter = self.tab_filter if console_settings["auto_suggest"]: # remove the builtin binding for auto-suggest acceptance key_bindings = self.prompt_session.app.key_bindings accept_binding = key_bindings.get_bindings_for_keys(("right", ))[0] key_bindings._bindings2.remove(accept_binding.handler) # this is required because of a pytest conflict when using the debugging console if sys.platform == "win32": import colorama colorama.init() super().__init__(locals_dict)
def show_dialog(questions, title, confirm, cancel): handlers = [] layouts = [] for q in questions: handler = get_instance(q) l = handler.get_layout() l.align = HorizontalAlign.JUSTIFY layouts.append(l) handlers.append(handler) def ok_handler(): result = dict() for handler in handlers: result.update(handler.get_answer()) get_app().exit(result=result) dialog = Dialog(title=title, body=HSplit(layouts, padding=1), buttons=[ Button(text=confirm, handler=ok_handler), Button(text=cancel, handler=lambda: get_app().exit()), ], with_background=True) # Key bindings. bindings = KeyBindings() app = Application(layout=Layout(dialog), key_bindings=merge_key_bindings([ load_key_bindings(), bindings, ]), mouse_support=True, style=for_dialog(), full_screen=True) size = app.renderer.output.get_size() container = app.layout.container height = container.preferred_height(size.columns, size.rows).preferred if height > size.rows: message_dialog(title='Too many questions', text='Cannot render a {} rows dialog in a ' '{} rows screen: too many questions!'.format( height, size.rows), ok_text='Got it!') return while True: validation_errors = [] answers = app.run() if answers is None: return for handler in handlers: if not handler.is_valid(): for msg in handler.errors: validation_errors.append('{}: {}'.format( handler.get_variable_name(), msg)) if not validation_errors: return answers show_error_dialog(validation_errors)
def __init__(self, layout=None, style=None, include_default_pygments_style=True, key_bindings=None, clipboard=None, full_screen=False, color_depth=None, mouse_support=False, enable_page_navigation_bindings=None, # Can be None, True or False. paste_mode=False, editing_mode=EditingMode.EMACS, erase_when_done=False, reverse_vi_search_direction=False, min_redraw_interval=None, max_render_postpone_time=0, on_reset=None, on_invalidate=None, before_render=None, after_render=None, # I/O. input=None, output=None): # If `enable_page_navigation_bindings` is not specified, enable it in # case of full screen applications only. This can be overridden by the user. if enable_page_navigation_bindings is None: enable_page_navigation_bindings = Condition(lambda: self.full_screen) paste_mode = to_filter(paste_mode) mouse_support = to_filter(mouse_support) reverse_vi_search_direction = to_filter(reverse_vi_search_direction) enable_page_navigation_bindings = to_filter(enable_page_navigation_bindings) include_default_pygments_style = to_filter(include_default_pygments_style) assert layout is None or isinstance(layout, Layout), 'Got layout: %r' % (layout, ) assert key_bindings is None or isinstance(key_bindings, KeyBindingsBase) assert clipboard is None or isinstance(clipboard, Clipboard) assert isinstance(full_screen, bool) assert (color_depth is None or callable(color_depth) or color_depth in ColorDepth._ALL), 'Got color_depth: %r' % (color_depth, ) assert isinstance(editing_mode, six.string_types) assert style is None or isinstance(style, BaseStyle) assert isinstance(erase_when_done, bool) assert min_redraw_interval is None or isinstance(min_redraw_interval, (float, int)) assert max_render_postpone_time is None or isinstance(max_render_postpone_time, (float, int)) assert on_reset is None or callable(on_reset) assert on_invalidate is None or callable(on_invalidate) assert before_render is None or callable(before_render) assert after_render is None or callable(after_render) assert output is None or isinstance(output, Output) assert input is None or isinstance(input, Input) self.style = style if layout is None: layout = create_dummy_layout() # Key bindings. self.key_bindings = key_bindings self._default_bindings = load_key_bindings() self._page_navigation_bindings = load_page_navigation_bindings() self.layout = layout self.clipboard = clipboard or InMemoryClipboard() self.full_screen = full_screen self._color_depth = color_depth self.mouse_support = mouse_support self.paste_mode = paste_mode self.editing_mode = editing_mode self.erase_when_done = erase_when_done self.reverse_vi_search_direction = reverse_vi_search_direction self.enable_page_navigation_bindings = enable_page_navigation_bindings self.min_redraw_interval = min_redraw_interval self.max_render_postpone_time = max_render_postpone_time # Events. self.on_invalidate = Event(self, on_invalidate) self.on_reset = Event(self, on_reset) self.before_render = Event(self, before_render) self.after_render = Event(self, after_render) # I/O. self.output = output or get_default_output() self.input = input or get_default_input() # List of 'extra' functions to execute before a Application.run. self.pre_run_callables = [] self._is_running = False self.future = None #: Quoted insert. This flag is set if we go into quoted insert mode. self.quoted_insert = False #: Vi state. (For Vi key bindings.) self.vi_state = ViState() self.emacs_state = EmacsState() #: When to flush the input (For flushing escape keys.) This is important #: on terminals that use vt100 input. We can't distinguish the escape #: key from for instance the left-arrow key, if we don't know what follows #: after "\x1b". This little timer will consider "\x1b" to be escape if #: nothing did follow in this time span. #: This seems to work like the `ttimeoutlen` option in Vim. self.ttimeoutlen = .5 # Seconds. #: Like Vim's `timeoutlen` option. This can be `None` or a float. For #: instance, suppose that we have a key binding AB and a second key #: binding A. If the uses presses A and then waits, we don't handle #: this binding yet (unless it was marked 'eager'), because we don't #: know what will follow. This timeout is the maximum amount of time #: that we wait until we call the handlers anyway. Pass `None` to #: disable this timeout. self.timeoutlen = 1.0 #: The `Renderer` instance. # Make sure that the same stdout is used, when a custom renderer has been passed. self._merged_style = self._create_merged_style(include_default_pygments_style) self.renderer = Renderer( self._merged_style, self.output, full_screen=full_screen, mouse_support=mouse_support, cpr_not_supported_callback=self.cpr_not_supported_callback) #: Render counter. This one is increased every time the UI is rendered. #: It can be used as a key for caching certain information during one #: rendering. self.render_counter = 0 # Invalidate flag. When 'True', a repaint has been scheduled. self._invalidated = False self._invalidate_events = [] # Collection of 'invalidate' Event objects. self._last_redraw_time = 0 # Unix timestamp of last redraw. Used when # `min_redraw_interval` is given. #: The `InputProcessor` instance. self.key_processor = KeyProcessor(_CombinedRegistry(self)) # If `run_in_terminal` was called. This will point to a `Future` what will be # set at the point when the previous run finishes. self._running_in_terminal = False self._running_in_terminal_f = None # Trigger initialize callback. self.reset()
from new_radio_list import NewRadioList library = 'jqueryui' resp = requests.get( 'https://api.cdnjs.com/libraries/{0}?fields=assets'.format(library)) if resp.ok: data = json.loads(resp.text) if isinstance(data, dict) and 'assets' in data: assets = data['assets'] versions = list(map(lambda item: item['version'], assets)) print(versions) values = list(map(lambda item: (item, item), versions)) rdo = NewRadioList(values) def do_exit(event): # get_app().exit() event.app.exit(result=rdo.current_value) def do_up_down(event): print(event) pass bindings = KeyBindings() bindings.add('enter')(do_exit) app_bindings = merge_key_bindings([load_key_bindings(), bindings]) selected = Application(layout=Layout(rdo), key_bindings=app_bindings).run() print('your choice is:', end=' ') # refer: https://github.com/jonathanslenders/python-prompt-toolkit/blob/master/examples/print-text/ansi.py print_formatted_text(ANSI('\x1b[91m{0}'.format(selected)))