Skip to main content

systemprompt_cli/commands/web/templates/
list.rs

1use anyhow::{Context, Result};
2use clap::Args;
3use std::fs;
4use std::path::Path;
5
6use crate::CliConfig;
7use crate::shared::CommandOutput;
8
9use super::super::paths::WebPaths;
10use super::super::types::{TemplateSummary, TemplatesConfig};
11
12#[derive(Debug, Clone, Copy, Args)]
13pub struct ListArgs {
14    #[arg(long, help = "Show only templates with missing files")]
15    pub missing: bool,
16}
17
18pub(super) fn execute(args: ListArgs, config: &CliConfig) -> Result<CommandOutput> {
19    execute_in_dir(args, config, &WebPaths::resolve()?.templates)
20}
21
22pub fn execute_in_dir(
23    args: ListArgs,
24    _config: &CliConfig,
25    templates_dir: &Path,
26) -> Result<CommandOutput> {
27    let templates_yaml_path = templates_dir.join("templates.yaml");
28
29    if !templates_yaml_path.exists() {
30        let empty: Vec<TemplateSummary> = vec![];
31        return Ok(CommandOutput::table_of(
32            vec!["name", "content_types", "file_exists", "file_path"],
33            &empty,
34        )
35        .with_title("Templates"));
36    }
37
38    let content = fs::read_to_string(&templates_yaml_path).with_context(|| {
39        format!(
40            "Failed to read templates config at {}",
41            templates_yaml_path.display()
42        )
43    })?;
44
45    let config: TemplatesConfig = serde_yaml::from_str(&content).with_context(|| {
46        format!(
47            "Failed to parse templates config at {}",
48            templates_yaml_path.display()
49        )
50    })?;
51
52    let mut templates: Vec<TemplateSummary> = config
53        .templates
54        .iter()
55        .map(|(name, entry)| {
56            let file_path = templates_dir.join(format!("{}.html", name));
57            let file_exists = file_path.exists();
58
59            TemplateSummary {
60                name: name.clone(),
61                content_types: entry.content_types.clone(),
62                file_exists,
63                file_path: file_path.to_string_lossy().to_string(),
64            }
65        })
66        .filter(|t| !args.missing || !t.file_exists)
67        .collect();
68
69    templates.sort_by(|a, b| a.name.cmp(&b.name));
70
71    Ok(CommandOutput::table_of(
72        vec!["name", "content_types", "file_exists", "file_path"],
73        &templates,
74    )
75    .with_title("Templates"))
76}