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 CliArtifact::Message { artifact } => {
64 for line in &artifact.messages {
65 match line.level.as_str() {
66 "success" => CliService::success(&line.text),
67 "warning" => CliService::warning(&line.text),
68 "error" => CliService::error(&line.text),
69 _ => CliService::info(&line.text),
70 }
71 }
72 },
73 }
74}
75
76fn render_table(artifact: &TableArtifact) {
77 let headers: Vec<&str> = artifact
78 .columns
79 .iter()
80 .map(|c| c.label.as_deref().unwrap_or(&c.name))
81 .collect();
82
83 let rows: Vec<Vec<String>> = artifact
84 .items
85 .iter()
86 .map(|item| {
87 artifact
88 .columns
89 .iter()
90 .map(|col| {
91 item.get(&col.name)
92 .map_or_else(String::new, value_to_display)
93 })
94 .collect()
95 })
96 .collect();
97
98 CliService::table(&headers, &rows);
99}
100
101fn render_list(artifact: &ListArtifact) {
102 for item in &artifact.items {
103 CliService::subsection(&item.title);
104 if !item.summary.is_empty() {
105 CliService::output(&item.summary);
106 }
107 if !item.link.is_empty() {
108 CliService::output(&item.link);
109 }
110 }
111}
112
113fn render_card(artifact: &PresentationCardArtifact) {
114 CliService::section(&artifact.title);
115 if let Some(subtitle) = &artifact.subtitle {
116 CliService::output(subtitle);
117 }
118 for section in &artifact.sections {
119 CliService::subsection(§ion.heading);
120 CliService::output(§ion.content);
121 }
122}
123
124fn render_chart(artifact: &ChartArtifact) {
125 let mut headers: Vec<&str> = vec!["label"];
126 for dataset in &artifact.datasets {
127 headers.push(&dataset.label);
128 }
129
130 let rows: Vec<Vec<String>> = artifact
131 .labels
132 .iter()
133 .enumerate()
134 .map(|(row, label)| {
135 let mut cells = vec![label.clone()];
136 for dataset in &artifact.datasets {
137 cells.push(
138 dataset
139 .data
140 .get(row)
141 .map_or_else(String::new, ToString::to_string),
142 );
143 }
144 cells
145 })
146 .collect();
147
148 CliService::table(&headers, &rows);
149}