mirror of
https://github.com/nushell/nushell.git
synced 2025-08-10 12:18:07 +02:00
Improves commands that support range input (#13113)
# Description Fixes: #13105 Fixes: #13077 This pr makes `str substring`, `bytes at` work better with negative index. And it also fixes the false range semantic on `detect columns -c` in some cases. # User-Facing Changes For `str substring`, `bytes at`, it will no-longer return an error if start index is larger than end index. It makes sense to return an empty string of empty bytes directly. ### Before ```nushell # str substring ❯ ("aaa" | str substring 2..-3) == "" Error: nu:🐚:type_mismatch × Type mismatch. ╭─[entry #23:1:10] 1 │ ("aaa" | str substring 2..-3) == "" · ──────┬────── · ╰── End must be greater than or equal to Start 2 │ true ╰──── # bytes at ❯ ("aaa" | encode utf-8 | bytes at 2..-3) == ("" | encode utf-8) Error: nu:🐚:type_mismatch × Type mismatch. ╭─[entry #27:1:25] 1 │ ("aaa" | encode utf-8 | bytes at 2..-3) == ("" | encode utf-8) · ────┬─── · ╰── End must be greater than or equal to Start ╰──── ``` ### After ```nushell # str substring ❯ ("aaa" | str substring 2..-3) == "" true # bytes at ❯ ("aaa" | encode utf-8 | bytes at 2..-3) == ("" | encode utf-8) true ``` # Tests + Formatting Added some tests, adjust existing tests
This commit is contained in:
@ -128,48 +128,24 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
|
||||
let range = &args.indexes;
|
||||
match input {
|
||||
Value::Binary { val, .. } => {
|
||||
use std::cmp::{self, Ordering};
|
||||
let len = val.len() as isize;
|
||||
|
||||
let start = if range.0 < 0 { range.0 + len } else { range.0 };
|
||||
let end = if range.1 < 0 { range.1 + len } else { range.1 };
|
||||
|
||||
let end = if range.1 < 0 {
|
||||
cmp::max(range.1 + len, 0)
|
||||
} else {
|
||||
range.1
|
||||
};
|
||||
|
||||
if start < len && end >= 0 {
|
||||
match start.cmp(&end) {
|
||||
Ordering::Equal => Value::binary(vec![], head),
|
||||
Ordering::Greater => Value::error(
|
||||
ShellError::TypeMismatch {
|
||||
err_message: "End must be greater than or equal to Start".to_string(),
|
||||
span: head,
|
||||
},
|
||||
head,
|
||||
),
|
||||
Ordering::Less => Value::binary(
|
||||
if end == isize::MAX {
|
||||
val.iter()
|
||||
.skip(start as usize)
|
||||
.copied()
|
||||
.collect::<Vec<u8>>()
|
||||
} else {
|
||||
val.iter()
|
||||
.skip(start as usize)
|
||||
.take((end - start) as usize)
|
||||
.copied()
|
||||
.collect()
|
||||
},
|
||||
head,
|
||||
),
|
||||
}
|
||||
} else {
|
||||
if start > end {
|
||||
Value::binary(vec![], head)
|
||||
} else {
|
||||
let val_iter = val.iter().skip(start as usize);
|
||||
Value::binary(
|
||||
if end == isize::MAX {
|
||||
val_iter.copied().collect::<Vec<u8>>()
|
||||
} else {
|
||||
val_iter.take((end - start + 1) as usize).copied().collect()
|
||||
},
|
||||
head,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Value::Error { .. } => input.clone(),
|
||||
|
||||
other => Value::error(
|
||||
|
Reference in New Issue
Block a user