Skip to main content
Glama
8b-is
by 8b-is
relations_cli_sketch.rs6.21 kB
// examples/relations_cli_sketch.rs // Aye, Aye, Hue! We're turning this sketch into a masterpiece! // First, we need to bring in all the tools for the job. use clap::{Parser, ValueEnum}; use std::io::Write; use std::path::{Path, PathBuf}; // This is our custom Result type. It's a simple way to handle // different kinds of errors that might pop up. Think of it as a // universal translator for "uh-ohs". type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>; // Here's the star of our show, the missing OutputMode! // We're defining it as an enum so clap can understand the // different choices for the --mode flag. It's like giving the // program a menu to choose from. #[derive(ValueEnum, Clone, Debug, PartialEq)] enum OutputMode { Mermaid, Dot, Compressed, Text, // Added a text option to be explicit } #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] struct Args { /// The path to analyze. path: PathBuf, /// Analyze code relationships (imports, calls, types, tests) #[arg(long, conflicts_with = "mcp")] relations: bool, /// Show function call graph #[arg(long, requires = "relations")] call_graph: bool, /// Show test coverage relationships #[arg(long, requires = "relations")] test_coverage: bool, /// Focus analysis on specific file #[arg(long, value_name = "FILE")] focus: Option<PathBuf>, /// Filter relationships by type (imports, calls, types, tests, coupled) #[arg(long, value_name = "TYPE")] filter: Option<String>, /// The output format for the analysis. #[arg(long, value_enum, default_value_t = OutputMode::Text)] mode: OutputMode, // A dummy mcp flag to resolve the conflict #[arg(long)] mcp: bool, } // --- Stubbed out components to make the sketch runnable --- // These are like stand-ins for the real actors. They have the right names // and do just enough to make the scene work. struct RelationAnalyzer; impl RelationAnalyzer { fn new() -> Self { Self } fn analyze_directory(&mut self, _path: &Path) -> Result<()> { println!("Analyzing directory... Pretend I'm doing something smart!"); Ok(()) } } // A generic formatter trait. It's a contract that says "if you're a formatter, // you MUST know how to format". trait RelationFormatter { fn format( &self, writer: &mut dyn Write, analyzer: &RelationAnalyzer, path: &Path, ) -> Result<()>; } struct MermaidRelationFormatter; impl RelationFormatter for MermaidRelationFormatter { fn format( &self, writer: &mut dyn Write, _analyzer: &RelationAnalyzer, _path: &Path, ) -> Result<()> { writeln!(writer, "graph TD;\n A-->B;")?; println!("Formatted output as a beautiful Mermaid diagram! 🧜‍♀️"); Ok(()) } } struct DotRelationFormatter; impl RelationFormatter for DotRelationFormatter { fn format( &self, writer: &mut dyn Write, _analyzer: &RelationAnalyzer, _path: &Path, ) -> Result<()> { writeln!(writer, "digraph G {{\n A -> B;\n}}")?; println!("Formatted output in Dot format. It's on point! •"); Ok(()) } } struct CompressedRelationFormatter; impl RelationFormatter for CompressedRelationFormatter { fn format( &self, writer: &mut dyn Write, _analyzer: &RelationAnalyzer, _path: &Path, ) -> Result<()> { writeln!(writer, "A->B")?; println!("Formatted output, compressed and ready to go! 📦"); Ok(()) } } struct TextRelationFormatter; impl RelationFormatter for TextRelationFormatter { fn format( &self, writer: &mut dyn Write, _analyzer: &RelationAnalyzer, _path: &Path, ) -> Result<()> { writeln!(writer, "File A is related to File B")?; println!("Formatted output as plain text. Simple and classic."); Ok(()) } } // In main(): fn main() -> Result<()> { let args = Args::parse(); // We'll just use stdout for our writer, to print to the console. let mut writer = std::io::stdout(); // The path comes from our args now. let path = &args.path; if args.relations { println!("Relationship analysis mode activated! Let's see how everything connects. 🔗"); // Initialize relationship analyzer let mut analyzer = RelationAnalyzer::new(); // Analyze the directory analyzer.analyze_directory(path)?; // Apply filters if specified if let Some(filter) = &args.filter { println!("Filtering relationships by type: {}", filter); // Filter relationships by type } // Focus on specific file if requested if let Some(focus_file) = &args.focus { println!("Focusing analysis on file: {:?}", focus_file); // Get relationships for specific file } // Format output based on mode // This is where we choose our formatter based on the --mode flag. // It's like choosing the right lens for the camera. match args.mode { OutputMode::Mermaid => { let formatter = MermaidRelationFormatter; formatter.format(&mut writer, &analyzer, path)?; } OutputMode::Dot => { let formatter = DotRelationFormatter; formatter.format(&mut writer, &analyzer, path)?; } OutputMode::Compressed => { let formatter = CompressedRelationFormatter; formatter.format(&mut writer, &analyzer, path)?; } // The original sketch had a catch-all `_`, but it's better to be // explicit with our Text mode. No surprises! OutputMode::Text => { let formatter = TextRelationFormatter; formatter.format(&mut writer, &analyzer, path)?; } } return Ok(()); } println!("No --relations flag, so we're just chilling. 😎"); // ... rest of normal tree logic would go here ... Ok(()) }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/8b-is/smart-tree'

If you have feedback or need assistance with the MCP directory API, please join our Discord server