use serde::{Serialize, Serializer};
macro_rules! string_enum {
($(#[$m:meta])* $name:ident { $($(#[$vm:meta])* $var:ident = $s:literal),* $(,)? }) => {
$(#[$m])*
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum $name {
$($(#[$vm])* $var,)*
Other(String),
}
impl $name {
pub fn as_str(&self) -> &str {
match self {
$(Self::$var => $s,)*
Self::Other(s) => s,
}
}
}
impl From<&str> for $name {
fn from(s: &str) -> Self {
match s {
$($s => Self::$var,)*
_ => Self::Other(s.to_owned()),
}
}
}
impl From<String> for $name {
fn from(s: String) -> Self {
Self::from(s.as_str())
}
}
impl ::std::fmt::Display for $name {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
f.write_str(self.as_str())
}
}
impl ::serde::Serialize for $name {
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
s.serialize_str(self.as_str())
}
}
};
}
pub(crate) use string_enum;
string_enum!(
Tone {
Neutral = "neutral",
Accent = "accent",
Info = "info",
Success = "success",
Warning = "warning",
Error = "error",
Pending = "pending",
Muted = "muted",
User = "user",
}
);
string_enum!(
Status {
Pending = "pending",
Running = "running",
Done = "done",
Error = "error",
Cancelled = "cancelled",
}
);
string_enum!(
AgentStatus {
Pending = "pending",
Running = "running",
Done = "done",
Failed = "failed",
Aborted = "aborted",
Idle = "idle",
Parked = "parked",
}
);
string_enum!(
Mark {
Pick = "pick",
Drop = "drop",
}
);
string_enum!(
Gap {
None = "none",
Xs = "xs",
Sm = "sm",
Md = "md",
Lg = "lg",
}
);
string_enum!(
Align {
Start = "start",
Center = "center",
End = "end",
Baseline = "baseline",
Stretch = "stretch",
}
);
string_enum!(
Justify {
Between = "between",
End = "end",
}
);
string_enum!(
Wrap {
Word = "word",
Char = "char",
None = "none",
}
);
string_enum!(
Truncate {
End = "end",
Start = "start",
Middle = "middle",
}
);
string_enum!(
TextAlign {
Start = "start",
Center = "center",
End = "end",
}
);
string_enum!(
Fx {
Shimmer = "shimmer",
Pulse = "pulse",
None = "none",
}
);
string_enum!(
Token {
Muted = "muted",
Dim = "dim",
Strong = "strong",
Em = "em",
Accent = "accent",
Success = "success",
Warning = "warning",
Error = "error",
Info = "info",
Code = "code",
Mono = "mono",
Path = "path",
Key = "key",
Link = "link",
Num = "num",
Ins = "ins",
Del = "del",
Mark = "mark",
Typo = "typo",
Icon = "icon",
Hide = "hide",
}
);
string_enum!(
SpinnerStyle {
Braille = "braille",
Dots = "dots",
Starburst = "starburst",
Orbit = "orbit",
}
);
string_enum!(
ShimmerMode {
Classic = "classic",
Kitt = "kitt",
}
);
string_enum!(
ElapsedFormat {
Short = "short",
Clock = "clock",
}
);
string_enum!(
MeterStyle {
Bar = "bar",
Ring = "ring",
Blocks = "blocks",
}
);
string_enum!(
Size {
Sm = "sm",
Md = "md",
Lg = "lg",
}
);
string_enum!(
ChartKind {
Heatmap = "heatmap",
Bars = "bars",
Spark = "spark",
}
);
string_enum!(
EffortLevel {
Off = "off",
Minimal = "minimal",
Low = "low",
Medium = "medium",
High = "high",
Xhigh = "xhigh",
Max = "max",
}
);
string_enum!(
DiffMode {
Unified = "unified",
Split = "split",
Auto = "auto",
}
);
string_enum!(
KvLayout {
Grid = "grid",
Inline = "inline",
}
);
string_enum!(
Measure {
Prose = "prose",
}
);
string_enum!(
CardVariant {
Bare = "bare",
}
);
string_enum!(
PickerSize {
Md = "md",
Lg = "lg",
Screen = "screen",
}
);
string_enum!(
PickerLayout {
Rows = "rows",
Cards = "cards",
Timeline = "timeline",
Tree = "tree",
}
);
string_enum!(
PickerPreview {
Side = "side",
Below = "below",
None = "none",
}
);
string_enum!(
PickerFocus {
List = "list",
Scopes = "scopes",
Tabs = "tabs",
Strip = "strip",
Preview = "preview",
}
);
string_enum!(
PickerState {
Ready = "ready",
Loading = "loading",
Error = "error",
}
);
string_enum!(
TargetKind {
Command = "command",
Path = "path",
Pattern = "pattern",
Query = "query",
Text = "text",
}
);
string_enum!(
ToolFrame {
Card = "card",
Inline = "inline",
}
);
string_enum!(
ChecklistMode {
Full = "full",
Hud = "hud",
Reminder = "reminder",
}
);
string_enum!(
ItemStatus {
Pending = "pending",
Active = "active",
Done = "done",
Dropped = "dropped",
Blocked = "blocked",
}
);
string_enum!(
OverlaySize {
Sm = "sm",
Md = "md",
Lg = "lg",
Full = "full",
}
);
string_enum!(
Side {
Right = "right",
}
);
string_enum!(
ColumnFormat {
Text = "text",
Num = "num",
Price = "price",
Bar = "bar",
Time = "time",
Elapsed = "elapsed",
Dim = "dim",
}
);
string_enum!(
ChoiceStyle {
Auto = "auto",
Segmented = "segmented",
Menu = "menu",
}
);
string_enum!(
InputType {
Checkbox = "checkbox",
Radio = "radio",
}
);
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct Span {
pub t: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub s: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fx: Option<Fx>,
#[serde(skip_serializing_if = "Option::is_none")]
pub href: Option<String>,
}
impl Span {
pub fn new(t: impl Into<String>) -> Self {
Self { t: t.into(), ..Self::default() }
}
pub fn style(mut self, token: impl Into<Token>) -> Self {
let token = token.into();
self.s = Some(match self.s.take() {
Some(s) if !s.is_empty() => format!("{s} {token}"),
_ => token.to_string(),
});
self
}
pub fn fx(mut self, fx: impl Into<Fx>) -> Self {
self.fx = Some(fx.into());
self
}
pub fn href(mut self, href: impl Into<String>) -> Self {
self.href = Some(href.into());
self
}
}
impl From<&str> for Span {
fn from(t: &str) -> Self {
Self::new(t)
}
}
impl From<String> for Span {
fn from(t: String) -> Self {
Self::new(t)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Text {
Plain(String),
Spans(Vec<Span>),
}
impl Text {
pub fn plain(&self) -> String {
match self {
Self::Plain(s) => s.clone(),
Self::Spans(spans) => spans.iter().map(|s| s.t.as_str()).collect(),
}
}
}
impl Default for Text {
fn default() -> Self {
Self::Plain(String::new())
}
}
impl Serialize for Text {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
match self {
Self::Plain(t) => s.serialize_str(t),
Self::Spans(spans) => spans.serialize(s),
}
}
}
impl From<&str> for Text {
fn from(t: &str) -> Self {
Self::Plain(t.to_owned())
}
}
impl From<String> for Text {
fn from(t: String) -> Self {
Self::Plain(t)
}
}
impl From<&String> for Text {
fn from(t: &String) -> Self {
Self::Plain(t.clone())
}
}
impl From<Span> for Text {
fn from(span: Span) -> Self {
Self::Spans(vec![span])
}
}
impl From<Vec<Span>> for Text {
fn from(spans: Vec<Span>) -> Self {
Self::Spans(spans)
}
}
impl<const N: usize> From<[Span; N]> for Text {
fn from(spans: [Span; N]) -> Self {
Self::Spans(spans.into())
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Extent {
Ch(f64),
Lines(f64),
Fraction(f64),
}
impl Serialize for Extent {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
match *self {
Self::Ch(n) => s.collect_str(&format_args!("{n}ch")),
Self::Lines(n) => s.collect_str(&format_args!("{n}lines")),
Self::Fraction(f) => s.serialize_f64(f),
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize)]
pub struct Bound {
#[serde(skip_serializing_if = "Option::is_none")]
pub w: Option<Extent>,
#[serde(skip_serializing_if = "Option::is_none")]
pub h: Option<Extent>,
}
impl Bound {
pub const fn w(w: Extent) -> Self {
Self { w: Some(w), h: None }
}
pub const fn h(h: Extent) -> Self {
Self { w: None, h: Some(h) }
}
pub const fn wh(w: Extent, h: Extent) -> Self {
Self { w: Some(w), h: Some(h) }
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Basis {
Fraction(f64),
Content,
}
impl Serialize for Basis {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
match *self {
Self::Fraction(f) => s.serialize_f64(f),
Self::Content => s.serialize_str("content"),
}
}
}
impl From<f64> for Basis {
fn from(f: f64) -> Self {
Self::Fraction(f)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum NodeKey {
Str(String),
Int(i64),
}
impl Serialize for NodeKey {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
match self {
Self::Str(k) => s.serialize_str(k),
Self::Int(n) => s.serialize_i64(*n),
}
}
}
impl From<&str> for NodeKey {
fn from(k: &str) -> Self {
Self::Str(k.to_owned())
}
}
impl From<String> for NodeKey {
fn from(k: String) -> Self {
Self::Str(k)
}
}
impl From<&String> for NodeKey {
fn from(k: &String) -> Self {
Self::Str(k.clone())
}
}
macro_rules! int_key {
($($t:ty),*) => {
$(impl From<$t> for NodeKey {
fn from(n: $t) -> Self {
Self::Int(n as i64)
}
})*
};
}
int_key!(i32, i64, u32, u64, usize);
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct Actions {
#[serde(skip_serializing_if = "Option::is_none")]
pub click: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dblclick: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub menu: Vec<String>,
}
impl Actions {
pub fn new() -> Self {
Self::default()
}
pub fn click(mut self, act: impl Into<String>) -> Self {
self.click = Some(act.into());
self
}
pub fn dblclick(mut self, act: impl Into<String>) -> Self {
self.dblclick = Some(act.into());
self
}
pub fn menu(mut self, act: impl Into<String>) -> Self {
self.menu.push(act.into());
self
}
}