def main(): # vytvoření aplikace s textovým uživatelským rozhraním application = Application(layout=layout, key_bindings=key_bindings, full_screen=True) # spuštění aplikace application.run()
def cli(): app = Application(full_screen=True, layout=LAYOUT, style=patched_style(), color_depth=ColorDepth.TRUE_COLOR, key_bindings=KG) app.editing_mode = EditingMode.VI app.run() shortcuts.clear_title()
def prompt(text: Union[str, FormattedText], title: str = '', actions: List[Action] = [], **kwargs: Any) -> None: """A simple and extensible prompt helper routine :param text: Text to be printed before the prompt, it can be formatted text :type text: str or FormattedText :param title: Title to be shown in a bottom bar :type title: str :param actions: A list of Actions as defined in `Action`. :type actions: [Action] :param kwargs: kwargs to prompt_toolkit application class """ assert (isinstance(actions, list)) assert (type(title) == str) kb = KeyBindings() for action in actions: kb.add(action.key)(action.action) print_formatted_text(FormattedText(text)) root_container = HSplit([ Window(wrap_lines=True, height=1, align=WindowAlign.LEFT, always_hide_cursor=True, style='bg:ansiblack fg:ansiwhite', content=FormattedTextControl( focusable=False, text=HTML(' '.join( "{a.name}<yellow>[{a.key}]</yellow>".format(a=a) for a in actions)))) ] + ([ Window(height=1, align=WindowAlign.LEFT, always_hide_cursor=True, style='bold fg:ansipurple bg:ansiwhite', content=FormattedTextControl(focusable=False, text=title)) ] if title else [])) app = Application(layout=Layout(root_container), key_bindings=kb, **kwargs) app.run()
def loop(cmd, history_file): buf = create_buffer(cmd, history_file) key_bindings = KeyBindings() bind_keys(buf, key_bindings) layout = create_layout( buffer=buf, multiline=True, lexer=SqlLexer, extra_input_processors=[ ConditionalProcessor( processor=HighlightMatchingBracketProcessor(chars='[](){}'), filter=HasFocus(DEFAULT_BUFFER) & ~IsDone()) ], get_bottom_toolbar_tokens=lambda: get_toolbar_tokens(cmd), get_prompt_tokens=lambda: [('class:prompt', 'cr> ')]) output = get_default_output() app = Application(layout=layout, style=style_from_pygments_cls(CrateStyle), key_bindings=merge_key_bindings( [key_bindings, load_open_in_editor_bindings()]), editing_mode=_get_editing_mode(), output=output) cmd.get_num_columns = lambda: output.get_size().columns while True: try: text = app.run() if text: cmd.process(text) buf.reset() except ProgrammingError as e: if '401' in e.message: username = cmd.username password = cmd.password cmd.username = input('Username: '******'Bye!') return
class CLI: def __init__(self, command, refresh_interval=2): self.setup_layout() self._command = command self._app = Application(layout=self._layout, key_bindings=self.generate_keybindings(), full_screen=False, erase_when_done=True, before_render=self.refresh, min_redraw_interval=refresh_interval) def setup_layout(self): self._text_area = TextArea( text=f'Loading...\nPress control-c to quit.', read_only=True) self._frame = Frame(self._text_area) self._layout = Layout(container=self._frame) def generate_keybindings(self): kb = KeyBindings() kb.add('c-c')(self._exit_keybinding_listener) return kb def _exit_keybinding_listener(self, event): event.app.exit() def refresh(self, event): output = subprocess.check_output(self._command, shell=True, encoding=sys.stdout.encoding).strip() try: datum = int(output) except ValueError: raise ValueError('Command output needs to be a number') self._text_area.text = (f'Last run: {datetime.now()}\n\n' f'{datum}\n\n' f'Press control-c to quit.') def run(self): self._app.run()
class PyTicker(object): def __init__(self, pyticker_db: PyTickerDBOperations): self._application = None self._pyticker_layout = PyTickerLayout(pyticker_db) self._watchlist_view = WatchListView() self._positions_view = PositionsView() self._pyticker_db = pyticker_db def init_application(self): layout = self._pyticker_layout.get_layout() self._application = Application(layout=layout, full_screen=True, key_bindings=bindings) def _invalidate(self): watchlist_stock_symbols, position_stock_symbols = self._pyticker_db.get_stock_symobls_to_fetch_quotes( ) yahoo_client = YahooHttpClient(watchlist_stock_symbols, position_stock_symbols, self._pyticker_db) watchlist_text, position_text = yahoo_client.get_stock_quotes() WATCHLIST_STOCKS_TEXT.text = watchlist_text POSITION_STOCKS_TEXT.text = position_text self._application.invalidate() def run(self): watchlist_stock_symbols, position_stock_symbols = self._pyticker_db.get_stock_symobls_to_fetch_quotes( ) yahoo_client = YahooHttpClient(watchlist_stock_symbols, position_stock_symbols, self._pyticker_db) watchlist_text, position_text = yahoo_client.get_stock_quotes() WATCHLIST_STOCKS_TEXT.text = watchlist_text POSITION_STOCKS_TEXT.text = position_text threading.Thread(target=lambda: every(1, self._invalidate), daemon=True).start() self._application.run()
def run(self): root_container = self.get_container() kb = self.get_key_bindings() layout = Layout(root_container) style = Style([ ('cursor-line', 'fg:ansiwhite bg:#003366'), ('cursor-line', 'fg:#CCCCCC bg:#003366'), ]) app = Application( layout=layout, full_screen=True, key_bindings=kb, editing_mode=EditingMode.VI, mouse_support=True, style=style, ) self.state.app = app self.state.layout = layout app.state = self.state app.run() self.state.print()
def select_menu(items, display_format=None, max_height=10): """ Presents a list of options and allows the user to select one. This presents a static list of options and prompts the user to select one. This is similar to a completion menu but is different in that it does not allow a user to type and the returned value is always a member of the list. :type items: list :param list: The list of items to be selected from. If this list contains elements that are not strings the display_format option must be specified. :type display_format: Callable[[Any], str] :param display_format: A callable that takes a single element from the items list as input and returns a string used to represent the item in the menu. :type max_height: int :param max_height: The max number of items to show in the list at a time. :returns: The selected element from the items list. """ app_bindings = KeyBindings() @app_bindings.add('c-c') def exit_app(event): event.app.exit(exception=KeyboardInterrupt, style='class:aborting') min_height = min(max_height, len(items)) menu_window = Window( SelectionMenuControl(items, display_format=display_format), always_hide_cursor=False, height=Dimension(min=min_height, max=min_height), scroll_offsets=ScrollOffsets(), right_margins=[ScrollbarMargin()], ) # Using a FloatContainer was the only way I was able to succesfully # limit the height and width of the window. content = FloatContainer( Window(height=Dimension(min=min_height, max=min_height)), [Float(menu_window, top=0, left=0)]) app = Application( layout=Layout(content), key_bindings=app_bindings, erase_when_done=True, ) return app.run()
def run(self): answer = None while True: try: widget = self._questions_iter.send(answer) except StopIteration: break layout = Layout(widget) app = Application( layout, full_screen=False, key_bindings=self._key_bindings, style=self._style, ) c = widget.main_control() if c is not None: app.layout.focus(c) widget._handler = self._make_handler(app) try: answer = app.run() except Cancel: break
def main(): # vytvoření aplikace s textovým uživatelským rozhraním application = Application(full_screen=True) # spuštění aplikace application.run()
class PtDebugCli: """ Command line interface using prompt_toolkit. """ def __init__(self, debugger): self._filename = None self.sources = {} self.debugger = debugger self.debugger.events.on_stop += self.on_stop self.current_address_margin = CurrentAddressMargin() kb = KeyBindings() self.locals_processor = DisplayVariablesProcessor() self.source_buffer = Buffer(multiline=True) self.bar_buffer = Buffer(multiline=True) self.register_buffer = Buffer(multiline=True) self.logs_buffer = Buffer(multiline=True) @kb.add(Keys.F10, eager=True) def quit_(event): event.app.exit() @kb.add(Keys.F8) def clear_breakpoint_(event): if self.has_source(): filename, row = self.get_current_location() self.debugger.clear_breakpoint(filename, row) @kb.add(Keys.F7) def set_breakpoint_(event): if self.has_source(): filename, row = self.get_current_location() self.debugger.set_breakpoint(filename, row) @kb.add(Keys.F6) def step_(event): self.debugger.step() @kb.add(Keys.F5) def run_(event): self.debugger.run() @kb.add(Keys.F4) def stop_(event): self.debugger.stop() @kb.add(Keys.PageUp) def scroll_up_(event): self.source_buffer.cursor_up(count=15) @kb.add(Keys.PageDown) def scroll_down_(event): self.source_buffer.cursor_down(count=15) src_lexer = PygmentsLexer(CLexer) source_code_window = Window( content=BufferControl( buffer=self.source_buffer, lexer=src_lexer, input_processors=[self.locals_processor], ), left_margins=[self.current_address_margin, NumberedMargin()], right_margins=[ScrollbarMargin(display_arrows=True)], cursorline=True, ) register_window = Window( content=BufferControl(buffer=self.register_buffer), width=20) title_text = "Welcome to the ppci debugger version {} running in prompt_toolkit {}".format( ppci_version, ptk_version) help_text = ("F4=stop F5=run F6=step F7=set breakpoint" + " F8=clear breakpoint F10=exit") # Application layout: body = HSplit([ Window(content=FormattedTextControl(text=title_text), height=1), VSplit([ HSplit([ Frame( body=source_code_window, title="source-code", ), Window( content=BufferControl(buffer=self.logs_buffer), height=2, ), ]), Frame(body=register_window, title="registers"), ]), Window( content=FormattedTextControl(self.get_status_tokens), height=1, ), Window(content=FormattedTextControl(help_text), height=1), ]) layout = Layout(body) style = style_from_pygments_cls(get_style_by_name("vim")) log_handler = MyHandler(self.logs_buffer) fmt = logging.Formatter(fmt=logformat) log_handler.setFormatter(fmt) log_handler.setLevel(logging.DEBUG) logging.getLogger().setLevel(logging.DEBUG) logging.getLogger().addHandler(log_handler) self._event_loop = get_event_loop() self.application = Application(layout=layout, style=style, key_bindings=kb, full_screen=True) def cmdloop(self): self.application.run() def get_status_tokens(self): tokens = [] tokens.append( ("class:status", "STATUS={} ".format(self.debugger.status))) tokens.append( ("class:status", "PC={:08X} ".format(self.debugger.get_pc()))) if self.debugger.has_symbols: loc = self.debugger.find_pc() if loc: filename, row = loc tokens.append( ("class:status", "LOCATION={}:{}".format(filename, row))) return tokens def on_stop(self): """ Handle stopped event. """ def callback(): self.display_registers() self.highlight_source() self.evaluate_locals() self.application.invalidate() self._event_loop.call_soon_threadsafe(callback) def evaluate_locals(self): # Locals: localz = self.debugger.local_vars() self.locals_processor.variables.clear() for name, var in localz.items(): value = self.debugger.eval_variable(var) var_text = "{} = {}".format(name, value) self.locals_processor.variables[var.loc.row] = var_text def has_source(self): return self._filename is not None def get_current_location(self): assert self.has_source() row = self.source_buffer.document.cursor_position_row + 1 return self._filename, row def highlight_source(self): if self.debugger.has_symbols: loc = self.debugger.find_pc() if loc: filename, row = loc self.source_buffer.text = self.get_file_source(filename) self._filename = filename self.source_buffer.cursor_position = 3 self.current_address_margin.current_line = row else: self.current_address_margin.current_line = None def display_registers(self): """ Update register buffer """ registers = self.debugger.get_registers() register_values = self.debugger.get_register_values(registers) lines = ["Register values:"] if register_values: for register, value in register_values.items(): size = register.bitsize // 4 lines.append("{:>5.5s} : 0x{:0{sz}X}".format(str(register), value, sz=size)) self.register_buffer.text = "\n".join(lines) def get_file_source(self, filename): if filename not in self.sources: with open(filename, "r") as f: source = f.read() self.sources[filename] = source return self.sources[filename]
class LinkTable: def __init__(self, filepath): self.db = Database(filepath) cursor = FormattedTextControl(focusable=True, text=[("", CURSOR)], show_cursor=False) sep = Window(width=len(SEPARATOR), char=SEPARATOR, style="class:line") self.ids = Column("ID") self.names = Column("Name") self.sources = Column("Source") self.tags = Column("Tags") self.urls = Column("URL") table_header = VSplit([ Label(text="", width=len(CURSOR)), sep, Label(self.ids.title, width=self.ids.width, style="bold"), sep, Label(self.names.title, width=self.names.width, style="bold"), sep, Label(self.tags.title, width=self.tags.width, style="bold"), sep, Label(self.sources.title, width=self.sources.width, style="bold"), sep, Label(self.urls.title, width=self.urls.width, style="bold"), ]) self.selection = Window(cursor, width=len(CURSOR), style="class:selector") table_body = VSplit([ self.selection, sep, Window(self.ids.col, width=self.ids.width), sep, Window(self.names.col, width=self.names.width), sep, Window(self.tags.col, width=self.tags.width), sep, Window(self.sources.col, width=self.sources.width), sep, Window(self.urls.col, width=self.urls.width), ]) self.prompt = TextArea( multiline=False, focusable=True, accept_handler=self._do_search, get_line_prefix=self._get_prompt, ) table = HSplit([table_header, table_body]) layout = HSplit([table, self.prompt]) kb = KeyBindings() @kb.add("c-c", eager=True) @kb.add("q", filter=has_focus(self.selection)) def close(event): event.app.exit() @kb.add("s", filter=has_focus(self.selection)) def start_search(event): event.app.layout.focus(self.prompt) @kb.add("o", filter=has_focus(self.selection)) @kb.add(Keys.Enter, filter=has_focus(self.selection)) def open_link(event): cursor = self.selection.content.text idx = len(cursor) selected = self.ids.col.text[idx - 1] link_id = int(selected[1]) Link.open(self.db, link_id) @kb.add(Keys.Down, filter=has_focus(self.selection)) def next_item(event): cursor = self.selection.content.text idx = len(cursor) max_idx = len(self.ids.col.text) if idx + 1 > max_idx: return cursor.insert(0, ("", "\n")) @kb.add(Keys.Up, filter=has_focus(self.selection)) def prev_item(event): cursor = self.selection.content.text idx = len(cursor) if idx == 1: return cursor.pop(0) self.app = Application(layout=Layout(layout), key_bindings=kb) def run(self): self._do_search() self.app.run() def _do_search(self, inpt: Buffer = None): self.selection.content.text = [("", CURSOR)] self.ids.clear() self.names.clear() self.tags.clear() self.sources.clear() self.urls.clear() name = None tags = None if inpt is not None and len(inpt.text) > 0: terms = inpt.text.split(" ") tags = [t.replace("#", "") for t in terms if t.startswith("#")] name = " ".join(n for n in terms if not n.startswith("#")) links = Link.search(self.db, name=name, top=10, tags=tags, sort="visits") for idx, link in enumerate(links): newline = "\n" if idx < len(links) - 1 else "" self.ids.col.text.append(("", f"{link.id}{newline}")) self.names.col.text.append(("", f"{link.name}{newline}")) self.urls.col.text.append(("", f"{link.url_expanded}{newline}")) tags = ", ".join(f"#{t.name}" for t in link.tags) self.tags.col.text.append(("", f"{tags}{newline}")) source = "" if not link.source else link.source.name self.sources.col.text.append(("", f"{source}{newline}")) self.app.layout.focus(self.selection) def _get_prompt(self, line_no, other): if has_focus(self.prompt)(): return "Search: " return "[s]earch | [o]pen | [q]uit"
class MultiPane: def __init__( self, entries, preview_callback=None, input_callback=None, input_completions=None, ): if not entries or len(entries) == 0: raise RuntimeError("Entries cannot be empty.") self.entries = entries self.input_callback = input_callback self.preview_callback = preview_callback self.ansi_escape_8bit = re.compile( r"(?:\x1B[@-Z\\-_]|[\x80-\x9A\x9C-\x9F]|(?:\x1B\[|\x9B)[0-?]*[ -/]*[@-~])" ) self.current_lineno = 1 self.max_entry_width = min( max( map( lambda x: len(x) + 1, self.ansi_escape_8bit.sub("", entries).split("\n") ) ), 48, ) entries_text = ANSI(self.entries) entries_formatted_text = to_formatted_text(entries_text) entries_plain_text = fragment_list_to_text(entries_formatted_text) self.entries_control = FormattedBufferControl( buffer=Buffer( document=Document(entries_plain_text, 0), name="entries", on_cursor_position_changed=self.update_entries, read_only=True, ), focusable=True, formatted_text=entries_formatted_text, include_default_input_processors=False, input_processors=[FormatTextProcessor(), HighlightSelectionProcessor()], ) if self.preview_callback: self.preview_text = ANSI(self.preview_callback(self.current_lineno)) formatted_text = to_formatted_text(self.preview_text) plain_text = fragment_list_to_text(formatted_text) self.preview_control = FormattedBufferControl( buffer=Buffer( document=Document(plain_text, 0), name="preview", on_cursor_position_changed=self.update_preview, read_only=True, ), focusable=True, formatted_text=formatted_text, include_default_input_processors=False, input_processors=[FormatTextProcessor(), HighlightSelectionProcessor()], ) # Alternative (not scrollable): # self.preview_control = FormattedTextControl( # focusable=True, # show_cursor=True, # text=ANSI(self.preview_callback(self.current_lineno)), # ) entries_container = VSplit( [ Window( content=self.entries_control, width=self.max_entry_width, wrap_lines=True, ), Window(width=3, char=" | "), Window(content=self.preview_control, wrap_lines=True), ] ) else: entries_container = Window( content=self.entries_control, width=self.max_entry_width, wrap_lines=True, ) if self.input_callback: self.search_field = SearchToolbar() self.input_field = TextArea( accept_handler=self.input_accept, completer=FuzzyWordCompleter(list(input_completions)), complete_while_typing=True, height=1, multiline=False, prompt="> ", search_field=self.search_field, wrap_lines=False, ) self.root_container = FloatContainer( content=HSplit( [entries_container, Window(height=1, char="-"), self.input_field,] ), floats=[ Float( content=CompletionsMenu(max_height=16, scroll_offset=1), xcursor=True, ycursor=True, ) ], ) else: self.root_container = entries_container self.layout = Layout(self.root_container) self.app = Application(full_screen=True, key_bindings=kb, layout=self.layout) def input_accept(self, buffer): self.input_callback(self.input_field.text) def get_lineno(self, text, pos): text = self.ansi_escape_8bit.sub("", text) lineno = 1 for i, c in enumerate(text): if (c == ord(b"\n") or c == "\n") and i != pos: lineno += 1 if i == pos: break i += 1 return lineno def update_preview(self, buffer): self.update_entries(self.entries_control.buffer) def update_entries(self, buffer, force=False): new_lineno = self.get_lineno(self.entries, buffer.cursor_position) if force or self.current_lineno != new_lineno: self.current_lineno = new_lineno text = ANSI(self.preview_callback(self.current_lineno)) formatted_text = to_formatted_text(text) plain_text = fragment_list_to_text(formatted_text) self.preview_control.buffer.set_document( Document(plain_text, 0), bypass_readonly=True ) self.preview_control.formatted_lines = self.preview_control.parse_formatted_text( formatted_text ) def replace_entries(self, entries): self.current_lineno = 1 self.entries_control.buffer.set_document( Document(entries, 0), bypass_readonly=True ) self.update_entries(self.entries_control.buffer, True) def run(self): self.app.run()
class App: toolbar_style = Style([("bgcolor", "reverse"), ("color", "reverse")]) error_text = "" output_text = "" script = "" def __init__(self, inpipe): self.inpipe = inpipe self.tempfile = tempfile.NamedTemporaryFile(mode="w", delete=True) self.initialize_nodes() root = VSplit( [ # Input buffer and status line HSplit( [ self.first_line, Window( content=BufferControl( buffer=self.input_buffer, # This lexer is disabled for now because # I don't want to mess with colourschemes # lexer=PygmentsLexer(PythonLexer), ) ), self.error_output, ], width=Dimension(), ), Window(width=1, char="|"), # Output display area Window(ignore_content_width=True, content=self.output, wrap_lines=True), ], width=Dimension(), ) layout = Layout(root) self.app = Application(layout=layout, key_bindings=kb, full_screen=True) def initialize_nodes(self): self.first_line = FormattedTextToolbar( self.get_first_line_text(), style="#ffffff bg:#444444" ) self.input_buffer = Buffer(on_text_changed=self.on_change) self.output = FormattedTextControl(text=self.get_output_text) self.error_output = FormattedTextToolbar( self.get_error_text, style="#ffffff bg:#444444" ) def on_change(self, b): self.tempfile.seek(0) self.tempfile.truncate() self.tempfile.write("inpipe = {}\n{}".format(self.inpipe, b.text)) self.tempfile.flush() self.execute(self.tempfile.name) def execute(self, script): try: proc = subprocess.run(["python", script], capture_output=True, timeout=5) self.write(proc.stderr, True) self.write(proc.stdout) except subprocess.TimeoutExpired: self.tempfile.truncate(0) self.write(b"Run time exceeded 5s and was killed", True) def write(self, msg, error=False): msg = msg.decode("utf-8") if error: self.error_text = str(msg) else: self.output_text = str(msg) def get_first_line_text(self): full_text = str(self.inpipe) if len(full_text) > 28: full_text = full_text[:25] + "..." return f"inpipe = {full_text}" def get_error_text(self): return self.error_text def get_output_text(self): return self.output_text def start(self): with patch_stdout(self.app): self.app.run() return self.tempfile
from prompt_toolkit import Application from prompt_toolkit.buffer import Buffer from prompt_toolkit.layout.containers import VSplit, Window from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl from prompt_toolkit.layout.layout import Layout buffer1 = Buffer() # Editable buffer. root_container = VSplit([ # One window that holds the BufferControl with the default buffer on # the left. Window(content=BufferControl(buffer=buffer1)), # A vertical line in the middle. We explicitly specify the width, to # make sure that the layout engine will not try to divide the whole # width by three for all these windows. The window will simply fill its # content by repeating this character. Window(width=1, char='|'), # Display the text 'Hello world' on the right. Window(content=FormattedTextControl(text='Hello world')), ]) layout = Layout(root_container) app = Application(layout=layout, full_screen=True) app.run() # You won't be able to Exit this app
class VoltronUI: """ Class that manages all UI elements """ def __init__(self, buffer_queue): self.buffer = Buffer() self.modules = {} self.module_prompt_callback = None self.prompt_ident = None self.prompt_ident_skip = [] key_bindings = KeyBindings() default_text = """ Welcome to VoltronBot! Type ? for available commands. Control-C or type 'quit' to exit """ lexer = PygmentsLexer(VoltronOutputLexer) ## Main output TextArea self.scrolling_output = TextArea(focusable=True, text=default_text, lexer=lexer) self.buffer_queue = buffer_queue self.buffer_thread = UIBufferQueue(self, self.buffer_queue, self.scrolling_output) self.buffer_thread.start() self.prompt_queue = queue.Queue() ## Exit keybinds @key_bindings.add('c-q') @key_bindings.add('c-c') def _exit(event): self.buffer_queue.put('SHUTDOWN') self.buffer_thread.join() event.app.exit() ## TextArea for prompt self.prompt = TextArea( height=1, #prompt=DEFAULT_PROMPT, multiline=False, wrap_lines=True) self.prompt.accept_handler = self.input_recv ## Create status bar self.status_text = FormattedTextControl(text=DEFAULT_STATUS) self.scroll_text = FormattedTextControl(text="") self.status_window = Window(content=self.status_text, height=1, style="class:status-bar") self.scroll_window = Window(content=self.scroll_text, height=1, width=6, style="class:status-bar") status_split = VSplit([self.status_window, self.scroll_window]) self.prompt_text = FormattedTextControl(text=DEFAULT_PROMPT) self.prompt_window = Window(content=self.prompt_text, height=1, width=len(DEFAULT_PROMPT) + 1) ## Create top bar self.main_container = HSplit([ Window(content=FormattedTextControl(text=f"VoltronBot v{VERSION}"), height=1, style="class:title-bar"), self.scrolling_output, status_split, VSplit([self.prompt_window, self.prompt]), ]) style = Style([ ('title-bar', 'bg:ansiblue #000000'), ('status-bar', 'bg:ansicyan #000000'), ('status-bar-important', 'bg:ansired #000000'), ]) self.layout = Layout(self.main_container, focused_element=self.prompt) ## Keybind for page up @key_bindings.add('pageup') def _scroll_up(event): self.layout.focus(self.scrolling_output) scroll_one_line_up(event) self.layout.focus(self.prompt) if not self._scrolled_to_bottom: self.scroll_text.text = '(more)' else: self.scroll_text.text = '' ## Keybind for page down @key_bindings.add('pagedown') def _scroll_down(event): self.layout.focus(self.scrolling_output) scroll_one_line_down(event) self.layout.focus(self.prompt) if not self._scrolled_to_bottom: self.scroll_text.text = '(more)' else: self.scroll_text.text = '' self._app = Application(layout=self.layout, full_screen=True, key_bindings=key_bindings, style=style) @property def _scrolled_to_bottom(self): ## True if the main output is scrolled to the bottom if self.scrolling_output.window.render_info == None: return True return (self.scrolling_output.window.vertical_scroll + self.scrolling_output.window.render_info.window_height ) >= self.scrolling_output.window.render_info.content_height def build_completer(self): completions = {'?': {}} for module_name in self.modules: actions = {} for action in self.modules[module_name].available_admin_commands(): actions[action] = None completions[module_name] = actions completions['?'][module_name] = actions self.prompt.completer = NestedCompleter.from_nested_dict(completions) def register_module(self, module): """ Modules are registered through the UI so we know about admin commands Args: module (instance): The instance of the module """ if module.module_name in self.modules: raise Exception('Duplicate module: {}'.format(module.module_name)) self.modules[module.module_name] = module self.build_completer() def update_status_text(self, text=None): """ Update the status text on the bottom bar Args: text (string): String to show on the status bar. If None it will reset to default """ if text: self.status_text.text = text self.status_window.style = 'class:status-bar-important' self.scroll_window.style = 'class:status-bar-important' else: self.status_text.text = DEFAULT_STATUS self.status_window.style = 'class:status-bar' self.scroll_window.style = 'class:status-bar' self._app.invalidate() def run(self): self._app.run() def reset(self): self.modules = {} def terminate_mod_prompt(self, ident): """ Cancel the prompt identified by ident Args: ident (string): Indentifier for the prompt to be cancelled """ if self.prompt_ident == ident: self.module_prompt_callback = None self.mod_prompt() def mod_prompt(self, prompt=None, callback=None): """ Change the prompt to send input to <callback>. This is used in modules to receive user input Args: prompt (string): The prompt to display callback (func): Function to call when user input is received """ ident = uuid4().hex if self.module_prompt_callback and not callback: return if self.module_prompt_callback and callback: self.prompt_queue.put((prompt, callback, ident)) return ident ## Add prompts to a queue in case a module is already waiting on a prompt if not callback and not self.prompt_queue.empty(): while not self.prompt_queue.empty(): prompt, callback, ident = self.prompt_queue.get_nowait() if ident in self.prompt_ident_skip: self.prompt_ident_skip.remove(ident) prompt, callback, ident = (None, None, None) else: break self.prompt_ident = ident if prompt: prompt = prompt.strip() self.prompt_text.text = prompt self.prompt_window.width = len(prompt) + 1 else: self.prompt_text.text = DEFAULT_PROMPT self.prompt_window.width = len(DEFAULT_PROMPT) + 1 self.module_prompt_callback = callback ## Must call invalidate on app to refresh UI self._app.invalidate() ## Return the unique identifier return self.prompt_ident def input_recv(self, buff): """ The default function called upon user input to the prompt """ ## If there is an active module wanting input, pass the data to ## the appropriate function if self.module_prompt_callback: status = self.module_prompt_callback(self.prompt.text) if status: self.module_prompt_callback = None self.mod_prompt(None, None) return if self.prompt.text.strip().lower() == 'quit': self.buffer_queue.put('SHUTDOWN') self.buffer_thread.join() get_app().exit() return ## Check for help command match = re.search(r'^\? ?([^ ]+)?( [^ ]+)?$', self.prompt.text) if match: module_name = match.group(1) command_name = match.group(2) if command_name: command_name = command_name.strip() self.show_help(module_name, command_name) return ## Check for a valid command match = re.search(r'^([^ ]+) ([^ ]+) ?(.*)$', self.prompt.text) if match: module_name = match.group(1) trigger = match.group(2) params = match.group(3) self._execute_admin_command(module_name, trigger, params) def _execute_admin_command(self, module_name, trigger, params): ## Execute an admin command for the appropriate module if not module_name in self.modules: pass elif trigger not in self.modules[module_name].available_admin_commands( ): pass else: command = self.modules[module_name].admin_command(trigger) command.execute(params.strip()) def show_help(self, module=None, trigger=None): """ Output help text for <module> Args: module (string): Name of the module. If none display installed modules trigger (string): Module command. If None display valid commands for <module> """ if module and module in self.modules.keys(): ## Check for valid module and trigger if trigger and trigger in self.modules[ module].available_admin_commands(): help_str = 'Help for {module} {trigger}:\n'.format( module=module, trigger=trigger) command = self.modules[module].admin_command(trigger) help_str += ' ' + command.description + '\n' help_str += ' Usage: ' + command.usage else: ## Module specified but no trigger help_str = "" if hasattr(self.modules[module], 'module_description'): help_str += self.modules[module].module_description.strip() help_str += '\n\n' help_str += f"Commands for {module} module:\n" count = 0 this_line = " " for trigger in self.modules[module].available_admin_commands(): if count == 3: help_str += f"{this_line}\n" count = 0 this_line = " " this_line += trigger.ljust(20) count += 1 help_str += "{}\n".format(this_line) help_str += f"Type '? {module} <command>' for more help." self.buffer_queue.put(("VOLTRON", '\n' + help_str + '\n')) else: ## Show available modules help_str = "Available Modules:\n" for module_name in self.modules: if hasattr(self.modules[module_name], 'configurable' ) and not self.modules[module_name].configurable: continue help_str += " {module_name}\n".format( module_name=module_name) help_str += "Type '? <module>' for more help." self.buffer_queue.put(('VOLTRON', '\n' + help_str + '\n'))
def main(): home = str(Path.home()) engine = chess.engine.SimpleEngine.popen_uci(home + "/stockfish_10_x64") username = prompt(HTML('<violet>Enter your lichess username: </violet>')) client = berserk.Client() move_place = 0 moves = [] game_list = [] game_number = 0 analysis_archive = [] kb = KeyBindings() kba = KeyBindings() @kb.add('c-q') def exit_(event): nonlocal move_place nonlocal moves move_place = 0 moves = [] game_list = [] game_number = 0 event.app.exit() @kb.add('c-a') def prev(event): nonlocal move_place nonlocal moves if move_place > 0: move_place = move_place - 1 display_simple_screen(event, game_list, game_number, moves, move_place) @kb.add('c-d') def next(event): nonlocal move_place nonlocal moves if move_place < len(moves) - 1: move_place = move_place + 1 display_simple_screen(event, game_list, game_number, moves, move_place) @kba.add('c-q') def exit_(event): nonlocal move_place nonlocal moves move_place = 0 moves = [] game_list = [] game_number = 0 analysis_archive = [] event.app.exit() @kba.add('c-a') def prev(event): nonlocal move_place nonlocal moves if move_place > 0: move_place = move_place - 1 display_analysis_screen(event, game_list, game_number, moves, move_place, analysis_archive) @kba.add('c-d') def next(event): nonlocal move_place nonlocal moves if move_place < len(moves) - 1: move_place = move_place + 1 display_analysis_screen(event, game_list, game_number, moves, move_place, analysis_archive) try: game_generator = client.games.export_by_player(username, as_pgn=False, max=10) game_list = list(game_generator) command = prompt( HTML( '\n\u265A <cyan>Welcome to ChessView!</cyan> \u2654\nType "help" for info on commands\n>' )) while (command != 'exit'): if (command == 'list'): print_games(game_list) elif (command == 'help'): help() elif (command.startswith('info(')): print_formatted_text(game_list[int(command[5:6])]) elif (re.match('view\(\d\)', command)): game_number = int(command[5:6]) moves = game_to_fenlist(game_list[game_number]['moves']) chess_text = set_simple_chess_text(game_list, game_number, moves, 0) root_container = VSplit([ Window(width=30, content=FormattedTextControl(), dont_extend_width=True, wrap_lines=True, allow_scroll_beyond_bottom=True, always_hide_cursor=True), Window(width=1, char='|', always_hide_cursor=True), Window(content=FormattedTextControl(text=HTML(chess_text)), always_hide_cursor=True) ]) layout = Layout(root_container) app = Application(key_bindings=kb, layout=layout, full_screen=True) app.run() elif (re.match('analyze\(\d\)', command)): game_number = int(command[8:9]) moves = game_to_fenlist(game_list[game_number]['moves']) analysis_archive = analysis_to_move_archive( game_list[game_number]['moves'], engine) chess_text = set_analysis_chess_text(game_list, game_number, moves, 0, analysis_archive) root_container = VSplit([ Window(width=30, content=FormattedTextControl(), dont_extend_width=True, wrap_lines=True, allow_scroll_beyond_bottom=True, always_hide_cursor=True), Window(width=1, char='|', always_hide_cursor=True), Window(content=FormattedTextControl(text=HTML(chess_text)), always_hide_cursor=True) ]) layout = Layout(root_container) app = Application(key_bindings=kba, layout=layout, full_screen=True) app.run() command = prompt(HTML('>')) except Exception as e: print("Username not found or does not exist.") engine.quit()
#!/usr/bin/env python # vim: set fileencoding=utf-8 from prompt_toolkit import Application # vytvoření aplikace s textovým uživatelským rozhraním application = Application() # spuštění aplikace application.run()
class IGCLI: kb = KeyBindings() strf_string = '%a %d %b %Y | %H:%M:%S' config_default = {'refresh': 5, 'currency': 'USD', 'tracked': []} def __init__(self) -> None: self.logger = logging.getLogger(self.__class__.__name__) self.config_file = os.getenv('IG_CLI_CONFIG', 'config.yml') self.config = {} self._id = None self.authd = False self._stop_update = Event() self.client = None self.positions_thread = None self.activity_thread = None self.orders_thread = None self.trackers_thread = None self.status_thread = RepeatTimer(self.update_status, 1) self.style = Style([('output-field', 'bg:#5F9EA0 #F0FFFF'), ('input-field', 'bg:#20B2AA #F0FFFF'), ('separator', '#000000'), ('status-bar', 'bg:#D3D3D3 #2F4F4F')]) self.trackers_field = TextArea(style='class:output-field') self.positions_field = TextArea(style='class:output-field') self.orders_field = TextArea(style='class:output-field') self.activity_field = TextArea(height=7, style='class:output-field') self.msg_field = TextArea(height=7, style='class:output-field') self.output_container = HSplit([ VSplit([ self.positions_field, Window(width=1, char='|', style='class:separator'), HSplit([ self.trackers_field, Window(height=1, char='-', style='class:separator'), self.orders_field ]) ]), Window(height=1, char='-', style='class:separator'), VSplit([ self.msg_field, Window(width=1, char='|', style='class:separator'), self.activity_field ]) ]) self.search_field = SearchToolbar() self.input_field = TextArea(height=1, prompt='>>> ', style='class:input-field', multiline=False, wrap_lines=False, search_field=self.search_field) self.input_field.accept_handler = self.parse self.status_field = TextArea(height=1, style='class:status-bar', multiline=False, wrap_lines=False, text=self.status) self.time_field = TextArea(height=1, style='class:status-bar', multiline=False, wrap_lines=False, text=self.get_time()) self.container = HSplit([ self.output_container, Window(height=1, char='-', style='class:separator'), self.input_field, self.search_field, self.status_field ]) self.app = Application(Layout(self.container, focused_element=self.input_field), style=self.style, full_screen=True, mouse_support=True, key_bindings=self.kb) self.autologin() self.status_thread.start() def get_time(self): return datetime.utcnow().strftime(self.strf_string) @req_auth def load_config(self, filename: str = 'config.yml'): self.msg_out(f'Loading {self._id} configuration...') with open(filename) as f: loaded = yaml.safe_load(f) if loaded: self.config = loaded.get(self._id, {}) if self.config: for key, default in self.config_default.items(): if key not in self.config: self.config[key] = default else: self.config = self.config_default.copy() self.msg_out(f'... Refresh rate: {self.config["refresh"]} s\n' f'... Currency: {self.config["currency"]}\n' f'... Added {len(self.config["tracked"])} trackers') @property def status(self): s = self.get_time() s += ' || Status: ' if not self.authd: s += 'Offline |' else: s += f'Online | ID: {self._id} ' return s def update_status(self): self.status_field.buffer.document = Document(text=self.status) def autologin(self): api_key = os.getenv('IG_API_KEY') identifier = os.getenv('IG_ID') password = os.getenv('IG_PWD') if api_key and identifier and password: self.set_api(api_key) self.login(api_key, identifier, password) def set_api(self, api_key: str) -> None: self.client = IGClient(api_key=api_key) def login(self, identifier: str, password: str) -> bool: successful = self.client.login(identifier, password) if successful: self.authd = True self._id = identifier self.load_config() self.start_threads() return True return False @req_auth def logout(self) -> None: self.__api_key = None self._id = None self.__password = None self.config = {} self.stop_treads() @req_auth def start_threads(self) -> None: if self.positions_thread and self.trackers_thread: self.logger.error('Threads already running!') return # Reset stop _threads if needed global stop_threads if stop_threads is None: stop_threads = Event() self.positions_thread = RepeatTimer(self.update_positions, self.config['refresh']) self.activity_thread = RepeatTimer(self.update_activity, self.config['refresh']) self.orders_thread = RepeatTimer(self.update_orders, self.config['refresh']) self.trackers_thread = RepeatTimer(self.update_trackers, self.config['refresh']) self.positions_thread.start() self.activity_thread.start() self.orders_thread.start() self.trackers_thread.start() @req_auth def stop_threads(self) -> None: global stop_threads stop_threads.set() self.positions_thread = None self.activity_thread = None self.orders_thread = None self.trackers_thread = None stop_threads = None @req_auth def restart_threads(self) -> None: self.stop_threads() self.start_threads() @req_auth def write_config(self) -> None: with open(self.config_file, 'r') as f: loaded = yaml.safe_load(f) if not loaded: loaded = {} loaded[self._id] = self.config with open(self.config_file, 'w') as f: yaml.dump(loaded, f) @req_auth def add_tracker(self, tracker: str) -> None: try: self.client.get_market(tracker) self.config['tracked'].append(tracker) except NotFoundError: self.msg_out(f'Unable to find market: {tracker}') @req_auth def del_tracker(self, tracker: str) -> None: if tracker in self.config['tracked']: self.config['tracked'].remove(tracker) def parse(self, buf: Document) -> None: self.logger.debug(f'Input: {buf.text}') args = buf.text.split() # replace aliases a_args = [] for arg in args: if arg in self.config['alias']: a_args = a_args + self.config['alias'][arg].split(' ') else: a_args.append(arg) args = a_args # try find command try: command = getattr(self, f'_cmd__{args[0]}') except AttributeError: self.msg_out(f'Unrecognised command: {args[0]}') return # run command command(*args[1:]) def msg_out(self, text: str) -> None: new_text = self.msg_field.text + f'\n{text}' self.msg_field.buffer.document = \ Document(text=new_text, cursor_position=len(new_text)) # cant figure out how to colour text for the Document @req_auth def update_positions(self) -> None: self.logger.debug('Updating positions...') positions = self.client.get_positions_profitloss() buf = f"{' POSITIONS ':-^60}\n" for i, pos in enumerate(positions): line = '{direction:4} {name:15} {size:>5.2f} ' +\ '{currency:3} @ {level:>10.2f} ' +\ '|| {profitloss:>10}' line = line.format(direction=pos['position']['direction'], name=pos['market']['instrumentName'], size=pos['position']['size'], currency=pos['position']['currency'], level=pos['position']['level'], profitloss=pos['profitloss']) buf += line if i + 1 != len(positions): #not last buf += '\n' self.positions_field.buffer.document = Document(text=buf) @req_auth def update_activity(self) -> None: self.logger.debug('Updating activity...') activities = self.client.get_activity()['activities'] buf = '' for i, activity in enumerate(activities): line = '{date} {activity:15} {name:10} {size:>5} ' +\ '{currency:3} @ {level:>10} ' +\ '|| {status:>10}' line = line.format(date=activity['date'], activity=activity['activity'], name=activity['marketName'], size=activity['size'], currency=activity['currency'], level=activity['level'], status=activity['actionStatus']) buf += line if i + 1 != len(activities): #not last buf += '\n' self.activity_field.buffer.document = Document(text=buf) @req_auth def update_orders(self) -> None: self.logger.debug('Updating orders...') orders = self.client.get_working_orders()['workingOrders'] buf = f"{' ORDERS ':-^60}\n" for i, order in enumerate(orders): line = '{direction:4} {name:15} {size:>5.2f} ' +\ '{currency:3} @ {level:>10.2f} ' line = line.format( direction=order['workingOrderData']['direction'], name=order['marketData']['instrumentName'], size=order['workingOrderData']['orderSize'], currency=order['workingOrderData']['currencyCode'], level=order['workingOrderData']['orderLevel']) buf += line if i + 1 != len(orders): #not last buf += '\n' self.orders_field.buffer.document = Document(text=buf) @req_auth def update_trackers(self) -> None: self.logger.debug('Updating trackers...') markets = self.client.get_markets( *self.config['tracked'])['marketDetails'] buf = f"{' TRACKERS ':-^60}\n" for i, market in enumerate(markets): line = '{name:15} || {low:>9} | {high:>9} || {bid:>9} | {offer:>9}' line = line.format(name=market['instrument']['name'], low=market['snapshot']['low'] or '-', high=market['snapshot']['high'] or '-', bid=market['snapshot']['bid'] or '-', offer=market['snapshot']['offer'] or '-') buf += line if i + 1 != len(self.config['tracked']): buf += '\n' self.trackers_field.buffer.document = Document(text=buf) # This does some super weird shit. The decorator calls this # without passing self. I'm too dumb to figure out where/how this # happens to monkey-patch (I think a flag on self would be better) # Thus, the global stop_threads. @kb.add('c-q') @kb.add('c-c') def exit_ctrl_q(event) -> None: global stop_threads stop_threads.set() event.app.exit() def __call__(self) -> None: self.logger.info('Starting CLI...') self.app.run() def __del__(self) -> None: self.stop_threads() # User Commands # all user commands should start with '_cmd__', and accept *args @req_auth def _cmd__update(self, *args: List[str]) -> None: self.update_positions() self.update_orders() self.update_trackers() self.msg_out('Updated positions, orders and trackers') def _cmd__api(self, *args: List[str]) -> None: if len(args) != 1: self.msg_out('Invalid syntax, expected: api <key>') return self.set_api(args[0]) self.msg_out('Updated API key') def _cmd__login(self, *args: List[str]): if len(args) != 2: self.msg_out('Invalid syntax, expected: login: '******'<username> <password>') return username, password = args successful = self.login(username, password) if successful: self.msg_out('Login successful') else: self.msg_out('Login failed') def _cmd__save(self, *args: List[str]) -> None: self.write_config() self.msg_out('Configuration saved') def _cmd__track(self, *args: List[str]) -> None: for arg in args: self.add_tracker(arg) self.msg_out('Added tracked market(s)') def _cmd__stoptrack(self, *args: List[str]) -> None: for arg in args: self.del_tracker(arg) self.msg_out('Removed tracked market(s)') def _cmd__search(self, *args: List[str]) -> None: markets = self.client.search_market(args[0])['markets'] s = 'Found epics: ' s += ', '.join([ f'{market["instrumentName"]}: {market["epic"]}' for market in markets ]) self.msg_out(s) def _cmd__buy(self, *args: List[str]) -> None: size, epic = args currency = self.config['currency'] try: self.client.get_market(epic) except BadRequestError: self.msg_out(f'Unable to find market: {epic}') return self.client.add_position('BUY', 'MARKET', epic, size, currency) self.msg_out(f'Submitted position on {epic} @ {size} {currency}') def _cmd__alias(self, *args: List[str]) -> None: self.config['alias'][args[0]] = ' '.join(args[1:]) self.msg_out(f'Added alias: {args[0]} = {" ".join(args[1:])}')
def run(): app = Application(full_screen=True, mouse_support=True, key_bindings=kb, layout=main_layout) app.run()
content=controls.BufferControl(buffer=buffer), height=1 ), containers.Window(height=1, char="-", style="class:line"), containers.Window(content=display), ] ), floats=[ containers.Float( xcursor=True, ycursor=True, content=menus.CompletionsMenu(max_height=12, scroll_offset=1), ) ], ), ] ) ) kb = KeyBindings() @kb.add("c-g") @kb.add("c-c") def exit_(event): event.app.exit() app = Application(layout=layout, full_screen=True, key_bindings=kb) app.run()
def start_app(store: RetroStore, connection_string: str = ''): kb = KeyBindings() @kb.add('c-q') def exit_(event): event.app.exit() @kb.add('c-r') def refresh_(event): refresh() def refresh(): items = store.list() texts = { Category.GOOD: StringIO(), Category.NEUTRAL: StringIO(), Category.BAD: StringIO(), } for item in items: texts[item.category].write(f'{item.key}. {item.text}\n') good_buffer.text = texts[Category.GOOD].getvalue() neutral_buffer.text = texts[Category.NEUTRAL].getvalue() bad_buffer.text = texts[Category.BAD].getvalue() @kb.add('c-m') def enter_(event): text = input_buffer.text if text.startswith('+'): input_buffer.reset() store.add_item(text[1:].strip(), Category.GOOD) elif text.startswith('.'): input_buffer.reset() store.add_item(text[1:].strip(), Category.NEUTRAL) elif text.startswith('-'): input_buffer.reset() store.add_item(text[1:].strip(), Category.BAD) elif text.startswith('mv '): cmd, key, column = text.split() categories = { '+': Category.GOOD, '.': Category.NEUTRAL, '-': Category.BAD, } input_buffer.reset() store.move_item(int(key), categories[column]) elif text.startswith('rm '): cmd, key = text.split() input_buffer.reset() store.remove(int(key)) refresh() @kb.add('c-p') def ping_(event): start = time() store.list(Category.GOOD) app.print_text(f'latency: {time() - start:.3f}') good_buffer = Buffer() neutral_buffer = Buffer() bad_buffer = Buffer() input_buffer = Buffer() input = Window(content=BufferControl(buffer=input_buffer), height=1) root_container = HSplit([ VSplit([ HSplit([ Window(content=FormattedTextControl(text=':)'), height=1, align=WindowAlign.CENTER), Window(height=1, char='-'), Window(content=BufferControl(buffer=good_buffer)), ], style="fg:white bold bg:ansigreen"), Window(width=2, char='|'), HSplit([ Window(content=FormattedTextControl(text=':|'), height=1, align=WindowAlign.CENTER), Window(height=1, char='-'), Window(content=BufferControl(buffer=neutral_buffer)), ], style="fg:white bold bg:ansiyellow"), Window(width=2, char='|'), HSplit([ Window(content=FormattedTextControl(text=':('), height=1, align=WindowAlign.CENTER), Window(height=1, char='-'), Window(content=BufferControl(buffer=bad_buffer)), ], style="fg:white bold bg:ansired"), ]), Window( content=FormattedTextControl(text=f'Invite: {connection_string}'), height=1, align=WindowAlign.CENTER), input ], style='bg:grey') layout = Layout(root_container) layout.focus(input) app = Application(layout=layout, key_bindings=kb, full_screen=True) async def active_refresh(): while True: refresh() await asyncio.sleep(2) app.create_background_task(active_refresh()) app.run()
class OOApplication: @staticmethod def source(self, event): """ Show and modify source of the object under cursor. """ source_is_already_open = False for tab in self.session.tabs: if tab.name == 'Source': source_is_already_open = True if not source_is_already_open: cursor_row_index = self.python_code_buffer.document.cursor_position_row cursor_col_index = self.python_code_buffer.document.cursor_position_col current_row = self.python_code_buffer.document.lines[ cursor_row_index] text_before_cursor = current_row[:cursor_col_index] self.inspected_class_object, self.inspected_method_object, source_code = inspect_code( text_before_cursor, self.interface) self.source_code_original = source_code self.source_code_buffer = Buffer() self.source_code_buffer.document = Document(text=source_code) formatted_text = BufferControl(buffer=self.source_code_buffer, lexer=PythonLexer( self.source_code_buffer)) source_window = Window(formatted_text, width=120, wrap_lines=True) tab_index = self.session.add_tab(Tab("Source", source_window)) self.tabs_container.set_selected_tab(tab_index) # Source float is already exist, so saving the modified version of the source and closing the float. else: # Source code modifications only works on method right now. # so it only works if source code inspector return both class ans method object. if self.inspected_class_object and \ self.inspected_method_object and \ self.source_code_original != self.source_code_buffer.document.text: # Only modify the method object if the code has actually changed try: # Should be method definition source = self.source_code_buffer.document.text # Evaluting the method object (with the original name) exec(source, self.interface) method_name = self.inspected_method_object.__name__ # The moment we evaluated the new method in the exec above, # we can get a pointer to that method using its name in the local context(scope) new_method_object = eval(method_name, self.interface) setattr( self.inspected_class_object, method_name, new_method_object.__get__( self.inspected_class_object, type(self.inspected_class_object))) # setattr(class_object, method_name, eval(method_name)) except Exception as e: self.__send_to_output("Exception: {}".format(e)) self.session.remove_tab_by_name("Source") self.tabs_container.update_selected_tab() @staticmethod def execute(self, event): """ Execute the code in the python code buffer in the current interpreter session. """ code = self.python_code_buffer.document.text output = None try: import sys from io import StringIO codeOut = StringIO() codeErr = StringIO() sys.stdout = codeOut sys.stderr = codeErr exec(code, self.interface) # restore stdout and stderr sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ # codeErr.getvalue() output = codeOut.getvalue() codeOut.close() codeErr.close() except Exception as e: output = e self.__send_to_output("------- start of python output -------") self.__send_to_output(output) self.__send_to_output("-------- end of python output --------") @staticmethod def exit(self, event): """ Pressing Ctrl-Q will exit the user interface. Setting a return value means: quit the event loop that drives the user interface and return this value from the `Application.run()` call. """ event.app.exit() @staticmethod def focus_next(self, event): selected_window = self.tabs_container.focus_next() self.app.layout.focus(selected_window) @staticmethod def return_to_command_line(self, event): self.app.layout.focus(self.input_container) def __configure_bindings(self): # Configure key bindings for app self.key_bindings = KeyBindings() # Bind Ctrl-c to return to command @self.key_bindings.add('c-c') def return_to_command_line_(event): OOApplication.return_to_command_line(self, event) # Bind Alt-Tab to change focus to next window @self.key_bindings.add('escape', 'c-i') def focus_next_(event): OOApplication.focus_next(self, event) # Bind Ctrl-s to view the source of a method @self.key_bindings.add('c-s') def source_(event): OOApplication.source(self, event) # Bind Ctrl-e for executing the python code. @self.key_bindings.add('c-e') def execute_(event): OOApplication.execute(self, event) # Bind Ctrl-q for existing the application. @self.key_bindings.add('c-q') def exit_(event): OOApplication.exit(self, event) def __configure_snippets(self): snippets = Snippets() # Add default snippets # snippets["modify_object_method"] = modify_object_method setattr(snippets, "modify_object_method", modify_object_method) if self.snippets_path == None: self.add_object_to_interface("snippets", snippets) return # Add user-defined snippets path.append(self.snippets_path) # So the import will work... files = [ join(self.snippets_path, file_name) for file_name in listdir(self.snippets_path) if isfile(join(self.snippets_path, file_name)) ] files = [ file_name for file_name in listdir(self.snippets_path) if isfile(join(self.snippets_path, file_name)) and file_name.endswith('.py') ] for f in files: try: module_name = splitext(f)[0] module = importlib.import_module(module_name) setattr(snippets, module_name, module) self.__send_to_output("[-] {} - loaded.".format(f)) except Exception as e: self.__send_to_output("[!] {} - Falied to load: {}".format( f, e)) self.add_object_to_interface("snippets", snippets) def __configure_layout(self): # Configure completers used by the application. commands_completer = NestedCommandsFuzzyWordCompleter( self.commands, completers=self.completers) # Configure PythonRuntimeCompleter python_runtime_completer = PythonRuntimeCompleter(self) # --------- This is the CLI input container --------- # Comfigure the input container and handler. self.input_container = TextArea(prompt='{}> '.format(self.app_name), style='class:input-field', multiline=False, wrap_lines=True, completer=commands_completer, history=InMemoryHistory()) self.input_container.accept_handler = lambda command: self.__root_command_handler( self.input_container.text) # Configure the python buffer to write interactive pytho code. self.python_code_buffer = Buffer(completer=python_runtime_completer) # --------- This is the Python code container --------- self.python_code_container = Window( width=130, # Is there any way to use precentage? content=BufferControl(buffer=self.python_code_buffer, lexer=PythonLexer(self.python_code_buffer)), get_line_prefix=self.__get_line_prefix, wrap_lines=True) # Configure the output buffer to 'print' out results. self.output_buffer = Buffer() # --------- This is the Output container --------- self.output_container = Window( content=BufferControl(buffer=self.output_buffer), wrap_lines=True) self.session = Session() self.session.add_tab(Tab("Console", self.output_container)) self.session.add_tab( Tab("Python Interpreter Environment", self.python_code_container)) self.tabs_container = TabbedBuffersContainer(self.session) self.tabs_container.set_selected_tab(0) # Configure the application layout. root_container = HSplit([ VSplit([ # Window for python code. self.tabs_container, ]), # Seperation line. Window(height=1, char='-', style='class:line'), # Command line prompt. self.input_container, ]) self.floating_container = FloatContainer( content=root_container, floats=[ Float(xcursor=True, ycursor=True, content=CompletionsMenu(max_height=16, scroll_offset=1)) ]) self.body_layout = Layout(self.floating_container) def __init__(self, app_name, commands, completers={}, snippets_path=None): # Configure the application name. self.app_name = app_name # Initialize the interface of this app. self.interface = {} self.snippets_path = snippets_path self.completers = completers self.commands = commands self.__configure_bindings() self.__configure_layout() self.__configure_snippets() # Creating the application. self.app = Application(layout=self.body_layout, key_bindings=self.key_bindings, full_screen=True, editing_mode=EditingMode.VI) # Focus on command line self.app.layout.focus(self.input_container) self.add_object_to_interface("ooa", self) def __get_line_prefix(self, line_number, wrap_count): return '' def __send_to_output(self, message): new_text = self.output_buffer.text + "{}\n".format(message) self.output_buffer.document = Document(text=new_text, cursor_position=len(new_text)) def __root_command_handler(self, command): commands = command.split() if len(commands) == 0: return try: curr_state = self.commands for c in commands: if not isinstance(curr_state, types.FunctionType): curr_state = curr_state[c] output = curr_state(self, commands) self.__send_to_output(output) except: pass def remove_object_from_interface(self, object_name): if object_name in self.interface: del self.interface[object_name] def add_object_to_interface(self, object_name, object_instance): self.interface[object_name] = object_instance def run(self): self.app.run() # You won't be able to Exit this app
class PybreakGui(Bdb): def __init__(self): super().__init__() self.paused = True self.app_thread = threading.Thread(target=self.start_gui, args=(asyncio.get_event_loop(),)) self.frame_history = FrameHistory() self.search_toolbar = SearchToolbar( text_if_not_searching=[("class:not-searching", "Press '/' to start searching.")] ) def get_view_file(): if len(self.frame_history.history) > 0: return self.frame_history.hist_frame.filename return ".py" self.text_area = TextArea( lexer=DynamicLexer( lambda: PygmentsLexer.from_filename( get_view_file(), sync_from_start=False ) ), search_field=self.search_toolbar, scrollbar=True, line_numbers=True, ) self.container = HSplit( [ self.text_area, self.search_toolbar, ] ) kb = KeyBindings() @kb.add("c-q") def _(event: KeyPressEvent): self.paused = False self._quit() @kb.add("c-n") def _(event): self.set_next(self.frame_history.exec_frame.raw_frame) self.paused = False # allow another frame to be processed self.app = Application( full_screen=True, layout=Layout(container=self.container), key_bindings=kb, ) self.app.loop = asyncio.get_event_loop() def start_gui(self, loop): asyncio.set_event_loop(loop) self.app.run() self.text_area.buffer.insert_text("HELLO WORLD") def start(self, frame): self.app_thread.start() super().set_trace(frame) def _quit(self): sys.settrace(None) self.quitting = True self.app.exit() def user_call(self, frame: types.FrameType, argument_list): # if self.stop_here(frame): # self.frame_history.append(frame) pass def user_line(self, frame: types.FrameType): """ This method is called from dispatch_line() when either stop_here() or break_here() yields True. i.e. when we stop OR break at this line. * stop_here() yields true if the frame lies below the frame where debugging started on the call stack. i.e. it will be called for every line after we start debugging. * break_here() yields true only if there's a breakpoint for this line """ self.text_area.buffer.insert_text(f"FRAME = {frame.f_code.co_filename}:{frame.f_lineno}") if self.stop_here(frame): self.text_area.buffer.insert_text(str(frame.f_code.co_filename) + str(frame.f_lineno) + "\n") self.frame_history.append(frame) while self.paused: time.sleep(.1) self.paused = True
now.strftime("DATE_NOW:%m/%d/%Y,%H:%M:%S")) @kb.add('c-c', 'q', 'u', 'i', 't') def exit_(event): event.app.exit() buffer1 = Buffer() buffer2 = Buffer() root_container = VSplit( [ # One window that holds the BufferControl with the default buffer on # the left. Window(content=BufferControl(buffer=buffer1)), # A vertical line in the middle. We explicitly specify the width, to # make sure that the layout engine will not try to divide the whole # width by three for all these windows. The window will simply fill its # content by repeating this character. Window(width=1, char='|'), # Display the text 'Hello world' on the right. Window(content=BufferControl(buffer=buffer2)), ], ) layout = Layout(root_container, ) app = Application(key_bindings=kb, full_screen=True, layout=layout) app.run()
def cli(ctx, email, password, token, graphql, **kwargs): '''Music player''' ctx.obj.u = lambda: user.User.new(email=email, password=password, token=token, graphql=graphql) mf = mfilter.Filter(**kwargs) p = ctx.obj.u().do_filter(mf) if not p: logger.warning('Empty playlist') return instance = vlc.Instance() songs = [song['path'] for song in p] player = instance.media_list_player_new() media_list = instance.media_list_new(songs) player.set_media_list(media_list) bindings = KeyBindings() @bindings.add('p') def _play_binding(event): def play(): """Play song""" player.play() run_in_terminal(play) @bindings.add('q') def _quit_binding(event): player.pause() event.app.exit() @bindings.add('s') def _pause_binding(event): player.pause() @bindings.add('l') def _playlist_binding(event): def playlist(): """List songs""" for s in songs: print(s) run_in_terminal(playlist) @bindings.add('right') def _next_binding(event): player.next() @bindings.add('left') def _previous_binding(event): player.previous() def bottom_toolbar(): media_player = player.get_media_player() media = media_player.get_media() media.parse() media_time = seconds_to_human(round(media_player.get_time() / 1000)) media_length = seconds_to_human(round(media_player.get_length() / 1000)) artist = media.get_meta(vlc.Meta.Artist) album = media.get_meta(vlc.Meta.Album) title = media.get_meta(vlc.Meta.Title) current = '({} / {}) {} - {} - {}'.format(media_time, media_length, artist, album, title) get_app().invalidate() return HTML('Current song: {}'.format(current)) player.play() print(HTML('Bindings: q = quit | p = play | s = pause/continue | right = next song | left = previous song | l = playlist')) root_container = HSplit( [Window(FormattedTextControl(lambda: bottom_toolbar, style='class:bottom-toolbar.text'), style='class:bottom-toolbar')] ) layout = Layout(root_container) app = Application(layout=layout, key_bindings=bindings) app.run()