mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-26 10:43:47 +08:00
Allow to omit indices in index range expansions
Missing range limits in, say $PATH[..] default to the first/last element, just like Python/Go/Rust slices.
This commit is contained in:
parent
4c66e69cd9
commit
be06f842a2
|
@ -5,6 +5,7 @@
|
|||
### Syntax changes and new commands
|
||||
|
||||
### Scripting improvements
|
||||
- Range limits in index range expansions like `$x[$start..$end]` may be omitted: `$start` and `$end` default to 1 and -1 (the last item) respectively.
|
||||
|
||||
### Interactive improvements
|
||||
|
||||
|
|
|
@ -661,6 +661,8 @@ Sequences of elements can be written with the range operator '``..``'. A range '
|
|||
|
||||
If the end is smaller than the start, or the start is larger than the end, range expansion will go in reverse. This is unless exactly one of the given indices is negative, so the direction doesn't change if the list has fewer elements than expected.
|
||||
|
||||
A missing starting index in a range defaults to 1. This is allowed if the range is the first index expression of the sequence. Similarly, a missing ending index, defaulting to -1 is allowed for the last index range in the sequence.
|
||||
|
||||
Some examples::
|
||||
|
||||
|
||||
|
@ -672,6 +674,9 @@ Some examples::
|
|||
# Uses elements from 2 to 5
|
||||
# Output is: 2 3 4 5
|
||||
|
||||
echo (seq 10)[7..]
|
||||
# Prints: 7 8 9 10
|
||||
|
||||
# Use overlapping ranges:
|
||||
echo (seq 10)[2..5 1..3]
|
||||
# Takes elements from 2 to 5 and then elements from 1 to 3
|
||||
|
|
|
@ -188,11 +188,20 @@ static size_t parse_slice(const wchar_t *in, wchar_t **end_ptr, std::vector<long
|
|||
}
|
||||
|
||||
const wchar_t *end;
|
||||
long tmp = fish_wcstol(&in[pos], &end);
|
||||
// We don't test `*end` as is typically done because we expect it to not be the null char.
|
||||
// Ignore the case of errno==-1 because it means the end char wasn't the null char.
|
||||
if (errno > 0) {
|
||||
return pos;
|
||||
long tmp;
|
||||
if (idx.empty() && in[pos] == L'.' && in[pos + 1] == L'.') {
|
||||
// If we are at the first index expression, a missing start index means the range starts
|
||||
// at the first item.
|
||||
tmp = 1; // first index
|
||||
end = &in[pos];
|
||||
} else {
|
||||
tmp = fish_wcstol(&in[pos], &end);
|
||||
if (errno > 0) {
|
||||
// We don't test `*end` as is typically done because we expect it to not be the null
|
||||
// char. Ignore the case of errno==-1 because it means the end char wasn't the null
|
||||
// char.
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
long i1 = tmp > -1 ? tmp : size + tmp + 1;
|
||||
|
@ -201,11 +210,20 @@ static size_t parse_slice(const wchar_t *in, wchar_t **end_ptr, std::vector<long
|
|||
if (in[pos] == L'.' && in[pos + 1] == L'.') {
|
||||
pos += 2;
|
||||
while (in[pos] == INTERNAL_SEPARATOR) pos++;
|
||||
while (iswspace(in[pos])) pos++; // Allow the space in "[.. ]".
|
||||
|
||||
long tmp1 = fish_wcstol(&in[pos], &end);
|
||||
// Ignore the case of errno==-1 because it means the end char wasn't the null char.
|
||||
if (errno > 0) {
|
||||
return pos;
|
||||
long tmp1;
|
||||
// Check if we are at the last index range expression, a missing end index means the
|
||||
// range spans until the last item.
|
||||
if (in[pos] == L']') {
|
||||
tmp1 = -1; // last index
|
||||
end = &in[pos];
|
||||
} else {
|
||||
tmp1 = fish_wcstol(&in[pos], &end);
|
||||
// Ignore the case of errno==-1 because it means the end char wasn't the null char.
|
||||
if (errno > 0) {
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
pos = end - in;
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ set n 10
|
|||
set test (seq $n)
|
||||
echo $test[1..$n] # normal range
|
||||
#CHECK: 1 2 3 4 5 6 7 8 9 10
|
||||
echo $test[1 .. 2] # spaces are allowed
|
||||
#CHECK: 1 2
|
||||
echo $test[$n..1] # inverted range
|
||||
#CHECK: 10 9 8 7 6 5 4 3 2 1
|
||||
echo $test[2..5 8..6] # several ranges
|
||||
|
@ -31,3 +33,36 @@ echo $test[(count $test)..1]
|
|||
#CHECK: 10 9 8 7 6 5 4 3 2 1
|
||||
echo $test[1..(count $test)]
|
||||
#CHECK: 1 2 3 4 5 6 7 8 9 10
|
||||
|
||||
echo $test[ .. ]
|
||||
#CHECK: 1 2 3 4 5 6 7 8 9 10
|
||||
echo $test[ ..3]
|
||||
#CHECK: 1 2 3
|
||||
echo $test[8.. ]
|
||||
#CHECK: 8 9 10
|
||||
echo $test[..2 5]
|
||||
# CHECK: 1 2 5
|
||||
echo $test[2 9..]
|
||||
# CHECK: 2 9 10
|
||||
|
||||
# missing start, cannot use implied range
|
||||
echo $test[1..2..]
|
||||
#CHECKERR: {{.*}}: Invalid index value
|
||||
#CHECKERR: echo $test[1..2..]
|
||||
#CHECKERR: ^
|
||||
echo $test[..1..2]
|
||||
#CHECKERR: {{.*}}: Invalid index value
|
||||
#CHECKERR: echo $test[..1..2]
|
||||
#CHECKERR: ^
|
||||
|
||||
set -l empty
|
||||
echo $test[ $empty..]
|
||||
#CHECK:
|
||||
echo $test[.."$empty"]
|
||||
#CHECK: 1 2 3 4 5 6 7 8 9 10
|
||||
echo $test["$empty"..]
|
||||
#CHECK: 1 2 3 4 5 6 7 8 9 10
|
||||
echo $test[ (true)..3]
|
||||
#CHECK:
|
||||
echo $test[ (string join \n 1 2 3)..3 ]
|
||||
#CHECK: 1 2 3 2 3 3
|
||||
|
|
Loading…
Reference in New Issue
Block a user