Subject: bug#60999: 30.0.50; [PATCH] Add support for negative indices and index ranges in Eshell

From: Jim Porter <[email-masked]>
Date: Sun, 22 Jan 2023 00:13:16 -0800

On 1/21/2023 10:29 PM, Eli Zaretskii wrote:
>> Date: Sat, 21 Jan 2023 19:47:47 -0800
>> From: Jim Porter <[email-masked]>
>>
>> I have just one question though: this implementation treats ranges as
>> half-open, i.e. "M..N" is [M, N). I think that's the best way of doing
>> things (and it matches how 'seq-subseq' works). However, "M..N" is the
>> Bash syntax, which uses a closed range, [M, N]. Maybe this would be too
>> confusing for users? [snip]
> 
> I think compatibility to other shells is an advantage.

True. Though, in practice I find that the half-open range is easier to 
use whenever things become more complex than just using constant values. 
For example, truncating a larger list to be the same size as a shorter 
one ("$#" means "length of"):

   $long-list[..$#short-list]

Using Bash-style closed ranges, you'd have to do:

   $long-list[..${1- $#short-list}]

(Note that unlike Bash syntax, I made this so that M and N are optional. 
That's another thing we could consider changing.)

Half-open ranges are also more consistent with Emacs Lisp in my 
experience. It would be strange (at least to me) to have things like 
'seq-subseq', 'add-text-properties', 'substring', etc use one way of 
specifying ranges, and Eshell to use another, especially when you can 
call any of those functions within Eshell. But like you say, 
compatibility with other shells is an advantage too...

In that sense, some non-Bash syntax might be nice. However, Eshell 
subscripts are already fairly complex, so we'd need to be careful about 
what we choose so that we don't break compatibility. For example, when 
subscripting a string, the first element in the subscript can be a 
regexp that splits the string, so to get the first element in your PATH, 
you could do:

   $PATH[: 0]

If ":" was the range separator, this would change meaning. There are 
ways to prevent that incompatible change if we're careful, but it's 
something to keep in mind. ".." has the advantage that while it's a 
valid regexp, it's not very useful in this context, so we probably 
wouldn't break anything in practice.

>> +(defcustom eshell-integer-regexp (rx (? "-") (+ digit))
>> +  "Regular expression used to match integer arguments."
>> +  :type 'regexp)
> 
> Why is this a defcustom? what alternative could a user possibly want?

Just for symmetry with 'eshell-number-regexp'. Maybe that shouldn't be a 
defcustom either though; if someone wanted to change 
'eshell-number-regexp', that's probably a sign that there's a bug, and 
the default value should be improved.

Either way we decide about 'eshell-number-regexp', I can turn 
'eshell-integer-regexp' into a regular defvar. (The only thing I can 
think of that a person would customize it to would be to allow a "+" at 
the start of an integer, like "+123".)