systemprompt_cli/shared/command_result/
render.rs1use systemprompt_logging::CliService;
7use systemprompt_models::artifacts::{
8 ChartArtifact, CliArtifact, ListArtifact, PresentationCardArtifact, TableArtifact,
9};
10
11use super::{CommandOutput, value_to_display};
12use crate::cli_settings::{OutputFormat, get_global_config};
13
14pub fn render_result(result: &CommandOutput) {
15 if result.should_skip_render() {
16 return;
17 }
18
19 match get_global_config().output_format() {
20 OutputFormat::Json => CliService::json(result.artifact()),
21 OutputFormat::Yaml => CliService::yaml(result.artifact()),
22 OutputFormat::Table => render_terminal(result),
23 }
24}
25
26fn render_terminal(result: &CommandOutput) {
27 if let Some(title) = result.title() {
28 CliService::section(title);
29 }
30
31 match result.artifact() {
32 CliArtifact::Text { artifact } => {
33 if result.title().is_none() {
34 if let Some(title) = &artifact.title {
35 CliService::section(title);
36 }
37 }
38 CliService::output(&artifact.content);
39 },
40 CliArtifact::CopyPasteText { artifact } => {
41 if result.title().is_none() {
42 if let Some(title) = &artifact.title {
43 CliService::section(title);
44 }
45 }
46 CliService::output(&artifact.content);
47 },
48 CliArtifact::Table { artifact } => render_table(artifact),
49 CliArtifact::List { artifact } => render_list(artifact),
50 CliArtifact::PresentationCard { artifact } => render_card(artifact),
51 CliArtifact::Dashboard { artifact } => {
52 if result.title().is_none() {
53 CliService::section(&artifact.title);
54 }
55 if let Some(description) = &artifact.description {
56 CliService::output(description);
57 }
58 },
59 CliArtifact::Chart { artifact } => render_chart(artifact),
60 CliArtifact::Audio { artifact } => CliService::output(&artifact.src),
61 CliArtifact::Image { artifact } => CliService::output(&artifact.src),
62 CliArtifact::Video { artifact } => CliService::output(&artifact.src),
63 }
64}
65
66fn render_table(artifact: &TableArtifact) {
67 let headers: Vec<&str> = artifact
68 .columns
69 .iter()
70 .map(|c| c.label.as_deref().unwrap_or(&c.name))
71 .collect();
72
73 let rows: Vec<Vec<String>> = artifact
74 .items
75 .iter()
76 .map(|item| {
77 artifact
78 .columns
79 .iter()
80 .map(|col| {
81 item.get(&col.name)
82 .map_or_else(String::new, value_to_display)
83 })
84 .collect()
85 })
86 .collect();
87
88 CliService::table(&headers, &rows);
89}
90
91fn render_list(artifact: &ListArtifact) {
92 for item in &artifact.items {
93 CliService::subsection(&item.title);
94 if !item.summary.is_empty() {
95 CliService::output(&item.summary);
96 }
97 if !item.link.is_empty() {
98 CliService::output(&item.link);
99 }
100 }
101}
102
103fn render_card(artifact: &PresentationCardArtifact) {
104 CliService::section(&artifact.title);
105 if let Some(subtitle) = &artifact.subtitle {
106 CliService::output(subtitle);
107 }
108 for section in &artifact.sections {
109 CliService::subsection(§ion.heading);
110 CliService::output(§ion.content);
111 }
112}
113
114fn render_chart(artifact: &ChartArtifact) {
115 let mut headers: Vec<&str> = vec!["label"];
116 for dataset in &artifact.datasets {
117 headers.push(&dataset.label);
118 }
119
120 let rows: Vec<Vec<String>> = artifact
121 .labels
122 .iter()
123 .enumerate()
124 .map(|(row, label)| {
125 let mut cells = vec![label.clone()];
126 for dataset in &artifact.datasets {
127 cells.push(
128 dataset
129 .data
130 .get(row)
131 .map_or_else(String::new, ToString::to_string),
132 );
133 }
134 cells
135 })
136 .collect();
137
138 CliService::table(&headers, &rows);
139}