Skip to content

Commit

Permalink
Add support for CSS three-letter color codes
Browse files Browse the repository at this point in the history
  • Loading branch information
Soft committed Mar 25, 2018
1 parent c34bb5d commit e6c77cb
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 14 deletions.
21 changes: 14 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ FLAGS:
OPTIONS:
-c, --custom <FORMAT> Custom output format
-f, --format <NAME> Output format (defaults to hex) [possible values: hex, HEX, plain, rgb]
-f, --format <NAME> Output format (defaults to hex) [possible values: hex, HEX, hex!, HEX!, plain, rgb]
-s, --selection <SELECTION> Output to selection (defaults to primary) [possible values: primary, secondary]
```

Expand All @@ -70,12 +70,19 @@ By default, the color values will be printed in lowercase hexadecimal format.
The output format can be changed using the `-f FORMAT` switch. The possible
format values are listed bellow:

| Format Specifier | Description | Example | Custom Format Equivalent |
| ---------------- | --------------------------------- | --------------------- | ------------------------ |
| `hex` | Lowercase hexadecimal (default) | `#ff00ff` | `#%{02hr}%{02hg}%{02hb}` |
| `HEX` | Uppercase hexadecimal | `#00FF00` | `#%{02Hr}%{02Hg}%{02Hb}` |
| `rgb` | Decimal RGB | `rgb(255, 255, 255)` | `rgb(%{r}, %{g}, %{b})` |
| `plain` | Decimal with semicolon separators | `0;0;0` | `%{r};%{g};%{b}` |
| Format Specifier | Description | Example | Custom Format Equivalent |
| ---------------- | --------------------------------- | --------------------- | ------------------------ |
| `hex` | Lowercase hexadecimal (default) | `#ff00ff` | `#%{02hr}%{02hg}%{02hb}` |
| `HEX` | Uppercase hexadecimal | `#00FF00` | `#%{02Hr}%{02Hg}%{02Hb}` |
| `hex!` | Compact lowercase hexadecimal<sup>1</sup> | `#fff` | Not expressible |
| `HEX!` | Compact uppercase hexadecimal<sup>1</sup> | `#F0F` | Not expressible |
| `rgb` | Decimal RGB | `rgb(255, 255, 255)` | `rgb(%{r}, %{g}, %{b})` |
| `plain` | Decimal with semicolon separators | `0;0;0` | `%{r};%{g};%{b}` |

**1:** The compact form refers to CSS three-letter color codes as specified by [CSS
Color Module Level 3](https://www.w3.org/TR/2018/PR-css-color-3-20180315/#rgb-color).
If the color is not expressible in three-letter form, the regular six-letter
form will be used.

### Custom Formatting

Expand Down
2 changes: 1 addition & 1 deletion src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub fn get_cli() -> App<'static, 'static> {
.takes_value(true)
.value_name("NAME")
.help("Output format (defaults to hex)")
.possible_values(&["hex", "HEX", "plain", "rgb"])
.possible_values(&["hex", "HEX", "hex!", "HEX!", "plain", "rgb"])
.conflicts_with("custom"))
.arg(Arg::with_name("custom")
.short("c")
Expand Down
49 changes: 43 additions & 6 deletions src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,15 @@ impl FormatColor for FormatString {

// Formatting Shortcuts

#[derive(PartialEq)]
pub enum HexCompaction {
Compact,
Full
}

pub enum Format {
LowercaseHex,
UppercaseHex,
LowercaseHex(HexCompaction),
UppercaseHex(HexCompaction),
Plain,
RGB
}
Expand All @@ -148,20 +154,42 @@ impl FromStr for Format {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"hex" => Ok(Format::LowercaseHex),
"HEX" => Ok(Format::UppercaseHex),
"hex" => Ok(Format::LowercaseHex(HexCompaction::Full)),
"HEX" => Ok(Format::UppercaseHex(HexCompaction::Full)),
"hex!" => Ok(Format::LowercaseHex(HexCompaction::Compact)),
"HEX!" => Ok(Format::UppercaseHex(HexCompaction::Compact)),
"plain" => Ok(Format::Plain),
"rgb" => Ok(Format::RGB),
_ => Err(err_msg("Invalid format"))
}
}
}


fn is_compactable((r, g, b): RGB) -> bool {
fn compact(n: u8) -> bool {
(n >> 4) == (n & 0xf)
}
compact(r) && compact(g) && compact(b)
}

impl FormatColor for Format {
fn format(&self, (r, g, b): RGB) -> String {
match *self {
Format::LowercaseHex => format!("#{:02x}{:02x}{:02x}", r, g, b),
Format::UppercaseHex => format!("#{:02X}{:02X}{:02X}", r, g, b),
Format::LowercaseHex(ref comp) => {
if *comp == HexCompaction::Compact && is_compactable((r, g, b)) {
format!("#{:x}{:x}{:x}", r & 0xf, g & 0xf, b & 0xf)
} else {
format!("#{:02x}{:02x}{:02x}", r, g, b)
}
},
Format::UppercaseHex(ref comp) => {
if *comp == HexCompaction::Compact && is_compactable((r, g, b)) {
format!("#{:X}{:X}{:X}", r & 0xf, g & 0xf, b & 0xf)
} else {
format!("#{:02X}{:02X}{:02X}", r, g, b)
}
},
Format::Plain => format!("{};{};{}", r, g, b),
Format::RGB => format!("rgb({}, {}, {})", r, g, b),
}
Expand Down Expand Up @@ -214,6 +242,15 @@ fn test_format_color() {
}
}

#[test]
fn test_compaction() {
assert!(is_compactable((0xff, 0xff, 0xff)));
assert!(is_compactable((0xee, 0xee, 0xee)));
assert!(is_compactable((0x00, 0x00, 0x00)));
assert!(!is_compactable((0xf7, 0xf7, 0xf7)));
assert!(!is_compactable((0xff, 0xf7, 0xff)));
}

#[test]
fn test_examples_from_readme() {
let fmt: FormatString = "#%{02hr}%{02hg}%{02hb}".parse().unwrap();
Expand Down

0 comments on commit e6c77cb

Please sign in to comment.