mirror of
https://github.com/nushell/nushell
synced 2024-11-10 07:04:13 +00:00
add nu-pretty-hex, add into binary, update binaryview (#3370)
* add nu-pretty-hex, add into binary, update binaryview * updated parameter name, updated examples * fixed nu-pretty-hex test * fixed tests again! and added a no color option to pretty-hex
This commit is contained in:
parent
a8f555856a
commit
8cd639f6a2
22 changed files with 1256 additions and 31 deletions
97
Cargo.lock
generated
97
Cargo.lock
generated
|
@ -183,6 +183,18 @@ version = "0.5.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||
|
||||
[[package]]
|
||||
name = "as-slice"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0"
|
||||
dependencies = [
|
||||
"generic-array 0.12.4",
|
||||
"generic-array 0.13.3",
|
||||
"generic-array 0.14.4",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "1.6.1"
|
||||
|
@ -1967,6 +1979,24 @@ dependencies = [
|
|||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.4"
|
||||
|
@ -2108,6 +2138,15 @@ dependencies = [
|
|||
"regex 1.4.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4041af86e63ac4298ce40e5cca669066e75b6f1aa3390fe2561ffa5e1d9f4cc"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.9.1"
|
||||
|
@ -2126,6 +2165,18 @@ dependencies = [
|
|||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "634bd4d29cbf24424d0a4bfcbf80c6960129dc24424752a7d1d1390607023422"
|
||||
dependencies = [
|
||||
"as-slice",
|
||||
"generic-array 0.14.4",
|
||||
"hash32",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.2"
|
||||
|
@ -3107,6 +3158,15 @@ dependencies = [
|
|||
"serial_test",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bd69a141e8fdfa5ac882d8b816db2b9ad138ef7e3baa7cb753a9b3789aa8c7e"
|
||||
dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.30.1"
|
||||
|
@ -3158,7 +3218,7 @@ dependencies = [
|
|||
"lazy_static 1.4.0",
|
||||
"log 0.4.14",
|
||||
"meval",
|
||||
"nu-ansi-term",
|
||||
"nu-ansi-term 0.30.1",
|
||||
"nu-command",
|
||||
"nu-data",
|
||||
"nu-engine",
|
||||
|
@ -3166,6 +3226,7 @@ dependencies = [
|
|||
"nu-json",
|
||||
"nu-parser",
|
||||
"nu-plugin",
|
||||
"nu-pretty-hex",
|
||||
"nu-protocol",
|
||||
"nu-source",
|
||||
"nu-stream",
|
||||
|
@ -3177,7 +3238,6 @@ dependencies = [
|
|||
"num-traits 0.2.14",
|
||||
"parking_lot 0.11.1",
|
||||
"pin-utils",
|
||||
"pretty-hex",
|
||||
"ptree",
|
||||
"query_interface",
|
||||
"quick-xml 0.21.0",
|
||||
|
@ -3258,13 +3318,14 @@ dependencies = [
|
|||
"md5 0.7.0",
|
||||
"meval",
|
||||
"minus",
|
||||
"nu-ansi-term",
|
||||
"nu-ansi-term 0.30.1",
|
||||
"nu-data",
|
||||
"nu-engine",
|
||||
"nu-errors",
|
||||
"nu-json",
|
||||
"nu-parser",
|
||||
"nu-plugin",
|
||||
"nu-pretty-hex",
|
||||
"nu-protocol",
|
||||
"nu-source",
|
||||
"nu-stream",
|
||||
|
@ -3276,7 +3337,6 @@ dependencies = [
|
|||
"num-traits 0.2.14",
|
||||
"parking_lot 0.11.1",
|
||||
"pin-utils",
|
||||
"pretty-hex",
|
||||
"ptree",
|
||||
"query_interface",
|
||||
"quick-xml 0.21.0",
|
||||
|
@ -3331,7 +3391,7 @@ dependencies = [
|
|||
"getset",
|
||||
"indexmap",
|
||||
"log 0.4.14",
|
||||
"nu-ansi-term",
|
||||
"nu-ansi-term 0.30.1",
|
||||
"nu-errors",
|
||||
"nu-protocol",
|
||||
"nu-source",
|
||||
|
@ -3375,7 +3435,7 @@ dependencies = [
|
|||
"indexmap",
|
||||
"itertools",
|
||||
"log 0.4.14",
|
||||
"nu-ansi-term",
|
||||
"nu-ansi-term 0.30.1",
|
||||
"nu-data",
|
||||
"nu-errors",
|
||||
"nu-parser",
|
||||
|
@ -3410,7 +3470,7 @@ dependencies = [
|
|||
"derive-new",
|
||||
"getset",
|
||||
"glob",
|
||||
"nu-ansi-term",
|
||||
"nu-ansi-term 0.30.1",
|
||||
"nu-source",
|
||||
"num-bigint 0.3.2",
|
||||
"num-traits 0.2.14",
|
||||
|
@ -3473,6 +3533,15 @@ dependencies = [
|
|||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-pretty-hex"
|
||||
version = "0.30.1"
|
||||
dependencies = [
|
||||
"heapless",
|
||||
"nu-ansi-term 0.29.0",
|
||||
"rand 0.8.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-protocol"
|
||||
version = "0.30.1"
|
||||
|
@ -3521,7 +3590,7 @@ dependencies = [
|
|||
name = "nu-table"
|
||||
version = "0.30.1"
|
||||
dependencies = [
|
||||
"nu-ansi-term",
|
||||
"nu-ansi-term 0.30.1",
|
||||
"regex 1.4.3",
|
||||
"unicode-width",
|
||||
]
|
||||
|
@ -3564,12 +3633,12 @@ dependencies = [
|
|||
"crossterm 0.19.0",
|
||||
"image 0.22.5",
|
||||
"neso",
|
||||
"nu-ansi-term",
|
||||
"nu-ansi-term 0.30.1",
|
||||
"nu-errors",
|
||||
"nu-plugin",
|
||||
"nu-pretty-hex",
|
||||
"nu-protocol",
|
||||
"nu-source",
|
||||
"pretty-hex",
|
||||
"rawkey",
|
||||
]
|
||||
|
||||
|
@ -3755,7 +3824,7 @@ name = "nu_plugin_textview"
|
|||
version = "0.30.1"
|
||||
dependencies = [
|
||||
"bat",
|
||||
"nu-ansi-term",
|
||||
"nu-ansi-term 0.30.1",
|
||||
"nu-data",
|
||||
"nu-errors",
|
||||
"nu-plugin",
|
||||
|
@ -4384,12 +4453,6 @@ dependencies = [
|
|||
"typed-arena",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pretty-hex"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc5c99d529f0d30937f6f4b8a86d988047327bb88d04d2c4afc356de74722131"
|
||||
|
||||
[[package]]
|
||||
name = "pretty_env_logger"
|
||||
version = "0.4.0"
|
||||
|
|
|
@ -25,6 +25,7 @@ nu-table = { version = "0.30.1", path = "../nu-table" }
|
|||
nu-test-support = { version = "0.30.1", path = "../nu-test-support" }
|
||||
nu-value-ext = { version = "0.30.1", path = "../nu-value-ext" }
|
||||
nu-ansi-term = { version = "0.30.1", path = "../nu-ansi-term" }
|
||||
nu-pretty-hex = { version = "0.30.1", path = "../nu-pretty-hex" }
|
||||
|
||||
Inflector = "0.11"
|
||||
arboard = { version = "1.1.0", optional = true }
|
||||
|
@ -67,7 +68,6 @@ num-format = { version = "0.4.0", features = ["with-num-bigint"] }
|
|||
num-traits = "0.2.14"
|
||||
parking_lot = "0.11.1"
|
||||
pin-utils = "0.1.0"
|
||||
pretty-hex = "0.2.1"
|
||||
ptree = { version = "0.3.1", optional = true }
|
||||
query_interface = "0.3.5"
|
||||
quick-xml = "0.21.0"
|
||||
|
|
|
@ -24,6 +24,7 @@ nu-table = { version = "0.30.1", path = "../nu-table" }
|
|||
nu-test-support = { version = "0.30.1", path = "../nu-test-support" }
|
||||
nu-value-ext = { version = "0.30.1", path = "../nu-value-ext" }
|
||||
nu-ansi-term = { version = "0.30.1", path = "../nu-ansi-term" }
|
||||
nu-pretty-hex = { version = "0.30.1", path = "../nu-pretty-hex" }
|
||||
|
||||
Inflector = "0.11"
|
||||
arboard = { version = "1.1.0", optional = true }
|
||||
|
@ -65,7 +66,6 @@ num-format = { version = "0.4.0", features = ["with-num-bigint"] }
|
|||
num-traits = "0.2.14"
|
||||
parking_lot = "0.11.1"
|
||||
pin-utils = "0.1.0"
|
||||
pretty-hex = "0.2.1"
|
||||
ptree = { version = "0.3.1", optional = true }
|
||||
query_interface = "0.3.5"
|
||||
quick-xml = "0.21.0"
|
||||
|
|
|
@ -172,6 +172,7 @@ pub(crate) use echo::Echo;
|
|||
pub(crate) use empty::Command as Empty;
|
||||
pub(crate) use if_::If;
|
||||
pub(crate) use into::Into;
|
||||
pub(crate) use into::IntoBinary;
|
||||
pub(crate) use into::IntoInt;
|
||||
pub(crate) use nu::NuPlugin;
|
||||
pub(crate) use update::Command as Update;
|
||||
|
|
|
@ -165,7 +165,7 @@ pub fn autoview(context: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
let result = binary.run_with_actions(command_args)?;
|
||||
let _ = result.collect::<Vec<_>>();
|
||||
} else {
|
||||
use pretty_hex::*;
|
||||
use nu_pretty_hex::*;
|
||||
out!("{:?}", b.hex_dump());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,6 +122,7 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
|
|||
whole_stream_command(Update),
|
||||
whole_stream_command(Insert),
|
||||
whole_stream_command(Into),
|
||||
whole_stream_command(IntoBinary),
|
||||
whole_stream_command(IntoInt),
|
||||
whole_stream_command(SplitBy),
|
||||
// Row manipulation
|
||||
|
|
170
crates/nu-command/src/commands/into/binary.rs
Normal file
170
crates/nu-command/src/commands/into/binary.rs
Normal file
|
@ -0,0 +1,170 @@
|
|||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
ColumnPath, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
};
|
||||
use num_bigint::{BigInt, ToBigInt};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Arguments {
|
||||
pub rest: Vec<ColumnPath>,
|
||||
}
|
||||
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"into binary"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("into binary").rest(
|
||||
SyntaxShape::ColumnPath,
|
||||
"column paths to convert to binary (for table input)",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Convert value to a binary primitive"
|
||||
}
|
||||
|
||||
fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
into_binary(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "convert string to a nushell binary primitive",
|
||||
example:
|
||||
"echo 'This is a string that is exactly 52 characters long.' | into binary",
|
||||
result: Some(vec![UntaggedValue::binary(
|
||||
"This is a string that is exactly 52 characters long."
|
||||
.to_string()
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
)
|
||||
.into()]),
|
||||
},
|
||||
Example {
|
||||
description: "convert a number to a nushell binary primitive",
|
||||
example: "echo 1 | into binary",
|
||||
result: Some(vec![
|
||||
UntaggedValue::binary(BigInt::from(1).to_bytes_le().1).into()
|
||||
]),
|
||||
},
|
||||
Example {
|
||||
description: "convert a boolean to a nushell binary primitive",
|
||||
example: "echo $true | into binary",
|
||||
result: Some(vec![
|
||||
UntaggedValue::binary(BigInt::from(1).to_bytes_le().1).into()
|
||||
]),
|
||||
},
|
||||
Example {
|
||||
description: "convert a filesize to a nushell binary primitive",
|
||||
example: "ls | where name == LICENSE | get size | into binary",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "convert a filepath to a nushell binary primitive",
|
||||
example: "ls | where name == LICENSE | get name | path expand | into binary",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "convert a decimal to a nushell binary primitive",
|
||||
example: "echo 1.234 | into binary",
|
||||
result: Some(vec![
|
||||
UntaggedValue::binary(BigInt::from(1).to_bytes_le().1).into()
|
||||
]),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn into_binary(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
let (Arguments { rest: column_paths }, input) = args.process()?;
|
||||
|
||||
Ok(input
|
||||
.map(move |v| {
|
||||
if column_paths.is_empty() {
|
||||
ReturnSuccess::value(action(&v, v.tag())?)
|
||||
} else {
|
||||
let mut ret = v;
|
||||
for path in &column_paths {
|
||||
ret = ret.swap_data_by_column_path(
|
||||
path,
|
||||
Box::new(move |old| action(old, old.tag())),
|
||||
)?;
|
||||
}
|
||||
|
||||
ReturnSuccess::value(ret)
|
||||
}
|
||||
})
|
||||
.to_action_stream())
|
||||
}
|
||||
|
||||
pub fn action(input: &Value, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||
let tag = tag.into();
|
||||
match &input.value {
|
||||
UntaggedValue::Primitive(prim) => Ok(UntaggedValue::binary(match prim {
|
||||
Primitive::Binary(b) => b.to_vec(),
|
||||
// TODO: Several places here we use Little Endian. We should probably
|
||||
// query the host to determine if it's Big Endian or Little Endian
|
||||
Primitive::Int(n_ref) => n_ref.to_bytes_le().1,
|
||||
Primitive::Decimal(dec) => match dec.to_bigint() {
|
||||
Some(n) => n.to_bytes_le().1,
|
||||
None => {
|
||||
return Err(ShellError::unimplemented(
|
||||
"failed to convert decimal to int",
|
||||
));
|
||||
}
|
||||
},
|
||||
Primitive::Filesize(a_filesize) => match a_filesize.to_bigint() {
|
||||
Some(n) => n.to_bytes_le().1,
|
||||
None => {
|
||||
return Err(ShellError::unimplemented(
|
||||
"failed to convert filesize to bigint",
|
||||
));
|
||||
}
|
||||
},
|
||||
Primitive::String(a_string) => a_string.as_bytes().to_vec(),
|
||||
Primitive::Boolean(a_bool) => match a_bool {
|
||||
false => BigInt::from(0).to_bytes_le().1,
|
||||
true => BigInt::from(1).to_bytes_le().1,
|
||||
},
|
||||
Primitive::Date(a_date) => a_date.format("%c").to_string().as_bytes().to_vec(),
|
||||
Primitive::FilePath(a_filepath) => a_filepath
|
||||
.as_path()
|
||||
.display()
|
||||
.to_string()
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
_ => {
|
||||
return Err(ShellError::unimplemented(
|
||||
"'into int' for non-numeric primitives",
|
||||
))
|
||||
}
|
||||
})
|
||||
.into_value(&tag)),
|
||||
UntaggedValue::Row(_) => Err(ShellError::labeled_error(
|
||||
"specify column name to use, with 'into int COLUMN'",
|
||||
"found table",
|
||||
tag,
|
||||
)),
|
||||
_ => Err(ShellError::unimplemented("'into int' for unsupported type")),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::SubCommand;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(SubCommand {})
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
mod binary;
|
||||
mod command;
|
||||
mod int;
|
||||
|
||||
pub use binary::SubCommand as IntoBinary;
|
||||
pub use command::Command as Into;
|
||||
pub use int::SubCommand as IntoInt;
|
||||
|
|
|
@ -435,7 +435,7 @@ fn html_value(value: &Value) -> String {
|
|||
output_string.push_str("\">");
|
||||
}
|
||||
_ => {
|
||||
let output = pretty_hex::pretty_hex(&b);
|
||||
let output = nu_pretty_hex::pretty_hex(&b);
|
||||
|
||||
output_string.push_str("<pre>");
|
||||
output_string.push_str(&output);
|
||||
|
@ -444,7 +444,7 @@ fn html_value(value: &Value) -> String {
|
|||
}
|
||||
}
|
||||
_ => {
|
||||
let output = pretty_hex::pretty_hex(&b);
|
||||
let output = nu_pretty_hex::pretty_hex(&b);
|
||||
|
||||
output_string.push_str("<pre>");
|
||||
output_string.push_str(&output);
|
||||
|
|
201
crates/nu-pretty-hex/Cargo.lock
generated
Normal file
201
crates/nu-pretty-hex/Cargo.lock
generated
Normal file
|
@ -0,0 +1,201 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "as-slice"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0"
|
||||
dependencies = [
|
||||
"generic-array 0.12.4",
|
||||
"generic-array 0.13.3",
|
||||
"generic-array 0.14.4",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4041af86e63ac4298ce40e5cca669066e75b6f1aa3390fe2561ffa5e1d9f4cc"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "634bd4d29cbf24424d0a4bfcbf80c6960129dc24424752a7d1d1390607023422"
|
||||
dependencies = [
|
||||
"as-slice",
|
||||
"generic-array 0.14.4",
|
||||
"hash32",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bd69a141e8fdfa5ac882d8b816db2b9ad138ef7e3baa7cb753a9b3789aa8c7e"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-pretty-hex"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"heapless",
|
||||
"nu-ansi-term",
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
30
crates/nu-pretty-hex/Cargo.toml
Normal file
30
crates/nu-pretty-hex/Cargo.toml
Normal file
|
@ -0,0 +1,30 @@
|
|||
[package]
|
||||
authors = [
|
||||
"Andrei Volnin <wolandr@gmail.com>",
|
||||
"The Nu Project Contributors"
|
||||
]
|
||||
description = "Pretty hex dump of bytes slice in the common style."
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
name = "nu-pretty-hex"
|
||||
version = "0.30.1"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
name = "nu_pretty_hex"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "nu_pretty_hex"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
nu-ansi-term = "0.29.0"
|
||||
rand = "0.8.3"
|
||||
|
||||
[dev-dependencies]
|
||||
heapless = "0.6.1"
|
||||
|
||||
# [features]
|
||||
# default = ["alloc"]
|
||||
# alloc = []
|
21
crates/nu-pretty-hex/LICENSE
Normal file
21
crates/nu-pretty-hex/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2018 Andrei Volnin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
81
crates/nu-pretty-hex/README.md
Normal file
81
crates/nu-pretty-hex/README.md
Normal file
|
@ -0,0 +1,81 @@
|
|||
# nu-pretty-hex
|
||||
|
||||
An update of prett-hex to make it prettier
|
||||
|
||||
[![crates.io](https://img.shields.io/crates/v/pretty-hex.svg)](https://crates.io/crates/pretty-hex)
|
||||
[![docs.rs](https://docs.rs/pretty-hex/badge.svg)](https://docs.rs/pretty-hex)
|
||||
|
||||
A Rust library providing pretty hex dump.
|
||||
|
||||
A `simple_hex()` way renders one-line hex dump, a `pretty_hex()` way renders
|
||||
columned multi-line hex dump with addressing and ASCII representation.
|
||||
A `config_hex()` way renders hex dump in specified format.
|
||||
|
||||
## Inspiration
|
||||
|
||||
[Hexed](https://github.com/adolfohw/hexed) \
|
||||
[Hexyl](https://github.com/sharkdp/hexyl) \
|
||||
[Pretty-hex](https://github.com/wolandr/pretty-hex)
|
||||
|
||||
## Example of `simple_hex()`
|
||||
|
||||
```rust
|
||||
use pretty_hex::*;
|
||||
|
||||
let v = vec![222, 173, 190, 239, 202, 254, 32, 24];
|
||||
assert_eq!(simple_hex(&v), format!("{}", v.hex_dump()));
|
||||
|
||||
println!("{}", v.hex_dump());
|
||||
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```text
|
||||
de ad be ef ca fe 20 18
|
||||
```
|
||||
|
||||
## Example of `pretty_hex()`
|
||||
|
||||
```rust
|
||||
use pretty_hex::*;
|
||||
|
||||
let v: &[u8] = &random::<[u8;30]>();
|
||||
assert_eq!(pretty_hex(&v), format!("{:?}", v.hex_dump()));
|
||||
|
||||
println!("{:?}", v.hex_dump());
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```text
|
||||
Length: 30 (0x1e) bytes
|
||||
0000: 6b 4e 1a c3 af 03 d2 1e 7e 73 ba c8 bd 84 0f 83 kN......~s......
|
||||
0010: 89 d5 cf 90 23 67 4b 48 db b1 bc 35 bf ee ....#gKH...5..
|
||||
```
|
||||
|
||||
## Example of `config_hex()`
|
||||
|
||||
```rust
|
||||
use pretty_hex::*;
|
||||
|
||||
let cfg = HexConfig {title: false, width: 8, group: 0, ..HexConfig::default() };
|
||||
|
||||
let v = &include_bytes!("data");
|
||||
assert_eq!(config_hex(&v, cfg), format!("{:?}", v.hex_conf(cfg)));
|
||||
|
||||
println!("{:?}", v.hex_conf(cfg));
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```text
|
||||
0000: 6b 4e 1a c3 af 03 d2 1e kN......
|
||||
0008: 7e 73 ba c8 bd 84 0f 83 ~s......
|
||||
0010: 89 d5 cf 90 23 67 4b 48 ....#gKH
|
||||
0018: db b1 bc 35 bf ee ...5..
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Inspired by [haskell's pretty-hex](https://hackage.haskell.org/package/pretty-hex-1.0).
|
66
crates/nu-pretty-hex/src/lib.rs
Normal file
66
crates/nu-pretty-hex/src/lib.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
// #![no_std]
|
||||
|
||||
//! A Rust library providing pretty hex dump.
|
||||
//!
|
||||
//! A `simple_hex()` way renders one-line hex dump, and a `pretty_hex()` way renders
|
||||
//! columned multi-line hex dump with addressing and ASCII representation.
|
||||
//! A `config_hex()` way renders hex dump in specified format.
|
||||
//!
|
||||
//! ## Example of `simple_hex()`
|
||||
//! ```
|
||||
//! use pretty_hex::*;
|
||||
//!
|
||||
//! let v = vec![222, 173, 190, 239, 202, 254, 32, 24];
|
||||
//! # #[cfg(feature = "alloc")]
|
||||
//! assert_eq!(simple_hex(&v), format!("{}", v.hex_dump()));
|
||||
//!
|
||||
//! println!("{}", v.hex_dump());
|
||||
//! ```
|
||||
//! Output:
|
||||
//!
|
||||
//! ```text
|
||||
//! de ad be ef ca fe 20 18
|
||||
//! ```
|
||||
//! ## Example of `pretty_hex()`
|
||||
//! ```
|
||||
//! use pretty_hex::*;
|
||||
//!
|
||||
//! let v = &include_bytes!("../tests/data");
|
||||
//! # #[cfg(feature = "alloc")]
|
||||
//! assert_eq!(pretty_hex(&v), format!("{:?}", v.hex_dump()));
|
||||
//!
|
||||
//! println!("{:?}", v.hex_dump());
|
||||
//! ```
|
||||
//! Output:
|
||||
//!
|
||||
//! ```text
|
||||
//! Length: 30 (0x1e) bytes
|
||||
//! 0000: 6b 4e 1a c3 af 03 d2 1e 7e 73 ba c8 bd 84 0f 83 kN......~s......
|
||||
//! 0010: 89 d5 cf 90 23 67 4b 48 db b1 bc 35 bf ee ....#gKH...5..
|
||||
//! ```
|
||||
//! ## Example of `config_hex()`
|
||||
//! ```
|
||||
//! use pretty_hex::*;
|
||||
//!
|
||||
//! let cfg = HexConfig {title: false, width: 8, group: 0, ..HexConfig::default() };
|
||||
//!
|
||||
//! let v = &include_bytes!("../tests/data");
|
||||
//! # #[cfg(feature = "alloc")]
|
||||
//! assert_eq!(config_hex(&v, cfg), format!("{:?}", v.hex_conf(cfg)));
|
||||
//!
|
||||
//! println!("{:?}", v.hex_conf(cfg));
|
||||
//! ```
|
||||
//! Output:
|
||||
//!
|
||||
//! ```text
|
||||
//! 0000: 6b 4e 1a c3 af 03 d2 1e kN......
|
||||
//! 0008: 7e 73 ba c8 bd 84 0f 83 ~s......
|
||||
//! 0010: 89 d5 cf 90 23 67 4b 48 ....#gKH
|
||||
//! 0018: db b1 bc 35 bf ee ...5..
|
||||
//! ```
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
|
||||
mod pretty_hex;
|
||||
pub use pretty_hex::*;
|
50
crates/nu-pretty-hex/src/main.rs
Normal file
50
crates/nu-pretty-hex/src/main.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
use nu_pretty_hex::*;
|
||||
|
||||
fn main() {
|
||||
let config = HexConfig {
|
||||
title: true,
|
||||
ascii: true,
|
||||
width: 16,
|
||||
group: 4,
|
||||
chunk: 1,
|
||||
skip: Some(10),
|
||||
// length: Some(5),
|
||||
// length: None,
|
||||
length: Some(50),
|
||||
};
|
||||
|
||||
let my_string = "Darren Schroeder 😉";
|
||||
println!("ConfigHex\n{}\n", config_hex(&my_string, config));
|
||||
println!("SimpleHex\n{}\n", simple_hex(&my_string));
|
||||
println!("PrettyHex\n{}\n", pretty_hex(&my_string));
|
||||
println!("ConfigHex\n{}\n", config_hex(&my_string, config));
|
||||
|
||||
// let mut my_str = String::new();
|
||||
// for x in 0..256 {
|
||||
// my_str.push(x as u8);
|
||||
// }
|
||||
let mut v: Vec<u8> = vec![];
|
||||
for x in 0..=127 {
|
||||
v.push(x);
|
||||
}
|
||||
let my_str = String::from_utf8_lossy(&v[..]);
|
||||
|
||||
println!("First128\n{}\n", pretty_hex(&my_str.as_bytes()));
|
||||
println!(
|
||||
"First128-Param\n{}\n",
|
||||
config_hex(&my_str.as_bytes(), config)
|
||||
);
|
||||
|
||||
let mut r_str = String::new();
|
||||
for _ in 0..=127 {
|
||||
r_str.push(rand::random::<u8>() as char);
|
||||
}
|
||||
|
||||
println!("Random127\n{}\n", pretty_hex(&r_str));
|
||||
}
|
||||
|
||||
//chunk 0 44617272656e20536368726f65646572 Darren Schroeder
|
||||
//chunk 1 44 61 72 72 65 6e 20 53 63 68 72 6f 65 64 65 72 Darren Schroeder
|
||||
//chunk 2 461 7272 656e 2053 6368 726f 6564 6572 Darren Schroeder
|
||||
//chunk 3 46172 72656e 205363 68726f 656465 72 Darren Schroeder
|
||||
//chunk 4 44617272 656e2053 6368726f 65646572 Darren Schroeder
|
305
crates/nu-pretty-hex/src/pretty_hex.rs
Normal file
305
crates/nu-pretty-hex/src/pretty_hex.rs
Normal file
|
@ -0,0 +1,305 @@
|
|||
use core::primitive::str;
|
||||
use core::{default::Default, fmt};
|
||||
use nu_ansi_term::{Color, Style};
|
||||
|
||||
/// Returns a one-line hexdump of `source` grouped in default format without header
|
||||
/// and ASCII column.
|
||||
pub fn simple_hex<T: AsRef<[u8]>>(source: &T) -> String {
|
||||
let mut writer = String::new();
|
||||
hex_write(&mut writer, source, HexConfig::simple(), None).unwrap_or(());
|
||||
writer
|
||||
}
|
||||
|
||||
/// Dump `source` as hex octets in default format without header and ASCII column to the `writer`.
|
||||
pub fn simple_hex_write<T, W>(writer: &mut W, source: &T) -> fmt::Result
|
||||
where
|
||||
T: AsRef<[u8]>,
|
||||
W: fmt::Write,
|
||||
{
|
||||
hex_write(writer, source, HexConfig::simple(), None)
|
||||
}
|
||||
|
||||
/// Return a multi-line hexdump in default format complete with addressing, hex digits,
|
||||
/// and ASCII representation.
|
||||
pub fn pretty_hex<T: AsRef<[u8]>>(source: &T) -> String {
|
||||
let mut writer = String::new();
|
||||
hex_write(&mut writer, source, HexConfig::default(), Some(true)).unwrap_or(());
|
||||
writer
|
||||
}
|
||||
|
||||
/// Write multi-line hexdump in default format complete with addressing, hex digits,
|
||||
/// and ASCII representation to the writer.
|
||||
pub fn pretty_hex_write<T, W>(writer: &mut W, source: &T) -> fmt::Result
|
||||
where
|
||||
T: AsRef<[u8]>,
|
||||
W: fmt::Write,
|
||||
{
|
||||
hex_write(writer, source, HexConfig::default(), Some(true))
|
||||
}
|
||||
|
||||
/// Return a hexdump of `source` in specified format.
|
||||
pub fn config_hex<T: AsRef<[u8]>>(source: &T, cfg: HexConfig) -> String {
|
||||
let mut writer = String::new();
|
||||
hex_write(&mut writer, source, cfg, Some(true)).unwrap_or(());
|
||||
writer
|
||||
}
|
||||
|
||||
/// Configuration parameters for hexdump.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct HexConfig {
|
||||
/// Write first line header with data length.
|
||||
pub title: bool,
|
||||
/// Append ASCII representation column.
|
||||
pub ascii: bool,
|
||||
/// Source bytes per row. 0 for single row without address prefix.
|
||||
pub width: usize,
|
||||
/// Chunks count per group. 0 for single group (column).
|
||||
pub group: usize,
|
||||
/// Source bytes per chunk (word). 0 for single word.
|
||||
pub chunk: usize,
|
||||
/// Bytes from 0 to skip
|
||||
pub skip: Option<usize>,
|
||||
/// Length to return
|
||||
pub length: Option<usize>,
|
||||
}
|
||||
|
||||
/// Default configuration with `title`, `ascii`, 16 source bytes `width` grouped to 4 separate
|
||||
/// hex bytes. Using in `pretty_hex`, `pretty_hex_write` and `fmt::Debug` implementation.
|
||||
impl Default for HexConfig {
|
||||
fn default() -> HexConfig {
|
||||
HexConfig {
|
||||
title: true,
|
||||
ascii: true,
|
||||
width: 16,
|
||||
group: 4,
|
||||
chunk: 1,
|
||||
skip: None,
|
||||
length: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HexConfig {
|
||||
/// Returns configuration for `simple_hex`, `simple_hex_write` and `fmt::Display` implementation.
|
||||
pub fn simple() -> Self {
|
||||
HexConfig::default().to_simple()
|
||||
}
|
||||
|
||||
fn delimiter(&self, i: usize) -> &'static str {
|
||||
if i > 0 && self.chunk > 0 && i % self.chunk == 0 {
|
||||
if self.group > 0 && i % (self.group * self.chunk) == 0 {
|
||||
" "
|
||||
} else {
|
||||
" "
|
||||
}
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
fn to_simple(self) -> Self {
|
||||
HexConfig {
|
||||
title: false,
|
||||
ascii: false,
|
||||
width: 0,
|
||||
..self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn categorize_byte(byte: &u8) -> (Style, Option<char>) {
|
||||
// This section is here so later we can configure these items
|
||||
let null_char_style = Style::default().fg(Color::Fixed(242));
|
||||
let null_char = Some('0');
|
||||
let ascii_printable_style = Style::default().fg(Color::Cyan).bold();
|
||||
let ascii_printable = None;
|
||||
let ascii_space_style = Style::default().fg(Color::Green).bold();
|
||||
let ascii_space = Some(' ');
|
||||
let ascii_white_space_style = Style::default().fg(Color::Green).bold();
|
||||
let ascii_white_space = Some('_');
|
||||
let ascii_other_style = Style::default().fg(Color::Purple).bold();
|
||||
let ascii_other = Some('•');
|
||||
let non_ascii_style = Style::default().fg(Color::Yellow).bold();
|
||||
let non_ascii = Some('×'); // or Some('.')
|
||||
|
||||
if byte == &0 {
|
||||
(null_char_style, null_char)
|
||||
} else if byte.is_ascii_graphic() {
|
||||
(ascii_printable_style, ascii_printable)
|
||||
} else if byte.is_ascii_whitespace() {
|
||||
// 0x20 == 32 decimal - replace with a real space
|
||||
if byte == &32 {
|
||||
(ascii_space_style, ascii_space)
|
||||
} else {
|
||||
(ascii_white_space_style, ascii_white_space)
|
||||
}
|
||||
} else if byte.is_ascii() {
|
||||
(ascii_other_style, ascii_other)
|
||||
} else {
|
||||
(non_ascii_style, non_ascii)
|
||||
}
|
||||
}
|
||||
|
||||
/// Write hex dump in specified format.
|
||||
pub fn hex_write<T, W>(
|
||||
writer: &mut W,
|
||||
source: &T,
|
||||
cfg: HexConfig,
|
||||
with_color: Option<bool>,
|
||||
) -> fmt::Result
|
||||
where
|
||||
T: AsRef<[u8]>,
|
||||
W: fmt::Write,
|
||||
{
|
||||
let use_color = with_color.unwrap_or(false);
|
||||
|
||||
if source.as_ref().is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let amount = match cfg.length {
|
||||
Some(len) => len,
|
||||
None => source.as_ref().len(),
|
||||
};
|
||||
|
||||
let skip = cfg.skip.unwrap_or(0);
|
||||
|
||||
let source_part_vec: Vec<u8> = source
|
||||
.as_ref()
|
||||
.iter()
|
||||
.skip(skip)
|
||||
.take(amount)
|
||||
.map(|x| *x as u8)
|
||||
.collect();
|
||||
|
||||
let source_part = String::from_utf8_lossy(&source_part_vec[..]);
|
||||
|
||||
if cfg.title {
|
||||
if use_color {
|
||||
writeln!(
|
||||
writer,
|
||||
"Length: {0} (0x{0:x}) bytes | {1}printable {2}whitespace {3}ascii_other {4}non_ascii{5}",
|
||||
source_part.as_bytes().as_ref().len(),
|
||||
Style::default().fg(Color::Cyan).bold().prefix(),
|
||||
Style::default().fg(Color::Green).bold().prefix(),
|
||||
Style::default().fg(Color::Purple).bold().prefix(),
|
||||
Style::default().fg(Color::Yellow).bold().prefix(),
|
||||
Style::default().fg(Color::Yellow).suffix()
|
||||
)?;
|
||||
} else {
|
||||
writeln!(
|
||||
writer,
|
||||
"Length: {0} (0x{0:x}) bytes",
|
||||
source_part.as_bytes().as_ref().len(),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
let lines = source_part.as_bytes().as_ref().chunks(if cfg.width > 0 {
|
||||
cfg.width
|
||||
} else {
|
||||
source_part.as_bytes().as_ref().len()
|
||||
});
|
||||
|
||||
let lines_len = lines.len();
|
||||
|
||||
for (i, row) in lines.enumerate() {
|
||||
if cfg.width > 0 {
|
||||
let style = Style::default().fg(Color::Cyan);
|
||||
if use_color {
|
||||
write!(
|
||||
writer,
|
||||
"{}{:08x}{}: ",
|
||||
style.prefix(),
|
||||
i * cfg.width + skip,
|
||||
style.suffix()
|
||||
)?;
|
||||
} else {
|
||||
write!(writer, "{:08x}: ", i * cfg.width + skip,)?;
|
||||
}
|
||||
}
|
||||
for (i, x) in row.as_ref().iter().enumerate() {
|
||||
if use_color {
|
||||
let (style, _char) = categorize_byte(x);
|
||||
write!(
|
||||
writer,
|
||||
"{}{}{:02x}{}",
|
||||
cfg.delimiter(i),
|
||||
style.prefix(),
|
||||
x,
|
||||
style.suffix()
|
||||
)?;
|
||||
} else {
|
||||
write!(writer, "{}{:02x}", cfg.delimiter(i), x,)?;
|
||||
}
|
||||
}
|
||||
if cfg.ascii {
|
||||
for j in row.len()..cfg.width {
|
||||
write!(writer, "{} ", cfg.delimiter(j))?;
|
||||
}
|
||||
write!(writer, " ")?;
|
||||
for x in row {
|
||||
let (style, a_char) = categorize_byte(x);
|
||||
let replacement_char = match a_char {
|
||||
Some(c) => c,
|
||||
None => *x as char,
|
||||
};
|
||||
if use_color {
|
||||
write!(
|
||||
writer,
|
||||
"{}{}{}",
|
||||
style.prefix(),
|
||||
replacement_char,
|
||||
style.suffix()
|
||||
)?;
|
||||
} else {
|
||||
write!(writer, "{}", replacement_char,)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
if i + 1 < lines_len {
|
||||
writeln!(writer)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Reference wrapper for use in arguments formatting.
|
||||
pub struct Hex<'a, T: 'a>(&'a T, HexConfig);
|
||||
|
||||
impl<'a, T: 'a + AsRef<[u8]>> fmt::Display for Hex<'a, T> {
|
||||
/// Formats the value by `simple_hex_write` using the given formatter.
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
hex_write(f, self.0, self.1.to_simple(), None)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a + AsRef<[u8]>> fmt::Debug for Hex<'a, T> {
|
||||
/// Formats the value by `pretty_hex_write` using the given formatter.
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
hex_write(f, self.0, self.1, None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows generates hex dumps to a formatter.
|
||||
pub trait PrettyHex: Sized {
|
||||
/// Wrap self reference for use in `std::fmt::Display` and `std::fmt::Debug`
|
||||
/// formatting as hex dumps.
|
||||
fn hex_dump(&self) -> Hex<Self>;
|
||||
|
||||
/// Wrap self reference for use in `std::fmt::Display` and `std::fmt::Debug`
|
||||
/// formatting as hex dumps in specified format.
|
||||
fn hex_conf(&self, cfg: HexConfig) -> Hex<Self>;
|
||||
}
|
||||
|
||||
impl<T> PrettyHex for T
|
||||
where
|
||||
T: AsRef<[u8]>,
|
||||
{
|
||||
fn hex_dump(&self) -> Hex<Self> {
|
||||
Hex(self, HexConfig::default())
|
||||
}
|
||||
fn hex_conf(&self, cfg: HexConfig) -> Hex<Self> {
|
||||
Hex(self, cfg)
|
||||
}
|
||||
}
|
17
crates/nu-pretty-hex/tests/256.txt
Normal file
17
crates/nu-pretty-hex/tests/256.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
Length: 256 (0x100) bytes
|
||||
0000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ................
|
||||
0010: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f ................
|
||||
0020: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f !"#$%&'()*+,-./
|
||||
0030: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 0123456789:;<=>?
|
||||
0040: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO
|
||||
0050: 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f PQRSTUVWXYZ[\]^_
|
||||
0060: 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f `abcdefghijklmno
|
||||
0070: 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f pqrstuvwxyz{|}~.
|
||||
0080: 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f ................
|
||||
0090: 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f ................
|
||||
00a0: a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af ................
|
||||
00b0: b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf ................
|
||||
00c0: c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf ................
|
||||
00d0: d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df ................
|
||||
00e0: e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef ................
|
||||
00f0: f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff ................
|
1
crates/nu-pretty-hex/tests/data
Normal file
1
crates/nu-pretty-hex/tests/data
Normal file
|
@ -0,0 +1 @@
|
|||
kNУЏв~sКШН<D0A8><0F><>еЯ<D0B5>#gKHлБМ5Пю
|
175
crates/nu-pretty-hex/tests/tests.rs
Normal file
175
crates/nu-pretty-hex/tests/tests.rs
Normal file
|
@ -0,0 +1,175 @@
|
|||
// #![no_std]
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
extern crate nu_pretty_hex;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::{format, string::String, vec, vec::Vec};
|
||||
use nu_pretty_hex::*;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
#[test]
|
||||
fn test_simple() {
|
||||
let bytes: Vec<u8> = (0..16).collect();
|
||||
let expected = "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f";
|
||||
assert_eq!(expected, simple_hex(&bytes));
|
||||
assert_eq!(expected, format!("{}", bytes.hex_dump()));
|
||||
assert_eq!(simple_hex(&bytes), config_hex(&bytes, HexConfig::simple()));
|
||||
|
||||
let mut have = String::new();
|
||||
simple_hex_write(&mut have, &bytes).unwrap();
|
||||
assert_eq!(expected, have);
|
||||
|
||||
let str = "string";
|
||||
let string: String = String::from("string");
|
||||
let slice: &[u8] = &[0x73, 0x74, 0x72, 0x69, 0x6e, 0x67];
|
||||
assert_eq!(simple_hex(&str), "73 74 72 69 6e 67");
|
||||
assert_eq!(simple_hex(&str), simple_hex(&string));
|
||||
assert_eq!(simple_hex(&str), simple_hex(&slice));
|
||||
|
||||
assert!(simple_hex(&vec![]).is_empty());
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
#[test]
|
||||
fn test_pretty() {
|
||||
let bytes: Vec<u8> = (0..256).map(|x| x as u8).collect();
|
||||
let want = include_str!("256.txt");
|
||||
|
||||
let mut hex = String::new();
|
||||
pretty_hex_write(&mut hex, &bytes).unwrap();
|
||||
assert_eq!(want, hex);
|
||||
assert_eq!(want, format!("{:?}", bytes.hex_dump()));
|
||||
assert_eq!(want, pretty_hex(&bytes));
|
||||
assert_eq!(want, config_hex(&bytes, HexConfig::default()));
|
||||
|
||||
assert_eq!("Length: 0 (0x0) bytes\n", pretty_hex(&vec![]));
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
#[test]
|
||||
fn test_config() {
|
||||
let cfg = HexConfig {
|
||||
title: false,
|
||||
ascii: false,
|
||||
width: 0,
|
||||
group: 0,
|
||||
chunk: 0,
|
||||
};
|
||||
assert!(config_hex(&vec![], cfg).is_empty());
|
||||
assert_eq!("2425262728", config_hex(&"$%&'(", cfg));
|
||||
|
||||
let v = include_bytes!("data");
|
||||
let cfg = HexConfig {
|
||||
title: false,
|
||||
group: 8,
|
||||
..HexConfig::default()
|
||||
};
|
||||
let hex = "0000: 6b 4e 1a c3 af 03 d2 1e 7e 73 ba c8 bd 84 0f 83 kN......~s......\n\
|
||||
0010: 89 d5 cf 90 23 67 4b 48 db b1 bc 35 bf ee ....#gKH...5..";
|
||||
assert_eq!(hex, config_hex(&v, cfg));
|
||||
assert_eq!(hex, format!("{:?}", v.hex_conf(cfg)));
|
||||
let mut str = String::new();
|
||||
hex_write(&mut str, v, cfg).unwrap();
|
||||
assert_eq!(hex, str);
|
||||
|
||||
assert_eq!(
|
||||
config_hex(
|
||||
&v,
|
||||
HexConfig {
|
||||
ascii: false,
|
||||
..cfg
|
||||
}
|
||||
),
|
||||
"0000: 6b 4e 1a c3 af 03 d2 1e 7e 73 ba c8 bd 84 0f 83\n\
|
||||
0010: 89 d5 cf 90 23 67 4b 48 db b1 bc 35 bf ee"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
config_hex(
|
||||
&v,
|
||||
HexConfig {
|
||||
ascii: false,
|
||||
group: 4,
|
||||
chunk: 2,
|
||||
..cfg
|
||||
}
|
||||
),
|
||||
"0000: 6b4e 1ac3 af03 d21e 7e73 bac8 bd84 0f83\n\
|
||||
0010: 89d5 cf90 2367 4b48 dbb1 bc35 bfee"
|
||||
);
|
||||
|
||||
let v: Vec<u8> = (0..21).collect();
|
||||
let want = r##"Length: 21 (0x15) bytes
|
||||
0000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ................
|
||||
0010: 10 11 12 13 14 ....."##;
|
||||
assert_eq!(want, pretty_hex(&v));
|
||||
|
||||
let v: Vec<u8> = (0..13).collect();
|
||||
assert_eq!(
|
||||
config_hex(
|
||||
&v,
|
||||
HexConfig {
|
||||
title: false,
|
||||
ascii: true,
|
||||
width: 11,
|
||||
group: 2,
|
||||
chunk: 3
|
||||
}
|
||||
),
|
||||
"0000: 000102 030405 060708 090a ...........\n\
|
||||
000b: 0b0c .."
|
||||
);
|
||||
|
||||
let v: Vec<u8> = (0..19).collect();
|
||||
assert_eq!(
|
||||
config_hex(
|
||||
&v,
|
||||
HexConfig {
|
||||
title: false,
|
||||
ascii: true,
|
||||
width: 16,
|
||||
group: 3,
|
||||
chunk: 3
|
||||
}
|
||||
),
|
||||
"0000: 000102 030405 060708 090a0b 0c0d0e 0f ................\n\
|
||||
0010: 101112 ..."
|
||||
);
|
||||
|
||||
let cfg = HexConfig {
|
||||
title: false,
|
||||
group: 0,
|
||||
..HexConfig::default()
|
||||
};
|
||||
assert_eq!(
|
||||
format!("{:?}", v.hex_conf(cfg)),
|
||||
"0000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ................\n\
|
||||
0010: 10 11 12 ..."
|
||||
);
|
||||
assert_eq!(
|
||||
format!("{}", v.hex_conf(cfg)),
|
||||
"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12"
|
||||
);
|
||||
}
|
||||
|
||||
// This test case checks that hex_write works even without the alloc crate.
|
||||
// Decorators to this function like simple_hex_write or PrettyHex::hex_dump()
|
||||
// will be tested when the alloc feature is selected because it feels quite
|
||||
// cumbersome to set up these tests without the comodity from `alloc`.
|
||||
#[test]
|
||||
fn test_hex_write_with_simple_config() {
|
||||
let config = HexConfig::simple();
|
||||
let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||
let expected =
|
||||
core::str::from_utf8(b"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f").unwrap();
|
||||
// let expected =
|
||||
// "\u{1b}[38;5;242m00\u{1b}[0m \u{1b}[1;35m01\u{1b}[0m \u{1b}[1;35m02\u{1b}[0m \u{1b}[1;";
|
||||
let mut buffer = heapless::Vec::<u8, heapless::consts::U50>::new();
|
||||
|
||||
hex_write(&mut buffer, &bytes, config, None).unwrap();
|
||||
|
||||
let have = core::str::from_utf8(&buffer).unwrap();
|
||||
assert_eq!(expected, have);
|
||||
}
|
|
@ -18,7 +18,7 @@ nu-plugin = { path = "../nu-plugin", version = "0.30.1" }
|
|||
nu-protocol = { path = "../nu-protocol", version = "0.30.1" }
|
||||
nu-source = { path = "../nu-source", version = "0.30.1" }
|
||||
nu-ansi-term = { version = "0.30.1", path = "../nu-ansi-term" }
|
||||
pretty-hex = "0.2.1"
|
||||
nu-pretty-hex = { version = "0.30.1", path = "../nu-pretty-hex" }
|
||||
rawkey = "0.1.3"
|
||||
|
||||
[build-dependencies]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crossterm::{style::Attribute, ExecutableCommand};
|
||||
use nu_protocol::outln;
|
||||
use nu_pretty_hex::*;
|
||||
use nu_protocol::{outln, Value};
|
||||
use nu_source::AnchorLocation;
|
||||
use pretty_hex::*;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BinaryView;
|
||||
|
@ -16,6 +16,8 @@ pub fn view_binary(
|
|||
b: &[u8],
|
||||
source: Option<&AnchorLocation>,
|
||||
lores_mode: bool,
|
||||
skip: Option<&Value>,
|
||||
length: Option<&Value>,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if b.len() > 3 {
|
||||
if let (0x4e, 0x45, 0x53) = (b[0], b[1], b[2]) {
|
||||
|
@ -23,7 +25,8 @@ pub fn view_binary(
|
|||
return Ok(());
|
||||
}
|
||||
}
|
||||
view_contents(b, source, lores_mode)?;
|
||||
|
||||
view_contents(b, source, lores_mode, skip, length)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -207,7 +210,29 @@ pub fn view_contents(
|
|||
buffer: &[u8],
|
||||
_source: Option<&AnchorLocation>,
|
||||
lores_mode: bool,
|
||||
skip: Option<&Value>,
|
||||
length: Option<&Value>,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let skip_bytes = match skip {
|
||||
Some(s) => Some(s.as_usize().unwrap_or(0)),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let num_bytes = match length {
|
||||
Some(b) => Some(b.as_usize().unwrap_or(0)),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let config = HexConfig {
|
||||
title: true,
|
||||
ascii: true,
|
||||
width: 16,
|
||||
group: 4,
|
||||
chunk: 1,
|
||||
skip: skip_bytes,
|
||||
length: num_bytes,
|
||||
};
|
||||
|
||||
let mut raw_image_buffer = load_from_png_buffer(buffer);
|
||||
|
||||
if raw_image_buffer.is_err() {
|
||||
|
@ -216,7 +241,7 @@ pub fn view_contents(
|
|||
|
||||
if raw_image_buffer.is_err() {
|
||||
//Not yet supported
|
||||
outln!("{:?}", buffer.hex_dump());
|
||||
outln!("{}", config_hex(&buffer, config));
|
||||
return Ok(());
|
||||
}
|
||||
let raw_image_buffer = raw_image_buffer?;
|
||||
|
@ -270,7 +295,8 @@ pub fn view_contents(
|
|||
}
|
||||
_ => {
|
||||
//Not yet supported
|
||||
outln!("{:?}", buffer.hex_dump());
|
||||
// outln!("{:?}", buffer.hex_dump());
|
||||
outln!("{}", config_hex(&buffer, config));
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use nu_errors::ShellError;
|
||||
use nu_plugin::Plugin;
|
||||
use nu_protocol::{CallInfo, Primitive, Signature, UntaggedValue, Value};
|
||||
use nu_protocol::{CallInfo, Primitive, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
|
||||
use crate::binaryview::view_binary;
|
||||
use crate::BinaryView;
|
||||
|
@ -9,14 +9,29 @@ impl Plugin for BinaryView {
|
|||
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||
Ok(Signature::build("binaryview")
|
||||
.desc("Autoview of binary data.")
|
||||
.switch("lores", "use low resolution output mode", Some('l')))
|
||||
.switch("lores", "use low resolution output mode", Some('l'))
|
||||
.named(
|
||||
"skip",
|
||||
SyntaxShape::Int,
|
||||
"skip x number of bytes",
|
||||
Some('s'),
|
||||
)
|
||||
.named(
|
||||
"bytes",
|
||||
SyntaxShape::Int,
|
||||
"show y number of bytes",
|
||||
Some('b'),
|
||||
))
|
||||
}
|
||||
|
||||
fn sink(&mut self, call_info: CallInfo, input: Vec<Value>) {
|
||||
for v in input {
|
||||
let value_anchor = v.anchor();
|
||||
if let UntaggedValue::Primitive(Primitive::Binary(b)) = &v.value {
|
||||
let _ = view_binary(&b, value_anchor.as_ref(), call_info.args.has("lores"));
|
||||
let low_res = call_info.args.has("lores");
|
||||
let skip = call_info.args.get("skip");
|
||||
let length = call_info.args.get("bytes");
|
||||
let _ = view_binary(&b, value_anchor.as_ref(), low_res, skip, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue