diff options
author | kotfu <kotfu@kotfu.net> | 2019-02-09 18:39:17 -0700 |
---|---|---|
committer | kotfu <kotfu@kotfu.net> | 2019-02-09 18:39:17 -0700 |
commit | 3911335e5533405dd7f65195fe1f20bf3ac08ef8 (patch) | |
tree | 1aa2c2b19b3256ce55e145823fdda8dad984d08b | |
parent | 321a8c72a48d227011177bb91006ed20607a1e44 (diff) | |
download | cmd2-git-3911335e5533405dd7f65195fe1f20bf3ac08ef8.tar.gz |
Added -x option to history command for #545
-rw-r--r-- | cmd2/cmd2.py | 42 | ||||
-rw-r--r-- | cmd2/history.py | 27 | ||||
-rw-r--r-- | tests/test_history.py | 61 |
3 files changed, 108 insertions, 22 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 69a6c2aa..1d9cbe85 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -3155,21 +3155,25 @@ class Cmd(cmd.Cmd): load_ipy(bridge) history_parser = ACArgumentParser() - history_parser_group = history_parser.add_mutually_exclusive_group() - history_parser_group.add_argument('-r', '--run', action='store_true', help='run selected history items') - history_parser_group.add_argument('-e', '--edit', action='store_true', + history_action_group = history_parser.add_mutually_exclusive_group() + history_action_group.add_argument('-r', '--run', action='store_true', help='run selected history items') + history_action_group.add_argument('-e', '--edit', action='store_true', help='edit and then run selected history items') - history_parser_group.add_argument('-s', '--script', action='store_true', help='output commands in script format') - setattr(history_parser_group.add_argument('-o', '--output-file', metavar='FILE', - help='output commands to a script file'), + setattr(history_action_group.add_argument('-o', '--output-file', metavar='FILE', + help='output commands to a script file, implies -s'), ACTION_ARG_CHOICES, ('path_complete',)) - setattr(history_parser_group.add_argument('-t', '--transcript', - help='output commands and results to a transcript file'), + setattr(history_action_group.add_argument('-t', '--transcript', + help='output commands and results to a transcript file, implies -s'), ACTION_ARG_CHOICES, ('path_complete',)) - history_parser_group.add_argument('-v', '--verbose', action='store_true', + history_action_group.add_argument('-c', '--clear', action='store_true', help='clear all history') + + history_format_group = history_parser.add_argument_group(title='formatting') + history_format_group.add_argument('-s', '--script', action='store_true', help='output commands in script format, i.e. without command numbers') + history_format_group.add_argument('-x', '--expanded', action='store_true', help='output expanded commands instead of entered command') + history_format_group.add_argument('-v', '--verbose', action='store_true', help='display history and include expanded commands if they' ' differ from the typed command.') - history_parser_group.add_argument('-c', '--clear', action="store_true", help='clear all history') + history_arg_help = ("empty all history items\n" "a one history item by number\n" "a..b, a:b, a:, ..b items by indices (inclusive)\n" @@ -3181,6 +3185,19 @@ class Cmd(cmd.Cmd): def do_history(self, args: argparse.Namespace) -> None: """View, run, edit, save, or clear previously entered commands""" + # -v must be used alone with no other options + if args.verbose: + if args.clear or args.edit or args.output_file or args.run or args.transcript or args.expanded or args.script: + self.poutput("-v can not be used with any other options") + self.poutput(self.history_parser.format_usage()) + return + + # -s and -x can only be used if none of these options are present: [-c -r -e -o -t] + if (args.script or args.expanded) and (args.clear or args.edit or args.output_file or args.run or args.transcript): + self.poutput("-s and -x can not be used with -c, -r, -e, -o, or -t") + self.poutput(self.history_parser.format_usage()) + return + if args.clear: # Clear command and readline history self.history.clear() @@ -3249,10 +3266,7 @@ class Cmd(cmd.Cmd): else: # Display the history items retrieved for hi in history: - if args.script: - self.poutput(hi) - else: - self.poutput(hi.pr(args.verbose)) + self.poutput(hi.pr(script=args.script, expanded=args.expanded, verbose=args.verbose)) def _generate_transcript(self, history: List[HistoryItem], transcript_file: str) -> None: """Generate a transcript file from a given history of commands.""" diff --git a/cmd2/history.py b/cmd2/history.py index 0989b7db..ad4b23aa 100644 --- a/cmd2/history.py +++ b/cmd2/history.py @@ -14,7 +14,7 @@ from .parsing import Statement class HistoryItem(str): """Class used to represent one command in the History list""" listformat = ' {:>4} {}\n' - ex_listformat = ' Ex: {}\n' + ex_listformat = ' {:>4}x {}\n' def __new__(cls, statement: Statement): """Create a new instance of HistoryItem @@ -32,15 +32,30 @@ class HistoryItem(str): """Return the command as run which includes shortcuts and aliases resolved plus any changes made in hooks""" return self.statement.expanded_command_line - def pr(self, verbose: bool) -> str: + def pr(self, script=False, expanded=False, verbose=False) -> str: """Represent a HistoryItem in a pretty fashion suitable for printing. + If you pass verbose=True, script and expanded will be ignored + :return: pretty print string version of a HistoryItem """ - ret_str = self.listformat.format(self.idx, str(self).rstrip()) - if verbose and self != self.expanded: - ret_str += self.ex_listformat.format(self.expanded.rstrip()) - + if verbose: + ret_str = self.listformat.format(self.idx, str(self).rstrip()) + if self != self.expanded: + ret_str += self.ex_listformat.format(self.idx, self.expanded.rstrip()) + else: + if script: + # display without entry numbers + if expanded: + ret_str = self.expanded.rstrip() + else: + ret_str = str(self) + else: + # display a numbered list + if expanded: + ret_str = self.listformat.format(self.idx, self.expanded.rstrip()) + else: + ret_str = self.listformat.format(self.idx, str(self).rstrip()) return ret_str diff --git a/tests/test_history.py b/tests/test_history.py index 0eddcc1f..98d72512 100644 --- a/tests/test_history.py +++ b/tests/test_history.py @@ -29,7 +29,7 @@ def hist(): HistoryItem(Statement('', raw='fourth'))]) return h -def test_history_span(hist): +def test_history_class_span(hist): h = hist assert h == ['first', 'second', 'third', 'fourth'] assert h.span('-2..') == ['third', 'fourth'] @@ -41,7 +41,7 @@ def test_history_span(hist): assert h.span('-2..-3') == ['third', 'second'] assert h.span('*') == h -def test_history_get(hist): +def test_history_class_get(hist): h = hist assert h == ['first', 'second', 'third', 'fourth'] assert h.get('') == h @@ -207,3 +207,60 @@ def test_history_clear(base_app): # Make sure history is empty out = run_cmd(base_app, 'history') assert out == [] + +def test_history_verbose_with_other_options(base_app): + # make sure -v shows a usage error if any other options are present + options_to_test = ['-r', '-e', '-o file', '-t file', '-c', '-x'] + for opt in options_to_test: + output = run_cmd(base_app, 'history -v ' + opt) + assert len(output) == 3 + assert output[1].startswith('Usage:') + +def test_history_verbose(base_app): + # validate function of -v option + run_cmd(base_app, 'alias create s shortcuts') + run_cmd(base_app, 's') + output = run_cmd(base_app, 'history -v') + assert len(output) == 3 + # TODO test for basic formatting once we figure it out + +def test_history_script_with_invalid_options(base_app): + # make sure -s shows a usage error if -c, -r, -e, -o, or -t are present + options_to_test = ['-r', '-e', '-o file', '-t file', '-c'] + for opt in options_to_test: + output = run_cmd(base_app, 'history -s ' + opt) + assert len(output) == 3 + assert output[1].startswith('Usage:') + +def test_history_script(base_app): + cmds = ['alias create s shortcuts', 's'] + for cmd in cmds: + run_cmd(base_app, cmd) + output = run_cmd(base_app, 'history -s') + assert output == cmds + +def test_history_expanded_with_invalid_options(base_app): + # make sure -x shows a usage error if -c, -r, -e, -o, or -t are present + options_to_test = ['-r', '-e', '-o file', '-t file', '-c'] + for opt in options_to_test: + output = run_cmd(base_app, 'history -x ' + opt) + assert len(output) == 3 + assert output[1].startswith('Usage:') + +def test_history_expanded(base_app): + # validate function of -x option + cmds = ['alias create s shortcuts', 's'] + for cmd in cmds: + run_cmd(base_app, cmd) + output = run_cmd(base_app, 'history -x') + expected = [' 1 alias create s shortcuts', ' 2 shortcuts'] + assert output == expected + +def test_history_script_expanded(base_app): + # validate function of -s -x options together + cmds = ['alias create s shortcuts', 's'] + for cmd in cmds: + run_cmd(base_app, cmd) + output = run_cmd(base_app, 'history -sx') + expected = ['alias create s shortcuts', 'shortcuts'] + assert output == expected |