Skip to content

Commit

Permalink
Add colored output
Browse files Browse the repository at this point in the history
Colored output can be controlled on the command line with
`--use-color auto|always|never`. The default is `auto`, which enables
color if `imdl` detects that it is printing to a terminal.

Color can be disabled entirely by setting the `NO_COLOR` environment
variable.

type: added
  • Loading branch information
casey committed Apr 8, 2020
1 parent b334fa4 commit d1f8f24
Show file tree
Hide file tree
Showing 12 changed files with 269 additions and 40 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/rust.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ jobs:
run: cargo build --verbose
- name: Test
run: cargo test --verbose
- name: Lint
- name: Clippy
run: cargo clippy
- name: Format
run: cargo fmt -- --check
- name: Lint
if: matrix.os != 'windows-latest'
run: "! grep --color -REn 'FIXME|TODO|XXX' src"
66 changes: 62 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 15 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,21 @@ repository = "https://github.com/casey/intermodal"
edition = "2018"

[dependencies]
libc = "0.2"
md5 = "0.7"
regex = "1"
serde_bencode = "0.2"
serde_bytes = "0.11"
sha1 = "0.6"
snafu = "0.6"
structopt = "0.3"
tempfile = "3"
url = "2"
walkdir = "2"
static_assertions = "1.1.0"
ansi_term = "0.12"
atty = "0.2"
env_logger = "0.7"
libc = "0.2"
md5 = "0.7"
regex = "1"
serde_bencode = "0.2"
serde_bytes = "0.11"
sha1 = "0.6"
snafu = "0.6"
static_assertions = "1"
structopt = "0.3"
tempfile = "3"
url = "2"
walkdir = "2"

[dependencies.serde]
version = "1"
Expand Down
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,36 @@
# intermodal: a 40' shipping container for the Internet

## Colored Output

Intermodal features colored help, error, and informational output. Colored
output is disabled if Intermodal detects that it is not printing to a TTY.

To disable colored output, set the `NO_COLOR` environment variable to any
valu or pass `--use-color never` on the command line.

To force colored output, pass `--use-color always` on the command line.

## Semantic Versioning and Unstable Features

Intermodal follows [semantic versioning](https://semver.org/).

In particular:

- v0.0.X: Breaking changes may be introduced at any time.
- v0.X.Y: Breaking changes may only be introduced with a minor version number
bump.
- vX.Y.Z: Breaking changes may only be introduced with a major version number
bump

To avoid premature stabilization and excessive version churn, unstable features
are unavailable unless the `--unstable` / `-u` flag is passed. Unstable
features may be changed or removed at any time.

```
$ imdl torrent stats --input tmp
error: Feature `torrent stats subcommand` cannot be used without passing the `--unstable` flag
$ imdl --unstable torrent stats tmp
Torrents processed: 0
Read failed: 0
Decode failed: 0
```
10 changes: 6 additions & 4 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ pub(crate) use std::{
borrow::Cow,
cmp::{Ordering, Reverse},
collections::{BTreeMap, HashMap},
convert::TryInto,
convert::{Infallible, TryInto},
env,
ffi::{OsStr, OsString},
fmt::{self, Display, Formatter},
fs::{self, File},
hash::Hash,
io::{self, Read, Write},
path::{Path, PathBuf},
process, str,
process,
str::{self, FromStr},
time::{SystemTime, SystemTimeError},
usize,
};
Expand All @@ -28,7 +29,7 @@ pub(crate) use url::Url;
pub(crate) use walkdir::WalkDir;

// modules
pub(crate) use crate::{bencode, consts, error, torrent};
pub(crate) use crate::{bencode, consts, error, torrent, use_color};

// traits
pub(crate) use crate::{
Expand All @@ -38,7 +39,8 @@ pub(crate) use crate::{
// structs and enums
pub(crate) use crate::{
env::Env, error::Error, file_info::FileInfo, hasher::Hasher, info::Info, metainfo::Metainfo,
mode::Mode, opt::Opt, subcommand::Subcommand, torrent::Torrent,
mode::Mode, opt::Opt, style::Style, subcommand::Subcommand, torrent::Torrent,
use_color::UseColor,
};

// test modules
Expand Down
57 changes: 50 additions & 7 deletions src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ pub(crate) struct Env {
args: Vec<String>,
dir: Box<dyn AsRef<Path>>,
pub(crate) err: Box<dyn Write>,
pub(crate) _out: Box<dyn Write>,
pub(crate) out: Box<dyn Write>,
err_style: Style,
}

impl Env {
Expand All @@ -14,14 +15,42 @@ impl Env {
Err(error) => panic!("Failed to get current directory: {}", error),
};

Self::new(dir, io::stdout(), io::stderr(), env::args())
let err_style = if env::var_os("NO_COLOR").is_some()
|| env::var_os("TERM").as_deref() == Some(OsStr::new("dumb"))
|| !atty::is(atty::Stream::Stderr)
{
Style::inactive()
} else {
Style::active()
};

Self::new(dir, io::stdout(), io::stderr(), err_style, env::args())
}

pub(crate) fn run(&mut self) -> Result<(), Error> {
Opt::from_iter_safe(&self.args)?.run(self)
#[cfg(windows)]
ansi_term::enable_ansi_support().ok();

#[cfg(not(test))]
env_logger::Builder::from_env(
env_logger::Env::new()
.filter("JUST_LOG")
.write_style("JUST_LOG_STYLE"),
)
.init();

let opt = Opt::from_iter_safe(&self.args)?;

match opt.use_color {
UseColor::Always => self.err_style = Style::active(),
UseColor::Auto => {}
UseColor::Never => self.err_style = Style::inactive(),
}

opt.run(self)
}

pub(crate) fn new<D, O, E, S, I>(dir: D, out: O, err: E, args: I) -> Self
pub(crate) fn new<D, O, E, S, I>(dir: D, out: O, err: E, err_style: Style, args: I) -> Self
where
D: AsRef<Path> + 'static,
O: Write + 'static,
Expand All @@ -33,21 +62,35 @@ impl Env {
args: args.into_iter().map(Into::into).collect(),
dir: Box::new(dir),
err: Box::new(err),
_out: Box::new(out),
out: Box::new(out),
err_style,
}
}

pub(crate) fn status(&mut self) -> Result<(), i32> {
use structopt::clap::ErrorKind;

if let Err(error) = self.run() {
if let Error::Clap { source } = error {
write!(&mut self.err, "{}", source).ok();
if source.use_stderr() {
write!(&mut self.err, "{}", source).ok();
} else {
write!(&mut self.out, "{}", source).ok();
}
match source.kind {
ErrorKind::VersionDisplayed | ErrorKind::HelpDisplayed => Ok(()),
_ => Err(EXIT_FAILURE),
}
} else {
write!(&mut self.err, "error: {}", error).ok();
writeln!(
&mut self.err,
"{}{}: {}{}",
self.err_style.error().paint("error"),
self.err_style.message().prefix(),
error,
self.err_style.message().suffix(),
)
.ok();
Err(EXIT_FAILURE)
}
} else {
Expand Down
Loading

0 comments on commit d1f8f24

Please sign in to comment.