def __init__(self, completekey='tab', stdin=None, stdout=None): BaseCmd.__init__(self, completekey, stdin, stdout) self.history = FileHistory(os.path.expanduser(HISTORY_PATH))
def implant_command_loop(implant_id, user): while (True): try: style = Style.from_dict({ '': '#80d130', }) session = PromptSession(history=FileHistory('%s/.implant-history' % PoshProjectDirectory), auto_suggest=AutoSuggestFromHistory(), style=style) implant_id_orig = implant_id if ("-" in implant_id) or ("all" in implant_id) or ("," in implant_id): print(Colours.GREEN) prompt_commands = POSH_COMMANDS command = session.prompt("%s> " % implant_id, completer=FirstWordFuzzyWordCompleter( prompt_commands, WORD=True)) if command == "back" or command == 'clear': do_back(user, command) return else: implant = get_implantbyid(implant_id) if not implant: print_bad("Unrecognised implant id or command: %s" % implant_id) input("Press Enter to continue...") clear() return prompt_commands = POSH_COMMANDS if implant.Pivot.startswith('Python'): prompt_commands = PY_COMMANDS if implant.Pivot.startswith('C#'): prompt_commands = SHARP_COMMANDS if 'PB' in implant.Pivot: style = Style.from_dict({ '': '#008ECC', }) session = PromptSession( history=FileHistory('%s/.implant-history' % PoshProjectDirectory), auto_suggest=AutoSuggestFromHistory(), style=style) prompt_commands = SHARP_COMMANDS print(Colours.BLUE) else: print(Colours.GREEN) print("%s\\%s @ %s (PID:%s)" % (implant.Domain, implant.User, implant.Hostname, implant.PID)) command = session.prompt( "%s %s> " % (get_implant_type_prompt_prefix(implant_id), implant_id), completer=FirstWordFuzzyWordCompleter(prompt_commands, WORD=True)) if command == "back" or command == 'clear': do_back(user, command) return # if "all" run through all implants get_implants() if implant_id == "all": if command == "back" or command == 'clear': do_back(user, command) return allcommands = command if "\n" in command: ri = input( "Do you want to run commands separately? (Y/n) ") implants_split = get_implants() if implants_split: for implant_details in implants_split: # if "\n" in command run each command individually or ask the question if that's what they want to do if "\n" in allcommands: if ri.lower() == "y" or ri == "": commands = allcommands.split('\n') for command in commands: run_implant_command( command, implant_details.RandomURI, implant_id_orig, user) else: run_implant_command(command, implant_details.RandomURI, implant_id_orig, user) else: run_implant_command(command, implant_details.RandomURI, implant_id_orig, user) # if "separated list" against single uri elif "," in implant_id: allcommands = command if "\n" in command: ri = input( "Do you want to run commands separately? (Y/n) ") implant_split = implant_id.split(",") for split_implant_id in implant_split: implant_randomuri = get_randomuri(split_implant_id) # if "\n" in command run each command individually or ask the question if that's what they want to do if "\n" in allcommands: if ri.lower() == "y" or ri == "": commands = allcommands.split('\n') for command in commands: run_implant_command(command, implant_randomuri, implant_id_orig, user) else: run_implant_command(command, implant_randomuri, implant_id_orig, user) else: run_implant_command(command, implant_randomuri, implant_id_orig, user) # if "range" against single uri elif "-" in implant_id: allcommands = command if "\n" in command: ri = input( "Do you want to run commands separately? (Y/n) ") implant_split = implant_id.split("-") for range_implant_id in range(int(implant_split[0]), int(implant_split[1]) + 1): try: implant_randomuri = get_randomuri(range_implant_id) # if "\n" in command run each command individually or ask the question if that's what they want to do if "\n" in allcommands: if ri.lower() == "y" or ri == "": commands = allcommands.split('\n') for command in commands: run_implant_command( command, implant_randomuri, implant_id_orig, user) else: run_implant_command(command, implant_randomuri, implant_id_orig, user) else: run_implant_command(command, implant_randomuri, implant_id_orig, user) except Exception: print_bad("Unknown ImplantID") # else run against single uri else: allcommands = command if "\n" in command: ri = input( "Do you want to run commands separately? (Y/n) ") implant_randomuri = get_randomuri(implant_id) # if "\n" in command run each command individually or ask the question if that's what they want to do if "\n" in allcommands: if ri.lower() == "y" or ri == "": commands = allcommands.split('\n') for command in commands: run_implant_command(command, implant_randomuri, implant_id_orig, user) else: run_implant_command(command, implant_randomuri, implant_id_orig, user) else: run_implant_command(command, implant_randomuri, implant_id_orig, user) except KeyboardInterrupt: continue except EOFError: new_c2_message("%s logged off." % user) sys.exit(0) except Exception as e: traceback.print_exc() print_bad( f"Error running against the selected implant ID, ensure you have typed the correct information: {e}" ) return
def implant_handler_command_loop(user, printhelp="", autohide=None): while (True): session = PromptSession(history=FileHistory('%s/.top-history' % PoshProjectDirectory), auto_suggest=AutoSuggestFromHistory()) try: if user is not None: print("User: "******"%s%s" % (user, Colours.GREEN)) print() C2 = get_c2server_all() killdate = datetime.strptime(C2.KillDate, '%Y-%m-%d').date() datedifference = number_of_days(date.today(), killdate) if datedifference < 8: print(Colours.RED + ("\nKill Date is - %s - expires in %s days" % (C2.KillDate, datedifference))) print(Colours.END) print() implants = get_implants() if implants: for implant in implants: ID = implant.ImplantID LastSeen = implant.LastSeen Hostname = implant.Hostname Domain = implant.Domain URLID = implant.URLID DomainUser = implant.User Arch = implant.Arch PID = implant.PID Pivot = implant.Pivot Sleep = implant.Sleep.strip() Label = implant.Label apmsuspendshut = False pwrStatus = get_powerstatusbyrandomuri(implant.RandomURI) if pwrStatus is not None: if Label is not None: Label += " " else: Label = "" apmstatus = pwrStatus[2].lower() if (apmstatus == "shutdown"): Label += "SHTDWN " apmsuspendshut = True elif (apmstatus == "suspend" or apmstatus == "querysuspend"): Label += "SUSPND " apmsuspendshut = True if not apmsuspendshut: if (pwrStatus[7]): Label += "LOCKED " if (not pwrStatus[8]): Label += "SCRN OFF " if (not pwrStatus[3]): if (pwrStatus[6] is not None and pwrStatus[6].isdigit()): Label += ("DSCHRG: %s%% " % pwrStatus[6]) else: Label += ("DSCHRG ") Pivot = get_implant_type_prompt_prefix(ID) LastSeenTime = datetime.strptime(LastSeen, "%Y-%m-%d %H:%M:%S") LastSeenTimeString = datetime.strftime( LastSeenTime, "%Y-%m-%d %H:%M:%S") now = datetime.now() if (Sleep.endswith('s')): sleep_int = int(Sleep[:-1]) elif (Sleep.endswith('m')): sleep_int = int(Sleep[:-1]) * 60 elif (Sleep.endswith('h')): sleep_int = int(Sleep[:-1]) * 60 * 60 else: print(Colours.RED) print("Incorrect sleep format: %s" % Sleep) print(Colours.GREEN) continue nowMinus3Beacons = now - timedelta(seconds=(sleep_int * 3)) nowMinus10Beacons = now - timedelta(seconds=(sleep_int * 10)) nowMinus30Beacons = now - timedelta(seconds=(sleep_int * 30)) sID = "[" + str(ID) + "]" if not Label: sLabel = "" else: Label = Label.strip() sLabel = Colours.BLUE + "[" + Label + "]" + Colours.GREEN if "C#;PB" in Pivot: print( Colours.BLUE + "%s: Seen:%s | PID:%s | %s | PBind | %s\\%s @ %s (%s) %s %s" % (sID.ljust(4), LastSeenTimeString, PID.ljust(5), Sleep, Domain, DomainUser, Hostname, Arch, Pivot, sLabel)) elif nowMinus30Beacons > LastSeenTime and autohide: pass elif nowMinus10Beacons > LastSeenTime: print( Colours.RED + "%s: Seen:%s | PID:%s | %s | URLID: %s | %s\\%s @ %s (%s) %s %s" % (sID.ljust(4), LastSeenTimeString, PID.ljust(5), Sleep, URLID, Domain, DomainUser, Hostname, Arch, Pivot, sLabel)) elif nowMinus3Beacons > LastSeenTime: print( Colours.YELLOW + "%s: Seen:%s | PID:%s | %s | URLID: %s | %s\\%s @ %s (%s) %s %s" % (sID.ljust(4), LastSeenTimeString, PID.ljust(5), Sleep, URLID, Domain, DomainUser, Hostname, Arch, Pivot, sLabel)) else: print( Colours.GREEN + "%s: Seen:%s | PID:%s | %s | URLID: %s | %s\\%s @ %s (%s) %s %s" % (sID.ljust(4), LastSeenTimeString, PID.ljust(5), Sleep, URLID, Domain, DomainUser, Hostname, Arch, Pivot, sLabel)) else: now = datetime.now() print(Colours.RED + "No Implants as of: %s" % now.strftime("%Y-%m-%d %H:%M:%S")) if printhelp: print(printhelp) command = session.prompt( "\nSelect ImplantID or ALL or Comma Separated List (Enter to refresh):: ", completer=FirstWordFuzzyWordCompleter(SERVER_COMMANDS, WORD=True)) print("") command = command.strip() if (command == "") or (command == "back") or (command == "clear"): do_back(user, command) continue if command.startswith("generate-reports"): do_generate_reports(user, command) continue if command.startswith("generate-csvs"): do_generate_csvs(user, command) continue if command.startswith("message "): do_message(user, command) continue if command.startswith("show-hosted-files"): do_show_hosted_files(user, command) continue if command.startswith("add-hosted-file"): do_add_hosted_file(user, command) continue if command.startswith("disable-hosted-file"): do_disable_hosted_file(user, command) continue if command.startswith("enable-hosted-file"): do_enable_hosted_file(user, command) continue if command.startswith("show-urls") or command.startswith( "list-urls"): do_show_urls(user, command) continue if command.startswith("add-autorun"): do_add_autorun(user, command) continue if command.startswith("list-autorun"): do_list_autoruns(user, command) continue if command.startswith("del-autorun"): do_del_autorun(user, command) continue if command.startswith("nuke-autorun"): do_nuke_autoruns(user, command) continue if command.startswith("kill"): do_del_task(user, command) continue if command.startswith("show-serverinfo"): do_show_serverinfo(user, command) continue if command.startswith("turnoff-notifications"): do_turnoff_notifications(user, command) continue if command.startswith("turnon-notifications"): do_turnon_notifications(user, command) continue if command.startswith("set-pushover-applicationtoken"): do_set_pushover_applicationtoken(user, command) continue if command.startswith("set-pushover-userkeys"): do_set_pushover_userkeys(user, command) continue if command.startswith("get-killdate"): do_get_killdate(user, command) continue if command.startswith("set-killdate"): do_set_killdate(user, command) continue if command.startswith("set-defaultbeacon"): do_set_defaultbeacon(user, command) continue if command == "get-opsec-events": do_get_opsec_events(user, command) continue if command == "add-opsec-event": do_insert_opsec_events(user, command) continue if command == "del-opsec-event": do_del_opsec_events(user, command) continue if command.startswith("opsec"): do_opsec(user, command) continue if command.startswith("listmodules"): do_listmodules(user, command) continue if command.startswith('creds ') or command.strip() == "creds": do_creds(user, command) input("Press Enter to continue...") clear() continue if (command == "pwnself") or (command == "p"): do_pwnself(user, command) continue if command == "tasks": do_tasks(user, command) continue if command == "cleartasks": do_cleartasks(user, command) continue if command.startswith("quit"): do_quit(user, command) continue if command.startswith("createdaisypayload"): do_createdaisypayload(user, command) continue if command.startswith("createproxypayload"): do_createnewpayload(user, command) continue if command.startswith("createnewpayload"): do_createnewpayload(user, command) continue if command.startswith("createnewshellcode"): do_createnewpayload(user, command, shellcodeOnly=True) continue if command == "help": do_help(user, command) continue if command == "history": do_history(user, command) continue if command.startswith("use "): do_use(user, command) implant_command_loop(command, user) except KeyboardInterrupt: clear() continue except EOFError: new_c2_message("%s logged off." % user) sys.exit(0) except Exception as e: if 'unable to open database file' not in str(e): print_bad("Error: %s" % e) traceback.print_exc()
def reset_history(self): history_file_path = os.path.join(self.config.get_config_dir(), self.config.get_history()) os.remove(history_file_path) self.history = FileHistory(history_file_path) self.cli.buffers[DEFAULT_BUFFER].history = self.history
def cli(spec, env, url, http_options): click.echo('Version: %s' % __version__) copied, config_path = config.initialize() if copied: click.echo('Config file not found. Initialized a new one: %s' % config_path) cfg = config.load() # Override pager/less options os.environ['PAGER'] = cfg['pager'] os.environ['LESS'] = '-RXF' if spec: f = urlopen(spec) try: content = f.read().decode('utf-8') try: spec = json.loads(content) except json.JSONDecodeError: try: spec = yaml.load(content) except yaml.YAMLError: click.secho( "Warning: Specification file '%s' is neither valid JSON nor YAML" % spec, err=True, fg='red') spec = None finally: f.close() if url: url = fix_incomplete_url(url) context = Context(url, spec=spec) output_style = cfg.get('output_style') if output_style: context.options['--style'] = output_style # For prompt-toolkit history = FileHistory(os.path.join(get_data_dir(), 'history')) lexer = PygmentsLexer(HttpPromptLexer) completer = HttpPromptCompleter(context) try: style_class = get_style_by_name(cfg['command_style']) except ClassNotFound: style_class = Solarized256Style style = style_from_pygments(style_class) listener = ExecutionListener(cfg) if len(sys.argv) == 1: # load previous context if nothing defined load_context(context) else: if env: load_context(context, env) if url: # Overwrite the env url if not default context.url = url if http_options: # Execute HTTPie options from CLI (can overwrite env file values) http_options = [smart_quote(a) for a in http_options] execute(' '.join(http_options), context, listener=listener) while True: try: text = prompt('%s> ' % context.url, completer=completer, lexer=lexer, style=style, history=history, auto_suggest=AutoSuggestFromHistory(), on_abort=AbortAction.RETRY, vi_mode=cfg['vi']) except EOFError: break # Control-D pressed else: execute(text, context, listener=listener, style=style_class) if context.should_exit: break click.echo("Goodbye!")
text = document.text if text.startswith('\\'): return job_config = bigquery.QueryJobConfig(dry_run=True, use_query_cache=False) try: self.client.query(document.text, job_config=job_config) except Exception as e: error = e.errors[0] raise ValidationError(message=error['message'], cursor_position=0) session = PromptSession(lexer=PygmentsLexer(SqlLexer), history=FileHistory(config.history_path), key_bindings=kb, completer=sql_completer, style=style, validate_while_typing=False, validator=SqlValidator(client)) @click.group() def cli(): pass while True: try: text = session.prompt('> ', multiline=True)
def prompt_search_tags(prompt_text): r""" Do an interactive prompt search in the Bibmanager database by the given keywords, with auto-complete and auto-suggest only offering non-None values of the given field. Only one keyword must be set in the prompt. A bottom toolbar dynamically shows additional info. Parameters ---------- prompt_text: String Text to display when launching the prompt. Returns ------- kw_input: List of strings List of the parsed input (same order as keywords). Items are None for the keywords not defined. """ bibs = load() bibkeys = [bib.key for bib in bibs] bibcodes = [bib.bibcode for bib in bibs if bib.bibcode is not None] tags = sorted( set( itertools.chain( *[bib.tags for bib in bibs if bib.tags is not None]))) entries = bibkeys + bibcodes key_words = { '': entries, 'tags:': tags, } completer = u.LastKeyCompleter(key_words) suggester = u.LastKeySuggestCompleter() validator = u.AlwaysPassValidator( bibs, toolbar_text="(Press 'tab' for autocomplete)") session = prompt_toolkit.PromptSession( history=FileHistory(u.BM_HISTORY_TAGS())) inputs = session.prompt( prompt_text, auto_suggest=suggester, completer=completer, complete_while_typing=False, validator=validator, validate_while_typing=True, bottom_toolbar=validator.bottom_toolbar, ) text = inputs.replace(' tags:', ' tags: ') if text.startswith('tags:'): text = 'tags: ' + text[5:] input_strings = text.split() if 'tags:' not in input_strings: tag_index = len(input_strings) else: tag_index = input_strings.index('tags:') entries = input_strings[0:tag_index] tags = input_strings[tag_index + 1:] # Translate bibcodes to keys and keep only valid keys: keys = [ find(bibcode=entry).key if entry in bibcodes else entry for entry in entries ] keys = [key for key in keys if key in bibkeys] return keys, tags
import io import json from prompt_toolkit.history import FileHistory import splitwise from bidi.algorithm import get_display from prompt_toolkit import print_formatted_text, HTML, PromptSession import config import utils from splitwise import Expense _ = utils.load_translation() session = PromptSession(history=FileHistory('storePromptHistory.hist')) categories = [ 'Electronic maintenance', 'Plumbing', 'Deck', 'Sails', 'Engine', 'General maintenance', 'Electricity', 'Berth', 'Dry dock', 'House', 'Registration', 'Insurance', 'Electronics', 'Safety', 'Fuel (domestic)', 'Other' ] def create_details_json(remarks, category, store, upgrade): ret = { 'remarks': remarks, 'category': category, 'store': store, 'is_boat_upgrade': upgrade }
# !/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'bit4' __github__ = 'https://github.com/bit4woo' from prompt_toolkit import prompt from prompt_toolkit.history import FileHistory from prompt_toolkit.auto_suggest import AutoSuggestFromHistory from prompt_toolkit.contrib.completers import WordCompleter import click SQLCompleter = WordCompleter( ['select', 'from', 'insert', 'update', 'delete', 'drop'], ignore_case=True) while 1: user_input = prompt( u'SQL>', history=FileHistory('history.txt'), auto_suggest=AutoSuggestFromHistory(), completer=SQLCompleter, ) click.echo_via_pager(user_input)
def run_cli(self): iterations = 0 sqlexecute = self.sqlexecute logger = self.logger self.configure_pager() self.refresh_completions() history_file = config_location() + "history" if dir_path_exists(history_file): history = FileHistory(history_file) else: history = None self.echo( 'Error: Unable to open the history file "{}". ' "Your query history will not be saved.".format(history_file), err=True, fg="red", ) key_bindings = cli_bindings(self) if not self.less_chatty: print("Version:", __version__) print( "Mail: https://groups.google.com/forum/#!forum/litecli-users") print("Github: https://github.com/dbcli/litecli") # print("Home: https://litecli.com") def get_message(): prompt = self.get_prompt(self.prompt_format) if (self.prompt_format == self.default_prompt and len(prompt) > self.max_len_prompt): prompt = self.get_prompt("\\d> ") return [("class:prompt", prompt)] def get_continuation(width, line_number, is_soft_wrap): continuation = " " * (width - 1) + " " return [("class:continuation", continuation)] def show_suggestion_tip(): return iterations < 2 def one_iteration(text=None): if text is None: try: text = self.prompt_app.prompt() except KeyboardInterrupt: return special.set_expanded_output(False) try: text = self.handle_editor_command(text) except RuntimeError as e: logger.error("sql: %r, error: %r", text, e) logger.error("traceback: %r", traceback.format_exc()) self.echo(str(e), err=True, fg="red") return if not text.strip(): return if self.destructive_warning: destroy = confirm_destructive_query(text) if destroy is None: pass # Query was not destructive. Nothing to do here. elif destroy is True: self.echo("Your call!") else: self.echo("Wise choice!") return # Keep track of whether or not the query is mutating. In case # of a multi-statement query, the overall query is considered # mutating if any one of the component statements is mutating mutating = False try: logger.debug("sql: %r", text) special.write_tee(self.get_prompt(self.prompt_format) + text) if self.logfile: self.logfile.write("\n# %s\n" % datetime.now()) self.logfile.write(text) self.logfile.write("\n") successful = False start = time() res = sqlexecute.run(text) self.formatter.query = text successful = True result_count = 0 for title, cur, headers, status in res: logger.debug("headers: %r", headers) logger.debug("rows: %r", cur) logger.debug("status: %r", status) threshold = 1000 if is_select(status) and cur and cur.rowcount > threshold: self.echo( "The result set has more than {} rows.".format( threshold), fg="red", ) if not confirm("Do you want to continue?"): self.echo("Aborted!", err=True, fg="red") break if self.auto_vertical_output: max_width = self.prompt_app.output.get_size().columns else: max_width = None formatted = self.format_output( title, cur, headers, special.is_expanded_output(), max_width) t = time() - start try: if result_count > 0: self.echo("") try: self.output(formatted, status) except KeyboardInterrupt: pass self.echo("Time: %0.03fs" % t) except KeyboardInterrupt: pass start = time() result_count += 1 mutating = mutating or is_mutating(status) special.unset_once_if_written() except EOFError as e: raise e except KeyboardInterrupt: # get last connection id connection_id_to_kill = sqlexecute.connection_id logger.debug("connection id to kill: %r", connection_id_to_kill) # Restart connection to the database sqlexecute.connect() try: for title, cur, headers, status in sqlexecute.run( "kill %s" % connection_id_to_kill): status_str = str(status).lower() if status_str.find("ok") > -1: logger.debug( "cancelled query, connection id: %r, sql: %r", connection_id_to_kill, text, ) self.echo("cancelled query", err=True, fg="red") except Exception as e: self.echo( "Encountered error while cancelling query: {}".format( e), err=True, fg="red", ) except NotImplementedError: self.echo("Not Yet Implemented.", fg="yellow") except OperationalError as e: logger.debug("Exception: %r", e) if e.args[0] in (2003, 2006, 2013): logger.debug("Attempting to reconnect.") self.echo("Reconnecting...", fg="yellow") try: sqlexecute.connect() logger.debug("Reconnected successfully.") one_iteration(text) return # OK to just return, cuz the recursion call runs to the end. except OperationalError as e: logger.debug("Reconnect failed. e: %r", e) self.echo(str(e), err=True, fg="red") # If reconnection failed, don't proceed further. return else: logger.error("sql: %r, error: %r", text, e) logger.error("traceback: %r", traceback.format_exc()) self.echo(str(e), err=True, fg="red") except Exception as e: logger.error("sql: %r, error: %r", text, e) logger.error("traceback: %r", traceback.format_exc()) self.echo(str(e), err=True, fg="red") else: if is_dropping_database(text, self.sqlexecute.dbname): self.sqlexecute.dbname = None self.sqlexecute.connect() # Refresh the table names and column names if necessary. if need_completion_refresh(text): self.refresh_completions(reset=need_completion_reset(text)) finally: if self.logfile is False: self.echo("Warning: This query was not logged.", err=True, fg="red") query = Query(text, successful, mutating) self.query_history.append(query) get_toolbar_tokens = create_toolbar_tokens_func( self, show_suggestion_tip) if self.wider_completion_menu: complete_style = CompleteStyle.MULTI_COLUMN else: complete_style = CompleteStyle.COLUMN with self._completer_lock: if self.key_bindings == "vi": editing_mode = EditingMode.VI else: editing_mode = EditingMode.EMACS self.prompt_app = PromptSession( lexer=PygmentsLexer(LiteCliLexer), reserve_space_for_menu=self.get_reserved_space(), message=get_message, prompt_continuation=get_continuation, bottom_toolbar=get_toolbar_tokens, complete_style=complete_style, input_processors=[ ConditionalProcessor( processor=HighlightMatchingBracketProcessor( chars="[](){}"), filter=HasFocus(DEFAULT_BUFFER) & ~IsDone(), ) ], tempfile_suffix=".sql", completer=DynamicCompleter(lambda: self.completer), history=history, auto_suggest=AutoSuggestFromHistory(), complete_while_typing=True, multiline=cli_is_multiline(self), style=style_factory(self.syntax_style, self.cli_style), include_default_pygments_style=False, key_bindings=key_bindings, enable_open_in_editor=True, enable_system_prompt=True, enable_suspend=True, editing_mode=editing_mode, search_ignore_case=True, ) try: while True: one_iteration() iterations += 1 except EOFError: special.close_tee() if not self.less_chatty: self.echo("Goodbye!")
def __init__( self, get_globals=None, get_locals=None, stdin=None, stdout=None, vi_mode=False, history_filename=None, style=PythonStyle, autocompletion_style=AutoCompletionStyle.POPUP_MENU, always_multiline=False, # For internal use. _completer=None, _validator=None): self.get_globals = get_globals or (lambda: {}) self.get_locals = get_locals or self.get_globals self.always_multiline = always_multiline self.autocompletion_style = autocompletion_style self.completer = _completer or PythonCompleter(self.get_globals, self.get_locals) validator = _validator or PythonValidator() layout = Layout( input_processors=[BracketsMismatchProcessor()], min_height=7, lexer=PythonLexer, left_margin=PythonLeftMargin(), menus=[CompletionsMenu()] if autocompletion_style == AutoCompletionStyle.POPUP_MENU else [], bottom_toolbars=[ ArgToolbar(), SignatureToolbar(), SearchToolbar(), SystemToolbar(), ValidationToolbar(), ] + ([CompletionsToolbar()] if autocompletion_style == AutoCompletionStyle.HORIZONTAL_MENU else []) + [ PythonToolbar(vi_mode=vi_mode), ], show_tildes=True) if history_filename: history = FileHistory(history_filename) else: history = History() if vi_mode: key_binding_factories = [vi_bindings, python_bindings] else: key_binding_factories = [emacs_bindings, python_bindings] line = PythonLine(always_multiline=always_multiline, tempfile_suffix='.py', history=history, completer=self.completer, validator=validator) #: Incremeting integer counting the current statement. self.current_statement_index = 1 self.get_signatures_thread_running = False super(PythonCommandLineInterface, self).__init__(layout=layout, style=style, key_binding_factories=key_binding_factories, line=line, create_async_autocompleters=True) def on_input_timeout(): """ When there is no input activity, in another thread, get the signature of the current code. """ # Never run multiple get-signature threads. if self.get_signatures_thread_running: return self.get_signatures_thread_running = True document = self.line.document def run(): script = get_jedi_script_from_document(document, self.get_locals(), self.get_globals()) # Show signatures in help text. if script: try: signatures = script.call_signatures() except ValueError: # e.g. in case of an invalid \\x escape. signatures = [] except Exception: # Sometimes we still get an exception (TypeError), because # of probably bugs in jedi. We can silence them. # See: https://github.com/davidhalter/jedi/issues/492 signatures = [] else: signatures = [] self.get_signatures_thread_running = False # Set signatures and redraw if the text didn't change in the # meantime. Otherwise request new signatures. if self.line.text == document.text: self.line.signatures = signatures self.request_redraw() else: on_input_timeout() self.run_in_executor(run) self.onInputTimeout += on_input_timeout
def run_cli(self): iterations = 0 sqlexecute = self.sqlexecute logger = self.logger self.configure_pager() if self.smart_completion: self.refresh_completions() author_file = os.path.join(PACKAGE_ROOT, 'AUTHORS') sponsor_file = os.path.join(PACKAGE_ROOT, 'SPONSORS') key_binding_manager = mycli_bindings() if not self.less_chatty: print('Version:', __version__) print('Chat: https://gitter.im/dbcli/mycli') print('Mail: https://groups.google.com/forum/#!forum/mycli-users') print('Home: http://mycli.net') print('Thanks to the contributor -', thanks_picker([author_file, sponsor_file])) def prompt_tokens(cli): prompt = self.get_prompt(self.prompt_format) if self.prompt_format == self.default_prompt and len( prompt) > self.max_len_prompt: prompt = self.get_prompt('\\d> ') return [(Token.Prompt, prompt)] def get_continuation_tokens(cli, width): continuation_prompt = self.get_prompt( self.prompt_continuation_format) return [(Token.Continuation, ' ' * (width - len(continuation_prompt)) + continuation_prompt)] def show_suggestion_tip(): return iterations < 2 def one_iteration(document=None): if document is None: document = self.cli.run() special.set_expanded_output(False) try: document = self.handle_editor_command(self.cli, document) except RuntimeError as e: logger.error("sql: %r, error: %r", document.text, e) logger.error("traceback: %r", traceback.format_exc()) self.echo(str(e), err=True, fg='red') return if not document.text.strip(): return if self.destructive_warning: destroy = confirm_destructive_query(document.text) if destroy is None: pass # Query was not destructive. Nothing to do here. elif destroy is True: self.echo('Your call!') else: self.echo('Wise choice!') return # Keep track of whether or not the query is mutating. In case # of a multi-statement query, the overall query is considered # mutating if any one of the component statements is mutating mutating = False try: logger.debug('sql: %r', document.text) special.write_tee( self.get_prompt(self.prompt_format) + document.text) if self.logfile: self.logfile.write('\n# %s\n' % datetime.now()) self.logfile.write(document.text) self.logfile.write('\n') successful = False start = time() res = sqlexecute.run(document.text) successful = True result_count = 0 for title, cur, headers, status in res: logger.debug("headers: %r", headers) logger.debug("rows: %r", cur) logger.debug("status: %r", status) threshold = 1000 if (is_select(status) and cur and cur.rowcount > threshold): self.echo( 'The result set has more than {} rows.'.format( threshold), fg='red') if not click.confirm('Do you want to continue?'): self.echo("Aborted!", err=True, fg='red') break if self.auto_vertical_output: max_width = self.cli.output.get_size().columns else: max_width = None formatted = self.format_output( title, cur, headers, special.is_expanded_output(), max_width) t = time() - start try: if result_count > 0: self.echo('') try: self.output('\n'.join(formatted), status) except KeyboardInterrupt: pass if special.is_timing_enabled(): self.echo('Time: %0.03fs' % t) except KeyboardInterrupt: pass start = time() result_count += 1 mutating = mutating or is_mutating(status) special.unset_once_if_written() except EOFError as e: raise e except KeyboardInterrupt: # get last connection id connection_id_to_kill = sqlexecute.connection_id logger.debug("connection id to kill: %r", connection_id_to_kill) # Restart connection to the database sqlexecute.connect() try: for title, cur, headers, status in sqlexecute.run( 'kill %s' % connection_id_to_kill): status_str = str(status).lower() if status_str.find('ok') > -1: logger.debug( "cancelled query, connection id: %r, sql: %r", connection_id_to_kill, document.text) self.echo("cancelled query", err=True, fg='red') except Exception as e: self.echo( 'Encountered error while cancelling query: {}'.format( e), err=True, fg='red') except NotImplementedError: self.echo('Not Yet Implemented.', fg="yellow") except OperationalError as e: logger.debug("Exception: %r", e) if (e.args[0] in (2003, 2006, 2013)): logger.debug('Attempting to reconnect.') self.echo('Reconnecting...', fg='yellow') try: sqlexecute.connect() logger.debug('Reconnected successfully.') one_iteration(document) return # OK to just return, cuz the recursion call runs to the end. except OperationalError as e: logger.debug('Reconnect failed. e: %r', e) self.echo(str(e), err=True, fg='red') # If reconnection failed, don't proceed further. return else: logger.error("sql: %r, error: %r", document.text, e) logger.error("traceback: %r", traceback.format_exc()) self.echo(str(e), err=True, fg='red') except Exception as e: logger.error("sql: %r, error: %r", document.text, e) logger.error("traceback: %r", traceback.format_exc()) self.echo(str(e), err=True, fg='red') else: if is_dropping_database(document.text, self.sqlexecute.dbname): self.sqlexecute.dbname = None self.sqlexecute.connect() # Refresh the table names and column names if necessary. if need_completion_refresh(document.text): self.refresh_completions( reset=need_completion_reset(document.text)) finally: if self.logfile is False: self.echo("Warning: This query was not logged.", err=True, fg='red') query = Query(document.text, successful, mutating) self.query_history.append(query) get_toolbar_tokens = create_toolbar_tokens_func( self.completion_refresher.is_refreshing, show_suggestion_tip) layout = create_prompt_layout( lexer=MyCliLexer, multiline=True, get_prompt_tokens=prompt_tokens, get_continuation_tokens=get_continuation_tokens, get_bottom_toolbar_tokens=get_toolbar_tokens, display_completions_in_columns=self.wider_completion_menu, extra_input_processors=[ ConditionalProcessor( processor=HighlightMatchingBracketProcessor( chars='[](){}'), filter=HasFocus(DEFAULT_BUFFER) & ~IsDone()) ], reserve_space_for_menu=self.get_reserved_space()) with self._completer_lock: buf = CLIBuffer(always_multiline=self.multi_line, completer=self.completer, history=FileHistory( os.path.expanduser( os.environ.get('MYCLI_HISTFILE', '~/.mycli-history'))), auto_suggest=AutoSuggestFromHistory(), complete_while_typing=Always(), accept_action=AcceptAction.RETURN_DOCUMENT) if self.key_bindings == 'vi': editing_mode = EditingMode.VI else: editing_mode = EditingMode.EMACS application = Application( style=style_from_pygments(style_cls=self.output_style), layout=layout, buffer=buf, key_bindings_registry=key_binding_manager.registry, on_exit=AbortAction.RAISE_EXCEPTION, on_abort=AbortAction.RETRY, editing_mode=editing_mode, ignore_case=True) self.cli = CommandLineInterface(application=application, eventloop=create_eventloop()) try: while True: one_iteration() iterations += 1 except EOFError: special.close_tee() if not self.less_chatty: self.echo('Goodbye!')
def __init__( self, get_globals: Optional[_GetNamespace] = None, get_locals: Optional[_GetNamespace] = None, history_filename: Optional[str] = None, vi_mode: bool = False, color_depth: Optional[ColorDepth] = None, # Input/output. input: Optional[Input] = None, output: Optional[Output] = None, # For internal use. extra_key_bindings: Optional[KeyBindings] = None, _completer: Optional[Completer] = None, _validator: Optional[Validator] = None, _lexer: Optional[Lexer] = None, _extra_buffer_processors=None, _extra_layout_body=None, _extra_toolbars=None, _input_buffer_height=None, ) -> None: self.get_globals: _GetNamespace = get_globals or (lambda: {}) self.get_locals: _GetNamespace = get_locals or self.get_globals self._completer = _completer or FuzzyCompleter( PythonCompleter( self.get_globals, self.get_locals, lambda: self.enable_dictionary_completion, ), enable_fuzzy=Condition(lambda: self.enable_fuzzy_completion), ) self._validator = _validator or PythonValidator( self.get_compiler_flags) self._lexer = _lexer or PygmentsLexer(PythonLexer) self.history: History if history_filename: self.history = ThreadedHistory(FileHistory(history_filename)) else: self.history = InMemoryHistory() self._input_buffer_height = _input_buffer_height self._extra_layout_body = _extra_layout_body or [] self._extra_toolbars = _extra_toolbars or [] self._extra_buffer_processors = _extra_buffer_processors or [] self.extra_key_bindings = extra_key_bindings or KeyBindings() # Settings. self.title: AnyFormattedText = "" self.show_signature: bool = False self.show_docstring: bool = False self.show_meta_enter_message: bool = True self.completion_visualisation: CompletionVisualisation = CompletionVisualisation.MULTI_COLUMN self.completion_menu_scroll_offset: int = 1 self.show_line_numbers: bool = False self.show_status_bar: bool = True self.wrap_lines: bool = True self.complete_while_typing: bool = True self.paste_mode: bool = False # When True, don't insert whitespace after newline. self.confirm_exit: bool = True # Ask for confirmation when Control-D is pressed. self.accept_input_on_enter: int = 2 # Accept when pressing Enter 'n' times. # 'None' means that meta-enter is always required. self.enable_open_in_editor: bool = True self.enable_system_bindings: bool = True self.enable_input_validation: bool = True self.enable_auto_suggest: bool = False self.enable_mouse_support: bool = False self.enable_history_search: bool = False # When True, like readline, going # back in history will filter the # history on the records starting # with the current input. self.enable_syntax_highlighting: bool = True self.enable_fuzzy_completion: bool = False self.enable_dictionary_completion: bool = False self.swap_light_and_dark: bool = False self.highlight_matching_parenthesis: bool = False self.show_sidebar: bool = False # Currently show the sidebar. # When the sidebar is visible, also show the help text. self.show_sidebar_help: bool = True # Currently show 'Do you really want to exit?' self.show_exit_confirmation: bool = False # The title to be displayed in the terminal. (None or string.) self.terminal_title: Optional[str] = None self.exit_message: str = "Do you really want to exit?" self.insert_blank_line_after_output: bool = True # (For the REPL.) # The buffers. self.default_buffer = self._create_buffer() self.search_buffer: Buffer = Buffer() self.docstring_buffer: Buffer = Buffer(read_only=True) # Tokens to be shown at the prompt. self.prompt_style: str = "classic" # The currently active style. # Styles selectable from the menu. self.all_prompt_styles: Dict[str, PromptStyle] = { "ipython": IPythonPrompt(self), "classic": ClassicPrompt(), } self.get_input_prompt = lambda: self.all_prompt_styles[ self.prompt_style].in_prompt() self.get_output_prompt = lambda: self.all_prompt_styles[ self.prompt_style].out_prompt() #: Load styles. self.code_styles: Dict[str, BaseStyle] = get_all_code_styles() self.ui_styles = get_all_ui_styles() self._current_code_style_name: str = "default" self._current_ui_style_name: str = "default" if is_windows(): self._current_code_style_name = "win32" self._current_style = self._generate_style() self.color_depth: ColorDepth = color_depth or ColorDepth.default() self.max_brightness: float = 1.0 self.min_brightness: float = 0.0 # Options to be configurable from the sidebar. self.options = self._create_options() self.selected_option_index: int = 0 #: Incremeting integer counting the current statement. self.current_statement_index: int = 1 # Code signatures. (This is set asynchronously after a timeout.) self.signatures: List[Any] = [] # Boolean indicating whether we have a signatures thread running. # (Never run more than one at the same time.) self._get_signatures_thread_running: bool = False self.style_transformation = merge_style_transformations([ ConditionalStyleTransformation( SwapLightAndDarkStyleTransformation(), filter=Condition(lambda: self.swap_light_and_dark), ), AdjustBrightnessStyleTransformation(lambda: self.min_brightness, lambda: self.max_brightness), ]) self.ptpython_layout = PtPythonLayout( self, lexer=DynamicLexer(lambda: self._lexer if self. enable_syntax_highlighting else SimpleLexer()), input_buffer_height=self._input_buffer_height, extra_buffer_processors=self._extra_buffer_processors, extra_body=self._extra_layout_body, extra_toolbars=self._extra_toolbars, ) self.app = self._create_application(input, output) if vi_mode: self.app.editing_mode = EditingMode.VI
async def prompt_loop(cluster): output = __DEFAULT_OUTPUT connections = await cluster.connect() if None not in connections: logging.error('Could not setup a connection') await stop(cluster) return completer = SiriCompleter() try: path = os.path.join(os.path.expanduser('~'), '.siridb-prompt') if not os.path.isdir(path): os.mkdir(path) history_file = os.path.join( path, '{}@{}.history'.format(cluster._username, cluster._dbname)) history = FileHistory(history_file) except Exception as e: history = InMemoryHistory() try: result = await cluster.query('show time_precision, version', timeout=5) writer.time_precision = result['data'][0]['value'] version = result['data'][1]['value'] if tuple(map(int, version.split('.')[:2])) != __version_info__[:2]: logging.warning('SiriDB Prompt is version is version {} while at ' 'least one server your connecting to is running ' 'version {}. This is not necessary a problem but ' 'we recommend using the same version.'.format( __version__, version)) except Exception as e: logging.warning('Could not read the version and time precision, ' 'timestamps will not be formatted and we are not sure ' 'if the database is running a correct version. ' '(reason: {})'.format(e)) sys.stdout.write('\x1b]2;{}@{}\x07'.format(cluster._username, cluster._dbname)) while True: force_exit.clear() method = cluster.query inp = await prompt_async('{}@{}> '.format(cluster._username, cluster._dbname), patch_stdout=True, key_bindings_registry=manager.registry, history=history, completer=completer) inp = inp.strip() if inp == 'exit': break if get_history(inp, history): continue if inp == 'clear': clear_history(history) print('History is cleared.\n') continue if inp == 'connections': writer.output_connections(cluster) continue if inp == 'get_output': print('{}\n'.format(output)) continue if inp == 'get_loglevel': print('{}\n'.format( logging._levelToName[logging.getLogger().level])) continue if set_loglevel(inp): continue o = set_output(inp) if o: output = o continue try: data = await import_from_file(inp) except Exception as e: writer.error('Import error: {}'.format(e)) continue else: if data is not None: inp = data method = cluster.insert try: result = await method(inp) except (QueryError, InsertError) as e: writer.error(e) except TimeoutError as e: logging.critical( '{} (You might receive another error \'Package ID ' 'not found\' if the result arrives)'.format(e)) except asyncio.CancelledError: logging.critical('Request is cancelled...') except Exception as e: if str(e): logging.critical(e) else: logging.exception(e) else: if isinstance(result, str) or output == 'RAW': print('{}\n'.format(result)) elif output == 'JSON': writer.output_json(result) elif output == 'PRETTY': writer.output_pretty(result) else: raise TypeError('Unknown output set: {}'.format(output)) await stop(cluster) crop_history(history)
class PromptInterface(object): """ class PromptInterface handle the wallet cli commands """ commands = [ 'help', 'quit', 'create wallet {path}', 'open wallet {path}', 'close', 'wallet', 'send {asset} {address} {amount}', 'history', 'lock cli', 'unlock cli', 'gas configure {amount}', 'gas query' ] go_on = True Wallet = None history = FileHistory(FILENAME_PROMPT_HISTORY) locked = False def __init__(self): self.token_style = Style.from_dict({ "command": preferences.token_style['Command'], "eth": preferences.token_style['Eth'], "default": preferences.token_style['Default'], "number": preferences.token_style['Number'], }) def get_bottom_toolbar(self, cli=None): """ :param cli: :return: """ return '[%s]' % (settings.NET_NAME if not PromptInterface.locked else settings.NET_NAME + " (Locked) ") def quit(self): self.go_on = False def help(self): tokens = [] for c in self.commands: tokens.append(("class:command", "%s\n" % c)) print_formatted_text(FormattedText(tokens), style=self.token_style) def do_create(self, arguments): """ :param arguments: :return: """ if self.Wallet: self.do_close_wallet() item = get_arg(arguments) if self.Wallet: self.do_close_wallet() if item and item == 'wallet': path = get_arg(arguments, 1) if path: if os.path.exists(path): print("File already exists") return passwd1 = prompt("[Password 1]> ", is_password=True) passwd2 = prompt("[Password 2]> ", is_password=True) if passwd1 != passwd2 or len(passwd1) < 1: print( "please provide matching passwords that are at least 1 characters long" ) return try: self.Wallet = Wallet.Create(path=path, password=passwd1) print("Wallet %s " % json.dumps(self.Wallet.ToJson(), indent=4)) except Exception as e: print("Exception creating wallet: %s " % e) self.Wallet = None if os.path.isfile(path): try: os.remove(path) except Exception as e: print("Could not remove {}: {}".format(path, e)) return else: print("Please specify a path") def do_open(self, arguments): """ :param arguments: :return: """ if self.Wallet: self.do_close_wallet() item = get_arg(arguments) if item and item == 'wallet': path = get_arg(arguments, 1) if path: if not os.path.exists(path): print("wallet file not found") return passwd = prompt("[Password]> ", is_password=True) try: self.Wallet = Wallet.Open(path, passwd) print("Opened wallet at %s" % path) except Exception as e: print("could not open wallet: %s " % e) else: print("Please specify a path") else: print("please specify something to open") def do_close_wallet(self): """ :return: """ if self.Wallet: path = self.Wallet._path self.Wallet = None print("closed wallet %s " % path) @command_wapper("wallet") def show_wallet(self, arguments): """ :param arguments: :return: """ if not self.Wallet: print("please open a wallet") return item = get_arg(arguments) if not item: print("Wallet %s " % json.dumps(self.Wallet.ToJson(), indent=4)) return else: print("wallet: '{}' is an invalid parameter".format(item)) @command_wapper("import") def do_import(self, arguments): """ :param arguments: :return: """ item = get_arg(arguments) if not item: print("please specify something to import") return else: print("Import of '%s' not implemented" % item) @command_wapper("export") def do_export(self, arguments): """ :param arguments: :return: """ item = get_arg(arguments) if item == 'wif': if not self.Wallet: return print("please open a wallet") address = get_arg(arguments, 1) if not address: return print("Please specify an address") passwd = prompt("[Wallet Password]> ", is_password=True) if not self.Wallet.ValidatePassword(passwd): return print("Incorrect password") keys = self.Wallet.GetKeys() for key in keys: if key.GetAddress() == address: export = key.Export() print("WIF key export: %s" % export) return print("Command export %s not found" % item) @command_wapper("send") def do_send(self, arguments): """ :param arguments: :return: """ if not self.Wallet: print("please open a wallet") return False if len(arguments) < 3: print("Not enough arguments") return False assetId = get_arg(arguments).upper() address_to = get_arg(arguments, 1) amount = float(get_arg(arguments, 2)) if amount <= 0: console_log.error("value can not less then 0") return None if not assetId in self.Wallet.SupportAssert: console_log.error("No support assert") return None gaslimit = int(get_arg(arguments, 3)) if get_arg(arguments, 3) else None gasprice = int(get_arg(arguments, 4)) if get_arg(arguments, 4) else None if assetId == "ETH": if amount >= self.Wallet.eth_balance: console_log.error("No balance") return None try: res = self.Wallet.send_eth(address_to, amount, gaslimit) print("txid: 0x" + res) except Exception as e: print("send failed %s" % e) elif assetId == "TNC": if amount > self.Wallet.tnc_balance or self.Wallet.eth_balance < 0: console_log.error("No balance") return None try: res = self.Wallet.send_erc20(assetId, address_to, amount, gaslimit, gasprice) print("txid: 0x" + res) except Exception as e: print("send failed %s" % e) else: pass return @command_wapper("unlock") def unlock(self, args): """ :param args: :return: """ item = get_arg(args) if item == "cli": if PromptInterface.locked: passwd = prompt("[Wallet Password]> ", is_password=True) if not self.Wallet.ValidatePassword(passwd): print("Incorrect password") return None PromptInterface.locked = False print("cli unlocked") else: print("cli not in locked mode") elif item == "wallet": pass else: print("please spacify unlock item [cli]") return None @command_wapper("lock") def do_lock(self, args): """ :param args: :return: """ item = get_arg(args) if item == "cli": if PromptInterface.locked: print("cli now is in locked mode") else: if self.Wallet: PromptInterface.locked = True print("lock cli with wallet %s" % self.Wallet.name) else: print("No opened wallet") elif item == "wallet": pass else: print("please spacify lock item [cli]") return None @command_wapper("history") def show_tx(self, args): """ :param args: :return: """ history = self.Wallet.query_history() if history is EnumStatusCode.DBQueryWithoutMatchedItems: print("No tx history") return for item in history: print("*" * 20) print(item) return def parse_result(self, result): """ :param result: :return: """ if result.strip(): commandParts = result.strip().split() return commandParts[0], commandParts[1:] return None, None @command_wapper("gas") def configure_gas(self, arguments): """ :param arguments: :return: """ subcommand = get_arg(arguments) if not subcommand: self.help() return False if subcommand == 'configure': coef = get_arg(arguments, 1, True) if coef is None or 0 >= coef: console_log.warn( 'Please use number. Attention: much larger, much more expensive charge.' ) return False Client.set_gas_price(coef) elif subcommand == 'query': console_log.info('Current use {} GWEI'.format( Client.get_gas_price())) else: self.help() return def handle_commands(self, command, arguments): """ :param command: :param arguments: :return: """ if command == "unlock": self.unlock(arguments) elif command == 'quit' or command == 'exit': self.quit() elif command == 'help': self.help() elif command == 'wallet': self.show_wallet(arguments) elif command is None: print('please specify a command') elif command == 'create': self.do_create(arguments) elif command == 'close': self.do_close_wallet() elif command == 'open': self.do_open(arguments) elif command == 'export': self.do_export(arguments) elif command == 'wallet': self.show_wallet(arguments) elif command == 'send': self.do_send(arguments) elif command == 'history': self.show_tx(arguments) elif command == "lock": self.do_lock(arguments) elif command == "gas": self.configure_gas(arguments) else: print("command %s not found" % command) def handle_locked_command(self, command, arguments): """ :param command: :param arguments: :return: """ if command == "unlock": self.unlock(arguments) else: print("cli is in locked mode please unlock cli via 'unlock cli'") return None def get_completer(self): standard_completions = [] for i in self.commands: sub_c = re.match(r"([^{\[]*).*", i) if sub_c: standard_completions.append(sub_c.groups()[0].strip()) all_completions = list(set(standard_completions)) prompt_completer = WordCompleter(all_completions, sentence=True) return prompt_completer def run(self): """ :return: """ tokens = [("class:eth", 'EthTrinity'), ("class:default", ' cli. Type '), ("class:command", '\'help\' '), ("class:default", 'to get started')] print_formatted_text(FormattedText(tokens), style=self.token_style) print('\n') while self.go_on: session = PromptSession("trinity> ", completer=self.get_completer(), history=self.history, bottom_toolbar=self.get_bottom_toolbar, style=self.token_style, refresh_interval=3, auto_suggest=AutoSuggestFromHistory()) try: result = session.prompt() except EOFError: # Control-D pressed: quit return self.quit() except KeyboardInterrupt: # Control-C pressed: do nothing continue # try: # command, arguments = self.parse_result(result) # # if command is not None and len(command) > 0: # command = command.lower() # # if self.locked: # self.handle_locked_command(command, arguments) # continue # # else: # self.handle_commands(command, arguments) # # except Exception as e: # # print("could not execute command: %s " % e) # traceback.print_stack() # traceback.print_exc() command, arguments = self.parse_result(result) if command is not None and len(command) > 0: command = command.lower() if PromptInterface.locked: self.handle_locked_command(command, arguments) continue else: self.handle_commands(command, arguments)
def run_cli(self): logger = self.logger history_file = self.config['main']['history_file'] if history_file == 'default': history_file = config_location() + 'history' history = FileHistory(os.path.expanduser(history_file)) self.refresh_completions(history=history, persist_priorities='none') self.cli = self._build_cli(history) if not self.less_chatty: print('Version:', __version__) print('Chat: https://gitter.im/dbcli/pgcli') print('Mail: https://groups.google.com/forum/#!forum/pgcli') print('Home: http://pgcli.com') try: while True: document = self.cli.run(True) # The reason we check here instead of inside the pgexecute is # because we want to raise the Exit exception which will be # caught by the try/except block that wraps the pgexecute.run() # statement. if quit_command(document.text): raise EOFError try: document = self.handle_editor_command(self.cli, document) except RuntimeError as e: logger.error("sql: %r, error: %r", document.text, e) logger.error("traceback: %r", traceback.format_exc()) click.secho(str(e), err=True, fg='red') continue # Initialize default metaquery in case execution fails query = MetaQuery(query=document.text, successful=False) watch_command, timing = special.get_watch_command( document.text) if watch_command: while watch_command: try: query = self.execute_command(watch_command, query) click.echo( 'Waiting for {0} seconds before repeating'. format(timing)) sleep(timing) except KeyboardInterrupt: watch_command = None else: query = self.execute_command(document.text, query) # Allow PGCompleter to learn user's preferred keywords, etc. with self._completer_lock: self.completer.extend_query_history(document.text) self.query_history.append(query) except EOFError: if not self.less_chatty: print('Goodbye!')
from __future__ import print_function import sys import os.path import prompt_toolkit from prompt_toolkit.history import FileHistory from prompt_toolkit.auto_suggest import AutoSuggestFromHistory from ergonomica.lib.interface.completer import ErgonomicaCompleter from ergonomica.lib.interface.key_bindings_manager import manager_for_environment from prompt_toolkit.styles import style_from_dict from prompt_toolkit.token import Token try: HISTORY = FileHistory( os.path.join(os.path.expanduser("~"), ".ergo", ".ergo_history")) except IOError as error: print( "[ergo: ConfigError]: No such file ~/.ergo_history. Please run ergo_setup. " + str(error), file=sys.stderr) def get_bottom_toolbar_tokens(cli): return [(prompt_toolkit.Token.Toolbar, ' This is a toolbar. ')] def get_rprompt_tokens(cli): return [(prompt_toolkit.Token, ' '), (prompt_toolkit.Token.RPrompt, '<rprompt>')]
def prompt_search(keywords, field, prompt_text): r""" Do an interactive prompt search in the Bibmanager database by the given keywords, with auto-complete and auto-suggest only offering non-None values of the given field. Only one keyword must be set in the prompt. A bottom toolbar dynamically shows additional info. Parameters ---------- keywords: List of strings BibTex keywords to search by. field: String Filtering BibTex field for auto-complete and auto-suggest. prompt_text: String Text to display when launching the prompt. Returns ------- kw_input: List of strings List of the parsed input (same order as keywords). Items are None for the keywords not defined. extra: List of strings Any further word written in the prompt. Examples -------- >>> import bibmanager.bib_manager as bm >>> # Search by key or bibcode, of entries with non-None bibcode: >>> keywords = ['key', 'bibcode'] >>> field = 'bibcode' >>> prompt_text = ("Sample search (Press 'tab' for autocomplete):\n") >>> prompt_input = bm.prompt_search(keywords, field, prompt_text) Sample search (Press 'tab' for autocomplete): key: Astropy2013aaAstroPy >>> # Look at the results (list corresponds to [key, bibcode]): >>> print(prompt_input[0]) ['Astropy2013aaAstroPy', None] >>> print(f'extra = {prompt_input[1]}') extra = [None] >>> # Repeat search, now by bibcode: >>> prompt_input = u.prompt_search(keywords, field, prompt_text) Sample search (Press 'tab' for autocomplete): bibcode: 2013A&A...558A..33A >>> print(prompt_input[0]) [None, '2013A&A...558A..33A'] """ bibs = [bib for bib in load() if getattr(bib, field) is not None] fetch_keywords = [f'{keyword}:' for keyword in keywords] completer = u.KeyPathCompleter(fetch_keywords, bibs) suggester = u.AutoSuggestKeyCompleter() validator = u.AlwaysPassValidator( bibs, toolbar_text="(Press 'tab' for autocomplete)") session = prompt_toolkit.PromptSession( history=FileHistory(u.BM_HISTORY_PDF())) inputs = session.prompt( prompt_text, auto_suggest=suggester, completer=completer, complete_while_typing=False, validator=validator, validate_while_typing=True, bottom_toolbar=validator.bottom_toolbar, ) kw_input = [ re.search(fr'(?:^|[\s]+){kw}[\s]*(.+)', inputs) for kw in fetch_keywords ] # Only one of these keywords should be defined: output = [val is not None for val in kw_input] if sum(output) != 1: raise ValueError("Invalid syntax.") index = output.index(True) content = kw_input[index].group(1).split() if content == []: raise ValueError("Invalid syntax.") kw_input[index] = content[0] extra = content[1:] if len(content) > 1 else [None] return kw_input, extra
class AzInteractiveShell(object): def __init__(self, cli_ctx, style=None, completer=None, lexer=None, history=None, input_custom=sys.stdin, output_custom=None, user_feedback=False, intermediate_sleep=.25, final_sleep=4): from .color_styles import style_factory self.cli_ctx = cli_ctx self.config = Configuration(cli_ctx.config, style=style) self.config.set_style(style) self.style = style_factory(self.config.get_style()) try: gathered_commands = GatherCommands(self.config) self.completer = completer or AzCompleter(self, gathered_commands) self.completer.initialize_command_table_attributes() self.lexer = lexer or get_az_lexer(gathered_commands) except IOError: # if there is no cache self.completer = AzCompleter(self, None) self.lexer = None self.history = history or FileHistory( os.path.join(self.config.get_config_dir(), self.config.get_history())) os.environ[ENV_ADDITIONAL_USER_AGENT] = 'AZURECLISHELL/' + VERSION # OH WHAT FUN TO FIGURE OUT WHAT THESE ARE! self._cli = None self.layout = None self.description_docs = u'' self.param_docs = u'' self.example_docs = u'' self.last = None self.last_exit = 0 self.user_feedback = user_feedback self.input = input_custom self.output = output_custom self.config_default = "" self.default_command = "" self.threads = [] self.curr_thread = None self.spin_val = -1 self.intermediate_sleep = intermediate_sleep self.final_sleep = final_sleep self.command_table_thread = None # try to consolidate state information here... # Used by key bindings and layout self.example_page = 1 self.is_prompting = False self.is_example_repl = False self.is_showing_default = False self.is_symbols = True def __call__(self): if self.cli_ctx.data["az_interactive_active"]: logger.warning("You're in the interactive shell already.") return if self.config.BOOLEAN_STATES[self.config.config.get( 'DEFAULT', 'firsttime')]: self.config.firsttime() if not self.config.has_feedback() and frequency_heuristic(self): print( "\n\nAny comments or concerns? You can use the \'feedback\' command!" + " We would greatly appreciate it.\n") self.cli_ctx.data["az_interactive_active"] = True self.run() self.cli_ctx.data["az_interactive_active"] = False @property def cli(self): """ Makes the interface or refreshes it """ if self._cli is None: self._cli = self.create_interface() return self._cli def handle_cd(self, cmd): """changes dir """ if len(cmd) != 2: print("Invalid syntax: cd path", file=self.output) return path = os.path.expandvars(os.path.expanduser(cmd[1])) try: os.chdir(path) except OSError as ex: print("cd: %s\n" % ex, file=self.output) def on_input_timeout(self, cli): """ brings up the metadata for the command if there is a valid command already typed """ document = cli.current_buffer.document text = document.text text = text.replace('az ', '') if self.default_command: text = self.default_command + ' ' + text param_info, example = self.generate_help_text() self.param_docs = u'{}'.format(param_info) self.example_docs = u'{}'.format(example) self._update_default_info() cli.buffers['description'].reset(initial_document=Document( self.description_docs, cursor_position=0)) cli.buffers['parameter'].reset( initial_document=Document(self.param_docs)) cli.buffers['examples'].reset( initial_document=Document(self.example_docs)) cli.buffers['default_values'].reset(initial_document=Document( u'{}'.format(self.config_default if self. config_default else 'No Default Values'))) self._update_toolbar() cli.request_redraw() def restart_completer(self): command_info = GatherCommands(self.config) if not self.completer: self.completer.start(command_info) self.completer.initialize_command_table_attributes() if not self.lexer: self.lexer = get_az_lexer(command_info) self._cli = None def _space_examples(self, list_examples, rows, section_value): """ makes the example text """ examples_with_index = [] for i, _ in list(enumerate(list_examples)): if len(list_examples[i]) > 1: examples_with_index.append("[" + str(i + 1) + "] " + list_examples[i][0] + list_examples[i][1]) example = "".join(exam for exam in examples_with_index) num_newline = example.count('\n') page_number = '' if num_newline > rows * PART_SCREEN_EXAMPLE and rows > PART_SCREEN_EXAMPLE * 10: len_of_excerpt = math.floor(float(rows) * PART_SCREEN_EXAMPLE) group = example.split('\n') end = int(section_value * len_of_excerpt) begin = int((section_value - 1) * len_of_excerpt) if end < num_newline: example = '\n'.join(group[begin:end]) + "\n" else: # default chops top off example = '\n'.join(group[begin:]) + "\n" while ((section_value - 1) * len_of_excerpt) > num_newline: self.example_page -= 1 page_number = '\n' + str(section_value) + "/" + str( int(math.ceil(num_newline / len_of_excerpt))) return example + page_number + ' CTRL+Y (^) CTRL+N (v)' def _update_toolbar(self): cli = self.cli _, cols = get_window_dim() cols = int(cols) empty_space = " " * cols delta = datetime.datetime.utcnow() - START_TIME if self.user_feedback and delta.seconds < DISPLAY_TIME: toolbar = [ ' Try out the \'feedback\' command', 'If refreshed disappear in: {}'.format( str(DISPLAY_TIME - delta.seconds)) ] elif self.command_table_thread.is_alive(): toolbar = [' Loading...', 'Hit [enter] to refresh'] else: toolbar = self._toolbar_info() toolbar, empty_space = space_toolbar(toolbar, empty_space) cli.buffers['bottom_toolbar'].reset(initial_document=Document( u'{}{}{}'.format(NOTIFICATIONS, toolbar, empty_space))) def _toolbar_info(self): sub_name = "" try: profile = Profile(cli_ctx=self.cli_ctx) sub_name = profile.get_subscription()[_SUBSCRIPTION_NAME] except CLIError: pass curr_cloud = "Cloud: {}".format(self.cli_ctx.cloud.name) tool_val = 'Subscription: {}'.format( sub_name) if sub_name else curr_cloud settings_items = [ " [F1]Layout", "[F2]Defaults", "[F3]Keys", "[Ctrl+D]Quit", tool_val ] return settings_items def generate_help_text(self): """ generates the help text based on commands typed """ param_descrip = example = "" self.description_docs = u'' rows, _ = get_window_dim() rows = int(rows) param_args = self.completer.leftover_args last_word = self.completer.unfinished_word command = self.completer.current_command new_command = ' '.join([command, last_word]).strip() if not self.completer.complete_command and new_command in self.completer.command_description: command = new_command # get command/group help if self.completer and command in self.completer.command_description: self.description_docs = u'{}'.format( self.completer.command_description[command]) # get parameter help if full command if self.completer and command in self.completer.command_param_info: param = param_args[-1] if param_args else '' param = last_word if last_word.startswith('-') else param if param in self.completer.command_param_info[ command] and self.completer.has_description(command + " " + param): param_descrip = ''.join([ param, ":", '\n', self.completer.param_description.get( command + " " + param, '') ]) if command in self.completer.command_examples: string_example = [] for example in self.completer.command_examples[command]: for part in example: string_example.append(part) ''.join(string_example) example = self._space_examples( self.completer.command_examples[command], rows, self.example_page) return param_descrip, example def _update_default_info(self): try: defaults_section = self.cli_ctx.config.defaults_section_name options = self.cli_ctx.config.config_parser.options( defaults_section) self.config_default = "" for opt in options: self.config_default += opt + ": " + self.cli_ctx.config.get( defaults_section, opt) + " " except configparser.NoSectionError: self.config_default = "" def create_application(self, full_layout=True): """ makes the application object and the buffers """ layout_manager = LayoutManager(self) if full_layout: layout = layout_manager.create_layout(ExampleLexer, ToolbarLexer) else: layout = layout_manager.create_tutorial_layout() buffers = { DEFAULT_BUFFER: Buffer(is_multiline=True), 'description': Buffer(is_multiline=True, read_only=True), 'parameter': Buffer(is_multiline=True, read_only=True), 'examples': Buffer(is_multiline=True, read_only=True), 'bottom_toolbar': Buffer(is_multiline=True), 'example_line': Buffer(is_multiline=True), 'default_values': Buffer(), 'symbols': Buffer(), 'progress': Buffer(is_multiline=False) } writing_buffer = Buffer(history=self.history, auto_suggest=AutoSuggestFromHistory(), enable_history_search=True, completer=self.completer, complete_while_typing=Always()) return Application( mouse_support=False, style=self.style, buffer=writing_buffer, on_input_timeout=self.on_input_timeout, key_bindings_registry=InteractiveKeyBindings(self).registry, layout=layout, buffers=buffers, ) def create_interface(self): """ instantiates the interface """ return CommandLineInterface(application=self.create_application(), eventloop=create_eventloop()) def set_prompt(self, prompt_command="", position=0): """ writes the prompt line """ self.description_docs = u'{}'.format(prompt_command) self.cli.current_buffer.reset(initial_document=Document( self.description_docs, cursor_position=position)) self.cli.request_redraw() def set_scope(self, value): """ narrows the scopes the commands """ if self.default_command: self.default_command += ' ' + value else: self.default_command += value return value def handle_example(self, text, continue_flag): """ parses for the tutorial """ cmd = text.partition(SELECT_SYMBOL['example'])[0].rstrip() num = text.partition(SELECT_SYMBOL['example'])[2].strip() example = "" try: num = int(num) - 1 except ValueError: print("An Integer should follow the colon", file=self.output) return "" if cmd in self.completer.command_examples: if num >= 0 and num < len(self.completer.command_examples[cmd]): example = self.completer.command_examples[cmd][num][1] example = example.replace('\n', '') else: print('Invalid example number', file=self.output) return '', True example = example.replace('az', '') starting_index = None counter = 0 example_no_fill = "" flag_fill = True for word in example.split(): if flag_fill: example_no_fill += word + " " if word.startswith('-'): example_no_fill += word + " " if not starting_index: starting_index = counter flag_fill = False counter += 1 return self.example_repl(example_no_fill, example, starting_index, continue_flag) def example_repl(self, text, example, start_index, continue_flag): """ REPL for interactive tutorials """ if start_index: start_index = start_index + 1 cmd = ' '.join(text.split()[:start_index]) example_cli = CommandLineInterface( application=self.create_application(full_layout=False), eventloop=create_eventloop()) example_cli.buffers['example_line'].reset( initial_document=Document(u'{}\n'.format(add_new_lines( example)))) while start_index < len(text.split()): if self.default_command: cmd = cmd.replace(self.default_command + ' ', '') example_cli.buffers[DEFAULT_BUFFER].reset( initial_document=Document(u'{}'.format(cmd), cursor_position=len(cmd))) example_cli.request_redraw() answer = example_cli.run() if not answer: return "", True answer = answer.text if answer.strip('\n') == cmd.strip('\n'): continue else: if len(answer.split()) > 1: start_index += 1 cmd += " " + answer.split()[-1] + " " +\ u' '.join(text.split()[start_index:start_index + 1]) example_cli.exit() del example_cli else: cmd = text return cmd, continue_flag # pylint: disable=too-many-statements def _special_cases(self, cmd, outside): break_flag = False continue_flag = False args = parse_quotes(cmd) cmd_stripped = cmd.strip() if not cmd_stripped and cmd: # add scope if there are only spaces cmd = self.default_command + " " + cmd elif cmd_stripped in ("quit", "exit"): break_flag = True elif cmd_stripped == "clear-history": continue_flag = True self.reset_history() elif cmd_stripped == CLEAR_WORD: outside = True cmd = CLEAR_WORD elif cmd_stripped[0] == SELECT_SYMBOL['outside']: cmd = cmd_stripped[1:] outside = True if cmd.strip() and cmd.split()[0] == 'cd': self.handle_cd(parse_quotes(cmd)) continue_flag = True telemetry.track_outside_gesture() elif cmd_stripped[0] == SELECT_SYMBOL['exit_code']: meaning = "Success" if self.last_exit == 0 else "Failure" print(meaning + ": " + str(self.last_exit), file=self.output) continue_flag = True telemetry.track_exit_code_gesture() elif SELECT_SYMBOL[ 'query'] in cmd_stripped and self.last and self.last.result: continue_flag = self.handle_jmespath_query(args) telemetry.track_query_gesture() elif not args: continue_flag = True elif args[0] == '--version' or args[0] == '-v': try: continue_flag = True self.cli_ctx.show_version() except SystemExit: pass elif SELECT_SYMBOL['example'] in cmd: cmd, continue_flag = self.handle_example(cmd, continue_flag) telemetry.track_ran_tutorial() elif SELECT_SYMBOL['scope'] == cmd_stripped[0:2]: continue_flag, cmd = self.handle_scoping_input( continue_flag, cmd, cmd_stripped) telemetry.track_scope_changes() else: # not a special character; add scope and remove 'az' if self.default_command: cmd = self.default_command + " " + cmd elif cmd.split(' ', 1)[0].lower() == 'az': cmd = ' '.join(cmd.split()[1:]) if "|" in cmd or ">" in cmd: # anything I don't parse, send off outside = True cmd = "az " + cmd telemetry.track_cli_commands_used() return break_flag, continue_flag, outside, cmd def handle_jmespath_query(self, args): """ handles the jmespath query for injection or printing """ continue_flag = False query_symbol = SELECT_SYMBOL['query'] symbol_len = len(query_symbol) try: if len(args) == 1: # if arguments start with query_symbol, just print query result if args[0] == query_symbol: result = self.last.result elif args[0].startswith(query_symbol): result = jmespath.search(args[0][symbol_len:], self.last.result) print(json.dumps(result, sort_keys=True, indent=2), file=self.output) elif args[0].startswith(query_symbol): # print error message, user unsure of query shortcut usage print(( "Usage Error: " + os.linesep + "1. Use {0} stand-alone to display previous result with optional filtering " "(Ex: {0}[jmespath query])" + os.linesep + "OR:" + os.linesep + "2. Use {0} to query the previous result for argument values " "(Ex: group show --name {0}[jmespath query])" ).format(query_symbol), file=self.output) else: # query, inject into cmd def jmespath_query(match): if match.group(0) == query_symbol: return str(self.last.result) query_result = jmespath.search( match.group(0)[symbol_len:], self.last.result) return str(query_result) def sub_result(arg): escaped_symbol = re.escape(query_symbol) # regex captures query symbol and all characters following it in the argument return json.dumps( re.sub(r'%s.*' % escaped_symbol, jmespath_query, arg)) cmd_base = ' '.join(map(sub_result, args)) self.cli_execute(cmd_base) continue_flag = True except (jmespath.exceptions.ParseError, CLIError) as e: print("Invalid Query Input: " + str(e), file=self.output) continue_flag = True return continue_flag def handle_scoping_input(self, continue_flag, cmd, text): """ handles what to do with a scoping gesture """ default_split = text.partition(SELECT_SYMBOL['scope'])[2].split() cmd = cmd.replace(SELECT_SYMBOL['scope'], '') continue_flag = True if not default_split: self.default_command = "" print('unscoping all', file=self.output) return continue_flag, cmd while default_split: if not text: value = '' else: value = default_split[0] tree_path = self.default_command.split() tree_path.append(value) if self.completer.command_tree.in_tree(tree_path): self.set_scope(value) print("defaulting: " + value, file=self.output) cmd = cmd.replace(SELECT_SYMBOL['scope'], '') elif SELECT_SYMBOL['unscope'] == default_split[ 0] and self.default_command.split(): value = self.default_command.split()[-1] self.default_command = ' ' + ' '.join( self.default_command.split()[:-1]) if not self.default_command.strip(): self.default_command = self.default_command.strip() print('unscoping: ' + value, file=self.output) elif SELECT_SYMBOL['unscope'] not in text: print("Scope must be a valid command", file=self.output) default_split = default_split[1:] return continue_flag, cmd def reset_history(self): history_file_path = os.path.join(self.config.get_config_dir(), self.config.get_history()) os.remove(history_file_path) self.history = FileHistory(history_file_path) self.cli.buffers[DEFAULT_BUFFER].history = self.history def cli_execute(self, cmd): """ sends the command to the CLI to be executed """ try: args = parse_quotes(cmd) if args and args[0] == 'feedback': self.config.set_feedback('yes') self.user_feedback = False azure_folder = get_config_dir() if not os.path.exists(azure_folder): os.makedirs(azure_folder) ACCOUNT.load(os.path.join(azure_folder, 'azureProfile.json')) CONFIG.load(os.path.join(azure_folder, 'az.json')) SESSION.load(os.path.join(azure_folder, 'az.sess'), max_age=3600) invocation = self.cli_ctx.invocation_cls( cli_ctx=self.cli_ctx, parser_cls=self.cli_ctx.parser_cls, commands_loader_cls=self.cli_ctx.commands_loader_cls, help_cls=self.cli_ctx.help_cls) if '--progress' in args: args.remove('--progress') execute_args = [args] thread = Thread(target=invocation.execute, args=execute_args) thread.daemon = True thread.start() self.threads.append(thread) self.curr_thread = thread progress_args = [self] thread = Thread(target=progress_view, args=progress_args) thread.daemon = True thread.start() self.threads.append(thread) result = None else: result = invocation.execute(args) self.last_exit = 0 if result and result.result is not None: if self.output: self.output.write(result) self.output.flush() else: formatter = self.cli_ctx.output.get_formatter( self.cli_ctx.invocation.data['output']) self.cli_ctx.output.out(result, formatter=formatter, out_file=sys.stdout) self.last = result except Exception as ex: # pylint: disable=broad-except self.last_exit = handle_exception(ex) except SystemExit as ex: self.last_exit = int(ex.code) def progress_patch(self, _=False): """ forces to use the Shell Progress """ from .progress import ShellProgressView self.cli_ctx.progress_controller.init_progress(ShellProgressView()) return self.cli_ctx.progress_controller def run(self): """ starts the REPL """ from .progress import ShellProgressView self.cli_ctx.get_progress_controller().init_progress( ShellProgressView()) self.cli_ctx.get_progress_controller = self.progress_patch self.command_table_thread = LoadCommandTableThread( self.restart_completer, self) self.command_table_thread.start() from .configuration import SHELL_HELP self.cli.buffers['symbols'].reset( initial_document=Document(u'{}'.format(SHELL_HELP))) # flush telemetry for new commands and send successful interactive mode entry event telemetry.set_success() telemetry.flush() while True: try: document = self.cli.run(reset_current_buffer=True) text = document.text if not text: # not input self.set_prompt() continue cmd = text outside = False except AttributeError: # when the user pressed Control D break except (KeyboardInterrupt, ValueError): # CTRL C self.set_prompt() continue else: self.history.append(text) b_flag, c_flag, outside, cmd = self._special_cases( cmd, outside) if b_flag: break if c_flag: self.set_prompt() continue self.set_prompt() if outside: subprocess.Popen(cmd, shell=True).communicate() else: telemetry.start() self.cli_execute(cmd) if self.last_exit and self.last_exit != 0: telemetry.set_failure() else: telemetry.set_success() telemetry.flush() telemetry.conclude()
from __future__ import unicode_literals from prompt_toolkit import prompt # 导入历史模块类,实现查找历史的功能 from prompt_toolkit.history import FileHistory # 实现用户输入时候自动提示 from prompt_toolkit.auto_suggest import AutoSuggestFromHistory # tab自动补全提示命令,旧版的WordCompleter不可用了 from prompt_toolkit.contrib.completers import SystemCompleter SQLCompleter = SystemCompleter() while True: user_input = prompt('>', history=FileHistory('history.txt'), auto_suggest=AutoSuggestFromHistory(), completer=SQLCompleter, ) print(user_input)
def __init__(self, get_globals=None, get_locals=None, history_filename=None, vi_mode=False, # For internal use. _completer=None, _validator=None, _lexer=None, _extra_buffers=None, _extra_buffer_processors=None, _on_start=None, _extra_layout_body=None, _extra_toolbars=None, _input_buffer_height=None, _accept_action=AcceptAction.RETURN_DOCUMENT, _on_exit=AbortAction.RAISE_EXCEPTION): self.get_globals = get_globals or (lambda: {}) self.get_locals = get_locals or self.get_globals self._completer = _completer or PythonCompleter(self.get_globals, self.get_locals) self._validator = _validator or PythonValidator(self.get_compiler_flags) self.history = FileHistory(history_filename) if history_filename else InMemoryHistory() self._lexer = _lexer or PygmentsLexer(PythonLexer) self._extra_buffers = _extra_buffers self._accept_action = _accept_action self._on_exit = _on_exit self._on_start = _on_start self._input_buffer_height = _input_buffer_height self._extra_layout_body = _extra_layout_body or [] self._extra_toolbars = _extra_toolbars or [] self._extra_buffer_processors = _extra_buffer_processors or [] # Settings. self.show_signature = False self.show_docstring = False self.show_meta_enter_message = True self.completion_visualisation = CompletionVisualisation.MULTI_COLUMN self.completion_menu_scroll_offset = 1 self.show_line_numbers = False self.show_status_bar = True self.wrap_lines = True self.complete_while_typing = True self.vi_mode = vi_mode self.paste_mode = False # When True, don't insert whitespace after newline. self.confirm_exit = True # Ask for confirmation when Control-D is pressed. self.accept_input_on_enter = 2 # Accept when pressing Enter 'n' times. # 'None' means that meta-enter is always required. self.enable_open_in_editor = True self.enable_system_bindings = True self.enable_input_validation = True self.enable_auto_suggest = False self.enable_mouse_support = False self.enable_history_search = False # When True, like readline, going # back in history will filter the # history on the records starting # with the current input. self.highlight_matching_parenthesis = False self.show_sidebar = False # Currently show the sidebar. self.show_sidebar_help = True # When the sidebar is visible, also show the help text. self.show_exit_confirmation = False # Currently show 'Do you really want to exit?' self.terminal_title = None # The title to be displayed in the terminal. (None or string.) self.exit_message = 'Do you really want to exit?' # Tokens to be shown at the prompt. self.prompt_style = 'classic' # The currently active style. self.all_prompt_styles = { # Styles selectable from the menu. 'ipython': IPythonPrompt(self), 'classic': ClassicPrompt(), } self.get_input_prompt_tokens = lambda cli: \ self.all_prompt_styles[self.prompt_style].in_tokens(cli) self.get_output_prompt_tokens = lambda cli: \ self.all_prompt_styles[self.prompt_style].out_tokens(cli) #: Load styles. self.code_styles = get_all_code_styles() self.ui_styles = get_all_ui_styles() self._current_code_style_name = 'default' self._current_ui_style_name = 'default' if is_windows(): self._current_code_style_name = 'win32' self._current_style = self._generate_style() self.true_color = False # Options to be configurable from the sidebar. self.options = self._create_options() self.selected_option_index = 0 #: Incremeting integer counting the current statement. self.current_statement_index = 1 # Code signatures. (This is set asynchronously after a timeout.) self.signatures = [] # Use a KeyBindingManager for loading the key bindings. self.key_bindings_manager = KeyBindingManager( enable_abort_and_exit_bindings=True, enable_search=True, enable_vi_mode=Condition(lambda cli: self.vi_mode), enable_open_in_editor=Condition(lambda cli: self.enable_open_in_editor), enable_system_bindings=Condition(lambda cli: self.enable_system_bindings), enable_auto_suggest_bindings=Condition(lambda cli: self.enable_auto_suggest), # Disable all default key bindings when the sidebar or the exit confirmation # are shown. enable_all=Condition(lambda cli: not (self.show_sidebar or self.show_exit_confirmation))) load_python_bindings(self.key_bindings_manager, self) load_sidebar_bindings(self.key_bindings_manager, self) load_confirm_exit_bindings(self.key_bindings_manager, self) # Boolean indicating whether we have a signatures thread running. # (Never run more than one at the same time.) self._get_signatures_thread_running = False
class AzInteractiveShell(object): def __init__(self, cli_ctx, style=None, completer=None, lexer=None, history=None, input_custom=sys.stdin, output_custom=None, user_feedback=False, intermediate_sleep=.25, final_sleep=4): from .color_styles import style_factory self.cli_ctx = cli_ctx self.config = Configuration(cli_ctx.config, style=style) self.config.set_style(style) self.style = style_factory(self.config.get_style()) try: gathered_commands = GatherCommands(self.config) self.completer = completer or AzCompleter(self, gathered_commands) self.completer.initialize_command_table_attributes() self.lexer = lexer or get_az_lexer(gathered_commands) except IOError: # if there is no cache self.completer = AzCompleter(self, None) self.lexer = None self.history = history or FileHistory(os.path.join(self.config.get_config_dir(), self.config.get_history())) os.environ[ENV_ADDITIONAL_USER_AGENT] = 'AZURECLISHELL/' + __version__ # OH WHAT FUN TO FIGURE OUT WHAT THESE ARE! self._cli = None self.layout = None self.description_docs = u'' self.param_docs = u'' self.example_docs = u'' self.last = None self.last_exit = 0 self.user_feedback = user_feedback self.input = input_custom self.output = output_custom self.config_default = "" self.default_command = "" self.threads = [] self.curr_thread = None self.spin_val = -1 self.intermediate_sleep = intermediate_sleep self.final_sleep = final_sleep self.command_table_thread = None # try to consolidate state information here... # Used by key bindings and layout self.example_page = 1 self.is_prompting = False self.is_example_repl = False self.is_showing_default = False self.is_symbols = True def __call__(self): if self.cli_ctx.data["az_interactive_active"]: logger.warning("You're in the interactive shell already.") return if self.config.BOOLEAN_STATES[self.config.config.get('DEFAULT', 'firsttime')]: self.config.firsttime() if not self.config.has_feedback() and frequency_heuristic(self): print("\n\nAny comments or concerns? You can use the \'feedback\' command!" + " We would greatly appreciate it.\n") self.cli_ctx.data["az_interactive_active"] = True self.run() self.cli_ctx.data["az_interactive_active"] = False @property def cli(self): """ Makes the interface or refreshes it """ if self._cli is None: self._cli = self.create_interface() return self._cli def handle_cd(self, cmd): """changes dir """ if len(cmd) != 2: print("Invalid syntax: cd path", file=self.output) return path = os.path.expandvars(os.path.expanduser(cmd[1])) try: os.chdir(path) except OSError as ex: print("cd: %s\n" % ex, file=self.output) def on_input_timeout(self, cli): """ brings up the metadata for the command if there is a valid command already typed """ document = cli.current_buffer.document text = document.text text = text.replace('az ', '') if self.default_command: text = self.default_command + ' ' + text param_info, example = self.generate_help_text() self.param_docs = u'{}'.format(param_info) self.example_docs = u'{}'.format(example) self._update_default_info() cli.buffers['description'].reset( initial_document=Document(self.description_docs, cursor_position=0)) cli.buffers['parameter'].reset( initial_document=Document(self.param_docs)) cli.buffers['examples'].reset( initial_document=Document(self.example_docs)) cli.buffers['default_values'].reset( initial_document=Document( u'{}'.format(self.config_default if self.config_default else 'No Default Values'))) self._update_toolbar() cli.request_redraw() def restart_completer(self): command_info = GatherCommands(self.config) if not self.completer: self.completer.start(command_info) self.completer.initialize_command_table_attributes() if not self.lexer: self.lexer = get_az_lexer(command_info) self._cli = None def _space_examples(self, list_examples, rows, section_value): """ makes the example text """ examples_with_index = [] for i, _ in list(enumerate(list_examples)): if len(list_examples[i]) > 1: examples_with_index.append("[" + str(i + 1) + "] " + list_examples[i][0] + list_examples[i][1]) example = "".join(exam for exam in examples_with_index) num_newline = example.count('\n') page_number = '' if num_newline > rows * PART_SCREEN_EXAMPLE and rows > PART_SCREEN_EXAMPLE * 10: len_of_excerpt = math.floor(float(rows) * PART_SCREEN_EXAMPLE) group = example.split('\n') end = int(section_value * len_of_excerpt) begin = int((section_value - 1) * len_of_excerpt) if end < num_newline: example = '\n'.join(group[begin:end]) + "\n" else: # default chops top off example = '\n'.join(group[begin:]) + "\n" while ((section_value - 1) * len_of_excerpt) > num_newline: self.example_page -= 1 page_number = '\n' + str(section_value) + "/" + str(int(math.ceil(num_newline / len_of_excerpt))) return example + page_number + ' CTRL+Y (^) CTRL+N (v)' def _update_toolbar(self): cli = self.cli _, cols = get_window_dim() cols = int(cols) empty_space = " " * cols delta = datetime.datetime.utcnow() - START_TIME if self.user_feedback and delta.seconds < DISPLAY_TIME: toolbar = [ ' Try out the \'feedback\' command', 'If refreshed disappear in: {}'.format(str(DISPLAY_TIME - delta.seconds))] elif self.command_table_thread.is_alive(): toolbar = [ ' Loading...', 'Hit [enter] to refresh' ] else: toolbar = self._toolbar_info() toolbar, empty_space = space_toolbar(toolbar, empty_space) cli.buffers['bottom_toolbar'].reset( initial_document=Document(u'{}{}{}'.format(NOTIFICATIONS, toolbar, empty_space))) def _toolbar_info(self): sub_name = "" try: profile = Profile(cli_ctx=self.cli_ctx) sub_name = profile.get_subscription()[_SUBSCRIPTION_NAME] except CLIError: pass curr_cloud = "Cloud: {}".format(self.cli_ctx.cloud.name) tool_val = 'Subscription: {}'.format(sub_name) if sub_name else curr_cloud settings_items = [ " [F1]Layout", "[F2]Defaults", "[F3]Keys", "[Ctrl+D]Quit", tool_val ] return settings_items def generate_help_text(self): """ generates the help text based on commands typed """ param_descrip = example = "" self.description_docs = u'' rows, _ = get_window_dim() rows = int(rows) param_args = self.completer.leftover_args last_word = self.completer.unfinished_word command = self.completer.current_command new_command = ' '.join([command, last_word]).strip() if not self.completer.complete_command and new_command in self.completer.command_description: command = new_command # get command/group help if self.completer and command in self.completer.command_description: self.description_docs = u'{}'.format(self.completer.command_description[command]) # get parameter help if full command if self.completer and command in self.completer.command_param_info: param = param_args[-1] if param_args else '' param = last_word if last_word.startswith('-') else param if param in self.completer.command_param_info[command] and self.completer.has_description( command + " " + param): param_descrip = ''.join([ param, ":", '\n', self.completer.param_description.get(command + " " + param, '')]) if command in self.completer.command_examples: string_example = [] for example in self.completer.command_examples[command]: for part in example: string_example.append(part) ''.join(string_example) example = self._space_examples( self.completer.command_examples[command], rows, self.example_page) return param_descrip, example def _update_default_info(self): try: options = self.cli_ctx.config.config_parser.options(DEFAULTS_SECTION) self.config_default = "" for opt in options: self.config_default += opt + ": " + self.cli_ctx.config.get(DEFAULTS_SECTION, opt) + " " except configparser.NoSectionError: self.config_default = "" def create_application(self, full_layout=True): """ makes the application object and the buffers """ layout_manager = LayoutManager(self) if full_layout: layout = layout_manager.create_layout(ExampleLexer, ToolbarLexer) else: layout = layout_manager.create_tutorial_layout() buffers = { DEFAULT_BUFFER: Buffer(is_multiline=True), 'description': Buffer(is_multiline=True, read_only=True), 'parameter': Buffer(is_multiline=True, read_only=True), 'examples': Buffer(is_multiline=True, read_only=True), 'bottom_toolbar': Buffer(is_multiline=True), 'example_line': Buffer(is_multiline=True), 'default_values': Buffer(), 'symbols': Buffer(), 'progress': Buffer(is_multiline=False) } writing_buffer = Buffer( history=self.history, auto_suggest=AutoSuggestFromHistory(), enable_history_search=True, completer=self.completer, complete_while_typing=Always() ) return Application( mouse_support=False, style=self.style, buffer=writing_buffer, on_input_timeout=self.on_input_timeout, key_bindings_registry=InteractiveKeyBindings(self).registry, layout=layout, buffers=buffers, ) def create_interface(self): """ instantiates the interface """ from prompt_toolkit.interface import CommandLineInterface return CommandLineInterface( application=self.create_application(), eventloop=create_eventloop()) def set_prompt(self, prompt_command="", position=0): """ writes the prompt line """ self.description_docs = u'{}'.format(prompt_command) self.cli.current_buffer.reset( initial_document=Document( self.description_docs, cursor_position=position)) self.cli.request_redraw() def set_scope(self, value): """ narrows the scopes the commands """ if self.default_command: self.default_command += ' ' + value else: self.default_command += value return value def handle_example(self, text, continue_flag): """ parses for the tutorial """ cmd = text.partition(SELECT_SYMBOL['example'])[0].rstrip() num = text.partition(SELECT_SYMBOL['example'])[2].strip() example = "" try: num = int(num) - 1 except ValueError: print("An Integer should follow the colon", file=self.output) return "" if cmd in self.completer.command_examples: if num >= 0 and num < len(self.completer.command_examples[cmd]): example = self.completer.command_examples[cmd][num][1] example = example.replace('\n', '') else: print('Invalid example number', file=self.output) return '', True example = example.replace('az', '') starting_index = None counter = 0 example_no_fill = "" flag_fill = True for word in example.split(): if flag_fill: example_no_fill += word + " " if word.startswith('-'): example_no_fill += word + " " if not starting_index: starting_index = counter flag_fill = False counter += 1 return self.example_repl(example_no_fill, example, starting_index, continue_flag) def example_repl(self, text, example, start_index, continue_flag): """ REPL for interactive tutorials """ from prompt_toolkit.interface import CommandLineInterface if start_index: start_index = start_index + 1 cmd = ' '.join(text.split()[:start_index]) example_cli = CommandLineInterface( application=self.create_application( full_layout=False), eventloop=create_eventloop()) example_cli.buffers['example_line'].reset( initial_document=Document(u'{}\n'.format( add_new_lines(example))) ) while start_index < len(text.split()): if self.default_command: cmd = cmd.replace(self.default_command + ' ', '') example_cli.buffers[DEFAULT_BUFFER].reset( initial_document=Document( u'{}'.format(cmd), cursor_position=len(cmd))) example_cli.request_redraw() answer = example_cli.run() if not answer: return "", True answer = answer.text if answer.strip('\n') == cmd.strip('\n'): continue else: if len(answer.split()) > 1: start_index += 1 cmd += " " + answer.split()[-1] + " " +\ u' '.join(text.split()[start_index:start_index + 1]) example_cli.exit() del example_cli else: cmd = text return cmd, continue_flag # pylint: disable=too-many-statements def _special_cases(self, cmd, outside): break_flag = False continue_flag = False args = parse_quotes(cmd) cmd_stripped = cmd.strip() if not cmd_stripped and cmd: # add scope if there are only spaces cmd = self.default_command + " " + cmd elif cmd_stripped == "quit" or cmd_stripped == "exit": break_flag = True elif cmd_stripped == "clear-history": continue_flag = True self.reset_history() elif cmd_stripped == CLEAR_WORD: outside = True cmd = CLEAR_WORD elif cmd_stripped[0] == SELECT_SYMBOL['outside']: cmd = cmd_stripped[1:] outside = True if cmd.strip() and cmd.split()[0] == 'cd': self.handle_cd(parse_quotes(cmd)) continue_flag = True telemetry.track_outside_gesture() elif cmd_stripped[0] == SELECT_SYMBOL['exit_code']: meaning = "Success" if self.last_exit == 0 else "Failure" print(meaning + ": " + str(self.last_exit), file=self.output) continue_flag = True telemetry.track_exit_code_gesture() elif SELECT_SYMBOL['query'] in cmd_stripped and self.last and self.last.result: continue_flag = self.handle_jmespath_query(args) telemetry.track_query_gesture() elif not args: continue_flag = True elif args[0] == '--version' or args[0] == '-v': try: continue_flag = True self.cli_ctx.show_version() except SystemExit: pass elif SELECT_SYMBOL['example'] in cmd: cmd, continue_flag = self.handle_example(cmd, continue_flag) telemetry.track_ran_tutorial() elif SELECT_SYMBOL['scope'] == cmd_stripped[0:2]: continue_flag, cmd = self.handle_scoping_input(continue_flag, cmd, cmd_stripped) telemetry.track_scope_changes() else: # not a special character; add scope and remove 'az' if self.default_command: cmd = self.default_command + " " + cmd elif cmd.split(' ', 1)[0].lower() == 'az': cmd = ' '.join(cmd.split()[1:]) if "|" in cmd or ">" in cmd: # anything I don't parse, send off outside = True cmd = "az " + cmd telemetry.track_cli_commands_used() return break_flag, continue_flag, outside, cmd def handle_jmespath_query(self, args): """ handles the jmespath query for injection or printing """ continue_flag = False query_symbol = SELECT_SYMBOL['query'] symbol_len = len(query_symbol) try: if len(args) == 1: # if arguments start with query_symbol, just print query result if args[0] == query_symbol: result = self.last.result elif args[0].startswith(query_symbol): result = jmespath.search(args[0][symbol_len:], self.last.result) print(json.dumps(result, sort_keys=True, indent=2), file=self.output) elif args[0].startswith(query_symbol): # print error message, user unsure of query shortcut usage print(("Usage Error: " + os.linesep + "1. Use {0} stand-alone to display previous result with optional filtering " "(Ex: {0}[jmespath query])" + os.linesep + "OR:" + os.linesep + "2. Use {0} to query the previous result for argument values " "(Ex: group show --name {0}[jmespath query])").format(query_symbol), file=self.output) else: # query, inject into cmd def jmespath_query(match): if match.group(0) == query_symbol: return str(self.last.result) query_result = jmespath.search(match.group(0)[symbol_len:], self.last.result) return str(query_result) def sub_result(arg): escaped_symbol = re.escape(query_symbol) # regex captures query symbol and all characters following it in the argument return json.dumps(re.sub(r'%s.*' % escaped_symbol, jmespath_query, arg)) cmd_base = ' '.join(map(sub_result, args)) self.cli_execute(cmd_base) continue_flag = True except (jmespath.exceptions.ParseError, CLIError) as e: print("Invalid Query Input: " + str(e), file=self.output) continue_flag = True return continue_flag def handle_scoping_input(self, continue_flag, cmd, text): """ handles what to do with a scoping gesture """ default_split = text.partition(SELECT_SYMBOL['scope'])[2].split() cmd = cmd.replace(SELECT_SYMBOL['scope'], '') continue_flag = True if not default_split: self.default_command = "" print('unscoping all', file=self.output) return continue_flag, cmd while default_split: if not text: value = '' else: value = default_split[0] tree_path = self.default_command.split() tree_path.append(value) if self.completer.command_tree.in_tree(tree_path): self.set_scope(value) print("defaulting: " + value, file=self.output) cmd = cmd.replace(SELECT_SYMBOL['scope'], '') elif SELECT_SYMBOL['unscope'] == default_split[0] and self.default_command.split(): value = self.default_command.split()[-1] self.default_command = ' ' + ' '.join(self.default_command.split()[:-1]) if not self.default_command.strip(): self.default_command = self.default_command.strip() print('unscoping: ' + value, file=self.output) elif SELECT_SYMBOL['unscope'] not in text: print("Scope must be a valid command", file=self.output) default_split = default_split[1:] return continue_flag, cmd def reset_history(self): history_file_path = os.path.join(self.config.get_config_dir(), self.config.get_history()) os.remove(history_file_path) self.history = FileHistory(history_file_path) self.cli.buffers[DEFAULT_BUFFER].history = self.history def cli_execute(self, cmd): """ sends the command to the CLI to be executed """ try: args = parse_quotes(cmd) if args and args[0] == 'feedback': self.config.set_feedback('yes') self.user_feedback = False azure_folder = get_config_dir() if not os.path.exists(azure_folder): os.makedirs(azure_folder) ACCOUNT.load(os.path.join(azure_folder, 'azureProfile.json')) CONFIG.load(os.path.join(azure_folder, 'az.json')) SESSION.load(os.path.join(azure_folder, 'az.sess'), max_age=3600) invocation = self.cli_ctx.invocation_cls(cli_ctx=self.cli_ctx, parser_cls=self.cli_ctx.parser_cls, commands_loader_cls=self.cli_ctx.commands_loader_cls, help_cls=self.cli_ctx.help_cls) if '--progress' in args: args.remove('--progress') execute_args = [args] thread = Thread(target=invocation.execute, args=execute_args) thread.daemon = True thread.start() self.threads.append(thread) self.curr_thread = thread progress_args = [self] thread = Thread(target=progress_view, args=progress_args) thread.daemon = True thread.start() self.threads.append(thread) result = None else: result = invocation.execute(args) self.last_exit = 0 if result and result.result is not None: from azure.cli.core._output import OutputProducer if self.output: self.output.write(result) self.output.flush() else: formatter = OutputProducer.get_formatter(self.cli_ctx.invocation.data['output']) OutputProducer(formatter=formatter).out(result) self.last = result except Exception as ex: # pylint: disable=broad-except self.last_exit = handle_exception(ex) except SystemExit as ex: self.last_exit = int(ex.code) def progress_patch(self, _=False): """ forces to use the Shell Progress """ from .progress import ShellProgressView self.cli_ctx.progress_controller.init_progress(ShellProgressView()) return self.cli_ctx.progress_controller def run(self): """ starts the REPL """ from .progress import ShellProgressView self.cli_ctx.get_progress_controller().init_progress(ShellProgressView()) self.cli_ctx.get_progress_controller = self.progress_patch self.command_table_thread = LoadCommandTableThread(self.restart_completer, self) self.command_table_thread.start() from .configuration import SHELL_HELP self.cli.buffers['symbols'].reset( initial_document=Document(u'{}'.format(SHELL_HELP))) # flush telemetry for new commands and send successful interactive mode entry event telemetry.set_success() telemetry.flush() while True: try: document = self.cli.run(reset_current_buffer=True) text = document.text if not text: # not input self.set_prompt() continue cmd = text outside = False except AttributeError: # when the user pressed Control D break except (KeyboardInterrupt, ValueError): # CTRL C self.set_prompt() continue else: self.history.append(text) b_flag, c_flag, outside, cmd = self._special_cases(cmd, outside) if b_flag: break if c_flag: self.set_prompt() continue self.set_prompt() if outside: subprocess.Popen(cmd, shell=True).communicate() else: telemetry.start() self.cli_execute(cmd) if self.last_exit and self.last_exit != 0: telemetry.set_failure() else: telemetry.set_success() telemetry.flush() telemetry.conclude()
def glob_search(env, search_text): p = _get_prefix(env) search_result = glob(os.path.join(p, search_text)) if search_result: console.print(remove_prefix(search_result)) else: console.print(f"[red]No results found for glob {search_text}[/red]") def bottom_toolbar(): return HTML( 'Interactive mode is <b><style bg="ansired">experimental</style></b>!') fh = FileHistory(".boa_tui_history") session = PromptSession(fh) def get_completer(): def get_paths(): return [build_context.config.work_dir] return NestedCompleter.from_nested_dict({ "help": None, "glob": { "build": None, "host": None }, "exit":