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