Skip to content

Commit d2244df

Browse files
Colored text for readability and transfer speed display (#279)
* added colored text for readability and transfer speed display * using bold for better readability * added compatibility with CLICOLOR standard * only display peer when connecting directly
1 parent 7287e34 commit d2244df

File tree

4 files changed

+112
-16
lines changed

4 files changed

+112
-16
lines changed

cli/src/main.rs

+98-14
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@ use std::{
99

1010
use async_std::sync::Arc;
1111
use clap::{Args, CommandFactory, Parser, Subcommand};
12-
use color_eyre::{eyre, eyre::Context};
12+
use color_eyre::{
13+
eyre::{self, Context},
14+
owo_colors::OwoColorize,
15+
};
1316
use completer::enter_code;
1417
use console::{style, Term};
1518
use futures::{future::Either, Future, FutureExt};
1619
use indicatif::{MultiProgress, ProgressBar};
1720
use magic_wormhole::{
1821
forwarding, transfer,
19-
transit::{self, TransitInfo},
22+
transit::{self, ConnectionType, TransitInfo},
2023
MailboxConnection, ParseCodeError, ParsePasswordError, Wormhole,
2124
};
2225
use std::{io::Write, path::PathBuf};
@@ -261,8 +264,18 @@ struct WormholeCli {
261264
display_order = 100
262265
)]
263266
log: bool,
267+
264268
#[clap(subcommand)]
265269
command: WormholeCommand,
270+
271+
/// Disable color output
272+
#[arg(
273+
long = "no-color",
274+
global = true,
275+
help = "Disable color output",
276+
display_order = 101
277+
)]
278+
no_color: bool,
266279
}
267280

