use std::collections::BTreeMap;
use serde::{Serialize, Serializer, ser::SerializeMap};
use serde_json::Value;
use super::{
icon::Icon,
types::{
AvatarVariant, ButtonVariant, ChoiceStyle, ColumnFormat, Disabled, ItemStatus, SortDir,
Status, Text, TextAlign, Tone, Truncate,
},
};
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct KvItem {
pub k: Text,
pub v: Text,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct Column {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub head: Option<Text>,
#[serde(skip_serializing_if = "Option::is_none")]
pub align: Option<TextAlign>,
#[serde(skip_serializing_if = "Option::is_none")]
pub truncate: Option<Truncate>,
#[serde(skip_serializing_if = "Option::is_none")]
pub priority: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub grow: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mono: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sortable: Option<bool>,
}
impl Column {
pub fn new(id: impl Into<String>, head: impl Into<Text>) -> Self {
Self { id: id.into(), head: Some(head.into()), ..Self::default() }
}
pub fn align(mut self, align: impl Into<TextAlign>) -> Self {
self.align = Some(align.into());
self
}
pub const fn grow(mut self, grow: f64) -> Self {
self.grow = Some(grow);
self
}
pub const fn priority(mut self, priority: f64) -> Self {
self.priority = Some(priority);
self
}
pub fn truncate(mut self, truncate: impl Into<Truncate>) -> Self {
self.truncate = Some(truncate.into());
self
}
pub const fn mono(mut self, mono: bool) -> Self {
self.mono = Some(mono);
self
}
pub const fn sortable(mut self, sortable: bool) -> Self {
self.sortable = Some(sortable);
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct Part {
pub value: f64,
#[serde(skip_serializing_if = "Option::is_none")]
pub token: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hatch: Option<bool>,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize)]
pub struct Thresholds {
#[serde(skip_serializing_if = "Option::is_none")]
pub warn: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bad: Option<f64>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct MeterCell {
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<f64>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub parts: Vec<Part>,
#[serde(skip_serializing_if = "Option::is_none")]
pub thresholds: Option<Thresholds>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tone: Option<Tone>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct TextCell {
pub text: Text,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<Icon>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dot: Option<Tone>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tone: Option<Tone>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
}
impl TextCell {
pub fn new(text: impl Into<Text>) -> Self {
Self { text: text.into(), ..Self::default() }
}
pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
self.icon = Some(icon.into());
self
}
pub fn dot(mut self, tone: impl Into<Tone>) -> Self {
self.dot = Some(tone.into());
self
}
pub fn tone(mut self, tone: impl Into<Tone>) -> Self {
self.tone = Some(tone.into());
self
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct ButtonCell {
pub text: String,
pub act: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<Icon>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub keys: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub variant: Option<ButtonVariant>,
#[serde(skip_serializing_if = "Option::is_none")]
pub disabled: Option<Disabled>,
}
impl ButtonCell {
pub fn new(text: impl Into<String>, act: impl Into<String>) -> Self {
Self { text: text.into(), act: act.into(), ..Self::default() }
}
pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
self.icon = Some(icon.into());
self
}
pub fn keys<K: Into<String>>(mut self, keys: impl IntoIterator<Item = K>) -> Self {
self.keys = keys.into_iter().map(Into::into).collect();
self
}
pub fn variant(mut self, variant: impl Into<ButtonVariant>) -> Self {
self.variant = Some(variant.into());
self
}
pub fn disabled(mut self, disabled: impl Into<Disabled>) -> Self {
self.disabled = Some(disabled.into());
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct SparkCell {
pub values: Vec<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tone: Option<Tone>,
#[serde(skip_serializing_if = "Option::is_none")]
pub min: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
}
impl SparkCell {
pub fn new(values: impl Into<Vec<f64>>) -> Self {
Self { values: values.into(), ..Self::default() }
}
pub fn tone(mut self, tone: impl Into<Tone>) -> Self {
self.tone = Some(tone.into());
self
}
pub const fn range(mut self, min: f64, max: f64) -> Self {
self.min = Some(min);
self.max = Some(max);
self
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Cell {
Text(Text),
Meter(MeterCell),
Rich(TextCell),
Badge(BadgeSpec),
Button(ButtonCell),
Spark(SparkCell),
}
impl Serialize for Cell {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
fn one<S: Serializer>(s: S, key: &str, value: &impl Serialize) -> Result<S::Ok, S::Error> {
let mut map = s.serialize_map(Some(1))?;
map.serialize_entry(key, value)?;
map.end()
}
match self {
Self::Text(t) => t.serialize(s),
Self::Rich(c) => c.serialize(s),
Self::Meter(m) => one(s, "meter", m),
Self::Badge(b) => one(s, "badge", b),
Self::Button(b) => one(s, "button", b),
Self::Spark(c) => one(s, "spark", c),
}
}
}
impl<T: Into<Text>> From<T> for Cell {
fn from(t: T) -> Self {
Self::Text(t.into())
}
}
impl From<MeterCell> for Cell {
fn from(m: MeterCell) -> Self {
Self::Meter(m)
}
}
impl From<TextCell> for Cell {
fn from(c: TextCell) -> Self {
Self::Rich(c)
}
}
impl From<BadgeSpec> for Cell {
fn from(b: BadgeSpec) -> Self {
Self::Badge(b)
}
}
impl From<ButtonCell> for Cell {
fn from(b: ButtonCell) -> Self {
Self::Button(b)
}
}
impl From<SparkCell> for Cell {
fn from(c: SparkCell) -> Self {
Self::Spark(c)
}
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct TableRow {
pub id: String,
pub cells: BTreeMap<String, Cell>,
#[serde(skip_serializing_if = "Option::is_none")]
pub disabled: Option<Disabled>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub menu: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
}
impl TableRow {
pub fn new(id: impl Into<String>) -> Self {
Self { id: id.into(), ..Self::default() }
}
pub fn disabled(mut self, disabled: impl Into<Disabled>) -> Self {
self.disabled = Some(disabled.into());
self
}
pub fn menu(mut self, act: impl Into<String>) -> Self {
self.menu.push(act.into());
self
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
pub fn cell(mut self, col: impl Into<String>, cell: impl Into<Cell>) -> Self {
self.cells.insert(col.into(), cell.into());
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct TreeItem {
pub id: String,
pub label: Text,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<Icon>,
#[serde(skip_serializing_if = "Option::is_none")]
pub open: Option<bool>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub children: Vec<Self>,
}
impl TreeItem {
pub fn new(id: impl Into<String>, label: impl Into<Text>) -> Self {
Self { id: id.into(), label: label.into(), ..Self::default() }
}
pub fn child(mut self, item: Self) -> Self {
self.children.push(item);
self
}
pub const fn open(mut self, open: bool) -> Self {
self.open = Some(open);
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct Tab {
pub id: String,
pub label: Text,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct CodeMark {
pub line: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub tone: Option<Tone>,
#[serde(skip_serializing_if = "Option::is_none")]
pub heat: Option<f64>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub ranges: Vec<[u64; 2]>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub wash: Vec<f64>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct CodeFold {
pub from: u64,
pub to: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub note: Option<Text>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tone: Option<Tone>,
#[serde(skip_serializing_if = "Option::is_none")]
pub open: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hovercard: Option<Value>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Hunk {
#[serde(skip_serializing_if = "Option::is_none")]
pub old_start: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_start: Option<u64>,
pub lines: Vec<String>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct Decor {
pub from: usize,
pub to: usize,
pub s: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub fx: Option<super::types::Fx>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct ShimmerPalette {
#[serde(skip_serializing_if = "Option::is_none")]
pub low: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub high: Option<String>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct MeterMark {
pub at: f64,
#[serde(skip_serializing_if = "Option::is_none")]
pub tone: Option<Tone>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<Icon>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct Point {
pub value: f64,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tone: Option<Tone>,
#[serde(skip_serializing_if = "Option::is_none")]
pub token: Option<String>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct Series {
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub token: Option<String>,
pub values: Vec<Option<f64>>,
}
impl Series {
pub fn new(values: impl Into<Vec<Option<f64>>>) -> Self {
Self { values: values.into(), ..Self::default() }
}
pub fn label(mut self, label: impl Into<String>) -> Self {
self.label = Some(label.into());
self
}
pub fn token(mut self, token: impl Into<String>) -> Self {
self.token = Some(token.into());
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct ChartMark {
pub value: f64,
#[serde(skip_serializing_if = "Option::is_none")]
pub tone: Option<Tone>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct ChartCol {
pub at: u32,
pub label: String,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Anchor {
Center,
Top,
Bottom,
Node {
id: String,
above: bool,
},
Caret(String),
}
impl Serialize for Anchor {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeMap as _;
match self {
Self::Center => s.serialize_str("center"),
Self::Top => s.serialize_str("top"),
Self::Bottom => s.serialize_str("bottom"),
Self::Node { id, above } => {
let mut m = s.serialize_map(Some(2))?;
m.serialize_entry("node", id)?;
m.serialize_entry("side", if *above { "above" } else { "below" })?;
m.end()
},
Self::Caret(id) => {
let mut m = s.serialize_map(Some(1))?;
m.serialize_entry("caret", id)?;
m.end()
},
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct BadgeSpec {
pub text: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub tone: Option<Tone>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
}
impl BadgeSpec {
pub fn new(text: impl Into<String>) -> Self {
Self { text: text.into(), ..Self::default() }
}
pub fn tone(mut self, tone: impl Into<Tone>) -> Self {
self.tone = Some(tone.into());
self
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct StatItem {
pub label: Text,
pub value: Text,
#[serde(skip_serializing_if = "Option::is_none")]
pub sub: Option<Text>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tone: Option<Tone>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
}
impl StatItem {
pub fn new(label: impl Into<Text>, value: impl Into<Text>) -> Self {
Self { label: label.into(), value: value.into(), ..Self::default() }
}
#[expect(clippy::should_implement_trait, reason = "named after the wire prop `sub`")]
pub fn sub(mut self, sub: impl Into<Text>) -> Self {
self.sub = Some(sub.into());
self
}
pub fn tone(mut self, tone: impl Into<Tone>) -> Self {
self.tone = Some(tone.into());
self
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct ToolButton {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub keys: Vec<String>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ToolPreview {
Lines(u32),
Tail(u32),
}
impl Serialize for ToolPreview {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeMap as _;
let mut m = s.serialize_map(Some(1))?;
match *self {
Self::Lines(n) => m.serialize_entry("lines", &n)?,
Self::Tail(n) => m.serialize_entry("tail", &n)?,
}
m.end()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Preview {
Auto,
Lines(u32),
}
impl Serialize for Preview {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeMap as _;
match *self {
Self::Auto => s.serialize_str("auto"),
Self::Lines(n) => {
let mut m = s.serialize_map(Some(1))?;
m.serialize_entry("lines", &n)?;
m.end()
},
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AgentStats {
#[serde(skip_serializing_if = "Option::is_none")]
pub tools: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub requests: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub done: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub context: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub context_label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tokens: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cost: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub age: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub took: Option<u64>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct AgentTool {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub intent: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub age: Option<i64>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct Retry {
#[serde(skip_serializing_if = "Option::is_none")]
pub attempt: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub delay: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub age: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct ChecklistItem {
pub id: String,
pub text: Text,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<ItemStatus>,
#[serde(skip_serializing_if = "Option::is_none")]
pub note: Option<Text>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct Phase {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<Text>,
pub items: Vec<ChecklistItem>,
#[serde(skip_serializing_if = "Option::is_none")]
pub collapsed: Option<bool>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct PickerItem {
pub id: String,
pub label: Text,
#[serde(skip_serializing_if = "Option::is_none")]
pub detail: Option<Text>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<Icon>,
#[serde(skip_serializing_if = "Option::is_none")]
pub role: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mark: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dot: Option<Tone>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mono: Option<bool>,
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
pub facts: BTreeMap<String, Value>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub badges: Vec<BadgeSpec>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub chips: Vec<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tone: Option<Tone>,
#[serde(skip_serializing_if = "Option::is_none")]
pub disabled: Option<Value>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub hits: Vec<[usize; 2]>,
#[serde(skip_serializing_if = "Option::is_none")]
pub node: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub depth: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub open: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
}
impl PickerItem {
pub fn new(id: impl Into<String>, label: impl Into<Text>) -> Self {
Self { id: id.into(), label: label.into(), ..Self::default() }
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum OrderEntry {
Item(String),
Group {
group: String,
label: String,
count: Option<u64>,
},
}
impl Serialize for OrderEntry {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeMap as _;
match self {
Self::Item(id) => s.serialize_str(id),
Self::Group { group, label, count } => {
let mut m = s.serialize_map(None)?;
m.serialize_entry("group", group)?;
m.serialize_entry("label", label)?;
if let Some(count) = count {
m.serialize_entry("count", count)?;
}
m.end()
},
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct PickerColumn {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub head: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub format: Option<ColumnFormat>,
#[serde(skip_serializing_if = "Option::is_none")]
pub priority: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub min: Option<u32>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct Confirm {
pub text: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub act: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct Scope {
pub id: String,
pub label: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub group: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mark: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<Icon>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dot: Option<Tone>,
#[serde(skip_serializing_if = "Option::is_none")]
pub count: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub disabled: Option<Value>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct PickerTab {
pub id: String,
pub label: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub count: Option<u64>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct StripItem {
pub id: String,
pub label: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub on: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dot: Option<String>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct Strip {
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
pub items: Vec<StripItem>,
#[serde(skip_serializing_if = "Option::is_none")]
pub selected: Option<String>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct PickerAction {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub keys: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub primary: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub danger: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub on: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub disabled: Option<Value>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct PrefsPage {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub group: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<Icon>,
#[serde(skip_serializing_if = "Option::is_none")]
pub disabled: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub changed: Option<u32>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
pub struct PrefsSection {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub page: Option<String>,
pub rows: Vec<PrefsRow>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PrefsRow {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hint: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub warning: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub disabled: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub changed: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default_label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub control: Option<Control>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct ChoiceOption {
pub value: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub detail: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize)]
#[serde(tag = "k", rename_all = "lowercase")]
pub enum Control {
Switch {
on: bool,
},
Choice {
value: String,
options: Vec<ChoiceOption>,
#[serde(skip_serializing_if = "Option::is_none")]
style: Option<ChoiceStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
mono: Option<bool>,
},
Number {
value: f64,
#[serde(skip_serializing_if = "Option::is_none")]
min: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
max: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
step: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
unit: Option<String>,
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
labels: BTreeMap<String, String>,
},
Text {
value: String,
#[serde(skip_serializing_if = "Option::is_none")]
placeholder: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
secret: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
mono: Option<bool>,
},
Keys {
keys: Vec<Vec<String>>,
},
Multi {
values: Vec<String>,
options: Vec<ChoiceOption>,
#[serde(skip_serializing_if = "Option::is_none")]
ordered: Option<bool>,
},
Action {
#[serde(skip_serializing_if = "Option::is_none")]
act: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
label: Option<String>,
},
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct Editing {
pub row: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub option: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub draft: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<usize>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MenuEntry {
Act(String),
Item(MenuItem),
Header(String),
Separator,
}
impl MenuEntry {
pub fn header(title: impl Into<String>) -> Self {
Self::Header(title.into())
}
}
impl Serialize for MenuEntry {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
match self {
Self::Act(act) => s.serialize_str(act),
Self::Item(item) => item.serialize(s),
Self::Header(title) => {
let mut map = s.serialize_map(Some(1))?;
map.serialize_entry("header", title)?;
map.end()
},
Self::Separator => s.serialize_str("-"),
}
}
}
impl From<&str> for MenuEntry {
fn from(act: &str) -> Self {
Self::Act(act.to_owned())
}
}
impl From<String> for MenuEntry {
fn from(act: String) -> Self {
Self::Act(act)
}
}
impl From<MenuItem> for MenuEntry {
fn from(item: MenuItem) -> Self {
Self::Item(item)
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct MenuItem {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<Icon>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub keys: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub detail: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub checked: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub radio: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub disabled: Option<Disabled>,
#[serde(skip_serializing_if = "Option::is_none")]
pub danger: Option<bool>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub items: Vec<MenuEntry>,
}
impl MenuItem {
pub fn new(id: impl Into<String>, label: impl Into<String>) -> Self {
Self { id: id.into(), label: Some(label.into()), ..Self::default() }
}
pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
self.icon = Some(icon.into());
self
}
pub fn keys<K: Into<String>>(mut self, keys: impl IntoIterator<Item = K>) -> Self {
self.keys = keys.into_iter().map(Into::into).collect();
self
}
pub fn detail(mut self, detail: impl Into<String>) -> Self {
self.detail = Some(detail.into());
self
}
pub const fn checked(mut self, checked: bool) -> Self {
self.checked = Some(checked);
self
}
pub fn radio(mut self, group: impl Into<String>) -> Self {
self.radio = Some(group.into());
self
}
pub fn disabled(mut self, disabled: impl Into<Disabled>) -> Self {
self.disabled = Some(disabled.into());
self
}
pub const fn danger(mut self, danger: bool) -> Self {
self.danger = Some(danger);
self
}
pub fn item(mut self, entry: impl Into<MenuEntry>) -> Self {
self.items.push(entry.into());
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct MenubarMenu {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
pub items: Vec<MenuEntry>,
}
impl MenubarMenu {
pub fn new(id: impl Into<String>, label: impl Into<String>) -> Self {
Self { id: id.into(), label: Some(label.into()), ..Self::default() }
}
pub fn item(mut self, entry: impl Into<MenuEntry>) -> Self {
self.items.push(entry.into());
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct ActButton {
pub act: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<Icon>,
#[serde(skip_serializing_if = "Option::is_none")]
pub variant: Option<ButtonVariant>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub keys: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub disabled: Option<Disabled>,
#[serde(skip_serializing_if = "Option::is_none")]
pub busy: Option<bool>,
}
impl ActButton {
pub fn new(act: impl Into<String>, text: impl Into<String>) -> Self {
Self { act: act.into(), text: Some(text.into()), ..Self::default() }
}
pub fn icon_only(act: impl Into<String>, icon: impl Into<Icon>) -> Self {
Self { act: act.into(), icon: Some(icon.into()), ..Self::default() }
}
pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
self.icon = Some(icon.into());
self
}
pub fn variant(mut self, variant: impl Into<ButtonVariant>) -> Self {
self.variant = Some(variant.into());
self
}
pub fn keys<K: Into<String>>(mut self, keys: impl IntoIterator<Item = K>) -> Self {
self.keys = keys.into_iter().map(Into::into).collect();
self
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
pub fn disabled(mut self, disabled: impl Into<Disabled>) -> Self {
self.disabled = Some(disabled.into());
self
}
pub const fn busy(mut self, busy: bool) -> Self {
self.busy = Some(busy);
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct IconAction {
pub act: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<Icon>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
}
impl IconAction {
pub fn new(act: impl Into<String>) -> Self {
Self { act: act.into(), ..Self::default() }
}
pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
self.icon = Some(icon.into());
self
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
pub struct Sort {
pub col: String,
pub dir: SortDir,
}
impl Sort {
pub fn asc(col: impl Into<String>) -> Self {
Self { col: col.into(), dir: SortDir::Asc }
}
pub fn desc(col: impl Into<String>) -> Self {
Self { col: col.into(), dir: SortDir::Desc }
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct AskScope {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
}
impl AskScope {
pub fn new(id: impl Into<String>, label: impl Into<String>) -> Self {
Self { id: id.into(), label: Some(label.into()) }
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AskAlways {
Label(String),
Hidden,
}
impl Serialize for AskAlways {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
match self {
Self::Label(label) => s.serialize_str(label),
Self::Hidden => s.serialize_bool(false),
}
}
}
impl From<&str> for AskAlways {
fn from(label: &str) -> Self {
Self::Label(label.to_owned())
}
}
impl From<String> for AskAlways {
fn from(label: String) -> Self {
Self::Label(label)
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct Ask {
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub allow: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deny: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub always: Option<AskAlways>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub scopes: Vec<AskScope>,
#[serde(skip_serializing_if = "Option::is_none")]
pub scope: Option<String>,
}
impl Ask {
pub fn new(text: impl Into<String>) -> Self {
Self { text: Some(text.into()), ..Self::default() }
}
pub fn allow(mut self, label: impl Into<String>) -> Self {
self.allow = Some(label.into());
self
}
pub fn deny(mut self, label: impl Into<String>) -> Self {
self.deny = Some(label.into());
self
}
pub fn always(mut self, always: impl Into<AskAlways>) -> Self {
self.always = Some(always.into());
self
}
pub fn scope_option(mut self, scope: AskScope) -> Self {
self.scopes.push(scope);
self
}
pub fn scope(mut self, id: impl Into<String>) -> Self {
self.scope = Some(id.into());
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct SelectOption {
pub value: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub detail: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<Icon>,
#[serde(skip_serializing_if = "Option::is_none")]
pub group: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub disabled: Option<bool>,
}
impl SelectOption {
pub fn new(value: impl Into<String>, label: impl Into<String>) -> Self {
Self { value: value.into(), label: Some(label.into()), ..Self::default() }
}
pub fn detail(mut self, detail: impl Into<String>) -> Self {
self.detail = Some(detail.into());
self
}
pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
self.icon = Some(icon.into());
self
}
pub fn group(mut self, group: impl Into<String>) -> Self {
self.group = Some(group.into());
self
}
pub const fn disabled(mut self, disabled: bool) -> Self {
self.disabled = Some(disabled);
self
}
}
impl From<&str> for SelectOption {
fn from(value: &str) -> Self {
Self { value: value.to_owned(), ..Self::default() }
}
}
impl From<String> for SelectOption {
fn from(value: String) -> Self {
Self { value, ..Self::default() }
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct AvatarItem {
pub text: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub variant: Option<AvatarVariant>,
#[serde(skip_serializing_if = "Option::is_none")]
pub seed: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<Icon>,
#[serde(skip_serializing_if = "Option::is_none")]
pub blob: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<Tone>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
}
impl AvatarItem {
pub fn new(text: impl Into<String>) -> Self {
Self { text: text.into(), ..Self::default() }
}
pub fn variant(mut self, variant: impl Into<AvatarVariant>) -> Self {
self.variant = Some(variant.into());
self
}
pub fn seed(mut self, seed: impl Into<String>) -> Self {
self.seed = Some(seed.into());
self
}
pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
self.icon = Some(icon.into());
self
}
pub fn blob(mut self, blob: impl Into<String>) -> Self {
self.blob = Some(blob.into());
self
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct Crumb {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<Icon>,
#[serde(skip_serializing_if = "Option::is_none")]
pub href: Option<String>,
}
impl Crumb {
pub fn new(id: impl Into<String>, label: impl Into<String>) -> Self {
Self { id: id.into(), label: Some(label.into()), ..Self::default() }
}
pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
self.icon = Some(icon.into());
self
}
pub fn href(mut self, href: impl Into<String>) -> Self {
self.href = Some(href.into());
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct DayMark {
pub date: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub tone: Option<Tone>,
}
impl DayMark {
pub fn new(date: impl Into<String>, tone: impl Into<Tone>) -> Self {
Self { date: date.into(), tone: Some(tone.into()) }
}
}
impl From<&str> for DayMark {
fn from(date: &str) -> Self {
Self { date: date.to_owned(), tone: None }
}
}
impl From<String> for DayMark {
fn from(date: String) -> Self {
Self { date, tone: None }
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct Preset {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
}
impl Preset {
pub fn new(id: impl Into<String>, label: impl Into<String>) -> Self {
Self { id: id.into(), label: Some(label.into()) }
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct NavItem {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<Icon>,
#[serde(skip_serializing_if = "Option::is_none")]
pub count: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub items: Vec<NavSubItem>,
}
impl NavItem {
pub fn new(id: impl Into<String>, label: impl Into<String>) -> Self {
Self { id: id.into(), label: Some(label.into()), ..Self::default() }
}
pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
self.icon = Some(icon.into());
self
}
pub fn count(mut self, count: impl Into<String>) -> Self {
self.count = Some(count.into());
self
}
pub fn item(mut self, item: NavSubItem) -> Self {
self.items.push(item);
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct NavSubItem {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub detail: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<Icon>,
}
impl NavSubItem {
pub fn new(id: impl Into<String>, label: impl Into<String>) -> Self {
Self { id: id.into(), label: Some(label.into()), ..Self::default() }
}
pub fn detail(mut self, detail: impl Into<String>) -> Self {
self.detail = Some(detail.into());
self
}
pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
self.icon = Some(icon.into());
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct Reaction {
pub text: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub count: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub on: Option<bool>,
}
impl Reaction {
pub fn new(text: impl Into<String>, count: u32) -> Self {
Self { text: text.into(), count: Some(count), on: None }
}
pub const fn on(mut self, on: bool) -> Self {
self.on = Some(on);
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct Source {
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub href: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub site: Option<String>,
}
impl Source {
pub fn new(href: impl Into<String>) -> Self {
Self { href: Some(href.into()), ..Self::default() }
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
pub fn site(mut self, site: impl Into<String>) -> Self {
self.site = Some(site.into());
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct TraceLine {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<Icon>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<Text>,
#[serde(skip_serializing_if = "Option::is_none")]
pub target: Option<Text>,
#[serde(skip_serializing_if = "Option::is_none")]
pub detail: Option<Text>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<Status>,
#[serde(skip_serializing_if = "Option::is_none")]
pub age: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub took: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub open: Option<bool>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub sources: Vec<Source>,
}
impl TraceLine {
pub fn new(id: impl Into<String>, title: impl Into<Text>) -> Self {
Self { id: Some(id.into()), title: Some(title.into()), ..Self::default() }
}
pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
self.icon = Some(icon.into());
self
}
pub fn target(mut self, target: impl Into<Text>) -> Self {
self.target = Some(target.into());
self
}
pub fn detail(mut self, detail: impl Into<Text>) -> Self {
self.detail = Some(detail.into());
self
}
pub fn status(mut self, status: impl Into<Status>) -> Self {
self.status = Some(status.into());
self
}
pub const fn age(mut self, age: u64) -> Self {
self.age = Some(age);
self
}
pub const fn took(mut self, took: u64) -> Self {
self.took = Some(took);
self
}
pub const fn open(mut self, open: bool) -> Self {
self.open = Some(open);
self
}
pub fn source(mut self, source: Source) -> Self {
self.sources.push(source);
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct StackError {
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
pub kind: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
}
impl StackError {
pub fn new(kind: impl Into<String>, message: impl Into<String>) -> Self {
Self { kind: Some(kind.into()), message: Some(message.into()) }
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct Frame {
#[serde(rename = "fn")]
pub func: String,
pub file: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub line: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub col: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub app: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub code: Option<FrameCode>,
}
impl Frame {
pub fn new(func: impl Into<String>, file: impl Into<String>) -> Self {
Self { func: func.into(), file: file.into(), ..Self::default() }
}
pub const fn at(mut self, line: u32, col: u32) -> Self {
self.line = Some(line);
self.col = Some(col);
self
}
pub const fn line(mut self, line: u32) -> Self {
self.line = Some(line);
self
}
pub const fn app(mut self, app: bool) -> Self {
self.app = Some(app);
self
}
pub fn code(mut self, code: FrameCode) -> Self {
self.code = Some(code);
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct FrameCode {
#[serde(skip_serializing_if = "Option::is_none")]
pub start: Option<u32>,
pub lines: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub line: Option<u32>,
}
impl FrameCode {
pub fn new<L: Into<String>>(start: u32, lines: impl IntoIterator<Item = L>) -> Self {
Self { start: Some(start), lines: lines.into_iter().map(Into::into).collect(), line: None }
}
pub const fn line(mut self, line: u32) -> Self {
self.line = Some(line);
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct Suggestion {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
pub text: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub detail: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<Icon>,
#[serde(skip_serializing_if = "Option::is_none")]
pub keys: Option<Vec<String>>,
}
impl Suggestion {
pub fn new(text: impl Into<String>) -> Self {
Self { text: text.into(), ..Self::default() }
}
pub fn id(mut self, id: impl Into<String>) -> Self {
self.id = Some(id.into());
self
}
pub fn detail(mut self, detail: impl Into<String>) -> Self {
self.detail = Some(detail.into());
self
}
pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
self.icon = Some(icon.into());
self
}
pub fn keys<K: Into<String>>(mut self, keys: impl IntoIterator<Item = K>) -> Self {
self.keys = Some(keys.into_iter().map(Into::into).collect());
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct Question {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub prompt: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub choices: Vec<QuestionChoice>,
#[serde(skip_serializing_if = "Option::is_none")]
pub multi: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub other: Option<OtherAnswer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub required: Option<bool>,
}
impl Question {
pub fn new(id: impl Into<String>, prompt: impl Into<String>) -> Self {
Self { id: id.into(), prompt: Some(prompt.into()), ..Self::default() }
}
pub fn description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
pub fn choice(mut self, choice: impl Into<QuestionChoice>) -> Self {
self.choices.push(choice.into());
self
}
pub const fn multi(mut self, multi: bool) -> Self {
self.multi = Some(multi);
self
}
pub fn other(mut self, other: impl Into<OtherAnswer>) -> Self {
self.other = Some(other.into());
self
}
pub const fn required(mut self, required: bool) -> Self {
self.required = Some(required);
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct QuestionChoice {
pub value: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub detail: Option<String>,
}
impl QuestionChoice {
pub fn new(value: impl Into<String>, label: impl Into<String>) -> Self {
Self { value: value.into(), label: Some(label.into()), detail: None }
}
pub fn detail(mut self, detail: impl Into<String>) -> Self {
self.detail = Some(detail.into());
self
}
}
impl From<&str> for QuestionChoice {
fn from(value: &str) -> Self {
Self { value: value.to_owned(), ..Self::default() }
}
}
impl From<String> for QuestionChoice {
fn from(value: String) -> Self {
Self { value, ..Self::default() }
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum OtherAnswer {
Flag(bool),
Placeholder(String),
}
impl Serialize for OtherAnswer {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
match self {
Self::Flag(on) => s.serialize_bool(*on),
Self::Placeholder(placeholder) => {
let mut map = s.serialize_map(Some(1))?;
map.serialize_entry("placeholder", placeholder)?;
map.end()
},
}
}
}
impl From<bool> for OtherAnswer {
fn from(on: bool) -> Self {
Self::Flag(on)
}
}
impl From<&str> for OtherAnswer {
fn from(placeholder: &str) -> Self {
Self::Placeholder(placeholder.to_owned())
}
}
impl From<String> for OtherAnswer {
fn from(placeholder: String) -> Self {
Self::Placeholder(placeholder)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum QuestionAnswer {
One(String),
Many(Vec<String>),
}
impl Serialize for QuestionAnswer {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
match self {
Self::One(value) => s.serialize_str(value),
Self::Many(values) => values.serialize(s),
}
}
}
impl From<&str> for QuestionAnswer {
fn from(value: &str) -> Self {
Self::One(value.to_owned())
}
}
impl From<String> for QuestionAnswer {
fn from(value: String) -> Self {
Self::One(value)
}
}
impl From<Vec<String>> for QuestionAnswer {
fn from(values: Vec<String>) -> Self {
Self::Many(values)
}
}