mirror of
https://github.com/nushell/nushell.git
synced 2025-02-20 12:32:05 +01:00
Fix char
panic (#12867)
# Description The `char` command can panic due to a failed `expect`: `char --integer ...[77 78 79]` This PR fixes the panic for the `--integer` flag and also the `--unicode` flag. # After Submitting Check other commands and places where similar bugs can occur due to usages of `Call::positional_nth` and related methods.
This commit is contained in:
parent
aa46bc97b3
commit
c3da44cbb7
@ -235,18 +235,18 @@ impl Command for Char {
|
|||||||
|
|
||||||
// handle -i flag
|
// handle -i flag
|
||||||
if integer {
|
if integer {
|
||||||
let int_args: Vec<i64> = call.rest_const(working_set, 0)?;
|
let int_args = call.rest_const(working_set, 0)?;
|
||||||
handle_integer_flag(int_args, call, call_span)
|
handle_integer_flag(int_args, call_span)
|
||||||
}
|
}
|
||||||
// handle -u flag
|
// handle -u flag
|
||||||
else if unicode {
|
else if unicode {
|
||||||
let string_args: Vec<String> = call.rest_const(working_set, 0)?;
|
let string_args = call.rest_const(working_set, 0)?;
|
||||||
handle_unicode_flag(string_args, call, call_span)
|
handle_unicode_flag(string_args, call_span)
|
||||||
}
|
}
|
||||||
// handle the rest
|
// handle the rest
|
||||||
else {
|
else {
|
||||||
let string_args: Vec<String> = call.rest_const(working_set, 0)?;
|
let string_args = call.rest_const(working_set, 0)?;
|
||||||
handle_the_rest(string_args, call, call_span)
|
handle_the_rest(string_args, call_span)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,18 +270,18 @@ impl Command for Char {
|
|||||||
|
|
||||||
// handle -i flag
|
// handle -i flag
|
||||||
if integer {
|
if integer {
|
||||||
let int_args: Vec<i64> = call.rest(engine_state, stack, 0)?;
|
let int_args = call.rest(engine_state, stack, 0)?;
|
||||||
handle_integer_flag(int_args, call, call_span)
|
handle_integer_flag(int_args, call_span)
|
||||||
}
|
}
|
||||||
// handle -u flag
|
// handle -u flag
|
||||||
else if unicode {
|
else if unicode {
|
||||||
let string_args: Vec<String> = call.rest(engine_state, stack, 0)?;
|
let string_args = call.rest(engine_state, stack, 0)?;
|
||||||
handle_unicode_flag(string_args, call, call_span)
|
handle_unicode_flag(string_args, call_span)
|
||||||
}
|
}
|
||||||
// handle the rest
|
// handle the rest
|
||||||
else {
|
else {
|
||||||
let string_args: Vec<String> = call.rest(engine_state, stack, 0)?;
|
let string_args = call.rest(engine_state, stack, 0)?;
|
||||||
handle_the_rest(string_args, call, call_span)
|
handle_the_rest(string_args, call_span)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -309,8 +309,7 @@ fn generate_character_list(ctrlc: Option<Arc<AtomicBool>>, call_span: Span) -> P
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_integer_flag(
|
fn handle_integer_flag(
|
||||||
int_args: Vec<i64>,
|
int_args: Vec<Spanned<i64>>,
|
||||||
call: &Call,
|
|
||||||
call_span: Span,
|
call_span: Span,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
if int_args.is_empty() {
|
if int_args.is_empty() {
|
||||||
@ -319,20 +318,17 @@ fn handle_integer_flag(
|
|||||||
span: call_span,
|
span: call_span,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let mut multi_byte = String::new();
|
|
||||||
for (i, &arg) in int_args.iter().enumerate() {
|
let str = int_args
|
||||||
let span = call
|
.into_iter()
|
||||||
.positional_nth(i)
|
.map(integer_to_unicode_char)
|
||||||
.expect("Unexpected missing argument")
|
.collect::<Result<String, _>>()?;
|
||||||
.span;
|
|
||||||
multi_byte.push(integer_to_unicode_char(arg, span)?)
|
Ok(Value::string(str, call_span).into_pipeline_data())
|
||||||
}
|
|
||||||
Ok(Value::string(multi_byte, call_span).into_pipeline_data())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_unicode_flag(
|
fn handle_unicode_flag(
|
||||||
string_args: Vec<String>,
|
string_args: Vec<Spanned<String>>,
|
||||||
call: &Call,
|
|
||||||
call_span: Span,
|
call_span: Span,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
if string_args.is_empty() {
|
if string_args.is_empty() {
|
||||||
@ -341,57 +337,53 @@ fn handle_unicode_flag(
|
|||||||
span: call_span,
|
span: call_span,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let mut multi_byte = String::new();
|
|
||||||
for (i, arg) in string_args.iter().enumerate() {
|
let str = string_args
|
||||||
let span = call
|
.into_iter()
|
||||||
.positional_nth(i)
|
.map(string_to_unicode_char)
|
||||||
.expect("Unexpected missing argument")
|
.collect::<Result<String, _>>()?;
|
||||||
.span;
|
|
||||||
multi_byte.push(string_to_unicode_char(arg, span)?)
|
Ok(Value::string(str, call_span).into_pipeline_data())
|
||||||
}
|
|
||||||
Ok(Value::string(multi_byte, call_span).into_pipeline_data())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_the_rest(
|
fn handle_the_rest(
|
||||||
string_args: Vec<String>,
|
string_args: Vec<Spanned<String>>,
|
||||||
call: &Call,
|
|
||||||
call_span: Span,
|
call_span: Span,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
if string_args.is_empty() {
|
let Some(s) = string_args.first() else {
|
||||||
return Err(ShellError::MissingParameter {
|
return Err(ShellError::MissingParameter {
|
||||||
param_name: "missing name of the character".into(),
|
param_name: "missing name of the character".into(),
|
||||||
span: call_span,
|
span: call_span,
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
let special_character = str_to_character(&string_args[0]);
|
|
||||||
|
let special_character = str_to_character(&s.item);
|
||||||
|
|
||||||
if let Some(output) = special_character {
|
if let Some(output) = special_character {
|
||||||
Ok(Value::string(output, call_span).into_pipeline_data())
|
Ok(Value::string(output, call_span).into_pipeline_data())
|
||||||
} else {
|
} else {
|
||||||
Err(ShellError::TypeMismatch {
|
Err(ShellError::TypeMismatch {
|
||||||
err_message: "error finding named character".into(),
|
err_message: "error finding named character".into(),
|
||||||
span: call
|
span: s.span,
|
||||||
.positional_nth(0)
|
|
||||||
.expect("Unexpected missing argument")
|
|
||||||
.span,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn integer_to_unicode_char(value: i64, t: Span) -> Result<char, ShellError> {
|
fn integer_to_unicode_char(value: Spanned<i64>) -> Result<char, ShellError> {
|
||||||
let decoded_char = value.try_into().ok().and_then(std::char::from_u32);
|
let decoded_char = value.item.try_into().ok().and_then(std::char::from_u32);
|
||||||
|
|
||||||
if let Some(ch) = decoded_char {
|
if let Some(ch) = decoded_char {
|
||||||
Ok(ch)
|
Ok(ch)
|
||||||
} else {
|
} else {
|
||||||
Err(ShellError::TypeMismatch {
|
Err(ShellError::TypeMismatch {
|
||||||
err_message: "not a valid Unicode codepoint".into(),
|
err_message: "not a valid Unicode codepoint".into(),
|
||||||
span: t,
|
span: value.span,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn string_to_unicode_char(s: &str, t: Span) -> Result<char, ShellError> {
|
fn string_to_unicode_char(s: Spanned<String>) -> Result<char, ShellError> {
|
||||||
let decoded_char = u32::from_str_radix(s, 16)
|
let decoded_char = u32::from_str_radix(&s.item, 16)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(std::char::from_u32);
|
.and_then(std::char::from_u32);
|
||||||
|
|
||||||
@ -400,7 +392,7 @@ fn string_to_unicode_char(s: &str, t: Span) -> Result<char, ShellError> {
|
|||||||
} else {
|
} else {
|
||||||
Err(ShellError::TypeMismatch {
|
Err(ShellError::TypeMismatch {
|
||||||
err_message: "error decoding Unicode character".into(),
|
err_message: "error decoding Unicode character".into(),
|
||||||
span: t,
|
span: s.span,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user