268281
#[async_std::main]
@@ -274,6 +287,11 @@ async fn main() -> eyre::Result<()> {
274287

275288
let mut term = Term::stdout();
276289

290+
// Set NO_COLOR environment variable if --no-color flag is used
291+
if app.no_color {
292+
std::env::set_var("NO_COLOR", "1");
293+
}
294+
277295
if app.log {
278296
tracing_subscriber::fmt()
279297
.with_max_level(tracing::Level::TRACE)
@@ -760,11 +778,16 @@ async fn make_send_offer(
760778
fn create_progress_bar(file_size: u64) -> ProgressBar {
761779
use indicatif::ProgressStyle;
762780

781+
let template = if should_use_color() {
782+
"[{elapsed_precise:.yellow.bold}] [{wide_bar}] {bytes:.blue.bold}/{total_bytes:.blue.bold} | {decimal_bytes_per_sec:.green.bold} | ETA: {eta:.yellow.bold}"
783+
} else {
784+
"[{elapsed_precise}] [{wide_bar}] {bytes}/{total_bytes} | {decimal_bytes_per_sec} | ETA: {eta}"
785+
};
786+
763787
let pb = ProgressBar::new(file_size);
764788
pb.set_style(
765789
ProgressStyle::default_bar()
766-
// .template("[{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})")
767-
.template("[{elapsed_precise}] [{wide_bar}] {bytes}/{total_bytes} ({eta})")
790+
.template(template)
768791
.unwrap()
769792
.progress_chars("#>-"),
770793
);
@@ -778,6 +801,7 @@ fn create_progress_handler(pb: ProgressBar) -> impl FnMut(u64, u64) {
778801
pb.set_length(total);
779802
pb.enable_steady_tick(std::time::Duration::from_millis(250));
780803
}
804+
781805
pb.set_position(sent);
782806
}
783807
}
@@ -1054,15 +1078,28 @@ async fn receive_inner_v1(
10541078
use number_prefix::NumberPrefix;
10551079
if !(noconfirm
10561080
|| util::ask_user(
1057-
format!(
1058-
"Receive file '{}' ({})?",
1059-
req.file_name(),
1060-
match NumberPrefix::binary(req.file_size() as f64) {
1061-
NumberPrefix::Standalone(bytes) => format!("{} bytes", bytes),
1062-
NumberPrefix::Prefixed(prefix, n) =>
1063-
format!("{:.1} {}B in size", n, prefix.symbol()),
1064-
},
1065-
),
1081+
match should_use_color() {
1082+
true => format!(
1083+
"Receive file '{}' ({})?",
1084+
req.file_name().green().bold(),
1085+
match NumberPrefix::binary(req.file_size() as f64) {
1086+
NumberPrefix::Standalone(bytes) => format!("{} bytes", bytes),
1087+
NumberPrefix::Prefixed(prefix, n) =>
1088+
format!("{:.1} {}B", n, prefix.symbol()),
1089+
}
1090+
.blue()
1091+
.bold(),
1092+
),
1093+
false => format!(
1094+
"Receive file '{}' ({})?",
1095+
req.file_name(),
1096+
match NumberPrefix::binary(req.file_size() as f64) {
1097+
NumberPrefix::Standalone(bytes) => format!("{} bytes", bytes),
1098+
NumberPrefix::Prefixed(prefix, n) =>
1099+
format!("{:.1} {}B", n, prefix.symbol()),
1100+
},
1101+
),
1102+
},
10661103
true,
10671104
)
10681105
.await)
@@ -1096,7 +1133,14 @@ async fn receive_inner_v1(
10961133

10971134
/* If there is a collision, ask whether to overwrite */
10981135
if !util::ask_user(
1099-
format!("Override existing file {}?", file_path.display()),
1136+
if should_use_color() {
1137+
format!(
1138+
"Override existing file {}?",
1139+
file_path.display().red().bold()
1140+
)
1141+
} else {
1142+
format!("Override existing file {}?", file_path.display())
1143+
},
11001144
false,
11011145
)
11021146
.await
@@ -1220,6 +1264,46 @@ async fn receive_inner_v2(
12201264

12211265
fn transit_handler(info: TransitInfo) {
12221266
tracing::info!("{info}");
1267+
let mut term = Term::stderr();
1268+
let use_color = should_use_color();
1269+
1270+
let conn_type = if use_color {
1271+
info.conn_type.bright_magenta().bold().to_string()
1272+
} else {
1273+
info.conn_type.to_string()
1274+
};
1275+
1276+
let peer_addr = if use_color {
1277+
info.peer_addr.cyan().bold().to_string()
1278+
} else {
1279+
info.peer_addr.to_string()
1280+
};
1281+
1282+
if info.conn_type == ConnectionType::Direct {
1283+
let _ = writeln!(term, "Connecting {} to {}", conn_type, peer_addr);
1284+
} else {
1285+
let _ = writeln!(term, "Connecting {}", conn_type);
1286+
};
1287+
}
1288+
1289+
fn should_use_color() -> bool {
1290+
// Check NO_COLOR first - if it exists with any value, disable colors
1291+
if std::env::var_os("NO_COLOR").is_some() {
1292+
return false;
1293+
}
1294+
1295+
// Then check CLICOLOR_FORCE - if set and not empty/"0", enable colors regardless of terminal
1296+
if std::env::var_os("CLICOLOR_FORCE").is_some_and(|e| !e.is_empty() && e != "0") {
1297+
return true;
1298+
}
1299+
1300+
// Check CLICOLOR - if set and not empty/"0", use colors only when writing to a terminal
1301+
if std::env::var_os("CLICOLOR").is_some_and(|e| !e.is_empty() && e != "0") {
1302+
return std::io::stdout().is_terminal();
1303+
}
1304+
1305+
// Modern default (acting as if CLICOLOR is set)
1306+
std::io::stdout().is_terminal()
12231307
}
12241308

12251309
#[cfg(test)]

cli/tests/cmd/basic.stderr

+3-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ Commands:
1010

1111
Options:
1212
-v, --verbose[..]
13-
-h, --help[..]
14-
-V, --version[..]
13+
--no-color Disable color output
14+
-h, --help Print help
15+
-V, --version Print version
1516

1617
Run a subcommand with `--help` to know how it's used.
1718
To send files, use `wormhole send <PATH>`.

cli/tests/cmd/help.stdout

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Commands:
1010

1111
Options:
1212
-v, --verbose[..]
13+
--no-color Disable color output
1314
-h, --help[..]
1415
-V, --version[..]
1516

src/transit.rs

+10
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,16 @@ pub enum ConnectionType {
665665
},
666666
}
667667

668+
impl std::fmt::Display for ConnectionType {
669+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
670+
match self {
671+
ConnectionType::Direct => write!(f, "directly"),
672+
ConnectionType::Relay { name: Some(name) } => write!(f, "via relay ({})", name),
673+
ConnectionType::Relay { name: None } => write!(f, "via relay"),
674+
}
675+
}
676+
}
677+
668678
/// Metadata for the established transit connection
669679
#[derive(Clone, Debug, Eq, PartialEq)]
670680
#[non_exhaustive]

0 commit comments

Comments
 (0)