blob: 8969caf61b09e6d287e2f4ed213691d25ae82407 [file] [log] [blame] [edit]
macro_rules! set_enum {
($T:ident { $($v:ident),+ $(,)? }) => {
impl $T {
pub(crate) const fn bit_mask(self) -> u16 {
1 << self as u16
}
pub(crate) const fn from_bit_mask(value: u16) -> Option<Self> {
$(if (value == $T::$v.bit_mask()) { return Some($T::$v); })+
None
}
}
impl crate::set::Set<$T> {
#[must_use]
pub const fn insert(mut self, value: $T) -> Self {
self.1 |= value.bit_mask();
self
}
}
impl crate::set::SetMember for $T {
const MAX_VALUE: u8 = { $($T::$v as u8);+ };
fn bit_mask(self) -> u16 { <$T>::bit_mask(self) }
fn from_bit_mask(v: u16) -> Option<Self> { <$T>::from_bit_mask(v) }
}
};
}
macro_rules! constructor {
(
[$($q:tt)*] $r:ty, $R:ty, $p:ident,
$(#[$pattr:meta])* $prop:ident => $V:path $([$($a:ident : $T:ty),+])?
) => {
/// Returns `self` with the
#[doc = concat!("[`", stringify!($p), "()`](Self::", stringify!($p), "())")]
/// set to
#[doc = concat!("[`", stringify!($V), "`].")]
///
/// # Example
///
/// ```rust
#[doc = concat!(
"# let value = yansi::Painted::new(0);",
$($("\n# let ", stringify!($a), " = 0;"),+)?
)]
#[doc = concat!(
"println!(\"{}\", value.", stringify!($prop), "(", $(stringify!($($a),+),)? "));"
)]
/// ```
#[inline]
$(#[$pattr])*
$($q)* fn $prop(self: $r $($(,$a: $T)+)?) -> $R {
let v = $V $(($($a),*))?;
self.apply(crate::style::Application::$p(v))
}
};
([$($q:tt)*] $(#[$attr:meta])* $r:ty, $R:ty, $kind:ident ($A:ty)) => {
$(#[$attr])*
#[inline]
$($q)* fn $kind(self: $r, value: $A) -> $R {
self.apply(crate::style::Application::$kind(value))
}
};
}
macro_rules! signature {
(
[$($q:tt)*] $r:ty, $R:ty, $p:ident,
$(#[$pattr:meta])* $prop:ident => $V:path $([$($a:ident : $T:ty),+])?
) => {
/// Returns `self` with the
#[doc = concat!("[`", stringify!($p), "()`](Self::", stringify!($p), "())")]
/// set to
#[doc = concat!("[`", stringify!($V), "`].")]
///
/// # Example
///
/// ```rust
#[doc = concat!(
"# let value = yansi::Painted::new(0);",
$($("\n# let ", stringify!($a), " = 0;"),+)?
)]
#[doc = concat!(
"println!(\"{}\", value.", stringify!($prop), "(", $(stringify!($($a),+),)? "));"
)]
/// ```
$(#[$pattr])*
$($q)* fn $prop(self: $r $($(,$a: $T)+)?) -> $R;
};
([$($q:tt)*] $(#[$attr:meta])* $r:ty, $R:ty, $kind:ident ($A:ty)) => {
$(#[$attr])*
$($q)* fn $kind(self: $r, value: $A) -> $R;
};
}
macro_rules! define_property {
([$d:tt] $(#[$attr:meta])* $kind:ident ($A:ty) {
$($(#[$pattr:meta])* $prop:ident => $V:path $([$($a:tt)*])?),* $(,)?
}) => {
macro_rules! $kind {
($d ([$d ($qual:tt)*])? $cont:ident ($r:ty) -> $R:ty) => (
$cont!([$d ($d ($qual)*)?] $(#[$attr])* $r, $R, $kind($A));
$(
$cont!(
[$d ($d ($qual)*)?]
$r, $R, $kind, $(#[$pattr])* $prop => $V $([$($a)*] )?
);
)*
)
}
};
($(#[$attr:meta])* $kind:ident ($A:ty)) => {
define_property!([$] $(#[$attr])* $kind ($A) {});
};
($($t:tt)*) => { define_property!([$] $($t)*); }
}
// Check that every variant of a property is covered.
macro_rules! check_property_exhaustiveness {
($A:ident $({ $($(#[$pattr:meta])* $p:ident => $V:path $([ $($a:tt)* ])?),* $(,)? })? ) => {
const _: () = {$(
use crate::*;
fn _check() {
#[allow(unreachable_code)]
match { let _v: $A = todo!(); _v } {
$($V { .. } => { },)*
}
}
)?};
}
}
macro_rules! define_properties {
($($(#[$attr:meta])* $kind:ident ($A:ident) $({ $($t:tt)* })?),* $(,)?) => {
$(define_property!($(#[$attr])* $kind($A) $({ $($t)* })?);)*
$(check_property_exhaustiveness!($A $({ $($t)* })?);)*
}
}
macro_rules! properties {
($([$($qual:tt)*])? $cont:ident ($r:ty) -> $R:ty) => (
fg!($([$($qual)*])? $cont ($r) -> $R);
bg!($([$($qual)*])? $cont ($r) -> $R);
attr!($([$($qual)*])? $cont ($r) -> $R);
quirk!($([$($qual)*])? $cont ($r) -> $R);
whenever!($([$($qual)*])? $cont ($r) -> $R);
)
}
define_properties! {
/// Returns a styled value derived from `self` with the foreground set to
/// `value`.
///
/// This method should be used rarely. Instead, prefer to use color-specific
/// builder methods like [`red()`](Self::red()) and
/// [`green()`](Self::green()), which have the same functionality but are
/// pithier.
///
/// # Example
///
/// Set foreground color to white using `fg()`:
///
/// ```rust
/// use yansi::{Paint, Color};
///
/// # let painted = ();
/// painted.fg(Color::White);
/// ```
///
/// Set foreground color to white using [`white()`](Self::white()).
///
/// ```rust
/// use yansi::Paint;
///
/// # let painted = ();
/// painted.white();
/// ```
fg(Color) {
primary => Color::Primary,
fixed => Color::Fixed[color: u8],
rgb => Color::Rgb[r: u8, g: u8, b: u8],
black => Color::Black,
red => Color::Red,
green => Color::Green,
yellow => Color::Yellow,
blue => Color::Blue,
magenta => Color::Magenta,
cyan => Color::Cyan,
white => Color::White,
bright_black => Color::BrightBlack,
bright_red => Color::BrightRed,
bright_green => Color::BrightGreen,
bright_yellow => Color::BrightYellow,
bright_blue => Color::BrightBlue,
bright_magenta => Color::BrightMagenta,
bright_cyan => Color::BrightCyan,
bright_white => Color::BrightWhite,
},
/// Returns a styled value derived from `self` with the background set to
/// `value`.
///
/// This method should be used rarely. Instead, prefer to use color-specific
/// builder methods like [`on_red()`](Self::on_red()) and
/// [`on_green()`](Self::on_green()), which have the same functionality but
/// are pithier.
///
/// # Example
///
/// Set background color to red using `fg()`:
///
/// ```rust
/// use yansi::{Paint, Color};
///
/// # let painted = ();
/// painted.bg(Color::Red);
/// ```
///
/// Set background color to red using [`on_red()`](Self::on_red()).
///
/// ```rust
/// use yansi::Paint;
///
/// # let painted = ();
/// painted.on_red();
/// ```
bg(Color) {
on_primary => Color::Primary,
on_fixed => Color::Fixed[color: u8],
on_rgb => Color::Rgb[r: u8, g: u8, b: u8],
on_black => Color::Black,
on_red => Color::Red,
on_green => Color::Green,
on_yellow => Color::Yellow,
on_blue => Color::Blue,
on_magenta => Color::Magenta,
on_cyan => Color::Cyan,
on_white => Color::White,
on_bright_black => Color::BrightBlack,
on_bright_red => Color::BrightRed,
on_bright_green => Color::BrightGreen,
on_bright_yellow => Color::BrightYellow,
on_bright_blue => Color::BrightBlue,
on_bright_magenta => Color::BrightMagenta,
on_bright_cyan => Color::BrightCyan,
on_bright_white => Color::BrightWhite,
},
/// Enables the styling [`Attribute`] `value`.
///
/// This method should be used rarely. Instead, prefer to use
/// attribute-specific builder methods like [`bold()`](Self::bold()) and
/// [`underline()`](Self::underline()), which have the same functionality
/// but are pithier.
///
/// # Example
///
/// Make text bold using `attr()`:
///
/// ```rust
/// use yansi::{Paint, Attribute};
///
/// # let painted = ();
/// painted.attr(Attribute::Bold);
/// ```
///
/// Make text bold using using [`bold()`](Self::bold()).
///
/// ```rust
/// use yansi::Paint;
///
/// # let painted = ();
/// painted.bold();
/// ```
attr(Attribute) {
bold => Attribute::Bold,
dim => Attribute::Dim,
italic => Attribute::Italic,
underline => Attribute::Underline,
blink => Attribute::Blink,
rapid_blink => Attribute::RapidBlink,
invert => Attribute::Invert,
conceal => Attribute::Conceal,
strike => Attribute::Strike,
},
/// Enables the `yansi` [`Quirk`] `value`.
///
/// This method should be used rarely. Instead, prefer to use quirk-specific
/// builder methods like [`mask()`](Self::mask()) and
/// [`wrap()`](Self::wrap()), which have the same functionality but are
/// pithier.
///
/// # Example
///
/// Enable wrapping using `.quirk()`:
///
/// ```rust
/// use yansi::{Paint, Quirk};
///
/// # let painted = ();
/// painted.quirk(Quirk::Wrap);
/// ```
///
/// Enable wrapping using [`wrap()`](Self::wrap()).
///
/// ```rust
/// use yansi::Paint;
///
/// # let painted = ();
/// painted.wrap();
/// ```
quirk(Quirk) {
mask => Quirk::Mask,
wrap => Quirk::Wrap,
linger => Quirk::Linger,
#[deprecated(
since = "1.0.1",
note = "renamed to `resetting()` due to conflicts with `Vec::clear()`.\n\
The `clear()` method will be removed in a future release."
)]
clear => Quirk::Clear,
resetting => Quirk::Resetting,
bright => Quirk::Bright,
on_bright => Quirk::OnBright,
},
/// Conditionally enable styling based on whether the [`Condition`] `value`
/// applies. Replaces any previous condition.
///
/// See the [crate level docs](crate#per-style) for more details.
///
/// # Example
///
/// Enable styling `painted` only when both `stdout` and `stderr` are TTYs:
///
/// ```rust
/// # #[cfg(feature = "detect-tty")] {
/// use yansi::{Paint, Condition};
///
/// # let painted = ();
/// painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);
/// # }
/// ```
whenever(Condition),
}
macro_rules! impl_fmt_trait {
($F:path, $f:literal <$G:ident> $T:ty => $s:ident.$v:ident ($V:ty)) => {
impl<$G: $F> $F for $T {
fn fmt(&$s, f: &mut core::fmt::Formatter) -> core::fmt::Result {
$s.fmt_args(&<$V>::fmt, f, format_args!($f, $s.$v))
}
}
};
}
macro_rules! impl_fmt_traits {
($($t:tt)*) => {
impl_fmt_trait!(core::fmt::Display, "{}" $($t)*);
impl_fmt_trait!(core::fmt::Debug, "{:?}" $($t)*);
impl_fmt_trait!(core::fmt::Octal, "{:o}" $($t)*);
impl_fmt_trait!(core::fmt::LowerHex, "{:x}" $($t)*);
impl_fmt_trait!(core::fmt::UpperHex, "{:X}" $($t)*);
impl_fmt_trait!(core::fmt::Pointer, "{:p}" $($t)*);
impl_fmt_trait!(core::fmt::Binary, "{:b}" $($t)*);
impl_fmt_trait!(core::fmt::LowerExp, "{:e}" $($t)*);
impl_fmt_trait!(core::fmt::UpperExp, "{:E}" $($t)*);
};
}