diff --git a/crates/nu-cmd-extra/src/extra/strings/format/number.rs b/crates/nu-cmd-extra/src/extra/strings/format/number.rs index ad8a6b08fb..7af6a6e798 100644 --- a/crates/nu-cmd-extra/src/extra/strings/format/number.rs +++ b/crates/nu-cmd-extra/src/extra/strings/format/number.rs @@ -16,6 +16,11 @@ impl Command for FormatNumber { fn signature(&self) -> nu_protocol::Signature { Signature::build("format number") .input_output_types(vec![(Type::Number, Type::record())]) + .switch( + "no-prefix", + "don't include the binary, hex or octal prefixes", + Some('n'), + ) .category(Category::Conversions) } @@ -24,20 +29,36 @@ impl Command for FormatNumber { } fn examples(&self) -> Vec { - vec![Example { - description: "Get a record containing multiple formats for the number 42", - example: "42 | format number", - result: Some(Value::test_record(record! { - "binary" => Value::test_string("0b101010"), - "debug" => Value::test_string("42"), - "display" => Value::test_string("42"), - "lowerexp" => Value::test_string("4.2e1"), - "lowerhex" => Value::test_string("0x2a"), - "octal" => Value::test_string("0o52"), - "upperexp" => Value::test_string("4.2E1"), - "upperhex" => Value::test_string("0x2A"), - })), - }] + vec![ + Example { + description: "Get a record containing multiple formats for the number 42", + example: "42 | format number", + result: Some(Value::test_record(record! { + "debug" => Value::test_string("42"), + "display" => Value::test_string("42"), + "binary" => Value::test_string("0b101010"), + "lowerexp" => Value::test_string("4.2e1"), + "upperexp" => Value::test_string("4.2E1"), + "lowerhex" => Value::test_string("0x2a"), + "upperhex" => Value::test_string("0x2A"), + "octal" => Value::test_string("0o52"), + })), + }, + Example { + description: "Format float without prefixes", + example: "3.14 | format number --no-prefix", + result: Some(Value::test_record(record! { + "debug" => Value::test_string("3.14"), + "display" => Value::test_string("3.14"), + "binary" => Value::test_string("100000000001001000111101011100001010001111010111000010100011111"), + "lowerexp" => Value::test_string("3.14e0"), + "upperexp" => Value::test_string("3.14E0"), + "lowerhex" => Value::test_string("40091eb851eb851f"), + "upperhex" => Value::test_string("40091EB851EB851F"), + "octal" => Value::test_string("400110753412172702437"), + })), + }, + ] } fn run( @@ -59,14 +80,24 @@ pub(crate) fn format_number( ) -> Result { let cell_paths: Vec = call.rest(engine_state, stack, 0)?; let args = CellPathOnlyArgs::from(cell_paths); - operate(action, args, input, call.head, engine_state.signals()) + if call.has_flag(engine_state, stack, "no-prefix")? { + operate( + action_no_prefix, + args, + input, + call.head, + engine_state.signals(), + ) + } else { + operate(action, args, input, call.head, engine_state.signals()) + } } fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value { match input { - Value::Float { val, .. } => format_f64(*val, span), - Value::Int { val, .. } => format_i64(*val, span), - Value::Filesize { val, .. } => format_i64(val.get(), span), + Value::Float { val, .. } => format_f64(*val, false, span), + Value::Int { val, .. } => format_i64(*val, false, span), + Value::Filesize { val, .. } => format_i64(val.get(), false, span), // Propagate errors by explicitly matching them before the final case. Value::Error { .. } => input.clone(), other => Value::error( @@ -81,33 +112,80 @@ fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value { } } -fn format_i64(num: i64, span: Span) -> Value { +fn action_no_prefix(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value { + match input { + Value::Float { val, .. } => format_f64(*val, true, span), + Value::Int { val, .. } => format_i64(*val, true, span), + Value::Filesize { val, .. } => format_i64(val.get(), true, span), + // Propagate errors by explicitly matching them before the final case. + Value::Error { .. } => input.clone(), + other => Value::error( + ShellError::OnlySupportsThisInputType { + exp_input_type: "float, int, or filesize".into(), + wrong_type: other.get_type().to_string(), + dst_span: span, + src_span: other.span(), + }, + span, + ), + } +} + +fn format_i64(num: i64, no_prefix: bool, span: Span) -> Value { Value::record( record! { - "binary" => Value::string(format!("{num:#b}"), span), "debug" => Value::string(format!("{num:#?}"), span), "display" => Value::string(format!("{num}"), span), + "binary" => Value::string( + if no_prefix { format!("{num:b}") } else { format!("{num:#b}") }, + span, + ), "lowerexp" => Value::string(format!("{num:#e}"), span), - "lowerhex" => Value::string(format!("{num:#x}"), span), - "octal" => Value::string(format!("{num:#o}"), span), "upperexp" => Value::string(format!("{num:#E}"), span), - "upperhex" => Value::string(format!("{num:#X}"), span), + "lowerhex" => Value::string( + if no_prefix { format!("{num:x}") } else { format!("{num:#x}") }, + span, + ), + "upperhex" => Value::string( + if no_prefix { format!("{num:X}") } else { format!("{num:#X}") }, + span, + ), + "octal" => Value::string( + if no_prefix { format!("{num:o}") } else { format!("{num:#o}") }, + span, + ) }, span, ) } -fn format_f64(num: f64, span: Span) -> Value { +fn format_f64(num: f64, no_prefix: bool, span: Span) -> Value { Value::record( record! { - "binary" => Value::string(format!("{:b}", num.to_bits()), span), "debug" => Value::string(format!("{num:#?}"), span), "display" => Value::string(format!("{num}"), span), + "binary" => Value::string( + if no_prefix { + format!("{:b}", num.to_bits()) + } else { + format!("{:#b}", num.to_bits()) + }, + span, + ), "lowerexp" => Value::string(format!("{num:#e}"), span), - "lowerhex" => Value::string(format!("{:0x}", num.to_bits()), span), - "octal" => Value::string(format!("{:0o}", num.to_bits()), span), "upperexp" => Value::string(format!("{num:#E}"), span), - "upperhex" => Value::string(format!("{:0X}", num.to_bits()), span), + "lowerhex" => Value::string( + if no_prefix { format!("{:x}", num.to_bits()) } else { format!("{:#x}", num.to_bits()) }, + span, + ), + "upperhex" => Value::string( + if no_prefix { format!("{:X}", num.to_bits()) } else { format!("{:#X}", num.to_bits()) }, + span, + ), + "octal" => Value::string( + if no_prefix { format!("{:o}", num.to_bits()) } else { format!("{:#o}", num.to_bits()) }, + span, + ) }, span, )