@@ -97,7 +97,7 @@ def get(self, index: Union[int, str]) -> HistoryItem:
97
97
"""
98
98
index = int (index )
99
99
if index == 0 :
100
- raise IndexError
100
+ raise IndexError ( 'The first command in history is command 1.' )
101
101
elif index < 0 :
102
102
return self [index ]
103
103
else :
@@ -108,22 +108,27 @@ def get(self, index: Union[int, str]) -> HistoryItem:
108
108
# ^\s* matches any whitespace at the beginning of the
109
109
# input. This is here so you don't have to trim the input
110
110
#
111
- # (?P<start>-?\d+)? create a capture group named 'start' which matches one
112
- # or more digits, optionally preceeded by a minus sign. This
113
- # group is optional so that we can match a string like '..2'
111
+ # (?P<start>-?[1-9]{1}\d*)? create a capture group named 'start' which matches an
112
+ # optional minus sign, followed by exactly one non-zero
113
+ # digit, and as many other digits as you want. This group
114
+ # is optional so that we can match an input string like '..2'.
115
+ # This regex will match 1, -1, 10, -10, but not 0 or -0.
114
116
#
115
117
# (?P<separator>:|(\.{2,}))? create a capture group named 'separator' which matches either
116
118
# a colon or two periods. This group is optional so we can
117
119
# match a string like '3'
118
120
#
119
- # (?P<end>-?\d+)? create a capture group named 'end' which matches one or more
120
- # digits, optionally preceeded by a minus sign. This group is
121
- # optional so that we can match a string like ':' or '5:'
121
+ # (?P<end>-?[1-9]{1}\d*)? create a capture group named 'end' which matches an
122
+ # optional minus sign, followed by exactly one non-zero
123
+ # digit, and as many other digits as you want. This group is
124
+ # optional so that we can match an input string like ':'
125
+ # or '5:'. This regex will match 1, -1, 10, -10, but not
126
+ # 0 or -0.
122
127
#
123
128
# \s*$ match any whitespace at the end of the input. This is here so
124
129
# you don't have to trim the input
125
130
#
126
- spanpattern = re .compile (r'^\s*(?P<start>-?\d+ )?(?P<separator>:|(\.{2,}))?(?P<end>-?\d+ )?\s*$' )
131
+ spanpattern = re .compile (r'^\s*(?P<start>-?[1-9]{1}\d* )?(?P<separator>:|(\.{2,}))?(?P<end>-?[1-9]{1}\d* )?\s*$' )
127
132
128
133
def span (self , span : str ) -> List [HistoryItem ]:
129
134
"""Return an index or slice of the History list,
@@ -156,7 +161,7 @@ def span(self, span: str) -> List[HistoryItem]:
156
161
results = self .spanpattern .search (span )
157
162
if not results :
158
163
# our regex doesn't match the input, bail out
159
- raise ValueError
164
+ raise ValueError ( 'History indices must be positive or negative integers, and may not be zero.' )
160
165
161
166
sep = results .group ('separator' )
162
167
start = results .group ('start' )
@@ -165,6 +170,16 @@ def span(self, span: str) -> List[HistoryItem]:
165
170
end = results .group ('end' )
166
171
if end :
167
172
end = int (end )
173
+ # modify end so it's inclusive of the last element
174
+ if end == - 1 :
175
+ # -1 as the end means include the last command in the array, which in pythonic
176
+ # terms means to not provide an ending index. If you put -1 as the ending index
177
+ # python excludes the last item in the list.
178
+ end = None
179
+ elif end < - 1 :
180
+ # if the ending is smaller than -1, make it one larger so it includes
181
+ # the element (python native indices exclude the last referenced element)
182
+ end += 1
168
183
169
184
if start is not None and end is not None :
170
185
# we have both start and end, return a slice of history
0 commit comments