1use std::collections::BTreeMap;
7
8use serde::{Serialize, Serializer, ser::SerializeMap};
9use serde_json::Value;
10
11use super::{
12 icon::Icon,
13 types::{ChoiceStyle, ColumnFormat, ItemStatus, Text, TextAlign, Tone, Truncate},
14};
15
16#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
18pub struct KvItem {
19 pub k: Text,
21 pub v: Text,
23}
24
25#[derive(Clone, Debug, Default, PartialEq, Serialize)]
27pub struct Column {
28 pub id: String,
30 #[serde(skip_serializing_if = "Option::is_none")]
32 pub head: Option<Text>,
33 #[serde(skip_serializing_if = "Option::is_none")]
35 pub align: Option<TextAlign>,
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub truncate: Option<Truncate>,
39 #[serde(skip_serializing_if = "Option::is_none")]
41 pub priority: Option<f64>,
42 #[serde(skip_serializing_if = "Option::is_none")]
44 pub grow: Option<f64>,
45}
46
47impl Column {
48 pub fn new(id: impl Into<String>, head: impl Into<Text>) -> Self {
50 Self { id: id.into(), head: Some(head.into()), ..Self::default() }
51 }
52
53 pub fn align(mut self, align: impl Into<TextAlign>) -> Self {
55 self.align = Some(align.into());
56 self
57 }
58
59 pub const fn grow(mut self, grow: f64) -> Self {
61 self.grow = Some(grow);
62 self
63 }
64
65 pub const fn priority(mut self, priority: f64) -> Self {
67 self.priority = Some(priority);
68 self
69 }
70
71 pub fn truncate(mut self, truncate: impl Into<Truncate>) -> Self {
73 self.truncate = Some(truncate.into());
74 self
75 }
76}
77
78#[derive(Clone, Debug, Default, PartialEq, Serialize)]
80pub struct Part {
81 pub value: f64,
83 #[serde(skip_serializing_if = "Option::is_none")]
85 pub token: Option<String>,
86 #[serde(skip_serializing_if = "Option::is_none")]
88 pub label: Option<String>,
89 #[serde(skip_serializing_if = "Option::is_none")]
91 pub hatch: Option<bool>,
92}
93
94#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize)]
96pub struct Thresholds {
97 #[serde(skip_serializing_if = "Option::is_none")]
99 pub warn: Option<f64>,
100 #[serde(skip_serializing_if = "Option::is_none")]
102 pub bad: Option<f64>,
103}
104
105#[derive(Clone, Debug, Default, PartialEq, Serialize)]
107pub struct MeterCell {
108 #[serde(skip_serializing_if = "Option::is_none")]
110 pub value: Option<f64>,
111 #[serde(skip_serializing_if = "Vec::is_empty")]
113 pub parts: Vec<Part>,
114 #[serde(skip_serializing_if = "Option::is_none")]
116 pub thresholds: Option<Thresholds>,
117 #[serde(skip_serializing_if = "Option::is_none")]
119 pub tone: Option<Tone>,
120 #[serde(skip_serializing_if = "Option::is_none")]
122 pub title: Option<String>,
123}
124
125#[derive(Clone, Debug, PartialEq)]
127pub enum Cell {
128 Text(Text),
130 Meter(MeterCell),
132}
133
134impl Serialize for Cell {
135 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
136 match self {
137 Self::Text(t) => t.serialize(s),
138 Self::Meter(m) => {
139 let mut map = s.serialize_map(Some(1))?;
140 map.serialize_entry("meter", m)?;
141 map.end()
142 },
143 }
144 }
145}
146
147impl<T: Into<Text>> From<T> for Cell {
148 fn from(t: T) -> Self {
149 Self::Text(t.into())
150 }
151}
152
153impl From<MeterCell> for Cell {
154 fn from(m: MeterCell) -> Self {
155 Self::Meter(m)
156 }
157}
158
159#[derive(Clone, Debug, Default, PartialEq, Serialize)]
161pub struct TableRow {
162 pub id: String,
164 pub cells: BTreeMap<String, Cell>,
166}
167
168impl TableRow {
169 pub fn new(id: impl Into<String>) -> Self {
171 Self { id: id.into(), cells: BTreeMap::new() }
172 }
173
174 pub fn cell(mut self, col: impl Into<String>, cell: impl Into<Cell>) -> Self {
176 self.cells.insert(col.into(), cell.into());
177 self
178 }
179}
180
181#[derive(Clone, Debug, Default, PartialEq, Serialize)]
183pub struct TreeItem {
184 pub id: String,
186 pub label: Text,
188 #[serde(skip_serializing_if = "Option::is_none")]
190 pub icon: Option<Icon>,
191 #[serde(skip_serializing_if = "Option::is_none")]
193 pub open: Option<bool>,
194 #[serde(skip_serializing_if = "Vec::is_empty")]
196 pub children: Vec<Self>,
197}
198
199impl TreeItem {
200 pub fn new(id: impl Into<String>, label: impl Into<Text>) -> Self {
202 Self { id: id.into(), label: label.into(), ..Self::default() }
203 }
204
205 pub fn child(mut self, item: Self) -> Self {
207 self.children.push(item);
208 self
209 }
210
211 pub const fn open(mut self, open: bool) -> Self {
213 self.open = Some(open);
214 self
215 }
216}
217
218#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
220pub struct Tab {
221 pub id: String,
223 pub label: Text,
225}
226
227#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
229pub struct CodeMark {
230 pub line: u64,
232 #[serde(skip_serializing_if = "Option::is_none")]
234 pub tone: Option<Tone>,
235 #[serde(skip_serializing_if = "Vec::is_empty")]
237 pub ranges: Vec<[u64; 2]>,
238}
239
240#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
242#[serde(rename_all = "camelCase")]
243pub struct Hunk {
244 #[serde(skip_serializing_if = "Option::is_none")]
246 pub old_start: Option<u64>,
247 #[serde(skip_serializing_if = "Option::is_none")]
249 pub new_start: Option<u64>,
250 pub lines: Vec<String>,
252}
253
254#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
256pub struct Decor {
257 pub from: usize,
259 pub to: usize,
261 pub s: String,
263 #[serde(skip_serializing_if = "Option::is_none")]
265 pub fx: Option<super::types::Fx>,
266}
267
268#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
270pub struct ShimmerPalette {
271 #[serde(skip_serializing_if = "Option::is_none")]
273 pub low: Option<String>,
274 #[serde(skip_serializing_if = "Option::is_none")]
276 pub mid: Option<String>,
277 #[serde(skip_serializing_if = "Option::is_none")]
279 pub high: Option<String>,
280}
281
282#[derive(Clone, Debug, Default, PartialEq, Serialize)]
284pub struct MeterMark {
285 pub at: f64,
287 #[serde(skip_serializing_if = "Option::is_none")]
289 pub tone: Option<Tone>,
290 #[serde(skip_serializing_if = "Option::is_none")]
292 pub title: Option<String>,
293 #[serde(skip_serializing_if = "Option::is_none")]
295 pub icon: Option<Icon>,
296}
297
298#[derive(Clone, Debug, Default, PartialEq, Serialize)]
300pub struct Point {
301 pub value: f64,
303 #[serde(skip_serializing_if = "Option::is_none")]
305 pub label: Option<String>,
306 #[serde(skip_serializing_if = "Option::is_none")]
308 pub title: Option<String>,
309}
310
311#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
313pub struct ChartCol {
314 pub at: u32,
316 pub label: String,
318}
319
320#[derive(Clone, Debug, PartialEq, Eq)]
322pub enum Anchor {
323 Center,
325 Top,
327 Bottom,
329 Node {
331 id: String,
333 above: bool,
335 },
336 Caret(String),
338}
339
340impl Serialize for Anchor {
341 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
342 use serde::ser::SerializeMap as _;
343 match self {
344 Self::Center => s.serialize_str("center"),
345 Self::Top => s.serialize_str("top"),
346 Self::Bottom => s.serialize_str("bottom"),
347 Self::Node { id, above } => {
348 let mut m = s.serialize_map(Some(2))?;
349 m.serialize_entry("node", id)?;
350 m.serialize_entry("side", if *above { "above" } else { "below" })?;
351 m.end()
352 },
353 Self::Caret(id) => {
354 let mut m = s.serialize_map(Some(1))?;
355 m.serialize_entry("caret", id)?;
356 m.end()
357 },
358 }
359 }
360}
361
362#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
364pub struct BadgeSpec {
365 pub text: String,
367 #[serde(skip_serializing_if = "Option::is_none")]
369 pub tone: Option<Tone>,
370 #[serde(skip_serializing_if = "Option::is_none")]
372 pub title: Option<String>,
373}
374
375#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
377pub struct ToolButton {
378 pub id: String,
380 #[serde(skip_serializing_if = "Option::is_none")]
382 pub label: Option<String>,
383 #[serde(skip_serializing_if = "Vec::is_empty")]
385 pub keys: Vec<String>,
386}
387
388#[derive(Clone, Copy, Debug, PartialEq, Eq)]
390pub enum ToolPreview {
391 Lines(u32),
393 Tail(u32),
395}
396
397impl Serialize for ToolPreview {
398 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
399 use serde::ser::SerializeMap as _;
400 let mut m = s.serialize_map(Some(1))?;
401 match *self {
402 Self::Lines(n) => m.serialize_entry("lines", &n)?,
403 Self::Tail(n) => m.serialize_entry("tail", &n)?,
404 }
405 m.end()
406 }
407}
408
409#[derive(Clone, Copy, Debug, PartialEq, Eq)]
411pub enum Preview {
412 Auto,
414 Lines(u32),
416}
417
418impl Serialize for Preview {
419 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
420 use serde::ser::SerializeMap as _;
421 match *self {
422 Self::Auto => s.serialize_str("auto"),
423 Self::Lines(n) => {
424 let mut m = s.serialize_map(Some(1))?;
425 m.serialize_entry("lines", &n)?;
426 m.end()
427 },
428 }
429 }
430}
431
432#[derive(Clone, Debug, Default, PartialEq, Serialize)]
434#[serde(rename_all = "camelCase")]
435pub struct AgentStats {
436 #[serde(skip_serializing_if = "Option::is_none")]
438 pub tools: Option<u64>,
439 #[serde(skip_serializing_if = "Option::is_none")]
441 pub requests: Option<u64>,
442 #[serde(skip_serializing_if = "Option::is_none")]
444 pub done: Option<f64>,
445 #[serde(skip_serializing_if = "Option::is_none")]
447 pub context: Option<f64>,
448 #[serde(skip_serializing_if = "Option::is_none")]
450 pub context_label: Option<String>,
451 #[serde(skip_serializing_if = "Option::is_none")]
453 pub tokens: Option<u64>,
454 #[serde(skip_serializing_if = "Option::is_none")]
456 pub cost: Option<f64>,
457 #[serde(skip_serializing_if = "Option::is_none")]
459 pub age: Option<i64>,
460 #[serde(skip_serializing_if = "Option::is_none")]
462 pub took: Option<u64>,
463}
464
465#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
467pub struct AgentTool {
468 pub name: String,
470 #[serde(skip_serializing_if = "Option::is_none")]
472 pub intent: Option<String>,
473 #[serde(skip_serializing_if = "Option::is_none")]
475 pub age: Option<i64>,
476}
477
478#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
480pub struct Retry {
481 #[serde(skip_serializing_if = "Option::is_none")]
483 pub attempt: Option<u32>,
484 #[serde(skip_serializing_if = "Option::is_none")]
486 pub max: Option<u32>,
487 #[serde(skip_serializing_if = "Option::is_none")]
489 pub delay: Option<u64>,
490 #[serde(skip_serializing_if = "Option::is_none")]
492 pub age: Option<i64>,
493 #[serde(skip_serializing_if = "Option::is_none")]
495 pub error: Option<String>,
496}
497
498#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
500pub struct ChecklistItem {
501 pub id: String,
503 pub text: Text,
505 #[serde(skip_serializing_if = "Option::is_none")]
507 pub status: Option<ItemStatus>,
508 #[serde(skip_serializing_if = "Option::is_none")]
510 pub note: Option<Text>,
511}
512
513#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
515pub struct Phase {
516 pub id: String,
518 #[serde(skip_serializing_if = "Option::is_none")]
520 pub title: Option<Text>,
521 pub items: Vec<ChecklistItem>,
523 #[serde(skip_serializing_if = "Option::is_none")]
525 pub collapsed: Option<bool>,
526}
527
528#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
530pub struct PickerItem {
531 pub id: String,
533 pub label: Text,
535 #[serde(skip_serializing_if = "Option::is_none")]
537 pub detail: Option<Text>,
538 #[serde(skip_serializing_if = "Option::is_none")]
540 pub icon: Option<Icon>,
541 #[serde(skip_serializing_if = "Option::is_none")]
543 pub role: Option<String>,
544 #[serde(skip_serializing_if = "Option::is_none")]
546 pub mark: Option<Value>,
547 #[serde(skip_serializing_if = "Option::is_none")]
549 pub dot: Option<Tone>,
550 #[serde(skip_serializing_if = "Option::is_none")]
552 pub mono: Option<bool>,
553 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
555 pub facts: BTreeMap<String, Value>,
556 #[serde(skip_serializing_if = "Vec::is_empty")]
558 pub badges: Vec<BadgeSpec>,
559 #[serde(skip_serializing_if = "Vec::is_empty")]
561 pub chips: Vec<Value>,
562 #[serde(skip_serializing_if = "Option::is_none")]
564 pub tone: Option<Tone>,
565 #[serde(skip_serializing_if = "Option::is_none")]
567 pub disabled: Option<Value>,
568 #[serde(skip_serializing_if = "Vec::is_empty")]
570 pub hits: Vec<[usize; 2]>,
571 #[serde(skip_serializing_if = "Option::is_none")]
573 pub node: Option<String>,
574 #[serde(skip_serializing_if = "Option::is_none")]
576 pub depth: Option<u32>,
577 #[serde(skip_serializing_if = "Option::is_none")]
579 pub open: Option<bool>,
580 #[serde(skip_serializing_if = "Option::is_none")]
582 pub title: Option<String>,
583}
584
585impl PickerItem {
586 pub fn new(id: impl Into<String>, label: impl Into<Text>) -> Self {
588 Self { id: id.into(), label: label.into(), ..Self::default() }
589 }
590}
591
592#[derive(Clone, Debug, PartialEq, Eq)]
594pub enum OrderEntry {
595 Item(String),
597 Group {
599 group: String,
601 label: String,
603 count: Option<u64>,
605 },
606}
607
608impl Serialize for OrderEntry {
609 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
610 use serde::ser::SerializeMap as _;
611 match self {
612 Self::Item(id) => s.serialize_str(id),
613 Self::Group { group, label, count } => {
614 let mut m = s.serialize_map(None)?;
615 m.serialize_entry("group", group)?;
616 m.serialize_entry("label", label)?;
617 if let Some(count) = count {
618 m.serialize_entry("count", count)?;
619 }
620 m.end()
621 },
622 }
623 }
624}
625
626#[derive(Clone, Debug, Default, PartialEq, Serialize)]
628pub struct PickerColumn {
629 pub id: String,
631 #[serde(skip_serializing_if = "Option::is_none")]
633 pub head: Option<String>,
634 #[serde(skip_serializing_if = "Option::is_none")]
636 pub format: Option<ColumnFormat>,
637 #[serde(skip_serializing_if = "Option::is_none")]
639 pub priority: Option<f64>,
640 #[serde(skip_serializing_if = "Option::is_none")]
642 pub min: Option<u32>,
643}
644
645#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
647pub struct Confirm {
648 pub text: String,
650 #[serde(skip_serializing_if = "Option::is_none")]
652 pub act: Option<String>,
653 #[serde(skip_serializing_if = "Option::is_none")]
655 pub label: Option<String>,
656}
657
658#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
660pub struct Scope {
661 pub id: String,
663 pub label: String,
665 #[serde(skip_serializing_if = "Option::is_none")]
667 pub group: Option<String>,
668 #[serde(skip_serializing_if = "Option::is_none")]
670 pub mark: Option<Value>,
671 #[serde(skip_serializing_if = "Option::is_none")]
673 pub icon: Option<Icon>,
674 #[serde(skip_serializing_if = "Option::is_none")]
676 pub dot: Option<Tone>,
677 #[serde(skip_serializing_if = "Option::is_none")]
679 pub count: Option<u64>,
680 #[serde(skip_serializing_if = "Option::is_none")]
682 pub disabled: Option<Value>,
683}
684
685#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
687pub struct PickerTab {
688 pub id: String,
690 pub label: String,
692 #[serde(skip_serializing_if = "Option::is_none")]
694 pub count: Option<u64>,
695}
696
697#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
699pub struct StripItem {
700 pub id: String,
702 pub label: String,
704 #[serde(skip_serializing_if = "Option::is_none")]
706 pub on: Option<bool>,
707 #[serde(skip_serializing_if = "Option::is_none")]
709 pub dot: Option<String>,
710}
711
712#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
714pub struct Strip {
715 #[serde(skip_serializing_if = "Option::is_none")]
717 pub label: Option<String>,
718 pub items: Vec<StripItem>,
720 #[serde(skip_serializing_if = "Option::is_none")]
722 pub selected: Option<String>,
723}
724
725#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
727pub struct PickerAction {
728 pub id: String,
730 #[serde(skip_serializing_if = "Option::is_none")]
732 pub label: Option<String>,
733 #[serde(skip_serializing_if = "Vec::is_empty")]
735 pub keys: Vec<String>,
736 #[serde(skip_serializing_if = "Option::is_none")]
738 pub primary: Option<bool>,
739 #[serde(skip_serializing_if = "Option::is_none")]
741 pub end: Option<bool>,
742 #[serde(skip_serializing_if = "Option::is_none")]
744 pub danger: Option<bool>,
745 #[serde(skip_serializing_if = "Option::is_none")]
747 pub on: Option<bool>,
748 #[serde(skip_serializing_if = "Option::is_none")]
750 pub disabled: Option<Value>,
751}
752
753#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
755pub struct PrefsPage {
756 pub id: String,
758 #[serde(skip_serializing_if = "Option::is_none")]
760 pub label: Option<String>,
761 #[serde(skip_serializing_if = "Option::is_none")]
763 pub group: Option<String>,
764 #[serde(skip_serializing_if = "Option::is_none")]
766 pub icon: Option<Icon>,
767 #[serde(skip_serializing_if = "Option::is_none")]
769 pub disabled: Option<String>,
770 #[serde(skip_serializing_if = "Option::is_none")]
772 pub changed: Option<u32>,
773}
774
775#[derive(Clone, Debug, Default, PartialEq, Serialize)]
777pub struct PrefsSection {
778 #[serde(skip_serializing_if = "Option::is_none")]
780 pub id: Option<String>,
781 #[serde(skip_serializing_if = "Option::is_none")]
783 pub title: Option<String>,
784 #[serde(skip_serializing_if = "Option::is_none")]
786 pub page: Option<String>,
787 pub rows: Vec<PrefsRow>,
789}
790
791#[derive(Clone, Debug, Default, PartialEq, Serialize)]
793#[serde(rename_all = "camelCase")]
794pub struct PrefsRow {
795 pub id: String,
797 #[serde(skip_serializing_if = "Option::is_none")]
799 pub label: Option<String>,
800 #[serde(skip_serializing_if = "Option::is_none")]
802 pub hint: Option<String>,
803 #[serde(skip_serializing_if = "Option::is_none")]
805 pub warning: Option<String>,
806 #[serde(skip_serializing_if = "Option::is_none")]
808 pub disabled: Option<String>,
809 #[serde(skip_serializing_if = "Option::is_none")]
811 pub changed: Option<bool>,
812 #[serde(skip_serializing_if = "Option::is_none")]
814 pub default_label: Option<String>,
815 #[serde(skip_serializing_if = "Option::is_none")]
817 pub control: Option<Control>,
818}
819
820#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
822pub struct ChoiceOption {
823 pub value: String,
825 #[serde(skip_serializing_if = "Option::is_none")]
827 pub label: Option<String>,
828 #[serde(skip_serializing_if = "Option::is_none")]
830 pub detail: Option<String>,
831}
832
833#[derive(Clone, Debug, PartialEq, Serialize)]
835#[serde(tag = "k", rename_all = "lowercase")]
836pub enum Control {
837 Switch {
839 on: bool,
841 },
842 Choice {
844 value: String,
846 options: Vec<ChoiceOption>,
848 #[serde(skip_serializing_if = "Option::is_none")]
850 style: Option<ChoiceStyle>,
851 #[serde(skip_serializing_if = "Option::is_none")]
853 mono: Option<bool>,
854 },
855 Number {
857 value: f64,
859 #[serde(skip_serializing_if = "Option::is_none")]
861 min: Option<f64>,
862 #[serde(skip_serializing_if = "Option::is_none")]
864 max: Option<f64>,
865 #[serde(skip_serializing_if = "Option::is_none")]
867 step: Option<f64>,
868 #[serde(skip_serializing_if = "Option::is_none")]
870 unit: Option<String>,
871 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
873 labels: BTreeMap<String, String>,
874 },
875 Text {
877 value: String,
879 #[serde(skip_serializing_if = "Option::is_none")]
881 placeholder: Option<String>,
882 #[serde(skip_serializing_if = "Option::is_none")]
884 secret: Option<bool>,
885 #[serde(skip_serializing_if = "Option::is_none")]
887 mono: Option<bool>,
888 },
889 Keys {
891 keys: Vec<Vec<String>>,
893 },
894 Multi {
896 values: Vec<String>,
898 options: Vec<ChoiceOption>,
900 #[serde(skip_serializing_if = "Option::is_none")]
902 ordered: Option<bool>,
903 },
904 Action {
906 #[serde(skip_serializing_if = "Option::is_none")]
908 act: Option<String>,
909 #[serde(skip_serializing_if = "Option::is_none")]
911 label: Option<String>,
912 },
913}
914
915#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
917pub struct Editing {
918 pub row: String,
920 #[serde(skip_serializing_if = "Option::is_none")]
922 pub option: Option<String>,
923 #[serde(skip_serializing_if = "Option::is_none")]
925 pub draft: Option<String>,
926 #[serde(skip_serializing_if = "Option::is_none")]
928 pub cursor: Option<usize>,
929}