termcolor: add underline support

This commit adds underline support to the termcolor crate, and
exposes it through ripgrep.

Fixes #798
This commit is contained in:
Balaji Sivaraman 2018-02-20 17:40:03 +05:30 committed by Andrew Gallant
parent d09538c974
commit d57fc58081
6 changed files with 45 additions and 10 deletions

8
FAQ.md
View File

@ -190,10 +190,10 @@ The --colors` flag is a bit more complicated. The general format is:
* `{attribute}` should be one of `fg`, `bg` or `style`, corresponding to * `{attribute}` should be one of `fg`, `bg` or `style`, corresponding to
foreground color, background color, or miscellaneous styling (such as whether foreground color, background color, or miscellaneous styling (such as whether
to bold the output or not). to bold the output or not).
* `{value}` is determined by the value of `{attribute}`. If `{attribute}` is * `{value}` is determined by the value of `{attribute}`. If
`style`, then `{value}` should be one of `nobold`, `bold`, `nointense` or `{attribute}` is `style`, then `{value}` should be one of `nobold`,
`intense`. If `{attribute}` is `fg` or `bg`, then `{value}` should be a `bold`, `nointense`, `intense`, `nounderline` or `underline`. If
color. `{attribute}` is `fg` or `bg`, then `{value}` should be a color.
A color is specified by either one of eight of English names, a single 256-bit A color is specified by either one of eight of English names, a single 256-bit
number or an RGB triple (with over 16 million possible values, or "true number or an RGB triple (with over 16 million possible values, or "true

View File

@ -125,7 +125,7 @@ _rg() {
[[ "${state}" == 'style' ]] && [[ "${state}" == 'style' ]] &&
_values -S ':' 'style value' \ _values -S ':' 'style value' \
bold nobold intense nointense && return 0 bold nobold intense nointense underline nounderline && return 0
;; ;;
typespec) typespec)

View File

@ -682,7 +682,8 @@ fn flag_colors(args: &mut Vec<RGArg>) {
This flag specifies color settings for use in the output. This flag may be This flag specifies color settings for use in the output. This flag may be
provided multiple times. Settings are applied iteratively. Colors are limited provided multiple times. Settings are applied iteratively. Colors are limited
to one of eight choices: red, blue, green, cyan, magenta, yellow, white and to one of eight choices: red, blue, green, cyan, magenta, yellow, white and
black. Styles are limited to nobold, bold, nointense or intense. black. Styles are limited to nobold, bold, nointense, intense, nounderline
or underline.
The format of the flag is `{type}:{attribute}:{value}`. `{type}` should be The format of the flag is `{type}:{attribute}:{value}`. `{type}` should be
one of path, line, column or match. `{attribute}` can be fg, bg or style. one of path, line, column or match. `{attribute}` can be fg, bg or style.

View File

@ -555,7 +555,8 @@ impl fmt::Display for Error {
} }
Error::UnrecognizedStyle(ref name) => { Error::UnrecognizedStyle(ref name) => {
write!(f, "Unrecognized style attribute '{}'. Choose from: \ write!(f, "Unrecognized style attribute '{}'. Choose from: \
nobold, bold, nointense, intense.", name) nobold, bold, nointense, intense, nounderline, \
underline.", name)
} }
Error::InvalidFormat(ref original) => { Error::InvalidFormat(ref original) => {
write!( write!(
@ -627,7 +628,8 @@ pub struct ColorSpecs {
/// Valid colors are `black`, `blue`, `green`, `red`, `cyan`, `magenta`, /// Valid colors are `black`, `blue`, `green`, `red`, `cyan`, `magenta`,
/// `yellow`, `white`. /// `yellow`, `white`.
/// ///
/// Valid style instructions are `nobold`, `bold`, `intense`, `nointense`. /// Valid style instructions are `nobold`, `bold`, `intense`, `nointense`,
/// `underline`, `nounderline`.
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Spec { pub struct Spec {
ty: OutType, ty: OutType,
@ -668,6 +670,8 @@ enum Style {
NoBold, NoBold,
Intense, Intense,
NoIntense, NoIntense,
Underline,
NoUnderline
} }
impl ColorSpecs { impl ColorSpecs {
@ -727,6 +731,8 @@ impl SpecValue {
Style::NoBold => { cspec.set_bold(false); } Style::NoBold => { cspec.set_bold(false); }
Style::Intense => { cspec.set_intense(true); } Style::Intense => { cspec.set_intense(true); }
Style::NoIntense => { cspec.set_intense(false); } Style::NoIntense => { cspec.set_intense(false); }
Style::Underline => { cspec.set_underline(true); }
Style::NoUnderline => { cspec.set_underline(false); }
} }
} }
} }
@ -806,6 +812,8 @@ impl FromStr for Style {
"nobold" => Ok(Style::NoBold), "nobold" => Ok(Style::NoBold),
"intense" => Ok(Style::Intense), "intense" => Ok(Style::Intense),
"nointense" => Ok(Style::NoIntense), "nointense" => Ok(Style::NoIntense),
"underline" => Ok(Style::Underline),
"nounderline" => Ok(Style::NoUnderline),
_ => Err(Error::UnrecognizedStyle(s.to_string())), _ => Err(Error::UnrecognizedStyle(s.to_string())),
} }
} }
@ -859,6 +867,12 @@ mod tests {
value: SpecValue::Style(Style::Intense), value: SpecValue::Style(Style::Intense),
}); });
let spec: Spec = "match:style:underline".parse().unwrap();
assert_eq!(spec, Spec {
ty: OutType::Match,
value: SpecValue::Style(Style::Underline),
});
let spec: Spec = "line:none".parse().unwrap(); let spec: Spec = "line:none".parse().unwrap();
assert_eq!(spec, Spec { assert_eq!(spec, Spec {
ty: OutType::Line, ty: OutType::Line,

View File

@ -980,6 +980,9 @@ impl<W: io::Write> WriteColor for Ansi<W> {
if spec.bold { if spec.bold {
self.write_str("\x1B[1m")?; self.write_str("\x1B[1m")?;
} }
if spec.underline {
self.write_str("\x1B[4m")?;
}
Ok(()) Ok(())
} }
@ -1212,6 +1215,7 @@ pub struct ColorSpec {
bg_color: Option<Color>, bg_color: Option<Color>,
bold: bool, bold: bool,
intense: bool, intense: bool,
underline: bool,
} }
impl ColorSpec { impl ColorSpec {
@ -1251,6 +1255,19 @@ impl ColorSpec {
self self
} }
/// Get whether this is underline or not.
///
/// Note that the underline setting has no effect in a Windows console.
pub fn underline(&self) -> bool { self.underline }
/// Set whether the text is underlined or not.
///
/// Note that the underline setting has no effect in a Windows console.
pub fn set_underline(&mut self, yes: bool) -> &mut ColorSpec {
self.underline = yes;
self
}
/// Get whether this is intense or not. /// Get whether this is intense or not.
pub fn intense(&self) -> bool { self.intense } pub fn intense(&self) -> bool { self.intense }
@ -1262,7 +1279,8 @@ impl ColorSpec {
/// Returns true if this color specification has no colors or styles. /// Returns true if this color specification has no colors or styles.
pub fn is_none(&self) -> bool { pub fn is_none(&self) -> bool {
self.fg_color.is_none() && self.bg_color.is_none() && !self.bold self.fg_color.is_none() && self.bg_color.is_none()
&& !self.bold && !self.underline
} }
/// Clears this color specification so that it has no color/style settings. /// Clears this color specification so that it has no color/style settings.
@ -1270,6 +1288,7 @@ impl ColorSpec {
self.fg_color = None; self.fg_color = None;
self.bg_color = None; self.bg_color = None;
self.bold = false; self.bold = false;
self.underline = false;
} }
/// Writes this color spec to the given Windows console. /// Writes this color spec to the given Windows console.

View File

@ -1152,7 +1152,8 @@ clean!(regression_428_unrecognized_style, "Sherlok", ".",
let output = cmd.output().unwrap(); let output = cmd.output().unwrap();
let err = String::from_utf8_lossy(&output.stderr); let err = String::from_utf8_lossy(&output.stderr);
let expected = "\ let expected = "\
Unrecognized style attribute ''. Choose from: nobold, bold, nointense, intense. Unrecognized style attribute ''. Choose from: nobold, bold, nointense, intense, \
nounderline, underline.
"; ";
assert_eq!(err, expected); assert_eq!(err, expected);
}); });