summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkotfu <kotfu@kotfu.net>2019-03-11 20:32:21 -0600
committerkotfu <kotfu@kotfu.net>2019-03-11 20:32:21 -0600
commitb84798cfb2e0da5422936dfcf406c227b6a09723 (patch)
tree9bada0c3368bbe420e49b67b122adfe4d0dfbe0f
parenta4ff1a45b205171663559b0f7003ecf84face2aa (diff)
downloadcmd2-git-b84798cfb2e0da5422936dfcf406c227b6a09723.tar.gz
Negative ending history indices include the referenced command, instead of excluding it
-rw-r--r--cmd2/history.py33
-rw-r--r--docs/freefeatures.rst5
-rw-r--r--tests/test_history.py10
3 files changed, 32 insertions, 16 deletions
diff --git a/cmd2/history.py b/cmd2/history.py
index 04baf014..729cc6e3 100644
--- a/cmd2/history.py
+++ b/cmd2/history.py
@@ -97,7 +97,7 @@ class History(list):
"""
index = int(index)
if index == 0:
- raise IndexError
+ raise IndexError('The first command in history is command 1.')
elif index < 0:
return self[index]
else:
@@ -108,22 +108,27 @@ class History(list):
# ^\s* matches any whitespace at the beginning of the
# input. This is here so you don't have to trim the input
#
- # (?P<start>-?\d+)? create a capture group named 'start' which matches one
- # or more digits, optionally preceeded by a minus sign. This
- # group is optional so that we can match a string like '..2'
+ # (?P<start>-?[1-9]{1}\d*)? create a capture group named 'start' which matches an
+ # optional minus sign, followed by exactly one non-zero
+ # digit, and as many other digits as you want. This group
+ # is optional so that we can match an input string like '..2'.
+ # This regex will match 1, -1, 10, -10, but not 0 or -0.
#
# (?P<separator>:|(\.{2,}))? create a capture group named 'separator' which matches either
# a colon or two periods. This group is optional so we can
# match a string like '3'
#
- # (?P<end>-?\d+)? create a capture group named 'end' which matches one or more
- # digits, optionally preceeded by a minus sign. This group is
- # optional so that we can match a string like ':' or '5:'
+ # (?P<end>-?[1-9]{1}\d*)? create a capture group named 'end' which matches an
+ # optional minus sign, followed by exactly one non-zero
+ # digit, and as many other digits as you want. This group is
+ # optional so that we can match an input string like ':'
+ # or '5:'. This regex will match 1, -1, 10, -10, but not
+ # 0 or -0.
#
# \s*$ match any whitespace at the end of the input. This is here so
# you don't have to trim the input
#
- spanpattern = re.compile(r'^\s*(?P<start>-?\d+)?(?P<separator>:|(\.{2,}))?(?P<end>-?\d+)?\s*$')
+ spanpattern = re.compile(r'^\s*(?P<start>-?[1-9]{1}\d*)?(?P<separator>:|(\.{2,}))?(?P<end>-?[1-9]{1}\d*)?\s*$')
def span(self, span: str) -> List[HistoryItem]:
"""Return an index or slice of the History list,
@@ -156,7 +161,7 @@ class History(list):
results = self.spanpattern.search(span)
if not results:
# our regex doesn't match the input, bail out
- raise ValueError
+ raise ValueError('History indices must be positive or negative integers, and may not be zero.')
sep = results.group('separator')
start = results.group('start')
@@ -165,6 +170,16 @@ class History(list):
end = results.group('end')
if end:
end = int(end)
+ # modify end so it's inclusive of the last element
+ if end == -1:
+ # -1 as the end means include the last command in the array, which in pythonic
+ # terms means to not provide an ending index. If you put -1 as the ending index
+ # python excludes the last item in the list.
+ end = None
+ elif end < -1:
+ # if the ending is smaller than -1, make it one larger so it includes
+ # the element (python native indices exclude the last referenced element)
+ end += 1
if start is not None and end is not None:
# we have both start and end, return a slice of history
diff --git a/docs/freefeatures.rst b/docs/freefeatures.rst
index 4bfeffd0..001a7599 100644
--- a/docs/freefeatures.rst
+++ b/docs/freefeatures.rst
@@ -293,9 +293,10 @@ entered, and so forth::
You can use a similar mechanism to display a range of commands. Simply give two
command numbers separated by ``..`` or ``:``, and you will see all commands
-between those two numbers::
+between, and including, those two numbers::
- (Cmd) history 2:3
+ (Cmd) history 1:3
+ 1 alias create one !echo one
2 alias create two !echo two
3 alias create three !echo three
diff --git a/tests/test_history.py b/tests/test_history.py
index d9918b7a..9046e877 100644
--- a/tests/test_history.py
+++ b/tests/test_history.py
@@ -77,14 +77,14 @@ def test_history_class_span(hist):
assert hist.span('1..3') == ['first', 'second', 'third']
assert hist.span('1:3') == ['first', 'second', 'third']
- assert hist.span('2:-1') == ['second', 'third']
+ assert hist.span('2:-1') == ['second', 'third', 'fourth']
assert hist.span('-3:4') == ['second', 'third','fourth']
- assert hist.span('-4:-2') == ['first', 'second']
+ assert hist.span('-4:-2') == ['first', 'second', 'third']
- assert hist.span(':-2') == ['first', 'second']
- assert hist.span('..-2') == ['first', 'second']
+ assert hist.span(':-2') == ['first', 'second', 'third']
+ assert hist.span('..-2') == ['first', 'second', 'third']
- value_errors = ['fred', 'fred:joe', 'a..b', '2 ..', '1 : 3']
+ value_errors = ['fred', 'fred:joe', 'a..b', '2 ..', '1 : 3', '1:0', '0:3']
for tryit in value_errors:
with pytest.raises(ValueError):
hist.span(tryit)