mirror of https://github.com/xvxx/phetch
add color themes
parent
6861848217
commit
8ebeb8dec9
@ -0,0 +1,20 @@
|
||||
tls true
|
||||
emoji true
|
||||
|
||||
# Color Scheme
|
||||
## UI
|
||||
ui.cursor white bold
|
||||
ui.number magenta
|
||||
ui.menu yellow
|
||||
ui.text white
|
||||
|
||||
## Items
|
||||
item.text cyan
|
||||
item.menu blue
|
||||
item.error red
|
||||
item.search white
|
||||
item.telnet grey
|
||||
item.external green
|
||||
item.download white underline
|
||||
item.media green underline
|
||||
item.unsupported whitebg red
|
@ -1,121 +0,0 @@
|
||||
//! Terminal colors.
|
||||
//! Provides a macro to color text as well as sturcts to get their
|
||||
//! raw ansi codes.
|
||||
|
||||
use std::fmt;
|
||||
|
||||
/// Shortcut to produce a String colored with one or more colors.
|
||||
/// Example:
|
||||
/// ```ignore
|
||||
/// let s = color_string!("Red string", Red);
|
||||
/// let x = color_string!("Hyperlink-ish", Blue, Underline);
|
||||
macro_rules! color_string {
|
||||
($s:expr, $( $color:ident ),+) => {{
|
||||
if *crate::NO_COLOR {
|
||||
$s.to_string()
|
||||
} else {
|
||||
let mut out = String::from("\x1b[");
|
||||
$( out.push_str(crate::color::$color::code()); out.push_str(";"); )+
|
||||
out.push('m');
|
||||
out.push_str(&$s);
|
||||
out.push_str(crate::color::Reset.as_ref());
|
||||
out.replace(";m", "m")
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
/// Shortcut to produce a color's ANSI escape code. Don't forget to Reset!
|
||||
/// ```ignore
|
||||
/// let mut o = String::new();
|
||||
/// o.push_str(color!(Blue));
|
||||
/// o.push_str(color!(Underline));
|
||||
/// o.push_str("Hyperlinkish.");
|
||||
/// o.push_str(color!(Reset));
|
||||
macro_rules! color {
|
||||
($color:ident) => {
|
||||
if *crate::NO_COLOR {
|
||||
""
|
||||
} else {
|
||||
crate::color::$color.as_ref()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Create a color:: struct that can be used with format!.
|
||||
/// Example:
|
||||
/// ```ignore
|
||||
/// define_color(Red, 91);
|
||||
/// define_color(Reset, 0);
|
||||
///
|
||||
/// println!("{}Error: {}{}", color::Red, msg, color::Reset);
|
||||
macro_rules! define_color {
|
||||
($color:ident, $code:literal) => {
|
||||
#[allow(missing_docs)]
|
||||
pub struct $color;
|
||||
impl fmt::Display for $color {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.as_ref())
|
||||
}
|
||||
}
|
||||
impl $color {
|
||||
#[allow(missing_docs)]
|
||||
#[inline]
|
||||
pub fn code() -> &'static str {
|
||||
concat!($code)
|
||||
}
|
||||
}
|
||||
impl AsRef<str> for $color {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &'static str {
|
||||
concat!("\x1b[", $code, "m")
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
define_color!(Reset, 0);
|
||||
define_color!(Bold, 1);
|
||||
define_color!(Underline, 4);
|
||||
|
||||
define_color!(Grey, 90);
|
||||
define_color!(Red, 91);
|
||||
define_color!(Green, 92);
|
||||
define_color!(Yellow, 93);
|
||||
define_color!(Blue, 94);
|
||||
define_color!(Magenta, 95);
|
||||
define_color!(Cyan, 96);
|
||||
define_color!(White, 97);
|
||||
|
||||
define_color!(Black, 30);
|
||||
define_color!(DarkRed, 31);
|
||||
define_color!(DarkGreen, 32);
|
||||
define_color!(DarkYellow, 33);
|
||||
define_color!(DarkBlue, 34);
|
||||
define_color!(DarkMagenta, 35);
|
||||
define_color!(DarkCyan, 36);
|
||||
define_color!(DarkWhite, 37);
|
||||
|
||||
define_color!(BlackBG, 40);
|
||||
define_color!(RedBG, 41);
|
||||
define_color!(GreenBG, 42);
|
||||
define_color!(YellowBG, 43);
|
||||
define_color!(BlueBG, 44);
|
||||
define_color!(MagentaBG, 45);
|
||||
define_color!(CyanBG, 46);
|
||||
define_color!(WhiteBG, 47);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn test_colors() {
|
||||
assert_eq!(color_string!("Error", Red), "\x1b[91mError\x1b[0m");
|
||||
assert_eq!(
|
||||
color_string!("Fancy Pants", Blue, Underline),
|
||||
"\x1b[94;4mFancy Pants\x1b[0m"
|
||||
);
|
||||
assert_eq!(
|
||||
color_string!("Super-duper-fancy-pants", Magenta, Underline, Bold, BlueBG),
|
||||
"\x1b[95;4;1;44mSuper-duper-fancy-pants\x1b[0m"
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,228 @@
|
||||
//! Terminal color scheme.
|
||||
//! Provides the Theme struct and functions/macros for making use of it.
|
||||
|
||||
/// Provides a shortcut to the Reset color code.
|
||||
pub mod color {
|
||||
use std::fmt;
|
||||
|
||||
/// Can be used with fmt calls to reset to terminal defaults.
|
||||
pub struct Reset;
|
||||
|
||||
impl fmt::Display for Reset {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "\x1b[0m")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Use with push_str() or something.
|
||||
macro_rules! reset_color {
|
||||
() => {
|
||||
"\x1b[0m"
|
||||
};
|
||||
}
|
||||
|
||||
/// Color scheme for UI and menu items.
|
||||
#[derive(Debug)]
|
||||
pub struct Theme {
|
||||
// UI Colors
|
||||
/// The * cursor that appears next to the selected menu item.
|
||||
pub ui_cursor: String,
|
||||
/// The Number that appears to the left of a menu item.
|
||||
pub ui_number: String,
|
||||
/// The text in a menu.
|
||||
pub ui_menu: String,
|
||||
/// The color of the text content in a document.
|
||||
pub ui_text: String,
|
||||
|
||||
// Menu Item Colors
|
||||
/// Text document.
|
||||
pub item_text: String,
|
||||
/// Another menu.
|
||||
pub item_menu: String,
|
||||
/// Something went wrong.
|
||||
pub item_error: String,
|
||||
/// Gopher search prompt
|
||||
pub item_search: String,
|
||||
/// Telnet item. MUDs and stuff.
|
||||
pub item_telnet: String,
|
||||
/// External link. HTTP, usually.
|
||||
pub item_external: String,
|
||||
/// Binary file that can be downloaded to disk.
|
||||
pub item_download: String,
|
||||
/// Media that can be opened, like an image or mp3.
|
||||
pub item_media: String,
|
||||
/// An unknown or unsupported Gopher type.
|
||||
pub item_unsupported: String,
|
||||
}
|
||||
|
||||
impl Default for Theme {
|
||||
fn default() -> Theme {
|
||||
Theme {
|
||||
ui_cursor: to_color("white bold").into(),
|
||||
ui_number: to_color("magenta").into(),
|
||||
ui_menu: to_color("yellow").into(),
|
||||
ui_text: to_color("white").into(),
|
||||
|
||||
item_text: to_color("cyan").into(),
|
||||
item_menu: to_color("blue").into(),
|
||||
item_error: to_color("red").into(),
|
||||
item_search: to_color("white").into(),
|
||||
item_telnet: to_color("grey").into(),
|
||||
item_external: to_color("green").into(),
|
||||
item_download: to_color("white underline").into(),
|
||||
item_media: to_color("green underline").into(),
|
||||
item_unsupported: to_color("whitebg red").into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Theme {
|
||||
/// Return theme file for this theme
|
||||
pub fn to_string(&self) -> String {
|
||||
format!(
|
||||
"# phetch theme
|
||||
ui.cursor {ui_cursor}
|
||||
ui.number {ui_number}
|
||||
ui.menu {ui_menu}
|
||||
ui.text {ui_text}
|
||||
|
||||
item.text {item_text}
|
||||
item.menu {item_menu}
|
||||
item.error {item_error}
|
||||
item.search {item_search}
|
||||
item.telnet {item_telnet}
|
||||
item.external {item_external}
|
||||
item.download {item_download}
|
||||
item.media {item_media}
|
||||
item.unsupported {item_unsupported}",
|
||||
ui_cursor = to_words(&self.ui_cursor),
|
||||
ui_number = to_words(&self.ui_number),
|
||||
ui_menu = to_words(&self.ui_menu),
|
||||
ui_text = to_words(&self.ui_text),
|
||||
item_text = to_words(&self.item_text),
|
||||
item_menu = to_words(&self.item_menu),
|
||||
item_error = to_words(&self.item_error),
|
||||
item_search = to_words(&self.item_search),
|
||||
item_telnet = to_words(&self.item_telnet),
|
||||
item_external = to_words(&self.item_external),
|
||||
item_download = to_words(&self.item_download),
|
||||
item_media = to_words(&self.item_media),
|
||||
item_unsupported = to_words(&self.item_unsupported),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a string like "blue underline" or "red" into a color code.
|
||||
pub fn to_color<S: AsRef<str>>(line: S) -> String {
|
||||
let parts = line.as_ref().split(' ').collect::<Vec<_>>();
|
||||
|
||||
if parts.is_empty() {
|
||||
return "".into();
|
||||
}
|
||||
|
||||
let mut out = String::from("\x1b[");
|
||||
let len = parts.len();
|
||||
|
||||
for (i, part) in parts.iter().enumerate() {
|
||||
out.push_str(&color_code(part).to_string());
|
||||
if i < len - 1 {
|
||||
out.push(';');
|
||||
}
|
||||
}
|
||||
out.push('m');
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
/// Convert color code like "\x1b[91m" into something like "red"
|
||||
pub fn to_words<S: AsRef<str>>(code: S) -> String {
|
||||
code.as_ref()
|
||||
.replace("\x1b[", "")
|
||||
.replace('m', "")
|
||||
.split(';')
|
||||
.map(color_word)
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
fn color_code(color: &str) -> usize {
|
||||
match color {
|
||||
"bold" => 1,
|
||||
"underline" => 4,
|
||||
"grey" => 90,
|
||||
"red" => 91,
|
||||
"green" => 92,
|
||||
"yellow" => 93,
|
||||
"blue" => 94,
|
||||
"magenta" => 95,
|
||||
"cyan" => 96,
|
||||
"white" => 97,
|
||||
"black" => 30,
|
||||
"darkred" => 31,
|
||||
"darkgreen" => 32,
|
||||
"darkyellow" => 33,
|
||||
"darkblue" => 34,
|
||||
"darkmagenta" => 35,
|
||||
"darkcyan" => 36,
|
||||
"darkwhite" => 37,
|
||||
"blackbg" => 40,
|
||||
"redbg" => 41,
|
||||
"greenbg" => 42,
|
||||
"yellowbg" => 43,
|
||||
"bluebg" => 44,
|
||||
"magentabg" => 45,
|
||||
"cyanbg" => 46,
|
||||
"whitebg" => 47,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn color_word(code: &str) -> &'static str {
|
||||
match code {
|
||||
"1" => "bold",
|
||||
"4" => "underline",
|
||||
"90" => "grey",
|
||||
"91" => "red",
|
||||
"92" => "green",
|
||||
"93" => "yellow",
|
||||
"94" => "blue",
|
||||
"95" => "magenta",
|
||||
"96" => "cyan",
|
||||
"97" => "white",
|
||||
"30" => "black",
|
||||
"31" => "darkred",
|
||||
"32" => "darkgreen",
|
||||
"33" => "darkyellow",
|
||||
"34" => "darkblue",
|
||||
"35" => "darkmagenta",
|
||||
"36" => "darkcyan",
|
||||
"37" => "darkwhite",
|
||||
"40" => "blackbg",
|
||||
"41" => "redbg",
|
||||
"42" => "greenbg",
|
||||
"43" => "yellowbg",
|
||||
"44" => "bluebg",
|
||||
"45" => "magentabg",
|
||||
"46" => "cyanbg",
|
||||
"47" => "whitebg",
|
||||
_ => "white",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_color_scheme() {
|
||||
let mut theme = Theme::default();
|
||||
theme.ui_cursor = to_color("bold").into();
|
||||
theme.ui_menu = to_color("red").into();
|
||||
theme.item_menu = to_color("blue underline").into();
|
||||
|
||||
assert_eq!("\u{1b}[1m", theme.ui_cursor);
|
||||
assert_eq!("\u{1b}[91m", theme.ui_menu);
|
||||
assert_eq!("\u{1b}[94;4m", theme.item_menu);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue