Skip to content

Commit

Permalink
Auto merge of #520 - kbknapp:issues-512,518,519, r=kbknapp
Browse files Browse the repository at this point in the history
Issues 512,518,519
  • Loading branch information
homu committed Jun 8, 2016
2 parents 34e608c + 01e7dfd commit a77c800
Show file tree
Hide file tree
Showing 16 changed files with 802 additions and 187 deletions.
147 changes: 147 additions & 0 deletions '
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
use std::fmt;

#[cfg(all(feature = "color", not(target_os = "windows")))]
use ansi_term::Colour::{Green, Red, Yellow};
#[cfg(all(feature = "color", not(target_os = "windows")))]
use ansi_term::ANSIString;

#[cfg(color)]
use libc;

#[cfg(color)]
const STDERR: i32 = libc::STDERR_FILENO;
#[cfg(color)]
const STDOUT: i32 = libc::STDOUT_FILENO;
#[cfg(not(color))]
const STDERR: i32 = 0;
#[cfg(not(color))]
const STDOUT: i32 = 0;

#[doc(hidden)]
#[derive(Debug, PartialEq)]
pub enum ColorWhen {
Auto, // Default
Always,
Never
}

#[cfg(color)]
pub fn is_a_tty(stderr: bool) -> bool {
let fd = if stderr { STDERR } else { STDOUT };
unsafe { libc::isatty(fd) != 0 }
}

#[cfg(not(color))]
pub fn is_a_tty(stderr: bool) -> bool {
false
}

#[doc(hidden)]
pub struct Colorizer {
use_stderr: bool,
when: ColorWhen
}

macro_rules! color {
($_self:ident, $c:ident, $m:expr) => {
match $_self.when {
ColorWhen::Auto => if is_a_tty($_self.use_stderr) {
Format::$c($m)
} else {
$m
},
ColorWhen::Always => Format::$c($m),
ColorWhen::Never => $m,
}
};
}

impl Colorizer {
pub fn good<T>(&self, msg: T) -> &fmt::Display where T: fmt::Display {
use Format::Good;
color!(self, Good, msg)
}
pub fn warning<T>(&self, msg: T) -> &fmt::Display where T: fmt::Display {
use Format::Warning;
color!(self, Warning, msg)
}
pub fn error<T>(&self, msg: T) -> &fmt::Display where T: fmt::Display {
use Format::Error;
color!(self, Error, msg)
}
}

impl Default for Colorizer {
fn default() -> Self {
Colorizer {
use_stderr: true,
when: ColorWhen::Auto
}
}
}

/// Defines styles for different types of error messages. Defaults to Error=Red, Warning=Yellow,
/// and Good=Green
#[derive(Debug)]
#[doc(hidden)]
pub enum Format<T> {
/// Defines the style used for errors, defaults to Red
Error(T),
/// Defines the style used for warnings, defaults to Yellow
Warning(T),
/// Defines the style used for good values, defaults to Green
Good(T),
}

#[cfg(all(feature = "color", not(target_os = "windows")))]
impl<T: AsRef<str>> Format<T> {
fn format(&self) -> ANSIString {
match *self {
Format::Error(ref e) => Red.bold().paint(e.as_ref()),
Format::Warning(ref e) => Yellow.paint(e.as_ref()),
Format::Good(ref e) => Green.paint(e.as_ref()),
}
}
}

#[cfg(all(feature = "color", not(target_os = "windows")))]
impl<T: AsRef<str>> fmt::Display for Format<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &self.format())
}
}

#[cfg(any(not(feature = "color"), target_os = "windows"))]
impl<T: fmt::Display> Format<T> {
fn format(&self) -> &T {
match *self {
Format::Error(ref e) => e,
Format::Warning(ref e) => e,
Format::Good(ref e) => e,
}
}
}

#[cfg(any(not(feature = "color"), target_os = "windows"))]
impl<T: fmt::Display> fmt::Display for Format<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &self.format())
}
}

#[cfg(all(test, feature = "color", not(target_os = "windows")))]
mod test {
use super::Format;
use ansi_term::Colour::{Green, Red, Yellow};

#[test]
fn colored_output() {
let err = Format::Error("error");
assert_eq!(&*format!("{}", err),
&*format!("{}", Red.bold().paint("error")));
let good = Format::Good("good");
assert_eq!(&*format!("{}", good), &*format!("{}", Green.paint("good")));
let warn = Format::Warning("warn");
assert_eq!(&*format!("{}", warn), &*format!("{}", Yellow.paint("warn")));
}
}
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]

name = "clap"
version = "2.5.2"
version = "2.6.0"
authors = ["Kevin K. <kbknapp@gmail.com>"]
exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
description = "A simple to use, efficient, and full featured Command Line Argument Parser"
Expand All @@ -27,7 +27,7 @@ regex = "~0.1.69"
[features]
default = ["suggestions", "color", "wrap_help"]
suggestions = ["strsim"]
color = ["ansi_term"]
color = ["ansi_term", "libc"]
yaml = ["yaml-rust"]
wrap_help = ["libc", "unicode-width"]
lints = ["clippy", "nightly"]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ features = [ "suggestions", "color" ]
The following is a list of optional `clap` features:

* **"suggestions"**: Turns on the `Did you mean '--myoption' ?` feature for when users make typos. (builds dependency `strsim`)
* **"color"**: Turns on colored error messages. This feature only works on non-Windows OSs. (builds dependency `ansi-term`)
* **"color"**: Turns on colored error messages. This feature only works on non-Windows OSs. (builds dependency `ansi-term` and `libc`)
* **"wrap_help"**: Automatically detects terminal width and wraps long help text lines with proper indentation alignment (builds dependency `libc` and 'unicode-width')
* **"lints"**: This is **not** included by default and should only be used while developing to run basic lints against changes. This can only be used on Rust nightly. (builds dependency `clippy`)
* **"debug"**: This is **not** included by default and should only be used while developing to display debugging information.
Expand Down
Loading

0 comments on commit a77c800

Please sign in to comment.