diff options
author | kotfu <kotfu@kotfu.net> | 2019-03-11 20:32:21 -0600 |
---|---|---|
committer | kotfu <kotfu@kotfu.net> | 2019-03-11 20:32:21 -0600 |
commit | b84798cfb2e0da5422936dfcf406c227b6a09723 (patch) | |
tree | 9bada0c3368bbe420e49b67b122adfe4d0dfbe0f | |
parent | a4ff1a45b205171663559b0f7003ecf84face2aa (diff) | |
download | cmd2-git-b84798cfb2e0da5422936dfcf406c227b6a09723.tar.gz |
Negative ending history indices include the referenced command, instead of excluding it
-rw-r--r-- | cmd2/history.py | 33 | ||||
-rw-r--r-- | docs/freefeatures.rst | 5 | ||||
-rw-r--r-- | tests/test_history.py | 10 |
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) |