diff options
author | Zearin <zearin@gonk.net> | 2011-10-08 09:05:10 -0400 |
---|---|---|
committer | Zearin <zearin@gonk.net> | 2011-10-08 09:05:10 -0400 |
commit | e641f29289cd22aeea7fa277c9c3beaa93028a84 (patch) | |
tree | 511dfd3a5cce027491285fe5aa48e331e82a033a | |
parent | 55084970e49c839cee9b2c7337f2905bc7950391 (diff) | |
download | cmd2-e641f29289cd22aeea7fa277c9c3beaa93028a84.tar.gz |
Moved all `do_*` methods to commands.py.
The contents of commands.py gets imported at the top of the Cmd class.
Also did a couple other small tweaks to the Cmd class. Mostly moving stuff around (private defs first, sorted the class variables near the top of Cmd, etc.)
-rwxr-xr-x | cmd2.py | 667 | ||||
-rw-r--r-- | commands.py | 354 |
2 files changed, 520 insertions, 501 deletions
@@ -48,8 +48,8 @@ import pyparsing # Local imports -from . import commands, \ - errors, \ +# (commands.py is imported in the Cmd class) +from . import errors, \ parsers, \ support, \ tests @@ -73,48 +73,88 @@ if sys.version_info[0] == 2: class Cmd(cmd.Cmd): - echo = False + from . import commands # I *think* this lets commands get their own file + # while still limiting their scope to this class... + + + _STOP_AND_EXIT = True # distinguish script file's end from actual exit + _STOP_SCRIPT_NO_EXIT = -999 + + + # @TODO + # Refactor all shell settings into a module or single + # data structure (list/dict/whatever). + # Perhaps call it "shopt"? + # + # Currently the "settable" StubbornDict groups user-settable + # options, but I'd prefer they *existed* as a group, + # rather than merely a bunch of variables that get *referenced* + # as a group. + + + + + abbrev = True # Abbreviated commands recognized case_insensitive = True # Commands recognized regardless of case continuation_prompt = '> ' - timing = False # Prints elapsed time for each command + current_script_dir = None + debug = False + default_file_name = 'command.txt' # For ``save``, ``load``, etc. + default_to_shell = False + defaultExtension = 'txt' # For ``save``, ``load``, etc. + echo = False + excludeFromHistory = '''run r list l history hi ed edit li eof'''.split() + feedback_to_output = False # Include nonessentials in >, | output + kept_state = None # make sure your terminators are not in legalChars! legalChars = u'!#$%.:?@_' + pyparsing.alphanums + pyparsing.alphas8bit + locals_in_py = True + noSpecialParse = 'set ed edit exit'.split() + quiet = False # Do not suppress nonessential output + redirector = '>' # For redirecting output to a file + reserved_words = [] shortcuts = { '?': 'help', '!': 'shell', '@': 'load', '@@': '_relative_load' } - - excludeFromHistory = '''run r list l history hi ed edit li eof'''.split() - default_to_shell = False - noSpecialParse = 'set ed edit exit'.split() - defaultExtension = 'txt' # For ``save``, ``load``, etc. - default_file_name = 'command.txt' # For ``save``, ``load``, etc. - abbrev = True # Abbreviated commands recognized - current_script_dir = None - reserved_words = [] - feedback_to_output = False # Include nonessentials in >, | output - quiet = False # Do not suppress nonessential output - debug = False - locals_in_py = True - kept_state = None - redirector = '>' # For redirecting output to a file + timing = False # Prints elapsed time for each command settable = stubbornDict(''' - prompt + abbrev Accept abbreviated commands + case_insensitive upper- and lower-case both OK colors Colorized output (*nix only) continuation_prompt On 2nd+ line of input debug Show full error stack on error default_file_name for ``save``, ``load``, etc. + echo Echo command issued into output editor Program used by ``edit`` - case_insensitive upper- and lower-case both OK feedback_to_output include nonessentials in `|`, `>` results + prompt quiet Don't print nonessential feedback - echo Echo command issued into output timing Report execution times - abbrev Accept abbreviated commands ''') + editor = os.environ.get('EDITOR') + + if not editor: + if sys.platform[:3] == 'win': + editor = 'notepad' + else: + for editor in ['gedit', 'kate', 'vim', 'emacs', 'nano', 'pico']: + if subprocess.Popen(['which', editor], stdout=subprocess.PIPE).communicate()[0]: + break + + + prefixParser = pyparsing.Empty() + commentGrammars = pyparsing.Or([pyparsing.pythonStyleComment, pyparsing.cStyleComment]) + commentGrammars.addParseAction(lambda x: '') + commentInProgress = pyparsing.Literal('/*') + pyparsing.SkipTo(pyparsing.stringEnd ^ '*/') + terminators = [';'] + blankLinesAllowed = False + multilineCommands = [] + + def __init__(self, *args, **kwargs): # @FIXME # @@ -132,83 +172,60 @@ class Cmd(cmd.Cmd): self._init_parser() - def poutput(self, msg): - ''' - Convenience shortcut for self.stdout.write(). Adds newline if necessary. - ''' - if msg: - self.stdout.write(msg) - if msg[-1] != '\n': - self.stdout.write('\n') - - - def perror(self, errmsg, statement=None): - if self.debug: - traceback.print_exc() - print (str(errmsg)) - - - def pfeedback(self, msg): + def _cmdloop(self, intro=None): ''' - Prints nonessential feedback. Can be silenced with `quiet`. - - Inclusion in redirected output is controlled by `feedback_to_output`. + Repeatedly issue a prompt, accept input, parse an initial prefix + off the received input, and dispatch to action methods, passing them + the remainder of the line as argument. ''' - if not self.quiet: - if self.feedback_to_output: - self.poutput(msg) - else: - print (msg) - - _STOP_AND_EXIT = True # distinguish script file's end from actual exit - _STOP_SCRIPT_NO_EXIT = -999 - - editor = os.environ.get('EDITOR') - - if not editor: - if sys.platform[:3] == 'win': - editor = 'notepad' - else: - for editor in ['gedit', 'kate', 'vim', 'emacs', 'nano', 'pico']: - if subprocess.Popen(['which', editor], stdout=subprocess.PIPE).communicate()[0]: - break - - colorcodes = { 'bold' :{True:'\x1b[1m' ,False:'\x1b[22m'}, - 'cyan' :{True:'\x1b[36m',False:'\x1b[39m'}, - 'blue' :{True:'\x1b[34m',False:'\x1b[39m'}, - 'red' :{True:'\x1b[31m',False:'\x1b[39m'}, - 'magenta' :{True:'\x1b[35m',False:'\x1b[39m'}, - 'green' :{True:'\x1b[32m',False:'\x1b[39m'}, - 'underline' :{True:'\x1b[4m' ,False:'\x1b[24m'} - } - - colors = (platform.system() != 'Windows') - - - def colorize(self, val, color): - ''' - Wraps the provided string in UNIX-style special characters that - turn on (and then off) text color and style. + # An almost-perfect copy from Cmd. + # + # However, the `pseudo_raw_input` portion has been + # split out so that it can be called separately. - The string is returned unchanged if the ``colors`` environment variable - is ``False`` or the application is running on Windows. + self.preloop() - ``color`` should be one of the supported strings (or styles): - red/blue/green/cyan/magenta, bold, underline - ''' - if self.colors and (self.stdout == self.initial_stdout): - return self.colorcodes[color][True] + val + self.colorcodes[color][False] - return val + if self.use_rawinput and self.completekey: + try: + import readline + self.old_completer = readline.get_completer() + readline.set_completer(self.complete) + readline.parse_and_bind(self.completekey+": complete") + except ImportError: + pass + try: + if intro is not None: + self.intro = intro + if self.intro: + self.stdout.write(str(self.intro)+"\n") + stop = None + while not stop: + if self.cmdqueue: + line = self.cmdqueue.pop(0) + else: + line = self.pseudo_raw_input(self.prompt) + if (self.echo) and (isinstance(self.stdin, file)): + self.stdout.write(line + '\n') + stop = self.onecmd_plus_hooks(line) + self.postloop() + finally: + if self.use_rawinput and self.completekey: + try: + import readline + readline.set_completer(self.old_completer) + except ImportError: + pass + return stop - prefixParser = pyparsing.Empty() - commentGrammars = pyparsing.Or([pyparsing.pythonStyleComment, pyparsing.cStyleComment]) - commentGrammars.addParseAction(lambda x: '') - commentInProgress = pyparsing.Literal('/*') + pyparsing.SkipTo(pyparsing.stringEnd ^ '*/') - terminators = [';'] - blankLinesAllowed = False - multilineCommands = [] + def _default(self, statement): + arg = statement.full_parsed_statement() + if self.default_to_shell: + result = os.system(arg) + if not result: + return self.postparsing_postcmd(None) + return self.postparsing_postcmd(self.default(arg)) # @TODO @@ -502,6 +519,64 @@ class Cmd(cmd.Cmd): return stop + def poutput(self, msg): + ''' + Convenience shortcut for self.stdout.write(). Adds newline if necessary. + ''' + if msg: + self.stdout.write(msg) + if msg[-1] != '\n': + self.stdout.write('\n') + + + def perror(self, errmsg, statement=None): + if self.debug: + traceback.print_exc() + print (str(errmsg)) + + + def pfeedback(self, msg): + ''' + Prints nonessential feedback. Can be silenced with `quiet`. + + Inclusion in redirected output is controlled by `feedback_to_output`. + ''' + if not self.quiet: + if self.feedback_to_output: + self.poutput(msg) + else: + print (msg) + + + colorcodes = { 'bold' :{True:'\x1b[1m' ,False:'\x1b[22m'}, + 'cyan' :{True:'\x1b[36m',False:'\x1b[39m'}, + 'blue' :{True:'\x1b[34m',False:'\x1b[39m'}, + 'red' :{True:'\x1b[31m',False:'\x1b[39m'}, + 'magenta' :{True:'\x1b[35m',False:'\x1b[39m'}, + 'green' :{True:'\x1b[32m',False:'\x1b[39m'}, + 'underline' :{True:'\x1b[4m' ,False:'\x1b[24m'} + } + + + colors = (platform.system() != 'Windows') + + + def colorize(self, val, color): + ''' + Wraps the provided string in UNIX-style special characters that + turn on (and then off) text color and style. + + The string is returned unchanged if the ``colors`` environment variable + is ``False`` or the application is running on Windows. + + ``color`` should be one of the supported strings (or styles): + red/blue/green/cyan/magenta, bold, underline + ''' + if self.colors and (self.stdout == self.initial_stdout): + return self.colorcodes[color][True] + val + self.colorcodes[color][False] + return val + + def func_named(self, arg): result = None target = 'do_' + arg @@ -633,15 +708,6 @@ class Cmd(cmd.Cmd): return stop - def _default(self, statement): - arg = statement.full_parsed_statement() - if self.default_to_shell: - result = os.system(arg) - if not result: - return self.postparsing_postcmd(None) - return self.postparsing_postcmd(self.default(arg)) - - def pseudo_raw_input(self, prompt): ''' Copied from cmd's cmdloop. Similar to raw_input, but accounts for changed stdin/stdout. @@ -663,53 +729,6 @@ class Cmd(cmd.Cmd): return line - def _cmdloop(self, intro=None): - ''' - Repeatedly issue a prompt, accept input, parse an initial prefix - off the received input, and dispatch to action methods, passing them - the remainder of the line as argument. - ''' - - # An almost-perfect copy from Cmd. - # - # However, the `pseudo_raw_input` portion has been - # split out so that it can be called separately. - - self.preloop() - - if self.use_rawinput and self.completekey: - try: - import readline - self.old_completer = readline.get_completer() - readline.set_completer(self.complete) - readline.parse_and_bind(self.completekey+": complete") - except ImportError: - pass - try: - if intro is not None: - self.intro = intro - if self.intro: - self.stdout.write(str(self.intro)+"\n") - stop = None - while not stop: - if self.cmdqueue: - line = self.cmdqueue.pop(0) - else: - line = self.pseudo_raw_input(self.prompt) - if (self.echo) and (isinstance(self.stdin, file)): - self.stdout.write(line + '\n') - stop = self.onecmd_plus_hooks(line) - self.postloop() - finally: - if self.use_rawinput and self.completekey: - try: - import readline - readline.set_completer(self.old_completer) - except ImportError: - pass - return stop - - def select(self, options, prompt='Your choice? '): ''' Presents a numbered menu to the user. Modeled after @@ -814,356 +833,6 @@ class Cmd(cmd.Cmd): return self._STOP_AND_EXIT - def do__relative_load(self, arg=None): - ''' - Runs commands in script at file or URL; if this is called from within an - already-running script, the filename will be interpreted relative to the - already-running script's directory. - ''' - if arg: - arg = arg.split(None, 1) - targetname, args = arg[0], (arg[1:] or [''])[0] - targetname = os.path.join(self.current_script_dir or '', targetname) - self.do__load('%s %s' % (targetname, args)) - - urlre = re.compile('(https?://[-\\w\\./]+)') - - def do_cmdenvironment(self, args): - ''' - Summary report of interactive parameters. - ''' - - self.stdout.write(""" - Commands are %(casesensitive)scase-sensitive. - Commands may be terminated with: %(terminators)s - - Settable parameters: %(settable)s\n""" % \ - { 'casesensitive' : (self.case_insensitive and 'not ') or '', - 'terminators' : str(self.terminators), - 'settable' : ' '.join(self.settable) - }) - - - def do_help(self, arg): - if arg: - funcname = self.func_named(arg) - if funcname: - fn = getattr(self, funcname) - try: - fn.optionParser.print_help(file=self.stdout) - except AttributeError: - cmd.Cmd.do_help(self, funcname[3:]) - else: - cmd.Cmd.do_help(self, arg) - - - def do_shortcuts(self, args): - ''' - Lists single-key shortcuts available. - ''' - result = "\n".join('%s: %s' % (sc[0], sc[1]) for sc in sorted(self.shortcuts)) - self.stdout.write("Single-key shortcuts for other commands:\n%s\n" % (result)) - - - def do_EOF(self, arg): - return self._STOP_SCRIPT_NO_EXIT # End of script; should not exit app - - do_eof = do_EOF - - - def do_quit(self, arg): - return self._STOP_AND_EXIT - - do_exit = do_quit - do_q = do_quit - - - @options( - [make_option( - '-l', '--long', - action ="store_true", - help ="describe function of parameter")]) - def do_show(self, arg, opts): - ''' - Show the value of a parameter. - ''' - param = arg.strip().lower() - result = {} - maxlen = 0 - for p in self.settable: - if (not param) or p.startswith(param): - result[p] = '%s: %s' % (p, str(getattr(self, p))) - maxlen = max(maxlen, len(result[p])) - if result: - for p in sorted(result): - if opts.long: - self.poutput('%s # %s' % (result[p].ljust(maxlen), self.settable[p])) - else: - self.poutput(result[p]) - else: - raise NotImplementedError("Parameter '%s' not supported (type 'show' for list of parameters)." % param) - - - def do_set(self, arg): - ''' - Set a cmd2 parameter. Accepts abbreviated parameter names - if there is no ambiguity. Lists settable parameters and values if - called with no arguments. - ''' - try: - statement, paramName, val = arg.parsed.raw.split(None, 2) - val = val.strip() - paramName = paramName.strip().lower() - - if paramName not in self.settable: - hits = [p for p in self.settable if p.startswith(paramName)] - if len(hits) == 1: - paramName = hits[0] - else: - return self.do_show(paramName) - currentVal = getattr(self, paramName) - - if (val[0] == val[-1]) and val[0] in ("'", '"'): - val = val[1:-1] - else: - val = cast(currentVal, val) - - setattr(self, paramName, val) - self.stdout.write('%s - was: %s\nnow: %s\n' % (paramName, currentVal, val)) - - if currentVal != val: - try: - onchange_hook = getattr(self, '_onchange_%s' % paramName) - onchange_hook(old=currentVal, new=val) - except AttributeError: - pass - except (ValueError, AttributeError, NotSettableError), e: - self.do_show(arg) - - - def do_pause(self, arg): - '''Display the provided text, then wait for the user to press RETURN.''' - raw_input(arg + '\n') - - - def do_shell(self, arg): - ''' - Executes a command as if at the OS prompt. - ''' - os.system(arg) - - - def do_py(self, arg): - ''' - py <command>: Executes a Python command. - py: Enters interactive Python mode. - - End with ``Ctrl-D`` (Unix) / ``Ctrl-Z`` (Windows), ``quit()``, '`exit()``. - - Non-python commands can be issued with ``cmd("your command")``. - Run python code from external files with ``run("filename.py")`` - ''' - self.pystate['self'] = self - arg = arg.parsed.raw[2:].strip() - localvars = (self.locals_in_py and self.pystate) or {} - interp = InteractiveConsole(locals=localvars) - interp.runcode('import sys, os;sys.path.insert(0, os.getcwd())') - - if arg.strip(): - interp.runcode(arg) - else: - def quit(): - raise EmbeddedConsoleExit - def onecmd_plus_hooks(arg): - return self.onecmd_plus_hooks(arg + '\n') - def run(arg): - try: - file = open(arg) - interp.runcode(file.read()) - file.close() - except IOError, e: - self.perror(e) - self.pystate['quit'] = quit - self.pystate['exit'] = quit - self.pystate['cmd'] = onecmd_plus_hooks - self.pystate['run'] = run - - try: - cprt = 'Type "help", "copyright", "credits" or "license" for more information.' - keepstate = Statekeeper(sys, ('stdin','stdout')) - sys.stdout = self.stdout - sys.stdin = self.stdin - interp.interact(banner= "Python %s on %s\n%s\n(%s)\n%s" % - (sys.version, sys.platform, cprt, self.__class__.__name__, self.do_py.__doc__)) - except EmbeddedConsoleExit: - pass - keepstate.restore() - - - @options( - [make_option( - '-s', '--script', - action = 'store_true', - help = 'Script format; no separation lines'),], - arg_desc = '(limit on which commands to include)') - def do_history(self, arg, opts): - ''' - history [arg]: lists past commands issued - - | no arg: list all - | arg is integer: list one history item, by index - | arg is string: string search - | /arg enclosed slashes/: regular expression search - ''' - if arg: - history = self.history.get(arg) - else: - history = self.history - for hi in history: - if opts.script: - self.poutput(hi) - else: - self.stdout.write(hi.pr()) - - - def do_list(self, arg): - '''list [arg]: lists last command issued - - no arg -> list most recent command - arg is integer -> list one history item, by index - a..b, a:b, a:, ..b -> list spans from a (or start) to b (or end) - arg is string -> list all commands matching string search - /arg enclosed in slashes/ -> regular expression search - ''' - try: - history = self.history.span(arg or '-1') - except IndexError: - history = self.history.search(arg) - for hi in history: - self.poutput(hi.pr()) - - do_hi = do_history - do_l = do_list - do_li = do_list - - - def do_ed(self, arg): - ''' - ed: edit most recent command in text editor - ed [N]: edit numbered command from history - ed [filename]: edit specified file name - - Commands are run after editor is closed. - - The editor defaults to the EDITOR environment variable. You - can also use `set edit <program-name>` to choose an editor. - ''' - if not self.editor: - raise EnvironmentError("Please use 'set editor' to specify your text editing program of choice.") - filename = self.default_file_name - if arg: - try: - buffer = self.last_matching(int(arg)) - except ValueError: - filename = arg - buffer = '' - else: - buffer = self.history[-1] - - if buffer: - f = open(os.path.expanduser(filename), 'w') - f.write(buffer or '') - f.close() - os.system('%s %s' % (self.editor, filename)) - self.do__load(filename) - - do_edit = do_ed - - saveparser = (pyparsing.Optional(pyparsing.Word(pyparsing.nums)^'*')("idx") + - pyparsing.Optional(pyparsing.Word(legalChars + '/\\'))("fname") + - pyparsing.stringEnd) - - - def do_save(self, arg): - ''' - `save [N] [filename.ext]` - - Saves command from history to file. - - | N => Number of command (from history), or `*`; - | most recent command if omitted - ''' - try: - args = self.saveparser.parseString(arg) - except pyparsing.ParseException: - self.perror('Could not understand save target %s' % arg) - raise SyntaxError(self.do_save.__doc__) - - fname = args.fname or self.default_file_name - - if args.idx == '*': - saveme = '\n\n'.join(self.history[:]) - elif args.idx: - saveme = self.history[int(args.idx)-1] - else: - saveme = self.history[-1] - - try: - f = open(os.path.expanduser(fname), 'w') - f.write(saveme) - f.close() - self.pfeedback('Saved to %s' % (fname)) - except Exception, e: - self.perror('Error saving %s' % (fname)) - raise - - - def do_load(self, arg=None): - ''' - Runs script of command(s) from a file or URL. - ''' - if arg is None: - targetname = self.default_file_name - else: - arg = arg.split(None, 1) - targetname, args = arg[0], (arg[1:] or [''])[0].strip() - try: - target = self.read_file_or_url(targetname) - except IOError, e: - self.perror('Problem accessing script from %s: \n%s' % (targetname, e)) - return - keepstate = Statekeeper(self, ('stdin','use_rawinput','prompt', - 'continuation_prompt','current_script_dir')) - self.stdin = target - self.use_rawinput = False - self.prompt = self.continuation_prompt = '' - self.current_script_dir = os.path.split(targetname)[0] - stop = self._cmdloop() - self.stdin.close() - keepstate.restore() - self.lastcmd = '' - return stop and (stop != self._STOP_SCRIPT_NO_EXIT) - - do__load = do_load # avoid an unfortunate legacy use of do_load from sqlpython - - def do_run(self, arg): - ''' - run [arg]: re-runs an earlier command - - no arg -> run most recent command - arg is integer -> run one history item, by index - arg is string -> run most recent command by string search - /arg enclosed in slashes/ -> run most recent by regex - ''' - 'run [N]: runs the SQL that was run N commands ago' - runme = self.last_matching(arg) - self.pfeedback(runme) - if runme: - stop = self.onecmd_plus_hooks(runme) - - do_r = do_run - - def cmdloop(self): parser = optparse.OptionParser() parser.add_option('-t', '--test', diff --git a/commands.py b/commands.py index 608bc63..61f5170 100644 --- a/commands.py +++ b/commands.py @@ -1,3 +1,353 @@ ''' -This file should contain all the `do_*` commands built-in to Cmd2. -'''
\ No newline at end of file +This file should contain all the built-in `do_*` commands of Cmd2. +''' + + +def do__relative_load(self, arg=None): + ''' + Runs commands in script at file or URL; if this is called from within an + already-running script, the filename will be interpreted relative to the + already-running script's directory. + ''' + if arg: + arg = arg.split(None, 1) + targetname, args = arg[0], (arg[1:] or [''])[0] + targetname = os.path.join(self.current_script_dir or '', targetname) + self.do__load('%s %s' % (targetname, args)) + +urlre = re.compile('(https?://[-\\w\\./]+)') + +def do_cmdenvironment(self, args): + ''' + Summary report of interactive parameters. + ''' + + self.stdout.write(""" + Commands are %(casesensitive)scase-sensitive. + Commands may be terminated with: %(terminators)s + + Settable parameters: %(settable)s\n""" % \ + { 'casesensitive' : (self.case_insensitive and 'not ') or '', + 'terminators' : str(self.terminators), + 'settable' : ' '.join(self.settable) + }) + + +def do_help(self, arg): + if arg: + funcname = self.func_named(arg) + if funcname: + fn = getattr(self, funcname) + try: + fn.optionParser.print_help(file=self.stdout) + except AttributeError: + cmd.Cmd.do_help(self, funcname[3:]) + else: + cmd.Cmd.do_help(self, arg) + + +def do_shortcuts(self, args): + ''' + Lists single-key shortcuts available. + ''' + result = "\n".join('%s: %s' % (sc[0], sc[1]) for sc in sorted(self.shortcuts)) + self.stdout.write("Single-key shortcuts for other commands:\n%s\n" % (result)) + + +def do_EOF(self, arg): + return self._STOP_SCRIPT_NO_EXIT # End of script; should not exit app + +do_eof = do_EOF + + +def do_quit(self, arg): + return self._STOP_AND_EXIT + +do_exit = do_quit +do_q = do_quit + + +@options( + [make_option( + '-l', '--long', + action ="store_true", + help ="describe function of parameter")]) +def do_show(self, arg, opts): + ''' + Show the value of a parameter. + ''' + param = arg.strip().lower() + result = {} + maxlen = 0 + for p in self.settable: + if (not param) or p.startswith(param): + result[p] = '%s: %s' % (p, str(getattr(self, p))) + maxlen = max(maxlen, len(result[p])) + if result: + for p in sorted(result): + if opts.long: + self.poutput('%s # %s' % (result[p].ljust(maxlen), self.settable[p])) + else: + self.poutput(result[p]) + else: + raise NotImplementedError("Parameter '%s' not supported (type 'show' for list of parameters)." % param) + + +def do_set(self, arg): + ''' + Set a cmd2 parameter. Accepts abbreviated parameter names + if there is no ambiguity. Lists settable parameters and values if + called with no arguments. + ''' + try: + statement, paramName, val = arg.parsed.raw.split(None, 2) + val = val.strip() + paramName = paramName.strip().lower() + + if paramName not in self.settable: + hits = [p for p in self.settable if p.startswith(paramName)] + if len(hits) == 1: + paramName = hits[0] + else: + return self.do_show(paramName) + currentVal = getattr(self, paramName) + + if (val[0] == val[-1]) and val[0] in ("'", '"'): + val = val[1:-1] + else: + val = cast(currentVal, val) + + setattr(self, paramName, val) + self.stdout.write('%s - was: %s\nnow: %s\n' % (paramName, currentVal, val)) + + if currentVal != val: + try: + onchange_hook = getattr(self, '_onchange_%s' % paramName) + onchange_hook(old=currentVal, new=val) + except AttributeError: + pass + except (ValueError, AttributeError, NotSettableError), e: + self.do_show(arg) + + +def do_pause(self, arg): + '''Display the provided text, then wait for the user to press RETURN.''' + raw_input(arg + '\n') + + +def do_shell(self, arg): + ''' + Executes a command as if at the OS prompt. + ''' + os.system(arg) + + +def do_py(self, arg): + ''' + py <command>: Executes a Python command. + py: Enters interactive Python mode. + + End with ``Ctrl-D`` (Unix) / ``Ctrl-Z`` (Windows), ``quit()``, '`exit()``. + + Non-python commands can be issued with ``cmd("your command")``. + Run python code from external files with ``run("filename.py")`` + ''' + self.pystate['self'] = self + arg = arg.parsed.raw[2:].strip() + localvars = (self.locals_in_py and self.pystate) or {} + interp = InteractiveConsole(locals=localvars) + interp.runcode('import sys, os;sys.path.insert(0, os.getcwd())') + + if arg.strip(): + interp.runcode(arg) + else: + def quit(): + raise EmbeddedConsoleExit + def onecmd_plus_hooks(arg): + return self.onecmd_plus_hooks(arg + '\n') + def run(arg): + try: + file = open(arg) + interp.runcode(file.read()) + file.close() + except IOError, e: + self.perror(e) + self.pystate['quit'] = quit + self.pystate['exit'] = quit + self.pystate['cmd'] = onecmd_plus_hooks + self.pystate['run'] = run + + try: + cprt = 'Type "help", "copyright", "credits" or "license" for more information.' + keepstate = Statekeeper(sys, ('stdin','stdout')) + sys.stdout = self.stdout + sys.stdin = self.stdin + interp.interact(banner= "Python %s on %s\n%s\n(%s)\n%s" % + (sys.version, sys.platform, cprt, self.__class__.__name__, self.do_py.__doc__)) + except EmbeddedConsoleExit: + pass + keepstate.restore() + + +@options( + [make_option( + '-s', '--script', + action = 'store_true', + help = 'Script format; no separation lines'),], + arg_desc = '(limit on which commands to include)') +def do_history(self, arg, opts): + ''' + history [arg]: lists past commands issued + + | no arg: list all + | arg is integer: list one history item, by index + | arg is string: string search + | /arg enclosed slashes/: regular expression search + ''' + if arg: + history = self.history.get(arg) + else: + history = self.history + for hi in history: + if opts.script: + self.poutput(hi) + else: + self.stdout.write(hi.pr()) + + +def do_list(self, arg): + '''list [arg]: lists last command issued + + no arg -> list most recent command + arg is integer -> list one history item, by index + a..b, a:b, a:, ..b -> list spans from a (or start) to b (or end) + arg is string -> list all commands matching string search + /arg enclosed in slashes/ -> regular expression search + ''' + try: + history = self.history.span(arg or '-1') + except IndexError: + history = self.history.search(arg) + for hi in history: + self.poutput(hi.pr()) + +do_hi = do_history +do_l = do_list +do_li = do_list + + +def do_ed(self, arg): + ''' + ed: edit most recent command in text editor + ed [N]: edit numbered command from history + ed [filename]: edit specified file name + + Commands are run after editor is closed. + + The editor defaults to the EDITOR environment variable. You + can also use `set edit <program-name>` to choose an editor. + ''' + if not self.editor: + raise EnvironmentError("Please use 'set editor' to specify your text editing program of choice.") + filename = self.default_file_name + if arg: + try: + buffer = self.last_matching(int(arg)) + except ValueError: + filename = arg + buffer = '' + else: + buffer = self.history[-1] + + if buffer: + f = open(os.path.expanduser(filename), 'w') + f.write(buffer or '') + f.close() + os.system('%s %s' % (self.editor, filename)) + self.do__load(filename) + +do_edit = do_ed + +saveparser = (pyparsing.Optional(pyparsing.Word(pyparsing.nums)^'*')("idx") + + pyparsing.Optional(pyparsing.Word(legalChars + '/\\'))("fname") + + pyparsing.stringEnd) + + +def do_save(self, arg): + ''' + `save [N] [filename.ext]` + + Saves command from history to file. + + | N => Number of command (from history), or `*`; + | most recent command if omitted + ''' + try: + args = self.saveparser.parseString(arg) + except pyparsing.ParseException: + self.perror('Could not understand save target %s' % arg) + raise SyntaxError(self.do_save.__doc__) + + fname = args.fname or self.default_file_name + + if args.idx == '*': + saveme = '\n\n'.join(self.history[:]) + elif args.idx: + saveme = self.history[int(args.idx)-1] + else: + saveme = self.history[-1] + + try: + f = open(os.path.expanduser(fname), 'w') + f.write(saveme) + f.close() + self.pfeedback('Saved to %s' % (fname)) + except Exception, e: + self.perror('Error saving %s' % (fname)) + raise + + +def do_load(self, arg=None): + ''' + Runs script of command(s) from a file or URL. + ''' + if arg is None: + targetname = self.default_file_name + else: + arg = arg.split(None, 1) + targetname, args = arg[0], (arg[1:] or [''])[0].strip() + try: + target = self.read_file_or_url(targetname) + except IOError, e: + self.perror('Problem accessing script from %s: \n%s' % (targetname, e)) + return + keepstate = Statekeeper(self, ('stdin','use_rawinput','prompt', + 'continuation_prompt','current_script_dir')) + self.stdin = target + self.use_rawinput = False + self.prompt = self.continuation_prompt = '' + self.current_script_dir = os.path.split(targetname)[0] + stop = self._cmdloop() + self.stdin.close() + keepstate.restore() + self.lastcmd = '' + return stop and (stop != self._STOP_SCRIPT_NO_EXIT) + +do__load = do_load # avoid an unfortunate legacy use of do_load from sqlpython + +def do_run(self, arg): + ''' + run [arg]: re-runs an earlier command + + no arg -> run most recent command + arg is integer -> run one history item, by index + arg is string -> run most recent command by string search + /arg enclosed in slashes/ -> run most recent by regex + ''' + 'run [N]: runs the SQL that was run N commands ago' + runme = self.last_matching(arg) + self.pfeedback(runme) + if runme: + stop = self.onecmd_plus_hooks(runme) + +do_r = do_run
\ No newline at end of file |