add panel using cnx
This commit is contained in:
parent
0174eeb4cc
commit
4036ed42f0
File diff suppressed because it is too large
Load Diff
|
@ -17,6 +17,12 @@ toml = "0.8.8"
|
||||||
which = "6.0.0"
|
which = "6.0.0"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pretty_env_logger = "0.5"
|
pretty_env_logger = "0.5"
|
||||||
|
cnx = { git = "https://github.com/mjkillough/cnx.git", rev = "7845d99baa296901171c083db61588a62f9a8b34" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "1.4.0"
|
pretty_assertions = "1.4.0"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = 3
|
||||||
|
strip = "debuginfo"
|
||||||
|
lto = "fat"
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
use std::{os::unix::process::ExitStatusExt, process::Output};
|
||||||
|
|
||||||
|
use log::error;
|
||||||
|
|
||||||
|
use crate::hlwm::command::CommandError;
|
||||||
|
|
||||||
|
pub fn check_status(output: &Output) -> Result<(), CommandError> {
|
||||||
|
let exit_status = output.status;
|
||||||
|
if let Some(code) = exit_status.code() {
|
||||||
|
if code == 0 {
|
||||||
|
return Ok(());
|
||||||
|
} else {
|
||||||
|
let output = String::from_utf8(output.stdout.clone())
|
||||||
|
.unwrap_or_default()
|
||||||
|
.trim()
|
||||||
|
.to_string();
|
||||||
|
error!("command failed with error code [{code}]");
|
||||||
|
if !output.is_empty() {
|
||||||
|
error!("command output: {output}");
|
||||||
|
}
|
||||||
|
return Err(CommandError::StatusCode(
|
||||||
|
code,
|
||||||
|
if output.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(output)
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(signal) = exit_status.signal() {
|
||||||
|
return Err(CommandError::KilledBySignal {
|
||||||
|
signal,
|
||||||
|
core_dumped: exit_status.core_dumped(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if let Some(signal) = exit_status.stopped_signal() {
|
||||||
|
return Err(CommandError::StoppedBySignal(signal));
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(CommandError::OtherExitStatus(exit_status))
|
||||||
|
}
|
|
@ -60,8 +60,13 @@ pub enum ConfigError {
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub font: Option<String>,
|
pub font: String,
|
||||||
pub font_bold: Option<String>,
|
pub font_bold: String,
|
||||||
|
/// Pango font for use where pango fonts are
|
||||||
|
/// used (i.e. panel)
|
||||||
|
pub font_pango: String,
|
||||||
|
/// Bold version of `font_pango`
|
||||||
|
pub font_pango_bold: String,
|
||||||
pub mod_key: Key,
|
pub mod_key: Key,
|
||||||
pub keybinds: Vec<Keybind>,
|
pub keybinds: Vec<Keybind>,
|
||||||
pub mousebinds: Vec<Mousebind>,
|
pub mousebinds: Vec<Mousebind>,
|
||||||
|
@ -210,9 +215,9 @@ impl Config {
|
||||||
fn attrs_set(&self) -> Result<Vec<HlwmCommand>, ConfigError> {
|
fn attrs_set(&self) -> Result<Vec<HlwmCommand>, ConfigError> {
|
||||||
info!("loading attr settings command set");
|
info!("loading attr settings command set");
|
||||||
Ok([
|
Ok([
|
||||||
(Self::FONT, self.font.clone()),
|
(Self::FONT, Some(self.font.clone())),
|
||||||
(Self::MOD_KEY, Some(self.mod_key.to_string())),
|
(Self::MOD_KEY, Some(self.mod_key.to_string())),
|
||||||
(Self::FONT_BOLD, self.font_bold.clone()),
|
(Self::FONT_BOLD, Some(self.font_bold.clone())),
|
||||||
(
|
(
|
||||||
Self::SERVICES,
|
Self::SERVICES,
|
||||||
if self.services.len() == 0 {
|
if self.services.len() == 0 {
|
||||||
|
@ -393,16 +398,14 @@ impl Config {
|
||||||
Config {
|
Config {
|
||||||
font: setting(
|
font: setting(
|
||||||
Self::FONT,
|
Self::FONT,
|
||||||
|f| -> Result<_, Infallible> { Ok(Some(f.to_string())) },
|
|f| -> Result<_, Infallible> { Ok(f.to_string()) },
|
||||||
default.font,
|
default.font,
|
||||||
),
|
),
|
||||||
mod_key: setting(Self::MOD_KEY, Key::from_str, default.mod_key),
|
mod_key: setting(Self::MOD_KEY, Key::from_str, default.mod_key),
|
||||||
font_bold: Some(
|
font_bold: client
|
||||||
client
|
|
||||||
.get_attr(ThemeAttr::TitleFont(String::new()).attr_path())
|
.get_attr(ThemeAttr::TitleFont(String::new()).attr_path())
|
||||||
.map(|a| a.to_string())
|
.map(|a| a.to_string())
|
||||||
.unwrap_or(default.font_bold.unwrap()),
|
.unwrap_or(default.font_bold),
|
||||||
),
|
|
||||||
services: setting(
|
services: setting(
|
||||||
Self::SERVICES,
|
Self::SERVICES,
|
||||||
|v| serde_json::de::from_str(v),
|
|v| serde_json::de::from_str(v),
|
||||||
|
@ -508,6 +511,45 @@ pub struct Theme {
|
||||||
pub attributes: Vec<ThemeAttr>,
|
pub attributes: Vec<ThemeAttr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
impl Theme {
|
||||||
|
pub fn active_color(&self) -> Option<Color> {
|
||||||
|
for attr in &self.attributes {
|
||||||
|
if let ThemeAttr::ActiveColor(col) = attr {
|
||||||
|
return Some(col.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn normal_color(&self) -> Option<Color> {
|
||||||
|
for attr in &self.attributes {
|
||||||
|
if let ThemeAttr::NormalColor(col) = attr {
|
||||||
|
return Some(col.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn urgent_color(&self) -> Option<Color> {
|
||||||
|
for attr in &self.attributes {
|
||||||
|
if let ThemeAttr::UrgentColor(col) = attr {
|
||||||
|
return Some(col.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn text_color(&self) -> Option<Color> {
|
||||||
|
for attr in &self.attributes {
|
||||||
|
if let ThemeAttr::TitleColor(col) = attr {
|
||||||
|
return Some(col.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Error)]
|
#[derive(Debug, Clone, Copy, PartialEq, Error)]
|
||||||
pub enum InclusiveError {
|
pub enum InclusiveError {
|
||||||
#[error("out of range")]
|
#[error("out of range")]
|
||||||
|
@ -712,8 +754,8 @@ impl Default for Config {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
mod_key,
|
mod_key,
|
||||||
font: Some(String::from("-*-fixed-medium-*-*-*-12-*-*-*-*-*-*-*")),
|
font: String::from("-*-fixed-medium-*-*-*-12-*-*-*-*-*-*-*"),
|
||||||
font_bold: Some(font_bold.clone()),
|
font_bold: font_bold.clone(),
|
||||||
keybinds: vec![
|
keybinds: vec![
|
||||||
Keybind::new(
|
Keybind::new(
|
||||||
[mod_key, Key::Shift, Key::Char('r')].into_iter(),
|
[mod_key, Key::Shift, Key::Char('r')].into_iter(),
|
||||||
|
@ -944,6 +986,8 @@ impl Default for Config {
|
||||||
Setting::FrameBorderActiveColor(active_color.clone()),
|
Setting::FrameBorderActiveColor(active_color.clone()),
|
||||||
Setting::FrameBgActiveColor(active_color.clone()),
|
Setting::FrameBgActiveColor(active_color.clone()),
|
||||||
],
|
],
|
||||||
|
font_pango: String::from("Monospace 9"),
|
||||||
|
font_pango_bold: String::from("Monospace Bold 9"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,426 +0,0 @@
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use serde::{de::Unexpected, Deserialize, Serialize};
|
|
||||||
use strum::IntoEnumIterator;
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
use crate::hlwm::StringParseError;
|
|
||||||
|
|
||||||
use super::hex::{HexError, ParseHex};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub enum Color {
|
|
||||||
RGB { r: u8, g: u8, b: u8 },
|
|
||||||
X11(X11Color),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Serialize for Color {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: serde::Serializer,
|
|
||||||
{
|
|
||||||
serializer.serialize_str(&self.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Color {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
struct ExpectedColor;
|
|
||||||
impl serde::de::Expected for ExpectedColor {
|
|
||||||
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
||||||
formatter.write_str("an X11 color string or a hex color string")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let str_val: String = Deserialize::deserialize(deserializer)?;
|
|
||||||
Ok(Color::from_str(&str_val).map_err(|_| {
|
|
||||||
serde::de::Error::invalid_value(Unexpected::Str(&str_val), &ExpectedColor)
|
|
||||||
})?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Color {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::RGB {
|
|
||||||
r: Default::default(),
|
|
||||||
g: Default::default(),
|
|
||||||
b: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Error)]
|
|
||||||
pub enum ParseError {
|
|
||||||
#[error("length must be either 6 characters or 7 with '#' prefix")]
|
|
||||||
InvalidLength,
|
|
||||||
#[error("invalid hex value: [{0}]")]
|
|
||||||
HexError(#[from] HexError),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for Color {
|
|
||||||
type Err = ParseError;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
if let Ok(x11) = X11Color::from_str(s) {
|
|
||||||
return Ok(Self::X11(x11));
|
|
||||||
}
|
|
||||||
Self::from_hex(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Color {
|
|
||||||
pub const BLACK: Color = Color::rgb(0, 0, 0);
|
|
||||||
|
|
||||||
pub fn from_hex(hex: &str) -> Result<Self, ParseError> {
|
|
||||||
let expected_len = if hex.starts_with('#') { 7 } else { 6 };
|
|
||||||
if hex.len() != expected_len {
|
|
||||||
return Err(ParseError::InvalidLength);
|
|
||||||
}
|
|
||||||
let hex = hex.strip_prefix('#').unwrap_or(hex);
|
|
||||||
|
|
||||||
Ok(Self::RGB {
|
|
||||||
r: (&hex[0..2]).parse_hex()?,
|
|
||||||
g: (&hex[2..4]).parse_hex()?,
|
|
||||||
b: (&hex[4..6]).parse_hex()?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
|
|
||||||
Self::RGB { r, g, b }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Color {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Color::RGB { r, g, b } => write!(f, "#{r:02X}{g:02X}{b:02X}"),
|
|
||||||
Color::X11(color) => f.write_str(&color.to_string()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, strum::Display, strum::EnumIter, PartialEq, Eq)]
|
|
||||||
pub enum X11Color {
|
|
||||||
GhostWhite,
|
|
||||||
WhiteSmoke,
|
|
||||||
FloralWhite,
|
|
||||||
OldLace,
|
|
||||||
AntiqueWhite,
|
|
||||||
PapayaWhip,
|
|
||||||
BlanchedAlmond,
|
|
||||||
PeachPuff,
|
|
||||||
NavajoWhite,
|
|
||||||
LemonChiffon,
|
|
||||||
MintCream,
|
|
||||||
AliceBlue,
|
|
||||||
LavenderBlush,
|
|
||||||
MistyRose,
|
|
||||||
DarkSlateGray,
|
|
||||||
DarkSlateGrey,
|
|
||||||
DimGray,
|
|
||||||
DimGrey,
|
|
||||||
SlateGray,
|
|
||||||
SlateGrey,
|
|
||||||
LightSlateGray,
|
|
||||||
LightSlateGrey,
|
|
||||||
X11Gray,
|
|
||||||
X11Grey,
|
|
||||||
WebGray,
|
|
||||||
WebGrey,
|
|
||||||
LightGrey,
|
|
||||||
LightGray,
|
|
||||||
MidnightBlue,
|
|
||||||
NavyBlue,
|
|
||||||
CornflowerBlue,
|
|
||||||
DarkSlateBlue,
|
|
||||||
SlateBlue,
|
|
||||||
MediumSlateBlue,
|
|
||||||
LightSlateBlue,
|
|
||||||
MediumBlue,
|
|
||||||
RoyalBlue,
|
|
||||||
DodgerBlue,
|
|
||||||
DeepSkyBlue,
|
|
||||||
SkyBlue,
|
|
||||||
LightSkyBlue,
|
|
||||||
SteelBlue,
|
|
||||||
LightSteelBlue,
|
|
||||||
LightBlue,
|
|
||||||
PowderBlue,
|
|
||||||
PaleTurquoise,
|
|
||||||
DarkTurquoise,
|
|
||||||
MediumTurquoise,
|
|
||||||
LightCyan,
|
|
||||||
CadetBlue,
|
|
||||||
MediumAquamarine,
|
|
||||||
DarkGreen,
|
|
||||||
DarkOliveGreen,
|
|
||||||
DarkSeaGreen,
|
|
||||||
SeaGreen,
|
|
||||||
MediumSeaGreen,
|
|
||||||
LightSeaGreen,
|
|
||||||
PaleGreen,
|
|
||||||
SpringGreen,
|
|
||||||
LawnGreen,
|
|
||||||
X11Green,
|
|
||||||
WebGreen,
|
|
||||||
MediumSpringGreen,
|
|
||||||
GreenYellow,
|
|
||||||
LimeGreen,
|
|
||||||
YellowGreen,
|
|
||||||
ForestGreen,
|
|
||||||
OliveDrab,
|
|
||||||
DarkKhaki,
|
|
||||||
PaleGoldenrod,
|
|
||||||
LightGoldenrodYellow,
|
|
||||||
LightYellow,
|
|
||||||
LightGoldenrod,
|
|
||||||
DarkGoldenrod,
|
|
||||||
RosyBrown,
|
|
||||||
IndianRed,
|
|
||||||
SaddleBrown,
|
|
||||||
SandyBrown,
|
|
||||||
DarkSalmon,
|
|
||||||
LightSalmon,
|
|
||||||
DarkOrange,
|
|
||||||
LightCoral,
|
|
||||||
OrangeRed,
|
|
||||||
HotPink,
|
|
||||||
DeepPink,
|
|
||||||
LightPink,
|
|
||||||
PaleVioletRed,
|
|
||||||
X11Maroon,
|
|
||||||
WebMaroon,
|
|
||||||
MediumVioletRed,
|
|
||||||
VioletRed,
|
|
||||||
MediumOrchid,
|
|
||||||
DarkOrchid,
|
|
||||||
DarkViolet,
|
|
||||||
BlueViolet,
|
|
||||||
X11Purple,
|
|
||||||
WebPurple,
|
|
||||||
MediumPurple,
|
|
||||||
AntiqueWhite1,
|
|
||||||
AntiqueWhite2,
|
|
||||||
AntiqueWhite3,
|
|
||||||
AntiqueWhite4,
|
|
||||||
PeachPuff1,
|
|
||||||
PeachPuff2,
|
|
||||||
PeachPuff3,
|
|
||||||
PeachPuff4,
|
|
||||||
NavajoWhite1,
|
|
||||||
NavajoWhite2,
|
|
||||||
NavajoWhite3,
|
|
||||||
NavajoWhite4,
|
|
||||||
LemonChiffon1,
|
|
||||||
LemonChiffon2,
|
|
||||||
LemonChiffon3,
|
|
||||||
LemonChiffon4,
|
|
||||||
LavenderBlush1,
|
|
||||||
LavenderBlush2,
|
|
||||||
LavenderBlush3,
|
|
||||||
LavenderBlush4,
|
|
||||||
MistyRose1,
|
|
||||||
MistyRose2,
|
|
||||||
MistyRose3,
|
|
||||||
MistyRose4,
|
|
||||||
SlateBlue1,
|
|
||||||
SlateBlue2,
|
|
||||||
SlateBlue3,
|
|
||||||
SlateBlue4,
|
|
||||||
RoyalBlue1,
|
|
||||||
RoyalBlue2,
|
|
||||||
RoyalBlue3,
|
|
||||||
RoyalBlue4,
|
|
||||||
DodgerBlue1,
|
|
||||||
DodgerBlue2,
|
|
||||||
DodgerBlue3,
|
|
||||||
DodgerBlue4,
|
|
||||||
SteelBlue1,
|
|
||||||
SteelBlue2,
|
|
||||||
SteelBlue3,
|
|
||||||
SteelBlue4,
|
|
||||||
DeepSkyBlue1,
|
|
||||||
DeepSkyBlue2,
|
|
||||||
DeepSkyBlue3,
|
|
||||||
DeepSkyBlue4,
|
|
||||||
SkyBlue1,
|
|
||||||
SkyBlue2,
|
|
||||||
SkyBlue3,
|
|
||||||
SkyBlue4,
|
|
||||||
LightSkyBlue1,
|
|
||||||
LightSkyBlue2,
|
|
||||||
LightSkyBlue3,
|
|
||||||
LightSkyBlue4,
|
|
||||||
SlateGray1,
|
|
||||||
SlateGray2,
|
|
||||||
SlateGray3,
|
|
||||||
SlateGray4,
|
|
||||||
LightSteelBlue1,
|
|
||||||
LightSteelBlue2,
|
|
||||||
LightSteelBlue3,
|
|
||||||
LightSteelBlue4,
|
|
||||||
LightBlue1,
|
|
||||||
LightBlue2,
|
|
||||||
LightBlue3,
|
|
||||||
LightBlue4,
|
|
||||||
LightCyan1,
|
|
||||||
LightCyan2,
|
|
||||||
LightCyan3,
|
|
||||||
LightCyan4,
|
|
||||||
PaleTurquoise1,
|
|
||||||
PaleTurquoise2,
|
|
||||||
PaleTurquoise3,
|
|
||||||
PaleTurquoise4,
|
|
||||||
CadetBlue1,
|
|
||||||
CadetBlue2,
|
|
||||||
CadetBlue3,
|
|
||||||
CadetBlue4,
|
|
||||||
DarkSlateGray1,
|
|
||||||
DarkSlateGray2,
|
|
||||||
DarkSlateGray3,
|
|
||||||
DarkSlateGray4,
|
|
||||||
DarkSeaGreen1,
|
|
||||||
DarkSeaGreen2,
|
|
||||||
DarkSeaGreen3,
|
|
||||||
DarkSeaGreen4,
|
|
||||||
SeaGreen1,
|
|
||||||
SeaGreen2,
|
|
||||||
SeaGreen3,
|
|
||||||
SeaGreen4,
|
|
||||||
PaleGreen1,
|
|
||||||
PaleGreen2,
|
|
||||||
PaleGreen3,
|
|
||||||
PaleGreen4,
|
|
||||||
SpringGreen1,
|
|
||||||
SpringGreen2,
|
|
||||||
SpringGreen3,
|
|
||||||
SpringGreen4,
|
|
||||||
OliveDrab1,
|
|
||||||
OliveDrab2,
|
|
||||||
OliveDrab3,
|
|
||||||
OliveDrab4,
|
|
||||||
DarkOliveGreen1,
|
|
||||||
DarkOliveGreen2,
|
|
||||||
DarkOliveGreen3,
|
|
||||||
DarkOliveGreen4,
|
|
||||||
LightGoldenrod1,
|
|
||||||
LightGoldenrod2,
|
|
||||||
LightGoldenrod3,
|
|
||||||
LightGoldenrod4,
|
|
||||||
LightYellow1,
|
|
||||||
LightYellow2,
|
|
||||||
LightYellow3,
|
|
||||||
LightYellow4,
|
|
||||||
DarkGoldenrod1,
|
|
||||||
DarkGoldenrod2,
|
|
||||||
DarkGoldenrod3,
|
|
||||||
DarkGoldenrod4,
|
|
||||||
RosyBrown1,
|
|
||||||
RosyBrown2,
|
|
||||||
RosyBrown3,
|
|
||||||
RosyBrown4,
|
|
||||||
IndianRed1,
|
|
||||||
IndianRed2,
|
|
||||||
IndianRed3,
|
|
||||||
IndianRed4,
|
|
||||||
LightSalmon1,
|
|
||||||
LightSalmon2,
|
|
||||||
LightSalmon3,
|
|
||||||
LightSalmon4,
|
|
||||||
DarkOrange1,
|
|
||||||
DarkOrange2,
|
|
||||||
DarkOrange3,
|
|
||||||
DarkOrange4,
|
|
||||||
OrangeRed1,
|
|
||||||
OrangeRed2,
|
|
||||||
OrangeRed3,
|
|
||||||
OrangeRed4,
|
|
||||||
DeepPink1,
|
|
||||||
DeepPink2,
|
|
||||||
DeepPink3,
|
|
||||||
DeepPink4,
|
|
||||||
HotPink1,
|
|
||||||
HotPink2,
|
|
||||||
HotPink3,
|
|
||||||
HotPink4,
|
|
||||||
LightPink1,
|
|
||||||
LightPink2,
|
|
||||||
LightPink3,
|
|
||||||
LightPink4,
|
|
||||||
PaleVioletRed1,
|
|
||||||
PaleVioletRed2,
|
|
||||||
PaleVioletRed3,
|
|
||||||
PaleVioletRed4,
|
|
||||||
VioletRed1,
|
|
||||||
VioletRed2,
|
|
||||||
VioletRed3,
|
|
||||||
VioletRed4,
|
|
||||||
MediumOrchid1,
|
|
||||||
MediumOrchid2,
|
|
||||||
MediumOrchid3,
|
|
||||||
MediumOrchid4,
|
|
||||||
DarkOrchid1,
|
|
||||||
DarkOrchid2,
|
|
||||||
DarkOrchid3,
|
|
||||||
DarkOrchid4,
|
|
||||||
MediumPurple1,
|
|
||||||
MediumPurple2,
|
|
||||||
MediumPurple3,
|
|
||||||
MediumPurple4,
|
|
||||||
DarkGrey,
|
|
||||||
DarkGray,
|
|
||||||
DarkBlue,
|
|
||||||
DarkCyan,
|
|
||||||
DarkMagenta,
|
|
||||||
DarkRed,
|
|
||||||
LightGreen,
|
|
||||||
RebeccaPurple,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for X11Color {
|
|
||||||
type Err = StringParseError;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
Self::iter()
|
|
||||||
.into_iter()
|
|
||||||
.find(|i| i.to_string() == s)
|
|
||||||
.ok_or(StringParseError::UnknownValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use super::{Color, X11Color};
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
pub struct ColorContainer {
|
|
||||||
color: Color,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn color_serialize_deserialize(color: Color) {
|
|
||||||
let original_color = color.clone();
|
|
||||||
let color_str =
|
|
||||||
toml::to_string_pretty(&ColorContainer { color }).expect("serialization failure");
|
|
||||||
let color_parsed: ColorContainer =
|
|
||||||
toml::from_str(color_str.as_str()).expect("deserialization failure");
|
|
||||||
assert_eq!(original_color, color_parsed.color);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn color_serialize_deserialize_rgb() {
|
|
||||||
color_serialize_deserialize(Color::RGB {
|
|
||||||
r: 128,
|
|
||||||
g: 128,
|
|
||||||
b: 128,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn color_serialize_deserialize_x11() {
|
|
||||||
color_serialize_deserialize(Color::X11(X11Color::HotPink2));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use serde::{de::Unexpected, Deserialize, Serialize};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use super::hex::{HexError, ParseHex};
|
||||||
|
|
||||||
|
mod x11;
|
||||||
|
pub use x11::X11Color;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum Color {
|
||||||
|
RGB { r: u8, g: u8, b: u8 },
|
||||||
|
X11(X11Color),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for Color {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_str(&self.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Color {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct ExpectedColor;
|
||||||
|
impl serde::de::Expected for ExpectedColor {
|
||||||
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
formatter.write_str("an X11 color string or a hex color string")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let str_val: String = Deserialize::deserialize(deserializer)?;
|
||||||
|
Ok(Color::from_str(&str_val).map_err(|_| {
|
||||||
|
serde::de::Error::invalid_value(Unexpected::Str(&str_val), &ExpectedColor)
|
||||||
|
})?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Color {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::RGB {
|
||||||
|
r: Default::default(),
|
||||||
|
g: Default::default(),
|
||||||
|
b: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Error)]
|
||||||
|
pub enum ParseError {
|
||||||
|
#[error("length must be either 6 characters or 7 with '#' prefix")]
|
||||||
|
InvalidLength,
|
||||||
|
#[error("invalid hex value: [{0}]")]
|
||||||
|
HexError(#[from] HexError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Color {
|
||||||
|
type Err = ParseError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
if let Ok(x11) = X11Color::from_str(s) {
|
||||||
|
return Ok(Self::X11(x11));
|
||||||
|
}
|
||||||
|
Self::from_hex(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Color {
|
||||||
|
pub const BLACK: Color = Color::from_rgb(0, 0, 0);
|
||||||
|
|
||||||
|
pub fn from_hex(hex: &str) -> Result<Self, ParseError> {
|
||||||
|
let expected_len = if hex.starts_with('#') { 7 } else { 6 };
|
||||||
|
if hex.len() != expected_len {
|
||||||
|
return Err(ParseError::InvalidLength);
|
||||||
|
}
|
||||||
|
let hex = hex.strip_prefix('#').unwrap_or(hex);
|
||||||
|
|
||||||
|
Ok(Self::RGB {
|
||||||
|
r: (&hex[0..2]).parse_hex()?,
|
||||||
|
g: (&hex[2..4]).parse_hex()?,
|
||||||
|
b: (&hex[4..6]).parse_hex()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn from_rgb(r: u8, g: u8, b: u8) -> Self {
|
||||||
|
Self::RGB { r, g, b }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn to_rgb(&self) -> (u8, u8, u8) {
|
||||||
|
match self {
|
||||||
|
Color::RGB { r, g, b } => (*r, *g, *b),
|
||||||
|
Color::X11(xc) => xc.to_rgb(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Color {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Color::RGB { r, g, b } => write!(f, "#{r:02X}{g:02X}{b:02X}"),
|
||||||
|
Color::X11(color) => f.write_str(&color.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Color> for cnx::text::Color {
|
||||||
|
fn from(value: Color) -> Self {
|
||||||
|
let (r, g, b) = value.to_rgb();
|
||||||
|
cnx::text::Color::from_rgb(r, g, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::{Color, X11Color};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct ColorContainer {
|
||||||
|
color: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn color_serialize_deserialize(color: Color) {
|
||||||
|
let original_color = color.clone();
|
||||||
|
let color_str =
|
||||||
|
toml::to_string_pretty(&ColorContainer { color }).expect("serialization failure");
|
||||||
|
let color_parsed: ColorContainer =
|
||||||
|
toml::from_str(color_str.as_str()).expect("deserialization failure");
|
||||||
|
assert_eq!(original_color, color_parsed.color);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn color_serialize_deserialize_rgb() {
|
||||||
|
color_serialize_deserialize(Color::RGB {
|
||||||
|
r: 128,
|
||||||
|
g: 128,
|
||||||
|
b: 128,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn color_serialize_deserialize_x11() {
|
||||||
|
color_serialize_deserialize(Color::X11(X11Color::HotPink2));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,728 @@
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::hlwm::StringParseError;
|
||||||
|
|
||||||
|
macro_rules! color_impl {
|
||||||
|
() => {};
|
||||||
|
($($name:tt($($str:literal),+) => $r:literal, $g:literal, $b:literal,)+) => {
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
pub enum X11Color {
|
||||||
|
$($name,)+
|
||||||
|
}
|
||||||
|
|
||||||
|
impl X11Color {
|
||||||
|
const ALL: [X11Color; 658] = [$(X11Color::$name,)+];
|
||||||
|
pub const fn to_rgb(&self) -> (u8, u8, u8) {
|
||||||
|
match self {
|
||||||
|
$(X11Color::$name => ($r, $g, $b),)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter() -> std::array::IntoIter<X11Color, 658> {
|
||||||
|
X11Color::ALL.into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn color_names(&self) -> Vec<&'static str> {
|
||||||
|
match self {
|
||||||
|
$(
|
||||||
|
X11Color::$name => vec![$($str),+],
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for X11Color {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
$(
|
||||||
|
X11Color::$name => f.write_str(color_impl!(First $($str,)+)),
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(First $lit:literal, $($lit2:literal,)*) => {
|
||||||
|
$lit
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for X11Color {
|
||||||
|
type Err = StringParseError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
X11Color::ALL
|
||||||
|
.into_iter()
|
||||||
|
.find(|c| c.color_names().into_iter().any(|n| n == s))
|
||||||
|
.ok_or(StringParseError::UnknownValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for X11Color {
|
||||||
|
fn default() -> Self {
|
||||||
|
X11Color::Black
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
color_impl! {
|
||||||
|
White("white") => 255,255,255,
|
||||||
|
Red3("red3") => 205,0,0,
|
||||||
|
VioletRed1("VioletRed1") => 255,62,150,
|
||||||
|
Gray54("gray54") => 138,138,138,
|
||||||
|
Gold1("gold1") => 255,215,0,
|
||||||
|
Pink1("pink1") => 255,181,197,
|
||||||
|
Grey76("grey76") => 194,194,194,
|
||||||
|
Goldenrod("goldenrod") => 218,165,32,
|
||||||
|
Wheat4("wheat4") => 139,126,102,
|
||||||
|
Gray71("gray71") => 181,181,181,
|
||||||
|
DarkTurquoise("dark turquoise", "DarkTurquoise") => 0,206,209,
|
||||||
|
Plum4("plum4") => 139,102,139,
|
||||||
|
Grey44("grey44") => 112,112,112,
|
||||||
|
Grey15("grey15") => 38,38,38,
|
||||||
|
Plum("plum") => 221,160,221,
|
||||||
|
Gray55("gray55") => 140,140,140,
|
||||||
|
Green2("green2") => 0,238,0,
|
||||||
|
Grey65("grey65") => 166,166,166,
|
||||||
|
MediumPurple1("MediumPurple1") => 171,130,255,
|
||||||
|
DarkOliveGreen2("DarkOliveGreen2") => 188,238,104,
|
||||||
|
Grey74("grey74") => 189,189,189,
|
||||||
|
LightGoldenrod1("LightGoldenrod1") => 255,236,139,
|
||||||
|
MistyRose2("MistyRose2") => 238,213,210,
|
||||||
|
LightSalmon4("LightSalmon4") => 139,87,66,
|
||||||
|
Ivory3("ivory3") => 205,205,193,
|
||||||
|
DarkGray("dark gray", "DarkGray") => 169,169,169,
|
||||||
|
SlateGray1("SlateGray1") => 198,226,255,
|
||||||
|
BlanchedAlmond("blanched almond", "BlanchedAlmond") => 255,235,205,
|
||||||
|
Gray8("gray8") => 20,20,20,
|
||||||
|
Orange("orange") => 255,165,0,
|
||||||
|
Cornsilk2("cornsilk2") => 238,232,205,
|
||||||
|
Thistle2("thistle2") => 238,210,238,
|
||||||
|
Gray91("gray91") => 232,232,232,
|
||||||
|
MediumPurple4("MediumPurple4") => 93,71,139,
|
||||||
|
Orchid4("orchid4") => 139,71,137,
|
||||||
|
PaleTurquoise4("PaleTurquoise4") => 102,139,139,
|
||||||
|
AntiqueWhite("antique white", "AntiqueWhite") => 250,235,215,
|
||||||
|
Grey92("grey92") => 235,235,235,
|
||||||
|
Lavender("lavender") => 230,230,250,
|
||||||
|
Sienna("sienna") => 160,82,45,
|
||||||
|
Tan("tan") => 210,180,140,
|
||||||
|
LightYellow("light yellow", "LightYellow") => 255,255,224,
|
||||||
|
Brown3("brown3") => 205,51,51,
|
||||||
|
AliceBlue("alice blue", "AliceBlue") => 240,248,255,
|
||||||
|
Grey96("grey96") => 245,245,245,
|
||||||
|
GhostWhite("ghost white", "GhostWhite") => 248,248,255,
|
||||||
|
PaleGoldenrod("pale goldenrod", "PaleGoldenrod") => 238,232,170,
|
||||||
|
Gray96("gray96") => 245,245,245,
|
||||||
|
Gray90("gray90") => 229,229,229,
|
||||||
|
Gray85("gray85") => 217,217,217,
|
||||||
|
Grey34("grey34") => 87,87,87,
|
||||||
|
Khaki2("khaki2") => 238,230,133,
|
||||||
|
Grey54("grey54") => 138,138,138,
|
||||||
|
DarkGrey("dark grey", "DarkGrey") => 169,169,169,
|
||||||
|
Gray42("gray42") => 107,107,107,
|
||||||
|
Grey18("grey18") => 46,46,46,
|
||||||
|
Gray17("gray17") => 43,43,43,
|
||||||
|
OrangeRed3("OrangeRed3") => 205,55,0,
|
||||||
|
Grey29("grey29") => 74,74,74,
|
||||||
|
LightPink("light pink", "LightPink") => 255,182,193,
|
||||||
|
Salmon4("salmon4") => 139,76,57,
|
||||||
|
CadetBlue3("CadetBlue3") => 122,197,205,
|
||||||
|
Grey36("grey36") => 92,92,92,
|
||||||
|
Tomato2("tomato2") => 238,92,66,
|
||||||
|
DeepPink("deep pink", "DeepPink") => 255,20,147,
|
||||||
|
Cyan4("cyan4") => 0,139,139,
|
||||||
|
LightCyan2("LightCyan2") => 209,238,238,
|
||||||
|
Chartreuse1("chartreuse1") => 127,255,0,
|
||||||
|
Gray62("gray62") => 158,158,158,
|
||||||
|
Bisque4("bisque4") => 139,125,107,
|
||||||
|
PaleTurquoise3("PaleTurquoise3") => 150,205,205,
|
||||||
|
SpringGreen1("SpringGreen1") => 0,255,127,
|
||||||
|
MediumTurquoise("medium turquoise", "MediumTurquoise") => 72,209,204,
|
||||||
|
Grey39("grey39") => 99,99,99,
|
||||||
|
SeaGreen2("SeaGreen2") => 78,238,148,
|
||||||
|
Grey17("grey17") => 43,43,43,
|
||||||
|
Grey6("grey6") => 15,15,15,
|
||||||
|
Pink("pink") => 255,192,203,
|
||||||
|
Cyan2("cyan2") => 0,238,238,
|
||||||
|
LightCyan3("LightCyan3") => 180,205,205,
|
||||||
|
Brown4("brown4") => 139,35,35,
|
||||||
|
Chartreuse3("chartreuse3") => 102,205,0,
|
||||||
|
GreenYellow("green yellow", "GreenYellow") => 173,255,47,
|
||||||
|
DarkSeaGreen3("DarkSeaGreen3") => 155,205,155,
|
||||||
|
Gray49("gray49") => 125,125,125,
|
||||||
|
VioletRed("violet red", "VioletRed") => 208,32,144,
|
||||||
|
PaleVioletRed1("PaleVioletRed1") => 255,130,171,
|
||||||
|
RosyBrown4("RosyBrown4") => 139,105,105,
|
||||||
|
Grey79("grey79") => 201,201,201,
|
||||||
|
Honeydew("honeydew") => 240,255,240,
|
||||||
|
Gray26("gray26") => 66,66,66,
|
||||||
|
Grey40("grey40") => 102,102,102,
|
||||||
|
MediumAquamarine("medium aquamarine", "MediumAquamarine") => 102,205,170,
|
||||||
|
Gray89("gray89") => 227,227,227,
|
||||||
|
Pink4("pink4") => 139,99,108,
|
||||||
|
Grey95("grey95") => 242,242,242,
|
||||||
|
Turquoise("turquoise") => 64,224,208,
|
||||||
|
Azure3("azure3") => 193,205,205,
|
||||||
|
NavajoWhite("navajo white", "NavajoWhite") => 255,222,173,
|
||||||
|
AntiqueWhite4("AntiqueWhite4") => 139,131,120,
|
||||||
|
PeachPuff("peach puff", "PeachPuff") => 255,218,185,
|
||||||
|
Turquoise4("turquoise4") => 0,134,139,
|
||||||
|
Gray68("gray68") => 173,173,173,
|
||||||
|
Burlywood4("burlywood4") => 139,115,85,
|
||||||
|
SlateBlue4("SlateBlue4") => 71,60,139,
|
||||||
|
DodgerBlue2("DodgerBlue2") => 28,134,238,
|
||||||
|
LightSlateGray("light slate gray", "LightSlateGray") => 119,136,153,
|
||||||
|
Red1("red1") => 255,0,0,
|
||||||
|
Yellow2("yellow2") => 238,238,0,
|
||||||
|
Gray32("gray32") => 82,82,82,
|
||||||
|
MistyRose("misty rose", "MistyRose") => 255,228,225,
|
||||||
|
Cornsilk3("cornsilk3") => 205,200,177,
|
||||||
|
RosyBrown3("RosyBrown3") => 205,155,155,
|
||||||
|
Pink2("pink2") => 238,169,184,
|
||||||
|
Gray6("gray6") => 15,15,15,
|
||||||
|
Khaki3("khaki3") => 205,198,115,
|
||||||
|
Turquoise2("turquoise2") => 0,229,238,
|
||||||
|
PowderBlue("powder blue", "PowderBlue") => 176,224,230,
|
||||||
|
Gray84("gray84") => 214,214,214,
|
||||||
|
Grey59("grey59") => 150,150,150,
|
||||||
|
Yellow3("yellow3") => 205,205,0,
|
||||||
|
SpringGreen2("SpringGreen2") => 0,238,118,
|
||||||
|
NavajoWhite1("NavajoWhite1") => 255,222,173,
|
||||||
|
Gray38("gray38") => 97,97,97,
|
||||||
|
AntiqueWhite2("AntiqueWhite2") => 238,223,204,
|
||||||
|
Azure4("azure4") => 131,139,139,
|
||||||
|
Green4("green4") => 0,139,0,
|
||||||
|
Gray72("gray72") => 184,184,184,
|
||||||
|
Gray31("gray31") => 79,79,79,
|
||||||
|
SpringGreen4("SpringGreen4") => 0,139,69,
|
||||||
|
DarkOrange1("DarkOrange1") => 255,127,0,
|
||||||
|
LightGoldenrod4("LightGoldenrod4") => 139,129,76,
|
||||||
|
DarkSeaGreen("dark sea green", "DarkSeaGreen") => 143,188,143,
|
||||||
|
LightBlue("light blue", "LightBlue") => 173,216,230,
|
||||||
|
DarkOliveGreen1("DarkOliveGreen1") => 202,255,112,
|
||||||
|
Gray24("gray24") => 61,61,61,
|
||||||
|
SeaGreen3("SeaGreen3") => 67,205,128,
|
||||||
|
Grey69("grey69") => 176,176,176,
|
||||||
|
Grey98("grey98") => 250,250,250,
|
||||||
|
DarkCyan("dark cyan", "DarkCyan") => 0,139,139,
|
||||||
|
Tomato4("tomato4") => 139,54,38,
|
||||||
|
OliveDrab4("OliveDrab4") => 105,139,34,
|
||||||
|
SlateBlue("slate blue", "SlateBlue") => 106,90,205,
|
||||||
|
DarkSeaGreen4("DarkSeaGreen4") => 105,139,105,
|
||||||
|
Gray0("gray0") => 0,0,0,
|
||||||
|
Gray9("gray9") => 23,23,23,
|
||||||
|
Gray60("gray60") => 153,153,153,
|
||||||
|
Gray45("gray45") => 115,115,115,
|
||||||
|
DarkBlue("dark blue", "DarkBlue") => 0,0,139,
|
||||||
|
Gray41("gray41") => 105,105,105,
|
||||||
|
LightBlue3("LightBlue3") => 154,192,205,
|
||||||
|
Blue2("blue2") => 0,0,238,
|
||||||
|
Gray48("gray48") => 122,122,122,
|
||||||
|
LightGoldenrodYellow("light goldenrod yellow", "LightGoldenrodYellow") => 250,250,210,
|
||||||
|
Seashell4("seashell4") => 139,134,130,
|
||||||
|
Chocolate3("chocolate3") => 205,102,29,
|
||||||
|
DarkOrange("dark orange", "DarkOrange") => 255,140,0,
|
||||||
|
DarkGoldenrod1("DarkGoldenrod1") => 255,185,15,
|
||||||
|
Aquamarine1("aquamarine1") => 127,255,212,
|
||||||
|
Gray78("gray78") => 199,199,199,
|
||||||
|
PaleVioletRed3("PaleVioletRed3") => 205,104,137,
|
||||||
|
Thistle("thistle") => 216,191,216,
|
||||||
|
LightSalmon1("LightSalmon1") => 255,160,122,
|
||||||
|
Blue3("blue3") => 0,0,205,
|
||||||
|
Gray1("gray1") => 3,3,3,
|
||||||
|
Grey5("grey5") => 13,13,13,
|
||||||
|
DeepSkyBlue1("DeepSkyBlue1") => 0,191,255,
|
||||||
|
RoyalBlue4("RoyalBlue4") => 39,64,139,
|
||||||
|
DeepPink4("DeepPink4") => 139,10,80,
|
||||||
|
MediumPurple3("MediumPurple3") => 137,104,205,
|
||||||
|
Yellow1("yellow1") => 255,255,0,
|
||||||
|
Grey8("grey8") => 20,20,20,
|
||||||
|
Blue1("blue1") => 0,0,255,
|
||||||
|
IndianRed2("IndianRed2") => 238,99,99,
|
||||||
|
SeaGreen4("SeaGreen4") => 46,139,87,
|
||||||
|
MediumSeaGreen("medium sea green", "MediumSeaGreen") => 60,179,113,
|
||||||
|
Orchid("orchid") => 218,112,214,
|
||||||
|
RosyBrown2("RosyBrown2") => 238,180,180,
|
||||||
|
Seashell("seashell") => 255,245,238,
|
||||||
|
MediumPurple2("MediumPurple2") => 159,121,238,
|
||||||
|
Tan3("tan3") => 205,133,63,
|
||||||
|
Pink3("pink3") => 205,145,158,
|
||||||
|
Maroon1("maroon1") => 255,52,179,
|
||||||
|
Plum1("plum1") => 255,187,255,
|
||||||
|
DebianRed("DebianRed") => 215,7,81,
|
||||||
|
SaddleBrown("saddle brown", "SaddleBrown") => 139,69,19,
|
||||||
|
Goldenrod4("goldenrod4") => 139,105,20,
|
||||||
|
Khaki4("khaki4") => 139,134,78,
|
||||||
|
Grey53("grey53") => 135,135,135,
|
||||||
|
Gray58("gray58") => 148,148,148,
|
||||||
|
Azure2("azure2") => 224,238,238,
|
||||||
|
SlateGray4("SlateGray4") => 108,123,139,
|
||||||
|
DodgerBlue4("DodgerBlue4") => 16,78,139,
|
||||||
|
IndianRed3("IndianRed3") => 205,85,85,
|
||||||
|
DarkKhaki("dark khaki", "DarkKhaki") => 189,183,107,
|
||||||
|
Grey73("grey73") => 186,186,186,
|
||||||
|
DodgerBlue3("DodgerBlue3") => 24,116,205,
|
||||||
|
Tan1("tan1") => 255,165,79,
|
||||||
|
OliveDrab2("OliveDrab2") => 179,238,58,
|
||||||
|
Seashell3("seashell3") => 205,197,191,
|
||||||
|
Gray30("gray30") => 77,77,77,
|
||||||
|
Gray65("gray65") => 166,166,166,
|
||||||
|
Orange4("orange4") => 139,90,0,
|
||||||
|
Gray43("gray43") => 110,110,110,
|
||||||
|
Grey12("grey12") => 31,31,31,
|
||||||
|
Snow3("snow3") => 205,201,201,
|
||||||
|
ForestGreen("forest green", "ForestGreen") => 34,139,34,
|
||||||
|
DarkSlateBlue("dark slate blue", "DarkSlateBlue") => 72,61,139,
|
||||||
|
Thistle1("thistle1") => 255,225,255,
|
||||||
|
Grey45("grey45") => 115,115,115,
|
||||||
|
DarkOrchid("dark orchid", "DarkOrchid") => 153,50,204,
|
||||||
|
MediumOrchid1("MediumOrchid1") => 224,102,255,
|
||||||
|
SkyBlue2("SkyBlue2") => 126,192,238,
|
||||||
|
DarkViolet("dark violet", "DarkViolet") => 148,0,211,
|
||||||
|
LightSteelBlue1("LightSteelBlue1") => 202,225,255,
|
||||||
|
Blue4("blue4") => 0,0,139,
|
||||||
|
LawnGreen("lawn green", "LawnGreen") => 124,252,0,
|
||||||
|
LemonChiffon4("LemonChiffon4") => 139,137,112,
|
||||||
|
SkyBlue1("SkyBlue1") => 135,206,255,
|
||||||
|
Turquoise3("turquoise3") => 0,197,205,
|
||||||
|
Gray64("gray64") => 163,163,163,
|
||||||
|
Grey33("grey33") => 84,84,84,
|
||||||
|
Orchid3("orchid3") => 205,105,201,
|
||||||
|
Grey77("grey77") => 196,196,196,
|
||||||
|
Grey81("grey81") => 207,207,207,
|
||||||
|
DarkOrchid4("DarkOrchid4") => 104,34,139,
|
||||||
|
Gray36("gray36") => 92,92,92,
|
||||||
|
Gray5("gray5") => 13,13,13,
|
||||||
|
Grey46("grey46") => 117,117,117,
|
||||||
|
Khaki("khaki") => 240,230,140,
|
||||||
|
Wheat2("wheat2") => 238,216,174,
|
||||||
|
Cornsilk1("cornsilk1") => 255,248,220,
|
||||||
|
Red2("red2") => 238,0,0,
|
||||||
|
Gray20("gray20") => 51,51,51,
|
||||||
|
OrangeRed("orange red", "OrangeRed") => 255,69,0,
|
||||||
|
CadetBlue("cadet blue", "CadetBlue") => 95,158,160,
|
||||||
|
Grey9("grey9") => 23,23,23,
|
||||||
|
Gray37("gray37") => 94,94,94,
|
||||||
|
SteelBlue3("SteelBlue3") => 79,148,205,
|
||||||
|
Firebrick2("firebrick2") => 238,44,44,
|
||||||
|
DarkSlateGrey("dark slate grey", "DarkSlateGrey") => 47,79,79,
|
||||||
|
LemonChiffon3("LemonChiffon3") => 205,201,165,
|
||||||
|
Violet("violet") => 238,130,238,
|
||||||
|
Orchid1("orchid1") => 255,131,250,
|
||||||
|
Yellow("yellow") => 255,255,0,
|
||||||
|
LightBlue2("LightBlue2") => 178,223,238,
|
||||||
|
Gray46("gray46") => 117,117,117,
|
||||||
|
MediumSpringGreen("medium spring green", "MediumSpringGreen") => 0,250,154,
|
||||||
|
LavenderBlush3("LavenderBlush3") => 205,193,197,
|
||||||
|
VioletRed2("VioletRed2") => 238,58,140,
|
||||||
|
Snow1("snow1") => 255,250,250,
|
||||||
|
Azure("azure") => 240,255,255,
|
||||||
|
MistyRose4("MistyRose4") => 139,125,123,
|
||||||
|
Grey22("grey22") => 56,56,56,
|
||||||
|
Sienna3("sienna3") => 205,104,57,
|
||||||
|
Salmon3("salmon3") => 205,112,84,
|
||||||
|
Burlywood1("burlywood1") => 255,211,155,
|
||||||
|
LightCyan("light cyan", "LightCyan") => 224,255,255,
|
||||||
|
Grey55("grey55") => 140,140,140,
|
||||||
|
Grey31("grey31") => 79,79,79,
|
||||||
|
AntiqueWhite3("AntiqueWhite3") => 205,192,176,
|
||||||
|
MediumOrchid3("MediumOrchid3") => 180,82,205,
|
||||||
|
Grey75("grey75") => 191,191,191,
|
||||||
|
DarkSalmon("dark salmon", "DarkSalmon") => 233,150,122,
|
||||||
|
HotPink2("HotPink2") => 238,106,167,
|
||||||
|
Gray69("gray69") => 176,176,176,
|
||||||
|
Gray52("gray52") => 133,133,133,
|
||||||
|
Gray21("gray21") => 54,54,54,
|
||||||
|
SlateGray2("SlateGray2") => 185,211,238,
|
||||||
|
Grey100("grey100") => 255,255,255,
|
||||||
|
VioletRed3("VioletRed3") => 205,50,120,
|
||||||
|
DimGray("dim gray", "DimGray") => 105,105,105,
|
||||||
|
RoyalBlue("royal blue", "RoyalBlue") => 65,105,225,
|
||||||
|
Yellow4("yellow4") => 139,139,0,
|
||||||
|
Gray39("gray39") => 99,99,99,
|
||||||
|
YellowGreen("yellow green", "YellowGreen") => 154,205,50,
|
||||||
|
Sienna1("sienna1") => 255,130,71,
|
||||||
|
Grey83("grey83") => 212,212,212,
|
||||||
|
Goldenrod1("goldenrod1") => 255,193,37,
|
||||||
|
MidnightBlue("midnight blue", "MidnightBlue") => 25,25,112,
|
||||||
|
Firebrick4("firebrick4") => 139,26,26,
|
||||||
|
MediumOrchid4("MediumOrchid4") => 122,55,139,
|
||||||
|
Gray82("gray82") => 209,209,209,
|
||||||
|
Brown("brown") => 165,42,42,
|
||||||
|
Grey24("grey24") => 61,61,61,
|
||||||
|
DarkOrchid3("DarkOrchid3") => 154,50,205,
|
||||||
|
Gainsboro("gainsboro") => 220,220,220,
|
||||||
|
MediumSlateBlue("medium slate blue", "MediumSlateBlue") => 123,104,238,
|
||||||
|
LightSkyBlue1("LightSkyBlue1") => 176,226,255,
|
||||||
|
Seashell2("seashell2") => 238,229,222,
|
||||||
|
PaleVioletRed("pale violet red", "PaleVioletRed") => 219,112,147,
|
||||||
|
RoyalBlue2("RoyalBlue2") => 67,110,238,
|
||||||
|
Gray4("gray4") => 10,10,10,
|
||||||
|
LimeGreen("lime green", "LimeGreen") => 50,205,50,
|
||||||
|
Maroon2("maroon2") => 238,48,167,
|
||||||
|
Grey2("grey2") => 5,5,5,
|
||||||
|
Grey11("grey11") => 28,28,28,
|
||||||
|
SteelBlue("steel blue", "SteelBlue") => 70,130,180,
|
||||||
|
Sienna2("sienna2") => 238,121,66,
|
||||||
|
NavajoWhite4("NavajoWhite4") => 139,121,94,
|
||||||
|
Grey25("grey25") => 64,64,64,
|
||||||
|
DeepSkyBlue("deep sky blue", "DeepSkyBlue") => 0,191,255,
|
||||||
|
Gray10("gray10") => 26,26,26,
|
||||||
|
Salmon2("salmon2") => 238,130,98,
|
||||||
|
LightGoldenrod2("LightGoldenrod2") => 238,220,130,
|
||||||
|
HotPink1("HotPink1") => 255,110,180,
|
||||||
|
Grey49("grey49") => 125,125,125,
|
||||||
|
Bisque2("bisque2") => 238,213,183,
|
||||||
|
Gray87("gray87") => 222,222,222,
|
||||||
|
Linen("linen") => 250,240,230,
|
||||||
|
Ivory1("ivory1") => 255,255,240,
|
||||||
|
Gray61("gray61") => 156,156,156,
|
||||||
|
LightSalmon2("LightSalmon2") => 238,149,114,
|
||||||
|
Grey61("grey61") => 156,156,156,
|
||||||
|
DarkGoldenrod2("DarkGoldenrod2") => 238,173,14,
|
||||||
|
Cyan3("cyan3") => 0,205,205,
|
||||||
|
Firebrick3("firebrick3") => 205,38,38,
|
||||||
|
Grey48("grey48") => 122,122,122,
|
||||||
|
LightSalmon("light salmon", "LightSalmon") => 255,160,122,
|
||||||
|
Cornsilk4("cornsilk4") => 139,136,120,
|
||||||
|
HotPink4("HotPink4") => 139,58,98,
|
||||||
|
DarkOrange2("DarkOrange2") => 238,118,0,
|
||||||
|
Goldenrod2("goldenrod2") => 238,180,34,
|
||||||
|
Gray53("gray53") => 135,135,135,
|
||||||
|
Grey85("grey85") => 217,217,217,
|
||||||
|
LightCyan1("LightCyan1") => 224,255,255,
|
||||||
|
PeachPuff3("PeachPuff3") => 205,175,149,
|
||||||
|
Gray95("gray95") => 242,242,242,
|
||||||
|
Grey80("grey80") => 204,204,204,
|
||||||
|
RoyalBlue3("RoyalBlue3") => 58,95,205,
|
||||||
|
Orange1("orange1") => 255,165,0,
|
||||||
|
MediumOrchid2("MediumOrchid2") => 209,95,238,
|
||||||
|
Grey86("grey86") => 219,219,219,
|
||||||
|
Gray80("gray80") => 204,204,204,
|
||||||
|
Grey3("grey3") => 8,8,8,
|
||||||
|
Gray34("gray34") => 87,87,87,
|
||||||
|
SpringGreen("spring green", "SpringGreen") => 0,255,127,
|
||||||
|
Aquamarine2("aquamarine2") => 118,238,198,
|
||||||
|
DarkOrange3("DarkOrange3") => 205,102,0,
|
||||||
|
Brown2("brown2") => 238,59,59,
|
||||||
|
Magenta1("magenta1") => 255,0,255,
|
||||||
|
Grey37("grey37") => 94,94,94,
|
||||||
|
Goldenrod3("goldenrod3") => 205,155,29,
|
||||||
|
LavenderBlush("lavender blush", "LavenderBlush") => 255,240,245,
|
||||||
|
Snow("snow") => 255,250,250,
|
||||||
|
PaleGreen3("PaleGreen3") => 124,205,124,
|
||||||
|
Gray99("gray99") => 252,252,252,
|
||||||
|
Gray76("gray76") => 194,194,194,
|
||||||
|
Tan2("tan2") => 238,154,73,
|
||||||
|
LightCoral("light coral", "LightCoral") => 240,128,128,
|
||||||
|
Grey10("grey10") => 26,26,26,
|
||||||
|
Ivory4("ivory4") => 139,139,131,
|
||||||
|
MediumVioletRed("medium violet red", "MediumVioletRed") => 199,21,133,
|
||||||
|
Gray66("gray66") => 168,168,168,
|
||||||
|
Magenta2("magenta2") => 238,0,238,
|
||||||
|
Purple("purple") => 160,32,240,
|
||||||
|
Gray81("gray81") => 207,207,207,
|
||||||
|
Plum2("plum2") => 238,174,238,
|
||||||
|
Peru("peru") => 205,133,63,
|
||||||
|
PaleGreen2("PaleGreen2") => 144,238,144,
|
||||||
|
Grey93("grey93") => 237,237,237,
|
||||||
|
IndianRed4("IndianRed4") => 139,58,58,
|
||||||
|
Grey58("grey58") => 148,148,148,
|
||||||
|
Tomato1("tomato1") => 255,99,71,
|
||||||
|
Aquamarine("aquamarine") => 127,255,212,
|
||||||
|
LightYellow1("LightYellow1") => 255,255,224,
|
||||||
|
Aquamarine4("aquamarine4") => 69,139,116,
|
||||||
|
IndianRed("indian red", "IndianRed") => 205,92,92,
|
||||||
|
Grey60("grey60") => 153,153,153,
|
||||||
|
Black("black") => 0,0,0,
|
||||||
|
LightSteelBlue2("LightSteelBlue2") => 188,210,238,
|
||||||
|
Gray92("gray92") => 235,235,235,
|
||||||
|
Grey0("grey0") => 0,0,0,
|
||||||
|
LightSlateBlue("light slate blue", "LightSlateBlue") => 132,112,255,
|
||||||
|
AntiqueWhite1("AntiqueWhite1") => 255,239,219,
|
||||||
|
DarkOliveGreen("dark olive green", "DarkOliveGreen") => 85,107,47,
|
||||||
|
Gray70("gray70") => 179,179,179,
|
||||||
|
Gray44("gray44") => 112,112,112,
|
||||||
|
LightGray("light gray", "LightGray") => 211,211,211,
|
||||||
|
Gray23("gray23") => 59,59,59,
|
||||||
|
Orange2("orange2") => 238,154,0,
|
||||||
|
Gold("gold") => 255,215,0,
|
||||||
|
Grey7("grey7") => 18,18,18,
|
||||||
|
DeepSkyBlue3("DeepSkyBlue3") => 0,154,205,
|
||||||
|
Wheat3("wheat3") => 205,186,150,
|
||||||
|
Green3("green3") => 0,205,0,
|
||||||
|
Chocolate("chocolate") => 210,105,30,
|
||||||
|
OrangeRed1("OrangeRed1") => 255,69,0,
|
||||||
|
DarkOrchid2("DarkOrchid2") => 178,58,238,
|
||||||
|
Gray("gray") => 190,190,190,
|
||||||
|
LightPink3("LightPink3") => 205,140,149,
|
||||||
|
BlueViolet("blue violet", "BlueViolet") => 138,43,226,
|
||||||
|
PaleTurquoise("pale turquoise", "PaleTurquoise") => 175,238,238,
|
||||||
|
LavenderBlush2("LavenderBlush2") => 238,224,229,
|
||||||
|
HotPink3("HotPink3") => 205,96,144,
|
||||||
|
Gray27("gray27") => 69,69,69,
|
||||||
|
DarkOliveGreen4("DarkOliveGreen4") => 110,139,61,
|
||||||
|
Chocolate2("chocolate2") => 238,118,33,
|
||||||
|
WhiteSmoke("white smoke", "WhiteSmoke") => 245,245,245,
|
||||||
|
PaleTurquoise1("PaleTurquoise1") => 187,255,255,
|
||||||
|
LightSkyBlue("light sky blue", "LightSkyBlue") => 135,206,250,
|
||||||
|
SteelBlue1("SteelBlue1") => 99,184,255,
|
||||||
|
Grey97("grey97") => 247,247,247,
|
||||||
|
Bisque("bisque") => 255,228,196,
|
||||||
|
Bisque3("bisque3") => 205,183,158,
|
||||||
|
Blue("blue") => 0,0,255,
|
||||||
|
LightSteelBlue("light steel blue", "LightSteelBlue") => 176,196,222,
|
||||||
|
Grey51("grey51") => 130,130,130,
|
||||||
|
MintCream("mint cream", "MintCream") => 245,255,250,
|
||||||
|
MediumOrchid("medium orchid", "MediumOrchid") => 186,85,211,
|
||||||
|
PaleVioletRed4("PaleVioletRed4") => 139,71,93,
|
||||||
|
Gold2("gold2") => 238,201,0,
|
||||||
|
Gray73("gray73") => 186,186,186,
|
||||||
|
Grey99("grey99") => 252,252,252,
|
||||||
|
Grey14("grey14") => 36,36,36,
|
||||||
|
Cyan("cyan") => 0,255,255,
|
||||||
|
Coral2("coral2") => 238,106,80,
|
||||||
|
Gray93("gray93") => 237,237,237,
|
||||||
|
LemonChiffon1("LemonChiffon1") => 255,250,205,
|
||||||
|
NavajoWhite3("NavajoWhite3") => 205,179,139,
|
||||||
|
Burlywood3("burlywood3") => 205,170,125,
|
||||||
|
Bisque1("bisque1") => 255,228,196,
|
||||||
|
Gray35("gray35") => 89,89,89,
|
||||||
|
LightYellow4("LightYellow4") => 139,139,122,
|
||||||
|
Snow4("snow4") => 139,137,137,
|
||||||
|
Gray56("gray56") => 143,143,143,
|
||||||
|
Gray59("gray59") => 150,150,150,
|
||||||
|
Gray15("gray15") => 38,38,38,
|
||||||
|
LightSteelBlue4("LightSteelBlue4") => 110,123,139,
|
||||||
|
LightSteelBlue3("LightSteelBlue3") => 162,181,205,
|
||||||
|
OliveDrab("olive drab", "OliveDrab") => 107,142,35,
|
||||||
|
RosyBrown1("RosyBrown1") => 255,193,193,
|
||||||
|
Grey84("grey84") => 214,214,214,
|
||||||
|
Green1("green1") => 0,255,0,
|
||||||
|
Gray63("gray63") => 161,161,161,
|
||||||
|
LightPink4("LightPink4") => 139,95,101,
|
||||||
|
Wheat("wheat") => 245,222,179,
|
||||||
|
Gray14("gray14") => 36,36,36,
|
||||||
|
Gray16("gray16") => 41,41,41,
|
||||||
|
MediumBlue("medium blue", "MediumBlue") => 0,0,205,
|
||||||
|
OrangeRed4("OrangeRed4") => 139,37,0,
|
||||||
|
LightPink1("LightPink1") => 255,174,185,
|
||||||
|
SlateBlue2("SlateBlue2") => 122,103,238,
|
||||||
|
SandyBrown("sandy brown", "SandyBrown") => 244,164,96,
|
||||||
|
Gray83("gray83") => 212,212,212,
|
||||||
|
SkyBlue3("SkyBlue3") => 108,166,205,
|
||||||
|
Moccasin("moccasin") => 255,228,181,
|
||||||
|
Grey27("grey27") => 69,69,69,
|
||||||
|
PaleTurquoise2("PaleTurquoise2") => 174,238,238,
|
||||||
|
Firebrick("firebrick") => 178,34,34,
|
||||||
|
Purple3("purple3") => 125,38,205,
|
||||||
|
SkyBlue4("SkyBlue4") => 74,112,139,
|
||||||
|
Gray67("gray67") => 171,171,171,
|
||||||
|
Aquamarine3("aquamarine3") => 102,205,170,
|
||||||
|
LightSkyBlue3("LightSkyBlue3") => 141,182,205,
|
||||||
|
Magenta("magenta") => 255,0,255,
|
||||||
|
Grey38("grey38") => 97,97,97,
|
||||||
|
SeaGreen("sea green", "SeaGreen") => 46,139,87,
|
||||||
|
Grey90("grey90") => 229,229,229,
|
||||||
|
Chartreuse("chartreuse") => 127,255,0,
|
||||||
|
DeepSkyBlue4("DeepSkyBlue4") => 0,104,139,
|
||||||
|
VioletRed4("VioletRed4") => 139,34,82,
|
||||||
|
DarkRed("dark red", "DarkRed") => 139,0,0,
|
||||||
|
Gray25("gray25") => 64,64,64,
|
||||||
|
Tan4("tan4") => 139,90,43,
|
||||||
|
Grey47("grey47") => 120,120,120,
|
||||||
|
SlateGrey("slate grey", "SlateGrey") => 112,128,144,
|
||||||
|
IndianRed1("IndianRed1") => 255,106,106,
|
||||||
|
LightGreen("light green", "LightGreen") => 144,238,144,
|
||||||
|
Honeydew3("honeydew3") => 193,205,193,
|
||||||
|
Orchid2("orchid2") => 238,122,233,
|
||||||
|
Honeydew2("honeydew2") => 224,238,224,
|
||||||
|
Snow2("snow2") => 238,233,233,
|
||||||
|
OliveDrab3("OliveDrab3") => 154,205,50,
|
||||||
|
Purple2("purple2") => 145,44,238,
|
||||||
|
Gray47("gray47") => 120,120,120,
|
||||||
|
Grey89("grey89") => 227,227,227,
|
||||||
|
Coral1("coral1") => 255,114,86,
|
||||||
|
Gray22("gray22") => 56,56,56,
|
||||||
|
Gray74("gray74") => 189,189,189,
|
||||||
|
Orange3("orange3") => 205,133,0,
|
||||||
|
Maroon3("maroon3") => 205,41,144,
|
||||||
|
Tomato3("tomato3") => 205,79,57,
|
||||||
|
RosyBrown("rosy brown", "RosyBrown") => 188,143,143,
|
||||||
|
Grey20("grey20") => 51,51,51,
|
||||||
|
Gray51("gray51") => 130,130,130,
|
||||||
|
DeepPink1("DeepPink1") => 255,20,147,
|
||||||
|
DarkGoldenrod4("DarkGoldenrod4") => 139,101,8,
|
||||||
|
Grey50("grey50") => 127,127,127,
|
||||||
|
Tomato("tomato") => 255,99,71,
|
||||||
|
Red("red") => 255,0,0,
|
||||||
|
SteelBlue4("SteelBlue4") => 54,100,139,
|
||||||
|
HotPink("hot pink", "HotPink") => 255,105,180,
|
||||||
|
SkyBlue("sky blue", "SkyBlue") => 135,206,235,
|
||||||
|
LightYellow3("LightYellow3") => 205,205,180,
|
||||||
|
Gray33("gray33") => 84,84,84,
|
||||||
|
Grey35("grey35") => 89,89,89,
|
||||||
|
Grey88("grey88") => 224,224,224,
|
||||||
|
CornflowerBlue("cornflower blue", "CornflowerBlue") => 100,149,237,
|
||||||
|
Grey13("grey13") => 33,33,33,
|
||||||
|
Grey19("grey19") => 48,48,48,
|
||||||
|
Chartreuse2("chartreuse2") => 118,238,0,
|
||||||
|
Grey72("grey72") => 184,184,184,
|
||||||
|
SlateGray("slate gray", "SlateGray") => 112,128,144,
|
||||||
|
CadetBlue2("CadetBlue2") => 142,229,238,
|
||||||
|
NavajoWhite2("NavajoWhite2") => 238,207,161,
|
||||||
|
Gray19("gray19") => 48,48,48,
|
||||||
|
DarkOrange4("DarkOrange4") => 139,69,0,
|
||||||
|
Turquoise1("turquoise1") => 0,245,255,
|
||||||
|
LightPink2("LightPink2") => 238,162,173,
|
||||||
|
LightBlue1("LightBlue1") => 191,239,255,
|
||||||
|
Grey71("grey71") => 181,181,181,
|
||||||
|
DimGrey("dim grey", "DimGrey") => 105,105,105,
|
||||||
|
LightGoldenrod3("LightGoldenrod3") => 205,190,112,
|
||||||
|
SlateGray3("SlateGray3") => 159,182,205,
|
||||||
|
Grey78("grey78") => 199,199,199,
|
||||||
|
Grey94("grey94") => 240,240,240,
|
||||||
|
Azure1("azure1") => 240,255,255,
|
||||||
|
Gray94("gray94") => 240,240,240,
|
||||||
|
Grey62("grey62") => 158,158,158,
|
||||||
|
Magenta4("magenta4") => 139,0,139,
|
||||||
|
Coral3("coral3") => 205,91,69,
|
||||||
|
Salmon("salmon") => 250,128,114,
|
||||||
|
Khaki1("khaki1") => 255,246,143,
|
||||||
|
Gray3("gray3") => 8,8,8,
|
||||||
|
Brown1("brown1") => 255,64,64,
|
||||||
|
Grey52("grey52") => 133,133,133,
|
||||||
|
Grey21("grey21") => 54,54,54,
|
||||||
|
LightSkyBlue4("LightSkyBlue4") => 96,123,139,
|
||||||
|
Gold3("gold3") => 205,173,0,
|
||||||
|
LavenderBlush4("LavenderBlush4") => 139,131,134,
|
||||||
|
Honeydew1("honeydew1") => 240,255,240,
|
||||||
|
DarkSlateGray("dark slate gray", "DarkSlateGray") => 47,79,79,
|
||||||
|
Maroon("maroon") => 176,48,96,
|
||||||
|
Wheat1("wheat1") => 255,231,186,
|
||||||
|
Gray28("gray28") => 71,71,71,
|
||||||
|
Gray40("gray40") => 102,102,102,
|
||||||
|
Grey91("grey91") => 232,232,232,
|
||||||
|
Gray57("gray57") => 145,145,145,
|
||||||
|
Grey68("grey68") => 173,173,173,
|
||||||
|
SpringGreen3("SpringGreen3") => 0,205,102,
|
||||||
|
PeachPuff1("PeachPuff1") => 255,218,185,
|
||||||
|
FloralWhite("floral white", "FloralWhite") => 255,250,240,
|
||||||
|
Coral4("coral4") => 139,62,47,
|
||||||
|
Gray50("gray50") => 127,127,127,
|
||||||
|
Grey82("grey82") => 209,209,209,
|
||||||
|
Gray86("gray86") => 219,219,219,
|
||||||
|
Sienna4("sienna4") => 139,71,38,
|
||||||
|
Grey57("grey57") => 145,145,145,
|
||||||
|
Grey70("grey70") => 179,179,179,
|
||||||
|
Grey63("grey63") => 161,161,161,
|
||||||
|
DarkOliveGreen3("DarkOliveGreen3") => 162,205,90,
|
||||||
|
Beige("beige") => 245,245,220,
|
||||||
|
OldLace("old lace", "OldLace") => 253,245,230,
|
||||||
|
Gray13("gray13") => 33,33,33,
|
||||||
|
MediumPurple("medium purple", "MediumPurple") => 147,112,219,
|
||||||
|
PaleGreen1("PaleGreen1") => 154,255,154,
|
||||||
|
Grey43("grey43") => 110,110,110,
|
||||||
|
Chocolate4("chocolate4") => 139,69,19,
|
||||||
|
Chocolate1("chocolate1") => 255,127,36,
|
||||||
|
DarkSeaGreen2("DarkSeaGreen2") => 180,238,180,
|
||||||
|
Gray77("gray77") => 196,196,196,
|
||||||
|
Maroon4("maroon4") => 139,28,98,
|
||||||
|
Gray2("gray2") => 5,5,5,
|
||||||
|
OrangeRed2("OrangeRed2") => 238,64,0,
|
||||||
|
PaleGreen4("PaleGreen4") => 84,139,84,
|
||||||
|
DarkGoldenrod3("DarkGoldenrod3") => 205,149,12,
|
||||||
|
Grey67("grey67") => 171,171,171,
|
||||||
|
PaleGreen("pale green", "PaleGreen") => 152,251,152,
|
||||||
|
Grey1("grey1") => 3,3,3,
|
||||||
|
PapayaWhip("papaya whip", "PapayaWhip") => 255,239,213,
|
||||||
|
Gray11("gray11") => 28,28,28,
|
||||||
|
Grey41("grey41") => 105,105,105,
|
||||||
|
Gray98("gray98") => 250,250,250,
|
||||||
|
Grey56("grey56") => 143,143,143,
|
||||||
|
Plum3("plum3") => 205,150,205,
|
||||||
|
DeepPink3("DeepPink3") => 205,16,118,
|
||||||
|
Grey64("grey64") => 163,163,163,
|
||||||
|
Grey26("grey26") => 66,66,66,
|
||||||
|
DodgerBlue("dodger blue", "DodgerBlue") => 30,144,255,
|
||||||
|
Grey42("grey42") => 107,107,107,
|
||||||
|
SlateBlue3("SlateBlue3") => 105,89,205,
|
||||||
|
Gold4("gold4") => 139,117,0,
|
||||||
|
DarkOrchid1("DarkOrchid1") => 191,62,255,
|
||||||
|
Grey("grey") => 190,190,190,
|
||||||
|
Ivory("ivory") => 255,255,240,
|
||||||
|
DarkSlateGray2("DarkSlateGray2") => 141,238,238,
|
||||||
|
Gray12("gray12") => 31,31,31,
|
||||||
|
Grey16("grey16") => 41,41,41,
|
||||||
|
LightCyan4("LightCyan4") => 122,139,139,
|
||||||
|
Burlywood2("burlywood2") => 238,197,145,
|
||||||
|
LemonChiffon("lemon chiffon", "LemonChiffon") => 255,250,205,
|
||||||
|
DeepPink2("DeepPink2") => 238,18,137,
|
||||||
|
Gray7("gray7") => 18,18,18,
|
||||||
|
Magenta3("magenta3") => 205,0,205,
|
||||||
|
LightSalmon3("LightSalmon3") => 205,129,98,
|
||||||
|
LemonChiffon2("LemonChiffon2") => 238,233,191,
|
||||||
|
Gray79("gray79") => 201,201,201,
|
||||||
|
DeepSkyBlue2("DeepSkyBlue2") => 0,178,238,
|
||||||
|
Burlywood("burlywood") => 222,184,135,
|
||||||
|
Grey30("grey30") => 77,77,77,
|
||||||
|
Green("green") => 0,255,0,
|
||||||
|
Navy("navy") => 0,0,128,
|
||||||
|
Grey66("grey66") => 168,168,168,
|
||||||
|
Grey87("grey87") => 222,222,222,
|
||||||
|
Honeydew4("honeydew4") => 131,139,131,
|
||||||
|
MistyRose1("MistyRose1") => 255,228,225,
|
||||||
|
Gray18("gray18") => 46,46,46,
|
||||||
|
Ivory2("ivory2") => 238,238,224,
|
||||||
|
LavenderBlush1("LavenderBlush1") => 255,240,245,
|
||||||
|
DodgerBlue1("DodgerBlue1") => 30,144,255,
|
||||||
|
Chartreuse4("chartreuse4") => 69,139,0,
|
||||||
|
MistyRose3("MistyRose3") => 205,183,181,
|
||||||
|
Grey28("grey28") => 71,71,71,
|
||||||
|
DarkSlateGray1("DarkSlateGray1") => 151,255,255,
|
||||||
|
Coral("coral") => 255,127,80,
|
||||||
|
Gray97("gray97") => 247,247,247,
|
||||||
|
Firebrick1("firebrick1") => 255,48,48,
|
||||||
|
DarkSeaGreen1("DarkSeaGreen1") => 193,255,193,
|
||||||
|
LightGrey("light grey", "LightGrey") => 211,211,211,
|
||||||
|
DarkSlateGray4("DarkSlateGray4") => 82,139,139,
|
||||||
|
Cornsilk("cornsilk") => 255,248,220,
|
||||||
|
Thistle3("thistle3") => 205,181,205,
|
||||||
|
Grey4("grey4") => 10,10,10,
|
||||||
|
DarkMagenta("dark magenta", "DarkMagenta") => 139,0,139,
|
||||||
|
Cyan1("cyan1") => 0,255,255,
|
||||||
|
Red4("red4") => 139,0,0,
|
||||||
|
Salmon1("salmon1") => 255,140,105,
|
||||||
|
PeachPuff4("PeachPuff4") => 139,119,101,
|
||||||
|
LightBlue4("LightBlue4") => 104,131,139,
|
||||||
|
SteelBlue2("SteelBlue2") => 92,172,238,
|
||||||
|
LightSeaGreen("light sea green", "LightSeaGreen") => 32,178,170,
|
||||||
|
CadetBlue4("CadetBlue4") => 83,134,139,
|
||||||
|
NavyBlue("navy blue", "NavyBlue") => 0,0,128,
|
||||||
|
SeaGreen1("SeaGreen1") => 84,255,159,
|
||||||
|
DarkSlateGray3("DarkSlateGray3") => 121,205,205,
|
||||||
|
Gray29("gray29") => 74,74,74,
|
||||||
|
Grey23("grey23") => 59,59,59,
|
||||||
|
LightYellow2("LightYellow2") => 238,238,209,
|
||||||
|
LightSlateGrey("light slate grey", "LightSlateGrey") => 119,136,153,
|
||||||
|
Gray88("gray88") => 224,224,224,
|
||||||
|
Seashell1("seashell1") => 255,245,238,
|
||||||
|
DarkGreen("dark green", "DarkGreen") => 0,100,0,
|
||||||
|
DarkGoldenrod("dark goldenrod", "DarkGoldenrod") => 184,134,11,
|
||||||
|
LightSkyBlue2("LightSkyBlue2") => 164,211,238,
|
||||||
|
Thistle4("thistle4") => 139,123,139,
|
||||||
|
Gray75("gray75") => 191,191,191,
|
||||||
|
RoyalBlue1("RoyalBlue1") => 72,118,255,
|
||||||
|
CadetBlue1("CadetBlue1") => 152,245,255,
|
||||||
|
Gray100("gray100") => 255,255,255,
|
||||||
|
OliveDrab1("OliveDrab1") => 192,255,62,
|
||||||
|
Purple1("purple1") => 155,48,255,
|
||||||
|
PeachPuff2("PeachPuff2") => 238,203,173,
|
||||||
|
Purple4("purple4") => 85,26,139,
|
||||||
|
SlateBlue1("SlateBlue1") => 131,111,255,
|
||||||
|
PaleVioletRed2("PaleVioletRed2") => 238,121,159,
|
||||||
|
Grey32("grey32") => 82,82,82,
|
||||||
|
LightGoldenrod("light goldenrod", "LightGoldenrod") => 238,221,130,
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ use super::{
|
||||||
hlwmbool::ToggleBool,
|
hlwmbool::ToggleBool,
|
||||||
hook::Hook,
|
hook::Hook,
|
||||||
key::{KeyUnbind, Keybind, Mousebind},
|
key::{KeyUnbind, Keybind, Mousebind},
|
||||||
|
pad::Pad,
|
||||||
rule::Rule,
|
rule::Rule,
|
||||||
setting::{FrameLayout, Setting, SettingName},
|
setting::{FrameLayout, Setting, SettingName},
|
||||||
split,
|
split,
|
||||||
|
@ -164,6 +165,19 @@ pub enum HlwmCommand {
|
||||||
Try(Box<HlwmCommand>),
|
Try(Box<HlwmCommand>),
|
||||||
/// executes the provided command, but discards its output and only returns its exit code.
|
/// executes the provided command, but discards its output and only returns its exit code.
|
||||||
Silent(Box<HlwmCommand>),
|
Silent(Box<HlwmCommand>),
|
||||||
|
/// Prints the rectangle of the specified monitor in the format: X Y W H
|
||||||
|
/// If no monitor is given, then the current monitor is used.
|
||||||
|
///
|
||||||
|
/// If `without_pad` is supplied, then the remaining rect without the pad around this
|
||||||
|
/// monitor is printed.
|
||||||
|
MonitorRect {
|
||||||
|
monitor: Option<Monitor>,
|
||||||
|
without_pad: bool,
|
||||||
|
},
|
||||||
|
Pad {
|
||||||
|
monitor: Monitor,
|
||||||
|
pad: Pad,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Box<HlwmCommand> {
|
impl FromStr for Box<HlwmCommand> {
|
||||||
|
@ -469,64 +483,27 @@ impl HlwmCommand {
|
||||||
index: _,
|
index: _,
|
||||||
skip_visible: _,
|
skip_visible: _,
|
||||||
} => {
|
} => {
|
||||||
if args.contains(&"--skip-visible".to_string()) {
|
parse!(skip_visible: [Flag("--skip-visible")], index: FromStr => MoveIndex)
|
||||||
Ok(HlwmCommand::MoveIndex {
|
|
||||||
index: args
|
|
||||||
.into_iter()
|
|
||||||
.filter(|a| a != "--skip-visible")
|
|
||||||
.next()
|
|
||||||
.ok_or(CommandParseError::BadArgument {
|
|
||||||
command: command.to_string(),
|
|
||||||
})?
|
|
||||||
.parse()?,
|
|
||||||
skip_visible: true,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Ok(HlwmCommand::MoveIndex {
|
|
||||||
index: args
|
|
||||||
.into_iter()
|
|
||||||
.next()
|
|
||||||
.ok_or(CommandParseError::BadArgument {
|
|
||||||
command: command.to_string(),
|
|
||||||
})?
|
|
||||||
.parse()?,
|
|
||||||
skip_visible: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
HlwmCommand::UseIndex {
|
HlwmCommand::UseIndex {
|
||||||
index: _,
|
index: _,
|
||||||
skip_visible: _,
|
skip_visible: _,
|
||||||
} => {
|
} => {
|
||||||
if args.contains(&"--skip-visible".to_string()) {
|
parse!(skip_visible: [Flag("--skip-visible")], index: FromStr => UseIndex)
|
||||||
Ok(HlwmCommand::UseIndex {
|
|
||||||
index: args
|
|
||||||
.into_iter()
|
|
||||||
.filter(|a| a != "--skip-visible")
|
|
||||||
.next()
|
|
||||||
.ok_or(CommandParseError::BadArgument {
|
|
||||||
command: command.to_string(),
|
|
||||||
})?
|
|
||||||
.parse()?,
|
|
||||||
skip_visible: true,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Ok(HlwmCommand::UseIndex {
|
|
||||||
index: args
|
|
||||||
.into_iter()
|
|
||||||
.next()
|
|
||||||
.ok_or(CommandParseError::BadArgument {
|
|
||||||
command: command.to_string(),
|
|
||||||
})?
|
|
||||||
.parse()?,
|
|
||||||
skip_visible: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
HlwmCommand::UseTag(_) => parse!(String => UseTag),
|
HlwmCommand::UseTag(_) => parse!(String => UseTag),
|
||||||
HlwmCommand::MoveTag(_) => parse!(String => MoveTag),
|
HlwmCommand::MoveTag(_) => parse!(String => MoveTag),
|
||||||
HlwmCommand::Try(_) => parse!(FromStrAll => Try),
|
HlwmCommand::Try(_) => parse!(FromStrAll => Try),
|
||||||
HlwmCommand::Silent(_) => parse!(FromStrAll => Silent),
|
HlwmCommand::Silent(_) => parse!(FromStrAll => Silent),
|
||||||
|
HlwmCommand::MonitorRect {
|
||||||
|
monitor: _,
|
||||||
|
without_pad: _,
|
||||||
|
} => {
|
||||||
|
parse!(without_pad: [Flag("-p")], monitor: [Option<FromStr>] => MonitorRect)
|
||||||
|
}
|
||||||
|
HlwmCommand::Pad { monitor: _, pad: _ } => {
|
||||||
|
parse!(monitor: FromStr, pad: FromStrAll => Pad)
|
||||||
|
}
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
assert_eq!(command.to_string(), parsed_command.to_string());
|
assert_eq!(command.to_string(), parsed_command.to_string());
|
||||||
|
@ -732,6 +709,21 @@ impl ToCommandString for HlwmCommand {
|
||||||
HlwmCommand::Try(cmd) | HlwmCommand::Silent(cmd) => {
|
HlwmCommand::Try(cmd) | HlwmCommand::Silent(cmd) => {
|
||||||
format!("{self}\t{}", cmd.to_command_string())
|
format!("{self}\t{}", cmd.to_command_string())
|
||||||
}
|
}
|
||||||
|
HlwmCommand::MonitorRect {
|
||||||
|
monitor,
|
||||||
|
without_pad,
|
||||||
|
} => {
|
||||||
|
let mut parts = Vec::with_capacity(3);
|
||||||
|
parts.push(self.to_string());
|
||||||
|
if let Some(monitor) = monitor {
|
||||||
|
parts.push(monitor.to_string());
|
||||||
|
}
|
||||||
|
if *without_pad {
|
||||||
|
parts.push("-p".to_string());
|
||||||
|
}
|
||||||
|
parts.join("\t")
|
||||||
|
}
|
||||||
|
HlwmCommand::Pad { monitor, pad } => format!("{self}\t{monitor}\t{pad}"),
|
||||||
};
|
};
|
||||||
if let Some(s) = cmd_string.strip_suffix('\t') {
|
if let Some(s) = cmd_string.strip_suffix('\t') {
|
||||||
return s.to_string();
|
return s.to_string();
|
||||||
|
@ -751,6 +743,7 @@ mod test {
|
||||||
hlwmbool::ToggleBool,
|
hlwmbool::ToggleBool,
|
||||||
hook::Hook,
|
hook::Hook,
|
||||||
key::{Key, KeyUnbind, MouseButton, Mousebind, MousebindAction},
|
key::{Key, KeyUnbind, MouseButton, Mousebind, MousebindAction},
|
||||||
|
pad::Pad,
|
||||||
rule::{Condition, Consequence, Rule, RuleOperator},
|
rule::{Condition, Consequence, Rule, RuleOperator},
|
||||||
setting::{Setting, SettingName},
|
setting::{Setting, SettingName},
|
||||||
window::Window,
|
window::Window,
|
||||||
|
@ -994,6 +987,23 @@ mod test {
|
||||||
})),
|
})),
|
||||||
"silent\tmerge_tag\tdefault".into(),
|
"silent\tmerge_tag\tdefault".into(),
|
||||||
),
|
),
|
||||||
|
HlwmCommand::MonitorRect {
|
||||||
|
monitor: _,
|
||||||
|
without_pad: _,
|
||||||
|
} => (
|
||||||
|
HlwmCommand::MonitorRect {
|
||||||
|
monitor: Some(1),
|
||||||
|
without_pad: true,
|
||||||
|
},
|
||||||
|
"monitor_rect\t1\t-p".into(),
|
||||||
|
),
|
||||||
|
HlwmCommand::Pad { monitor: _, pad: _ } => (
|
||||||
|
HlwmCommand::Pad {
|
||||||
|
monitor: 1,
|
||||||
|
pad: Pad::UpRightDownLeft(2, 3, 4, 5),
|
||||||
|
},
|
||||||
|
"pad\t1\t2\t3\t4\t5".into(),
|
||||||
|
),
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
for (command, expected_string) in commands {
|
for (command, expected_string) in commands {
|
||||||
|
|
|
@ -48,6 +48,17 @@ macro_rules! gen_parse {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
(Argument $$args:ident: [Flag($pat:literal)]) => {
|
||||||
|
{
|
||||||
|
let mut args = $$args.clone().into_iter();
|
||||||
|
let mut flag = false;
|
||||||
|
if args.any(|i| i == $pat) {
|
||||||
|
$$args = $$args.filter(|a| a != $pat).collect::<Vec<_>>().into_iter();
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
flag
|
||||||
|
}
|
||||||
|
};
|
||||||
(Argument $$args:ident: String) => {
|
(Argument $$args:ident: String) => {
|
||||||
$$args
|
$$args
|
||||||
.next()
|
.next()
|
||||||
|
|
|
@ -2,7 +2,6 @@ use std::{
|
||||||
convert::Infallible,
|
convert::Infallible,
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
num::{ParseFloatError, ParseIntError},
|
num::{ParseFloatError, ParseIntError},
|
||||||
os::unix::process::ExitStatusExt,
|
|
||||||
process::{self, Stdio},
|
process::{self, Stdio},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
@ -12,6 +11,8 @@ use serde::{Deserialize, Serialize};
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::cmd;
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
attribute::{Attribute, AttributeError},
|
attribute::{Attribute, AttributeError},
|
||||||
command::{CommandError, HlwmCommand},
|
command::{CommandError, HlwmCommand},
|
||||||
|
@ -28,6 +29,7 @@ mod hlwmbool;
|
||||||
pub mod hook;
|
pub mod hook;
|
||||||
pub mod key;
|
pub mod key;
|
||||||
mod octal;
|
mod octal;
|
||||||
|
pub mod pad;
|
||||||
pub mod rule;
|
pub mod rule;
|
||||||
pub mod setting;
|
pub mod setting;
|
||||||
mod split;
|
mod split;
|
||||||
|
@ -61,46 +63,15 @@ impl Client {
|
||||||
let args = command.args();
|
let args = command.args();
|
||||||
debug!("running command: [{}]", (&args).join(" "),);
|
debug!("running command: [{}]", (&args).join(" "),);
|
||||||
let output = Self::herbstclient()
|
let output = Self::herbstclient()
|
||||||
|
.arg("--no-newline")
|
||||||
.args(args)
|
.args(args)
|
||||||
.stderr(Stdio::null())
|
.stderr(Stdio::null())
|
||||||
.stdin(Stdio::null())
|
.stdin(Stdio::null())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()?
|
.spawn()?
|
||||||
.wait_with_output()?;
|
.wait_with_output()?;
|
||||||
let exit_status = output.status;
|
cmd::check_status(&output)?;
|
||||||
if let Some(code) = exit_status.code() {
|
Ok(output)
|
||||||
if code == 0 {
|
|
||||||
return Ok(output);
|
|
||||||
} else {
|
|
||||||
let output = String::from_utf8(output.stdout)
|
|
||||||
.unwrap_or_default()
|
|
||||||
.trim()
|
|
||||||
.to_string();
|
|
||||||
error!("command failed with error code [{code}]");
|
|
||||||
if !output.is_empty() {
|
|
||||||
error!("command output: {output}");
|
|
||||||
}
|
|
||||||
return Err(CommandError::StatusCode(
|
|
||||||
code,
|
|
||||||
if output.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(output)
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(signal) = exit_status.signal() {
|
|
||||||
return Err(CommandError::KilledBySignal {
|
|
||||||
signal,
|
|
||||||
core_dumped: exit_status.core_dumped(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if let Some(signal) = exit_status.stopped_signal() {
|
|
||||||
return Err(CommandError::StoppedBySignal(signal));
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(CommandError::OtherExitStatus(exit_status))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute_iter<I>(&self, commands: I) -> Result<(), (HlwmCommand, CommandError)>
|
pub fn execute_iter<I>(&self, commands: I) -> Result<(), (HlwmCommand, CommandError)>
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
use std::{fmt::Display, str::FromStr};
|
||||||
|
|
||||||
|
use crate::hlwm::split;
|
||||||
|
|
||||||
|
use super::StringParseError;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum Pad {
|
||||||
|
Unchanged,
|
||||||
|
Up(u32),
|
||||||
|
UpRight(u32, u32),
|
||||||
|
UpRightDown(u32, u32, u32),
|
||||||
|
UpRightDownLeft(u32, u32, u32, u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Pad {
|
||||||
|
type Err = StringParseError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let parts = split::tab_or_space(s);
|
||||||
|
match parts.len() {
|
||||||
|
0 => Err(StringParseError::InvalidLength(0, "pad")),
|
||||||
|
1 => Ok(Pad::Up(parts[0].parse()?)),
|
||||||
|
2 => Ok(Pad::UpRight(parts[0].parse()?, parts[1].parse()?)),
|
||||||
|
3 => Ok(Pad::UpRightDown(
|
||||||
|
parts[0].parse()?,
|
||||||
|
parts[1].parse()?,
|
||||||
|
parts[2].parse()?,
|
||||||
|
)),
|
||||||
|
_ => Ok(Pad::UpRightDownLeft(
|
||||||
|
parts[0].parse()?,
|
||||||
|
parts[1].parse()?,
|
||||||
|
parts[2].parse()?,
|
||||||
|
parts[3].parse()?,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Pad {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Pad::Unchanged => Ok(()),
|
||||||
|
Pad::Up(up) => f.write_str(&up.to_string()),
|
||||||
|
Pad::UpRight(up, right) => write!(f, "{up}\t{right}"),
|
||||||
|
Pad::UpRightDown(up, right, down) => write!(f, "{up}\t{right}\t{down}"),
|
||||||
|
Pad::UpRightDownLeft(up, right, down, left) => {
|
||||||
|
write!(f, "{up}\t{right}\t{down}\t{left}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Pad {
|
||||||
|
fn default() -> Self {
|
||||||
|
Pad::Unchanged
|
||||||
|
}
|
||||||
|
}
|
18
src/main.rs
18
src/main.rs
|
@ -5,8 +5,10 @@ use clap::{Parser, Subcommand};
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
|
|
||||||
|
pub mod cmd;
|
||||||
mod config;
|
mod config;
|
||||||
mod hlwm;
|
mod hlwm;
|
||||||
|
mod panel;
|
||||||
|
|
||||||
#[derive(Parser, Debug, Clone)]
|
#[derive(Parser, Debug, Clone)]
|
||||||
#[command(name = "hlctl")]
|
#[command(name = "hlctl")]
|
||||||
|
@ -19,13 +21,6 @@ struct Args {
|
||||||
enum HlctlCommand {
|
enum HlctlCommand {
|
||||||
/// Initialize herbstluftwm, should be run from the autostart script
|
/// Initialize herbstluftwm, should be run from the autostart script
|
||||||
Init,
|
Init,
|
||||||
#[command(arg_required_else_help = true)]
|
|
||||||
/// Draws notifications using dzen2
|
|
||||||
Notify {
|
|
||||||
/// Amount of seconds to persist for
|
|
||||||
#[arg(short = 's', long = None, default_value_t = 1)]
|
|
||||||
seconds: u8,
|
|
||||||
},
|
|
||||||
/// Save the currently loaded configuration to file
|
/// Save the currently loaded configuration to file
|
||||||
#[command(long_about = r#"
|
#[command(long_about = r#"
|
||||||
`save` Tries to find an existing config file. If not present, the default config is used.
|
`save` Tries to find an existing config file. If not present, the default config is used.
|
||||||
|
@ -34,7 +29,9 @@ enum HlctlCommand {
|
||||||
|
|
||||||
The configuration file located at $HOME/.config/herbstluftwm/hlctl.toml"#)]
|
The configuration file located at $HOME/.config/herbstluftwm/hlctl.toml"#)]
|
||||||
Save,
|
Save,
|
||||||
|
/// Print the toml config to stdout
|
||||||
PrintConfig,
|
PrintConfig,
|
||||||
|
/// Start the top panel
|
||||||
Panel,
|
Panel,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,10 +41,13 @@ fn main() {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
match args.command {
|
match args.command {
|
||||||
HlctlCommand::Init => init(),
|
HlctlCommand::Init => init(),
|
||||||
HlctlCommand::Notify { seconds } => println!("notify for {seconds}"),
|
|
||||||
HlctlCommand::Save => save(),
|
HlctlCommand::Save => save(),
|
||||||
HlctlCommand::PrintConfig => print_config(),
|
HlctlCommand::PrintConfig => print_config(),
|
||||||
HlctlCommand::Panel => todo!(),
|
HlctlCommand::Panel => {
|
||||||
|
if let Err(err) = panel::panel(&merged_config()) {
|
||||||
|
error!("panel: {err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
use cnx::{
|
||||||
|
text::{Attributes, Font, Padding, PagerAttributes},
|
||||||
|
widgets::{ActiveWindowTitle, Clock, Pager},
|
||||||
|
Cnx,
|
||||||
|
};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
config::Config,
|
||||||
|
hlwm::{
|
||||||
|
color::{Color, X11Color},
|
||||||
|
command::CommandError,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
type Result<T> = std::result::Result<T, PanelError>;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum PanelError {
|
||||||
|
#[error("command error: [{0}]")]
|
||||||
|
CommandError(#[from] CommandError),
|
||||||
|
#[error("io lib error: [{0}]")]
|
||||||
|
IoError(#[from] std::io::Error),
|
||||||
|
#[error("cnx panel error: [{0}]")]
|
||||||
|
CnxPanelError(#[from] anyhow::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn panel(config: &Config) -> Result<()> {
|
||||||
|
let font = Font::new(&config.font_pango);
|
||||||
|
let font_bold = Font::new(&config.font_pango_bold);
|
||||||
|
let (active, normal, text) = (
|
||||||
|
config
|
||||||
|
.theme
|
||||||
|
.active_color()
|
||||||
|
.expect("could not get theme's active color"),
|
||||||
|
config
|
||||||
|
.theme
|
||||||
|
.normal_color()
|
||||||
|
.expect("could not get theme's normal color"),
|
||||||
|
config
|
||||||
|
.theme
|
||||||
|
.text_color()
|
||||||
|
.expect("could not get theme's text color"),
|
||||||
|
);
|
||||||
|
let attr = Attributes {
|
||||||
|
font: font.clone(),
|
||||||
|
fg_color: text.into(),
|
||||||
|
bg_color: Some(Color::BLACK.into()),
|
||||||
|
padding: Padding::new(10.0, 10.0, 0.0, 0.0),
|
||||||
|
};
|
||||||
|
let pager_attr = PagerAttributes {
|
||||||
|
active_attr: Attributes {
|
||||||
|
font: font_bold.clone(),
|
||||||
|
fg_color: text.into(),
|
||||||
|
bg_color: Some(active.into()),
|
||||||
|
padding: Padding::new(8.0, 8.0, 0.0, 0.0),
|
||||||
|
},
|
||||||
|
inactive_attr: Attributes {
|
||||||
|
font: font.clone(),
|
||||||
|
fg_color: Color::X11(X11Color::DimGray).into(),
|
||||||
|
bg_color: Some(Color::BLACK.into()),
|
||||||
|
padding: Padding::new(5.0, 5.0, 0.0, 0.0),
|
||||||
|
},
|
||||||
|
non_empty_attr: Attributes {
|
||||||
|
font: font.clone(),
|
||||||
|
fg_color: text.into(),
|
||||||
|
bg_color: Some(normal.into()),
|
||||||
|
padding: Padding::new(5.0, 5.0, 0.0, 0.0),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut cnx = Cnx::new(cnx::Position::Top);
|
||||||
|
cnx.add_widget(Pager::new(pager_attr));
|
||||||
|
cnx.add_widget(ActiveWindowTitle::new(attr.clone()));
|
||||||
|
cnx.add_widget(Clock::new(
|
||||||
|
attr.clone(),
|
||||||
|
Some(String::from("%H:%M %a %Y-%m-%d")),
|
||||||
|
));
|
||||||
|
cnx.run()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue