Initial upload with CI/CD workflow
This commit is contained in:
215
app/src/generator/mod.rs
Normal file
215
app/src/generator/mod.rs
Normal file
@@ -0,0 +1,215 @@
|
||||
use anyhow::Result;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use crate::parser::{CommandInfo, Argument, SubCommand};
|
||||
|
||||
pub struct TuiGenerator;
|
||||
|
||||
impl TuiGenerator {
|
||||
pub fn generate_from_help(command_info: &CommandInfo) -> Result<String> {
|
||||
let mut output = String::new();
|
||||
|
||||
output.push_str(&format!("# TUI Configuration for {}\n\n", command_info.name));
|
||||
output.push_str(&format!("## Command Information\n"));
|
||||
output.push_str(&format!("- Name: {}\n", command_info.name));
|
||||
output.push_str(&format!("- Description: {}\n", command_info.description));
|
||||
|
||||
if let Some(version) = &command_info.version {
|
||||
output.push_str(&format!("- Version: {}\n", version));
|
||||
}
|
||||
|
||||
output.push_str("\n## Arguments\n");
|
||||
for arg in &command_info.arguments {
|
||||
output.push_str(&format!("- {}", Self::format_argument(arg)));
|
||||
}
|
||||
|
||||
if !command_info.subcommands.is_empty() {
|
||||
output.push_str("\n## Subcommands\n");
|
||||
for subcmd in &command_info.subcommands {
|
||||
output.push_str(&format!("- {}: {}\n", subcmd.name, subcmd.description));
|
||||
}
|
||||
}
|
||||
|
||||
if !command_info.examples.is_empty() {
|
||||
output.push_str("\n## Examples\n");
|
||||
for example in &command_info.examples {
|
||||
output.push_str(&format!("```\n{}\n```\n", example));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
fn format_argument(arg: &Argument) -> String {
|
||||
let mut parts = Vec::new();
|
||||
|
||||
if let Some(short) = arg.short {
|
||||
parts.push(format!("-{}", short));
|
||||
}
|
||||
|
||||
if let Some(long) = &arg.long {
|
||||
parts.push(format!("--{}", long));
|
||||
}
|
||||
|
||||
let flags = parts.join(", ");
|
||||
let required = if arg.required { " (required)" } else { "" };
|
||||
|
||||
format!("`{}`{}{}", flags, arg.description, required)
|
||||
}
|
||||
|
||||
pub fn generate_html_preview(command_info: &CommandInfo) -> Result<String> {
|
||||
let mut html = String::new();
|
||||
|
||||
html.push_str(r#"<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>TUI Preview - "#);
|
||||
html.push_str(&command_info.name);
|
||||
html.push_str(r#"</title>
|
||||
<style>
|
||||
body { font-family: monospace; background: #1a1b26; color: #a9b1d6; padding: 20px; }
|
||||
h1 { color: #7aa2f7; }
|
||||
h2 { color: #bb9af7; margin-top: 30px; }
|
||||
.arg { background: #24283b; padding: 10px; margin: 5px 0; border-radius: 5px; }
|
||||
.required { color: #f7768e; }
|
||||
.optional { color: #9ece6a; }
|
||||
code { background: #414868; padding: 2px 6px; border-radius: 3px; }
|
||||
pre { background: #24283b; padding: 15px; border-radius: 5px; overflow-x: auto; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>"#);
|
||||
html.push_str(&command_info.name);
|
||||
html.push_str(" - ");
|
||||
html.push_str(&command_info.description);
|
||||
html.push_str(r#"</h1>
|
||||
|
||||
<h2>Arguments</h2>
|
||||
"#);
|
||||
|
||||
for arg in &command_info.arguments {
|
||||
html.push_str(r#" <div class="arg">
|
||||
<code>"#);
|
||||
let mut flags = Vec::new();
|
||||
if let Some(short) = arg.short {
|
||||
flags.push(format!("-{}", short));
|
||||
}
|
||||
if let Some(long) = &arg.long {
|
||||
flags.push(format!("--{}", long));
|
||||
}
|
||||
html.push_str(&flags.join(", "));
|
||||
html.push_str(r#"</code>
|
||||
<p>"#);
|
||||
html.push_str(&arg.description);
|
||||
if arg.required {
|
||||
html.push_str(r#" <span class="required">(required)</span>"#);
|
||||
}
|
||||
html.push_str(r#"</p>
|
||||
</div>
|
||||
"#);
|
||||
}
|
||||
|
||||
html.push_str(r#"
|
||||
</body>
|
||||
</html>
|
||||
"#);
|
||||
|
||||
Ok(html)
|
||||
}
|
||||
|
||||
pub fn export_tui_config(command_info: &CommandInfo, output: &PathBuf) -> Result<()> {
|
||||
let config = Self::generate_toml_config(command_info)?;
|
||||
fs::write(output, config)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_toml_config(command_info: &CommandInfo) -> Result<String> {
|
||||
let mut toml = String::new();
|
||||
|
||||
toml.push_str(&format!("name = \"{}\"\n", command_info.name));
|
||||
toml.push_str(&format!("description = \"{}\"\n\n", command_info.description));
|
||||
|
||||
toml.push_str("[arguments]\n");
|
||||
for arg in &command_info.arguments {
|
||||
toml.push_str(&format!("[arguments.{}]\n", arg.name));
|
||||
if let Some(short) = arg.short {
|
||||
toml.push_str(&format!("short = '{}'\n", short));
|
||||
}
|
||||
if let Some(long) = &arg.long {
|
||||
toml.push_str(&format!("long = \"{}\"\n", long));
|
||||
}
|
||||
toml.push_str(&format!("description = \"{}\"\n", arg.description));
|
||||
toml.push_str(&format!("required = {}\n", arg.required));
|
||||
if let Some(default) = &arg.default_value {
|
||||
toml.push_str(&format!("default = \"{}\"\n", default));
|
||||
}
|
||||
if !arg.possible_values.is_empty() {
|
||||
toml.push_str(&format!("possible_values = {:?}\n", arg.possible_values));
|
||||
}
|
||||
toml.push_str("\n");
|
||||
}
|
||||
|
||||
if !command_info.subcommands.is_empty() {
|
||||
toml.push_str("\n[subcommands]\n");
|
||||
for subcmd in &command_info.subcommands {
|
||||
toml.push_str(&format!("[subcommands.{}]\n", subcmd.name));
|
||||
toml.push_str(&format!("description = \"{}\"\n", subcmd.description));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(toml)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::parser::{Argument, CommandInfo};
|
||||
|
||||
#[test]
|
||||
fn test_generate_from_help() {
|
||||
let info = CommandInfo {
|
||||
name: "test".to_string(),
|
||||
description: "A test command".to_string(),
|
||||
version: Some("1.0.0".to_string()),
|
||||
arguments: vec![Argument {
|
||||
name: "verbose".to_string(),
|
||||
short: Some('v'),
|
||||
long: Some("verbose".to_string()),
|
||||
description: "Enable verbose mode".to_string(),
|
||||
required: false,
|
||||
takes_value: false,
|
||||
default_value: None,
|
||||
possible_values: Vec::new(),
|
||||
}],
|
||||
subcommands: Vec::new(),
|
||||
examples: vec!["test -v".to_string()],
|
||||
environment_variables: Vec::new(),
|
||||
};
|
||||
|
||||
let result = TuiGenerator::generate_from_help(&info);
|
||||
assert!(result.is_ok());
|
||||
let output = result.unwrap();
|
||||
assert!(output.contains("test"));
|
||||
assert!(output.contains("A test command"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generate_html_preview() {
|
||||
let info = CommandInfo {
|
||||
name: "test".to_string(),
|
||||
description: "A test command".to_string(),
|
||||
version: None,
|
||||
arguments: vec![],
|
||||
subcommands: Vec::new(),
|
||||
examples: Vec::new(),
|
||||
environment_variables: Vec::new(),
|
||||
};
|
||||
|
||||
let result = TuiGenerator::generate_html_preview(&info);
|
||||
assert!(result.is_ok());
|
||||
let output = result.unwrap();
|
||||
assert!(output.contains("<!DOCTYPE html>"));
|
||||
assert!(output.contains("test"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user