Added colored output for head and base32 applets (file header is green)
This commit is contained in:
parent
dff8561875
commit
36835dd322
24
Cargo.lock
generated
24
Cargo.lock
generated
@ -2,6 +2,17 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atty"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi 0.1.19",
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.20.0"
|
version = "0.20.0"
|
||||||
@ -98,6 +109,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.2.6"
|
version = "0.2.6"
|
||||||
@ -134,7 +154,7 @@ version = "0.4.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330"
|
checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi",
|
"hermit-abi 0.2.6",
|
||||||
"io-lifetimes",
|
"io-lifetimes",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
@ -194,6 +214,7 @@ dependencies = [
|
|||||||
name = "shitbox"
|
name = "shitbox"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"atty",
|
||||||
"base64",
|
"base64",
|
||||||
"clap",
|
"clap",
|
||||||
"clap_complete",
|
"clap_complete",
|
||||||
@ -202,6 +223,7 @@ dependencies = [
|
|||||||
"data-encoding",
|
"data-encoding",
|
||||||
"hostname",
|
"hostname",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"termcolor",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -6,6 +6,7 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
atty = "0.2.14"
|
||||||
base64 = "0.20.0"
|
base64 = "0.20.0"
|
||||||
clap = "4.0.29"
|
clap = "4.0.29"
|
||||||
clap_complete = "4.0.6"
|
clap_complete = "4.0.6"
|
||||||
@ -14,6 +15,7 @@ clap_mangen = "0.2.5"
|
|||||||
data-encoding = "2.3.3"
|
data-encoding = "2.3.3"
|
||||||
hostname = { version = "0.3", features = ["set"] }
|
hostname = { version = "0.3", features = ["set"] }
|
||||||
once_cell = "1.16.0"
|
once_cell = "1.16.0"
|
||||||
|
termcolor = "1.1.3"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
|
@ -3,9 +3,10 @@ use clap::{value_parser, Arg, ArgAction, Command};
|
|||||||
use data_encoding::BASE32;
|
use data_encoding::BASE32;
|
||||||
use std::{
|
use std::{
|
||||||
fs,
|
fs,
|
||||||
io::{self, Read},
|
io::{self, Read, Write},
|
||||||
process,
|
process,
|
||||||
};
|
};
|
||||||
|
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Base32 {
|
pub struct Base32 {
|
||||||
@ -47,6 +48,10 @@ impl Cmd for Base32 {
|
|||||||
.long("wrap")
|
.long("wrap")
|
||||||
.value_parser(value_parser!(usize))
|
.value_parser(value_parser!(usize))
|
||||||
.default_value("76"),
|
.default_value("76"),
|
||||||
|
Arg::new("color")
|
||||||
|
.short('c')
|
||||||
|
.long("color")
|
||||||
|
.value_parser(["always", "ansi", "auto", "never"]),
|
||||||
Arg::new("VERBOSE")
|
Arg::new("VERBOSE")
|
||||||
.help("Display a header naming each file")
|
.help("Display a header naming each file")
|
||||||
.short('v')
|
.short('v')
|
||||||
@ -69,12 +74,27 @@ impl Cmd for Base32 {
|
|||||||
None => vec![String::from("-")],
|
None => vec![String::from("-")],
|
||||||
};
|
};
|
||||||
let len = files.len();
|
let len = files.len();
|
||||||
|
let color = match matches.get_one::<String>("color").map(|x| x.as_str()) {
|
||||||
|
Some("always") => ColorChoice::Always,
|
||||||
|
Some("ansi") => ColorChoice::AlwaysAnsi,
|
||||||
|
Some("auto") => {
|
||||||
|
if atty::is(atty::Stream::Stdout) {
|
||||||
|
ColorChoice::Auto
|
||||||
|
} else {
|
||||||
|
ColorChoice::Never
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => ColorChoice::Never,
|
||||||
|
};
|
||||||
for (index, file) in files.into_iter().enumerate() {
|
for (index, file) in files.into_iter().enumerate() {
|
||||||
if { len > 1 || matches.get_flag("VERBOSE") } && !matches.get_flag("QUIET") {
|
if { len > 1 || matches.get_flag("VERBOSE") } && !matches.get_flag("QUIET") {
|
||||||
|
let mut stdout = StandardStream::stdout(color);
|
||||||
|
stdout.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
|
||||||
match index {
|
match index {
|
||||||
0 => println!("===> {file} <==="),
|
0 => writeln!(stdout, "===> {file} <==="),
|
||||||
_ => println!("\n===> {file} <==="),
|
_ => writeln!(stdout, "\n===> {file} <==="),
|
||||||
};
|
}?;
|
||||||
|
stdout.reset()?;
|
||||||
} else if index > 0 {
|
} else if index > 0 {
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
|
@ -60,10 +60,10 @@ impl Cmd for Factor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn first_factor(num: u64) -> u64 {
|
fn first_factor(num: u64) -> u64 {
|
||||||
if crate::math::is_prime(num) {
|
if num % 2 == 0 {
|
||||||
return num;
|
return 2;
|
||||||
}
|
}
|
||||||
for n in 2..=num {
|
for n in (3..=num).step_by(1) {
|
||||||
if num % n == 0 {
|
if num % n == 0 {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,10 @@ use std::{
|
|||||||
env,
|
env,
|
||||||
error::Error,
|
error::Error,
|
||||||
fs,
|
fs,
|
||||||
io::{self, stdin, Read},
|
io::{self, stdin, Read, Write},
|
||||||
process,
|
process,
|
||||||
};
|
};
|
||||||
|
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Head {
|
pub struct Head {
|
||||||
@ -60,6 +61,10 @@ impl Cmd for Head {
|
|||||||
.allow_negative_numbers(false)
|
.allow_negative_numbers(false)
|
||||||
.conflicts_with("num")
|
.conflicts_with("num")
|
||||||
.value_parser(value_parser!(usize)),
|
.value_parser(value_parser!(usize)),
|
||||||
|
Arg::new("color")
|
||||||
|
.short('C')
|
||||||
|
.long("color")
|
||||||
|
.value_parser(["always", "ansi", "auto", "never"]),
|
||||||
Arg::new("num")
|
Arg::new("num")
|
||||||
.short('1')
|
.short('1')
|
||||||
.short_aliases(['2', '3', '4', '5', '6', '7', '8', '9'])
|
.short_aliases(['2', '3', '4', '5', '6', '7', '8', '9'])
|
||||||
@ -78,18 +83,19 @@ impl Cmd for Head {
|
|||||||
if args.len() > idx {
|
if args.len() > idx {
|
||||||
let arg1 = &args[idx];
|
let arg1 = &args[idx];
|
||||||
if arg1.starts_with('-') && arg1.len() > 1 {
|
if arg1.starts_with('-') && arg1.len() > 1 {
|
||||||
let lines: usize = arg1[1..].parse()?;
|
if let Ok(lines) = arg1[1..].parse::<usize>() {
|
||||||
let files: Vec<_> = if args.len() > idx + 1 {
|
let files: Vec<_> = if args.len() > idx + 1 {
|
||||||
args[idx + 1..].iter().map(String::as_str).collect()
|
args[idx + 1..].iter().map(String::as_str).collect()
|
||||||
} else {
|
} else {
|
||||||
vec!["-"]
|
vec!["-"]
|
||||||
};
|
};
|
||||||
for file in &files {
|
for file in &files {
|
||||||
head(file, lines, false, false);
|
head(file, lines, false, false, ColorChoice::Never)?;
|
||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
let Some(matches) = matches else {
|
let Some(matches) = matches else {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "No input").into());
|
return Err(io::Error::new(io::ErrorKind::Other, "No input").into());
|
||||||
};
|
};
|
||||||
@ -102,11 +108,23 @@ impl Cmd for Head {
|
|||||||
};
|
};
|
||||||
let header =
|
let header =
|
||||||
!matches.get_flag("QUIET") && { files.len() > 1 || matches.get_flag("HEADER") };
|
!matches.get_flag("QUIET") && { files.len() > 1 || matches.get_flag("HEADER") };
|
||||||
|
let color = match matches.get_one::<String>("color").map(|x| x.as_str()) {
|
||||||
|
Some("always") => ColorChoice::Always,
|
||||||
|
Some("ansi") => ColorChoice::AlwaysAnsi,
|
||||||
|
Some("auto") => {
|
||||||
|
if atty::is(atty::Stream::Stdout) {
|
||||||
|
ColorChoice::Auto
|
||||||
|
} else {
|
||||||
|
ColorChoice::Never
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => ColorChoice::Never,
|
||||||
|
};
|
||||||
for (index, file) in files.into_iter().enumerate() {
|
for (index, file) in files.into_iter().enumerate() {
|
||||||
if index == 1 && header {
|
if index == 1 && header {
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
head(&file, lines, header, matches.get_flag("BYTES"));
|
head(&file, lines, header, matches.get_flag("BYTES"), color)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -116,7 +134,13 @@ impl Cmd for Head {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn head(file: &str, count: usize, header: bool, bytes: bool) {
|
fn head(
|
||||||
|
file: &str,
|
||||||
|
count: usize,
|
||||||
|
header: bool,
|
||||||
|
bytes: bool,
|
||||||
|
color: ColorChoice,
|
||||||
|
) -> Result<(), Box<dyn Error>> {
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
if file == "-" {
|
if file == "-" {
|
||||||
match stdin().read_to_string(&mut contents) {
|
match stdin().read_to_string(&mut contents) {
|
||||||
@ -137,7 +161,10 @@ fn head(file: &str, count: usize, header: bool, bytes: bool) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
if header {
|
if header {
|
||||||
println!("==> {file} <==");
|
let mut stdout = StandardStream::stdout(color);
|
||||||
|
stdout.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
|
||||||
|
writeln!(stdout, "==> {file} <==")?;
|
||||||
|
stdout.reset()?;
|
||||||
}
|
}
|
||||||
if bytes {
|
if bytes {
|
||||||
for (index, char) in contents.chars().into_iter().enumerate() {
|
for (index, char) in contents.chars().into_iter().enumerate() {
|
||||||
@ -145,7 +172,7 @@ fn head(file: &str, count: usize, header: bool, bytes: bool) {
|
|||||||
print!("{char}");
|
print!("{char}");
|
||||||
} else {
|
} else {
|
||||||
println!();
|
println!();
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
@ -154,8 +181,9 @@ fn head(file: &str, count: usize, header: bool, bytes: bool) {
|
|||||||
if index < count {
|
if index < count {
|
||||||
println!("{line}");
|
println!("{line}");
|
||||||
} else {
|
} else {
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ pub mod head;
|
|||||||
pub mod hostname;
|
pub mod hostname;
|
||||||
mod ln;
|
mod ln;
|
||||||
mod ls;
|
mod ls;
|
||||||
mod mountpoint;
|
pub mod mountpoint;
|
||||||
mod mv;
|
mod mv;
|
||||||
pub mod nologin;
|
pub mod nologin;
|
||||||
mod pwd;
|
mod pwd;
|
||||||
@ -38,9 +38,9 @@ mod sync;
|
|||||||
pub mod r#true;
|
pub mod r#true;
|
||||||
|
|
||||||
pub use {
|
pub use {
|
||||||
|
self::base64::{Base64, BASE_64},
|
||||||
self::hostname::{Hostname, HOSTNAME},
|
self::hostname::{Hostname, HOSTNAME},
|
||||||
base32::{Base32, BASE_32},
|
base32::{Base32, BASE_32},
|
||||||
self::base64::{Base64, BASE_64},
|
|
||||||
bootstrap::{Bootstrap, BOOTSTRAP},
|
bootstrap::{Bootstrap, BOOTSTRAP},
|
||||||
dirname::{Dirname, DIRNAME},
|
dirname::{Dirname, DIRNAME},
|
||||||
echo::{Echo, ECHO},
|
echo::{Echo, ECHO},
|
||||||
|
@ -1 +1,50 @@
|
|||||||
|
use super::Cmd;
|
||||||
|
use clap::{Arg, ArgAction, Command};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Mountpoint {
|
||||||
|
name: &'static str,
|
||||||
|
path: Option<crate::Path>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MOUNTPOINT: Mountpoint = Mountpoint {
|
||||||
|
name: "mountpoint",
|
||||||
|
path: Some(crate::Path::Bin),
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Cmd for Mountpoint {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cli(&self) -> clap::Command {
|
||||||
|
Command::new(self.name)
|
||||||
|
.about("see if a directory or file is a mountpoint")
|
||||||
|
.author("Nathan Fisher")
|
||||||
|
.args([
|
||||||
|
Arg::new("fs-devno")
|
||||||
|
.help("Show the major/minor numbers of the device that is mounted on the given directory.")
|
||||||
|
.short('d')
|
||||||
|
.long("fs-devno")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
Arg::new("devno")
|
||||||
|
.help("Show the major/minor numbers of the given blockdevice on standard output.")
|
||||||
|
.short('x')
|
||||||
|
.long("devno")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
Arg::new("quiet")
|
||||||
|
.help("Be quiet - don’t print anything.")
|
||||||
|
.short('q')
|
||||||
|
.long("quiet")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, matches: Option<&clap::ArgMatches>) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path(&self) -> Option<crate::Path> {
|
||||||
|
self.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use super::{
|
use super::{
|
||||||
Cmd, BASE_32, BASE_64, BOOTSTRAP, DIRNAME, ECHO, FACTOR, FALSE, HEAD, HOSTNAME, NOLOGIN, SLEEP, TRUE,
|
Cmd, BASE_32, BASE_64, BOOTSTRAP, DIRNAME, ECHO, FACTOR, FALSE, HEAD, HOSTNAME, NOLOGIN, SLEEP,
|
||||||
|
TRUE,
|
||||||
};
|
};
|
||||||
use clap::Command;
|
use clap::Command;
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -3,8 +3,8 @@ use std::{env, error::Error, path::PathBuf, string::ToString};
|
|||||||
|
|
||||||
pub mod cmd;
|
pub mod cmd;
|
||||||
pub use cmd::{
|
pub use cmd::{
|
||||||
Cmd, Commands, BASE_32, BASE_64, BOOTSTRAP, DIRNAME, ECHO, FACTOR, FALSE, HEAD, HOSTNAME, NOLOGIN,
|
Cmd, Commands, BASE_32, BASE_64, BOOTSTRAP, DIRNAME, ECHO, FACTOR, FALSE, HEAD, HOSTNAME,
|
||||||
SHITBOX, SLEEP, TRUE,
|
NOLOGIN, SHITBOX, SLEEP, TRUE,
|
||||||
};
|
};
|
||||||
pub mod math;
|
pub mod math;
|
||||||
|
|
||||||
@ -41,8 +41,8 @@ pub fn run() -> Result<(), Box<dyn Error>> {
|
|||||||
cmd::COMMANDS
|
cmd::COMMANDS
|
||||||
.set(Commands {
|
.set(Commands {
|
||||||
items: vec![
|
items: vec![
|
||||||
&BASE_32, &BASE_64, &BOOTSTRAP, &DIRNAME, &ECHO, &FALSE, &FACTOR, &HEAD, &HOSTNAME,
|
&BASE_32, &BASE_64, &BOOTSTRAP, &DIRNAME, &ECHO, &FALSE, &FACTOR, &HEAD,
|
||||||
&NOLOGIN, &TRUE, &SLEEP, &SHITBOX,
|
&HOSTNAME, &NOLOGIN, &TRUE, &SLEEP, &SHITBOX,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
.expect("Cannot register commands");
|
.expect("Cannot register commands");
|
||||||
|
Loading…
Reference in New Issue
Block a user