summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd2/cmd2.py46
-rw-r--r--cmd2/parsing.py20
-rw-r--r--tests/conftest.py3
-rw-r--r--tests/test_cmd2.py51
-rw-r--r--tests/transcripts/from_cmdloop.txt18
5 files changed, 77 insertions, 61 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index fb1199c3..eb4b44bc 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -288,27 +288,36 @@ class EmptyStatement(Exception):
class HistoryItem(str):
- """Class used to represent an item in the History list.
+ """Class used to represent an item in the History list"""
+ listformat = ' {:>4} {}\n'
+ ex_listformat = ' Ex: {}\n'
- Thin wrapper around str class which adds a custom format for printing. It
- also keeps track of its index in the list as well as a lowercase
- representation of itself for convenience/efficiency.
+ def __new__(cls, statement: Statement):
+ """Create a new instance of HistoryItem
- """
- listformat = '-------------------------[{}]\n{}\n'
+ We must override __new__ because we are subclassing `str` which is
+ immutable and takes a different number of arguments as Statement.
+ """
+ hi = super().__new__(cls, statement.raw)
+ hi.statement = statement
+ hi.idx = None
+ return hi
- # noinspection PyUnusedLocal
- def __init__(self, instr: str) -> None:
- str.__init__(self)
- self.lowercase = self.lower()
- self.idx = None
+ @property
+ def expanded(self) -> 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) -> str:
+ def pr(self, verbose: bool) -> str:
"""Represent a HistoryItem in a pretty fashion suitable for printing.
:return: pretty print string version of a HistoryItem
"""
- return self.listformat.format(self.idx, str(self).rstrip())
+ 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())
+
+ return ret_str
class Cmd(cmd.Cmd):
@@ -1998,7 +2007,7 @@ class Cmd(cmd.Cmd):
if func:
# Since we have a valid command store it in the history
if statement.command not in self.exclude_from_history:
- self.history.append(statement.raw)
+ self.history.append(statement)
stop = func(statement)
@@ -2061,7 +2070,7 @@ class Cmd(cmd.Cmd):
"""
if self.default_to_shell:
if 'shell' not in self.exclude_from_history:
- self.history.append(statement.raw)
+ self.history.append(statement)
return self.do_shell(statement.command_and_args)
else:
@@ -3163,6 +3172,9 @@ class Cmd(cmd.Cmd):
setattr(history_parser_group.add_argument('-t', '--transcript',
help='output commands and results to a transcript file'),
ACTION_ARG_CHOICES, ('path_complete',))
+ history_parser_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"
@@ -3246,7 +3258,7 @@ class Cmd(cmd.Cmd):
if args.script:
self.poutput(hi)
else:
- self.poutput(hi.pr())
+ self.poutput(hi.pr(args.verbose))
def _generate_transcript(self, history: List[HistoryItem], transcript_file: str) -> None:
"""Generate a transcript file from a given history of commands."""
@@ -3820,7 +3832,7 @@ class History(list):
rangePattern = re.compile(r'^\s*(?P<start>[\d]+)?\s*-\s*(?P<end>[\d]+)?\s*$')
- def append(self, new: str) -> None:
+ def append(self, new: Statement) -> None:
"""Append a HistoryItem to end of the History list
:param new: command line to convert to HistoryItem and add to the end of the History list
diff --git a/cmd2/parsing.py b/cmd2/parsing.py
index d4f82ac9..070d3774 100644
--- a/cmd2/parsing.py
+++ b/cmd2/parsing.py
@@ -188,6 +188,26 @@ class Statement(str):
return rtn
@property
+ def expanded_command_line(self) -> str:
+ """Contains command_and_args plus any ending terminator, suffix, and redirection chars"""
+ rtn = self.command_and_args
+ if self.terminator:
+ rtn += self.terminator
+
+ if self.suffix:
+ rtn += ' ' + self.suffix
+
+ if self.pipe_to:
+ rtn += ' | ' + self.pipe_to
+
+ if self.output:
+ rtn += ' ' + self.output
+ if self.output_to:
+ rtn += ' ' + self.output_to
+
+ return rtn
+
+ @property
def argv(self) -> List[str]:
"""a list of arguments a la sys.argv.
diff --git a/tests/conftest.py b/tests/conftest.py
index 223389b9..7bc8e7d0 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -50,7 +50,7 @@ shortcuts List available shortcuts
"""
# Help text for the history command
-HELP_HISTORY = """Usage: history [-h] [-r | -e | -s | -o FILE | -t TRANSCRIPT | -c] [arg]
+HELP_HISTORY = """Usage: history [-h] [-r | -e | -s | -o FILE | -t TRANSCRIPT | -v | -c] [arg]
View, run, edit, save, or clear previously entered commands
@@ -70,6 +70,7 @@ optional arguments:
output commands to a script file
-t, --transcript TRANSCRIPT
output commands and results to a transcript file
+ -v, --verbose display history and include expanded commands if they differ from the typed command.
-c, --clear clear all history
"""
diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py
index b10322f1..576bdc0c 100644
--- a/tests/test_cmd2.py
+++ b/tests/test_cmd2.py
@@ -304,8 +304,12 @@ def test_base_error(base_app):
@pytest.fixture
def hist():
+ from cmd2.parsing import Statement
from cmd2.cmd2 import History, HistoryItem
- h = History([HistoryItem('first'), HistoryItem('second'), HistoryItem('third'), HistoryItem('fourth')])
+ h = History([HistoryItem(Statement('', raw='first')),
+ HistoryItem(Statement('', raw='second')),
+ HistoryItem(Statement('', raw='third')),
+ HistoryItem(Statement('', raw='fourth'))])
return h
def test_history_span(hist):
@@ -335,24 +339,20 @@ def test_base_history(base_app):
run_cmd(base_app, 'shortcuts')
out = run_cmd(base_app, 'history')
expected = normalize("""
--------------------------[1]
-help
--------------------------[2]
-shortcuts
+ 1 help
+ 2 shortcuts
""")
assert out == expected
out = run_cmd(base_app, 'history he')
expected = normalize("""
--------------------------[1]
-help
+ 1 help
""")
assert out == expected
out = run_cmd(base_app, 'history sh')
expected = normalize("""
--------------------------[2]
-shortcuts
+ 2 shortcuts
""")
assert out == expected
@@ -372,10 +372,8 @@ def test_history_with_string_argument(base_app):
run_cmd(base_app, 'help history')
out = run_cmd(base_app, 'history help')
expected = normalize("""
--------------------------[1]
-help
--------------------------[3]
-help history
+ 1 help
+ 3 help history
""")
assert out == expected
@@ -385,8 +383,7 @@ def test_history_with_integer_argument(base_app):
run_cmd(base_app, 'shortcuts')
out = run_cmd(base_app, 'history 1')
expected = normalize("""
--------------------------[1]
-help
+ 1 help
""")
assert out == expected
@@ -397,10 +394,8 @@ def test_history_with_integer_span(base_app):
run_cmd(base_app, 'help history')
out = run_cmd(base_app, 'history 1..2')
expected = normalize("""
--------------------------[1]
-help
--------------------------[2]
-shortcuts
+ 1 help
+ 2 shortcuts
""")
assert out == expected
@@ -410,10 +405,8 @@ def test_history_with_span_start(base_app):
run_cmd(base_app, 'help history')
out = run_cmd(base_app, 'history 2:')
expected = normalize("""
--------------------------[2]
-shortcuts
--------------------------[3]
-help history
+ 2 shortcuts
+ 3 help history
""")
assert out == expected
@@ -423,10 +416,8 @@ def test_history_with_span_end(base_app):
run_cmd(base_app, 'help history')
out = run_cmd(base_app, 'history :2')
expected = normalize("""
--------------------------[1]
-help
--------------------------[2]
-shortcuts
+ 1 help
+ 2 shortcuts
""")
assert out == expected
@@ -436,8 +427,7 @@ def test_history_with_span_index_error(base_app):
run_cmd(base_app, '!ls -hal :')
out = run_cmd(base_app, 'history "hal :"')
expected = normalize("""
--------------------------[3]
-!ls -hal :
+ 3 !ls -hal :
""")
assert out == expected
@@ -957,8 +947,7 @@ def test_exclude_from_history(base_app, monkeypatch):
run_cmd(base_app, 'help')
# And verify we have a history now ...
out = run_cmd(base_app, 'history')
- expected = normalize("""-------------------------[1]
-help""")
+ expected = normalize(""" 1 help""")
assert out == expected
diff --git a/tests/transcripts/from_cmdloop.txt b/tests/transcripts/from_cmdloop.txt
index 8c0dd007..871b71f1 100644
--- a/tests/transcripts/from_cmdloop.txt
+++ b/tests/transcripts/from_cmdloop.txt
@@ -35,18 +35,12 @@ OODNIGHT, GRACIEGAY
OODNIGHT, GRACIEGAY
OODNIGHT, GRACIEGAY
(Cmd) history
--------------------------[1]
-help
--------------------------[2]
-help say
--------------------------[3]
-say goodnight, Gracie
--------------------------[4]
-say -ps --repeat=5 goodnight, Gracie
--------------------------[5]
-set maxrepeats 5
--------------------------[6]
-say -ps --repeat=5 goodnight, Gracie
+ 1 help
+ 2 help say
+ 3 say goodnight, Gracie
+ 4 say -ps --repeat=5 goodnight, Gracie
+ 5 set maxrepeats 5
+ 6 say -ps --repeat=5 goodnight, Gracie
(Cmd) history -r 4
say -ps --repeat=5 goodnight, Gracie
OODNIGHT, GRACIEGAY