From ad3d32339f791faa31763fe3efb42d0be469ddef Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sat, 3 Jun 2017 10:59:06 -0400 Subject: [PATCH 1/4] Removed redundant list command The extra functionality of listing a span (slice) of history items present in the list command has been incorporated into the existing history command and the list command has been removed. Unit tests have been updated accordingly. In the process a bug was fixed that was causing a crash if and end was supplied to the span but not a start. --- cmd2.py | 49 ++++++++++++---------------------------- tests/conftest.py | 7 +++--- tests/test_cmd2.py | 44 ++++++++++++++++++++++++------------ tests/test_transcript.py | 5 ++-- tests/transcript.txt | 5 ++-- 5 files changed, 51 insertions(+), 59 deletions(-) diff --git a/cmd2.py b/cmd2.py index 4befe0191..93f0152c0 100755 --- a/cmd2.py +++ b/cmd2.py @@ -1592,7 +1592,8 @@ def do_history(self, arg, opts): | no arg: list all | arg is integer: list one history item, by index - | arg is string: string search + | a..b, a:b, a:, ..b -> list history items by a span of indices (inclusive) + | arg is string: list all commands matching string search | arg is /enclosed in forward-slashes/: regular expression search """ # If arguments are being passed as a list instead of as a string @@ -1602,10 +1603,20 @@ def do_history(self, arg, opts): else: arg = '' + # If an argument was supplied, then retrieve partial contents of the history if arg: - history = self.history.get(arg) + # If a character indicating a slice is present, retrieve a slice of the history + if '..' in arg or ':' in arg: + # Get a slice of history + history = self.history.span(arg) + else: + # Get item(s) from history by index or string search + history = self.history.get(arg) else: + # If no arg given, then retrieve the entire history history = self.history + + # Display the history items retrieved for hi in history: if opts.script: self.poutput(hi) @@ -1628,38 +1639,6 @@ def _last_matching(self, arg): except IndexError: return None - def do_list(self, arg): - """list [arg]: lists command(s) from history in a flexible/searchable way. - - :param arg: str - behavior varies as follows: - - * 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 is /enclosed in forward-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()) - - def help_list(self): - """Print help for do_list().""" - help_str = """Lists command(s) from history in a flexible/searchable way. - - Usage: list [arg] - - Where arg is: - 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 is /enclosed in forward-slashes/ -> regular expression search""" - self.stdout.write("{}\n".format(help_str)) - def do_edit(self, arg): """Edit a file or command in a text editor. @@ -2170,7 +2149,7 @@ def span(self, raw): raise IndexError if not results.group('separator'): return [self[self._to_index(results.group('start'))]] - start = self._to_index(results.group('start')) + start = self._to_index(results.group('start')) or 0 # Ensure start is not None end = self._to_index(results.group('end')) reverse = False if end is not None: diff --git a/tests/conftest.py b/tests/conftest.py index 3977de5f2..41bd007ab 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -15,8 +15,8 @@ # Help text for base cmd2.Cmd application BASE_HELP = """Documented commands (type help ): ======================================== -_relative_load edit history load py run set shortcuts -cmdenvironment help list pause quit save shell show +_relative_load edit history pause quit save shell show +cmdenvironment help load py run set shortcuts """ # Help text for the history command @@ -24,7 +24,8 @@ | no arg: list all | arg is integer: list one history item, by index - | arg is string: string search + | a..b, a:b, a:, ..b -> list history items by a span of indices (inclusive) + | arg is string: list all commands matching string search | arg is /enclosed in forward-slashes/: regular expression search Usage: history [options] (limit on which commands to include) diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py index ce47ef47a..7d60110e2 100644 --- a/tests/test_cmd2.py +++ b/tests/test_cmd2.py @@ -142,48 +142,62 @@ def test_base_history(base_app): """) assert out == expected - -def test_base_list(base_app): +def test_history_with_string_argument(base_app): run_cmd(base_app, 'help') run_cmd(base_app, 'shortcuts') - out = run_cmd(base_app, 'list') + run_cmd(base_app, 'help history') + out = run_cmd(base_app, 'history help') expected = normalize(""" --------------------------[2] -shortcuts +-------------------------[1] +help +-------------------------[3] +help history """) assert out == expected -def test_list_with_string_argument(base_app): +def test_history_with_integer_argument(base_app): run_cmd(base_app, 'help') run_cmd(base_app, 'shortcuts') - run_cmd(base_app, 'help list') - out = run_cmd(base_app, 'list help') + out = run_cmd(base_app, 'history 1') expected = normalize(""" -------------------------[1] help --------------------------[3] -help list """) assert out == expected -def test_list_with_integer_argument(base_app): +def test_history_with_integer_span(base_app): run_cmd(base_app, 'help') run_cmd(base_app, 'shortcuts') - out = run_cmd(base_app, 'list 1') + run_cmd(base_app, 'help history') + out = run_cmd(base_app, 'history 1..2') expected = normalize(""" -------------------------[1] help +-------------------------[2] +shortcuts """) assert out == expected +def test_history_with_span_start(base_app): + run_cmd(base_app, 'help') + run_cmd(base_app, 'shortcuts') + run_cmd(base_app, 'help history') + out = run_cmd(base_app, 'history 2:') + expected = normalize(""" +-------------------------[2] +shortcuts +-------------------------[3] +help history +""") + assert out == expected -def test_list_with_integer_span(base_app): +def test_history_with_span_end(base_app): run_cmd(base_app, 'help') run_cmd(base_app, 'shortcuts') - run_cmd(base_app, 'help list') - out = run_cmd(base_app, 'list 1..2') + run_cmd(base_app, 'help history') + out = run_cmd(base_app, 'history :2') expected = normalize(""" -------------------------[1] help diff --git a/tests/test_transcript.py b/tests/test_transcript.py index c31b519d5..03fec92a3 100644 --- a/tests/test_transcript.py +++ b/tests/test_transcript.py @@ -106,9 +106,8 @@ def test_base_with_transcript(_cmdline_app): Documented commands (type help ): ======================================== -_relative_load help load py save shell speak -cmdenvironment history orate quit say shortcuts -edit list pause run set show +_relative_load edit history orate py run say shell show +cmdenvironment help load pause quit save set shortcuts speak (Cmd) help say Repeats what you tell me to. diff --git a/tests/transcript.txt b/tests/transcript.txt index 013e2d0f4..d0fd86a6f 100644 --- a/tests/transcript.txt +++ b/tests/transcript.txt @@ -2,9 +2,8 @@ Documented commands (type help ): ======================================== -_relative_load help load py save shell speak -cmdenvironment history orate quit say shortcuts -edit list pause run set show +_relative_load edit history orate py run say shell show +cmdenvironment help load pause quit save set shortcuts speak (Cmd) help say Repeats what you tell me to. From 75800a2a7f2ffc60e3c9f59ba637bdefcd9227cd Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sat, 3 Jun 2017 11:12:25 -0400 Subject: [PATCH 2/4] Updated example transcript test and docs Updated these to reflect that the list command has been removed --- docs/freefeatures.rst | 2 -- examples/exampleSession.txt | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/freefeatures.rst b/docs/freefeatures.rst index 3c740c00b..5e3545494 100644 --- a/docs/freefeatures.rst +++ b/docs/freefeatures.rst @@ -220,8 +220,6 @@ also provide `bash-like history list editing`_. .. automethod:: cmd2.Cmd.do_history -.. automethod:: cmd2.Cmd.do_list - .. automethod:: cmd2.Cmd.do_run Quitting the application diff --git a/examples/exampleSession.txt b/examples/exampleSession.txt index 893d7b59a..62c130f03 100644 --- a/examples/exampleSession.txt +++ b/examples/exampleSession.txt @@ -3,8 +3,8 @@ Documented commands (type help ): ======================================== -_relative_load edit help list orate py run say shell show -cmdenvironment eof history load pause quit save set shortcuts speak +_relative_load edit history orate py run say shell show +cmdenvironment help load pause quit save set shortcuts speak (Cmd) help say Repeats what you tell me to. From 909c3041790d895e1ff2319ca2eb53c34b2860fb Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sat, 3 Jun 2017 11:40:15 -0400 Subject: [PATCH 3/4] Updated CHANGES.md --- CHANGES.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 98aa2cf07..2324522fd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,17 @@ News ==== +0.7.3 +----- + +*Release date: TBD* + +* Bug fixes + * Fixed a bug in display a span of history items when only an end index is supplied +* Enhancements + * Added the ability to exclude commands from the help menu (**eof** included by default) + * Redundant list command removed and features merged into history command + 0.7.2 ----- From b70b85067450b529a19a5a4bdbc8646c88f4e342 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sat, 3 Jun 2017 12:02:56 -0400 Subject: [PATCH 4/4] Updated cmdenvironment command It no longer displays settable parameters since this functionality was redundant since those are displayed with either set or show. It now shows additional global settings for parsing @options commands. In the future a few more things should probably be displayed here related to parameters which are not settable at runtime. --- cmd2.py | 9 ++++++--- tests/test_cmd2.py | 16 ++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/cmd2.py b/cmd2.py index 93f0152c0..3755ef562 100755 --- a/cmd2.py +++ b/cmd2.py @@ -1121,9 +1121,12 @@ def do_cmdenvironment(self, args): Commands may be terminated with: {} Command-line arguments allowed: {} Output redirection and pipes allowed: {} - Settable parameters: {}\n""".format(not self.case_insensitive, str(self.terminators), - self.allow_cli_args, - self.allow_redirection, ' '.join(self.settable))) + Parsing of @options commands: + Use POSIX-style argument parser (vs Windows): {} + Strip Quotes when using Windows-style argument parser: {} + Use a list of arguments instead of a single argument string: {} + \n""".format(not self.case_insensitive, str(self.terminators), self.allow_cli_args, self.allow_redirection, + POSIX_SHLEX, STRIP_QUOTES_FOR_NON_POSIX, USE_ARG_LIST)) def do_help(self, arg): """List available commands with "help" or detailed help with "help cmd".""" diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py index 7d60110e2..5783d9442 100644 --- a/tests/test_cmd2.py +++ b/tests/test_cmd2.py @@ -215,17 +215,13 @@ def test_base_cmdenvironment(base_app): Commands may be terminated with: [';'] Command-line arguments allowed: True Output redirection and pipes allowed: True + Parsing of @options commands: + Use POSIX-style argument parser (vs Windows): False + Strip Quotes when using Windows-style argument parser: True + Use a list of arguments instead of a single argument string: False + """) - assert out[:4] == expected[:4] - assert out[4].strip().startswith('Settable parameters: ') - - # Settable parameters can be listed in any order, so need to validate carefully using unordered sets - settable_params = {'continuation_prompt', 'default_file_name', 'prompt', 'abbrev', 'quiet', 'case_insensitive', - 'colors', 'echo', 'timing', 'editor', 'feedback_to_output', 'debug', 'autorun_on_edit', - 'locals_in_py'} - out_params = set(out[4].split("Settable parameters: ")[1].split()) - assert settable_params == out_params - + assert out == expected def test_base_load(base_app, request): test_dir = os.path.dirname(request.module.__file__)