Skip to main content
Glama
by 8b-is
relations_formatter.rs6 kB
//! Relations formatter that works with the standard formatter interface //! "Making relations a first-class mode!" - Omni use crate::formatters::Formatter; use crate::relations::RelationAnalyzer; use crate::scanner::{FileNode, TreeStats}; use anyhow::Result; use std::io::Write; use std::path::Path; /// Main relations formatter - delegates to text formatter by default pub struct RelationsFormatter { filter: Option<String>, focus: Option<std::path::PathBuf>, } impl RelationsFormatter { pub fn new(filter: Option<String>, focus: Option<std::path::PathBuf>) -> Self { Self { filter, focus } } } impl Formatter for RelationsFormatter { fn format( &self, writer: &mut dyn Write, _nodes: &[FileNode], _stats: &TreeStats, root_path: &Path, ) -> Result<()> { // Create relation analyzer let mut analyzer = RelationAnalyzer::new(); // Analyze the directory eprintln!("🔍 Analyzing code relationships..."); analyzer.analyze_directory(root_path)?; // Apply filters if specified if let Some(filter_type) = &self.filter { // In a real implementation, we'd filter the relations eprintln!("📋 Filtering by: {}", filter_type); } // Get relations based on focus or all let relations: Vec<&crate::relations::FileRelation> = if let Some(focus_file) = &self.focus { // Convert relative path to absolute for matching let abs_focus = if focus_file.is_relative() { root_path.join(focus_file) } else { focus_file.clone() }; let file_relations = analyzer.get_file_relations(&abs_focus); eprintln!( "📄 Found {} relationships for {}", file_relations.len(), focus_file.display() ); file_relations } else { analyzer.get_relations().iter().collect() }; // Write header writeln!(writer, "🔗 Code Relationship Analysis")?; writeln!(writer, "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")?; writeln!(writer)?; // If no relationships found if relations.is_empty() { if let Some(focus_file) = &self.focus { writeln!( writer, "No relationships found for: {}", focus_file.display() )?; } else { writeln!(writer, "No relationships found in the codebase.")?; } return Ok(()); } // Group relations by type use crate::relations::RelationType; let mut imports = Vec::new(); let mut calls = Vec::new(); let mut types = Vec::new(); let mut tests = Vec::new(); let mut coupled = Vec::new(); for relation in &relations { match &relation.relation_type { RelationType::Imports => imports.push(relation), RelationType::FunctionCall => calls.push(relation), RelationType::TypeUsage => types.push(relation), RelationType::TestedBy => tests.push(relation), RelationType::Coupled => coupled.push(relation), RelationType::Exports => {} // Skip exports for now } } // Display relationships by type if !imports.is_empty() { writeln!(writer, "📦 Imports ({}):", imports.len())?; for rel in imports { writeln!( writer, " {} → {}", rel.source.display(), rel.target.display() )?; } writeln!(writer)?; } if !calls.is_empty() { writeln!(writer, "📞 Function Calls ({}):", calls.len())?; for rel in calls { writeln!( writer, " {} → {}", rel.source.display(), rel.target.display() )?; } writeln!(writer)?; } if !types.is_empty() { writeln!(writer, "🏷️ Type Usage ({}):", types.len())?; for rel in types { writeln!( writer, " {} → {}", rel.source.display(), rel.target.display() )?; } writeln!(writer)?; } if !tests.is_empty() { writeln!(writer, "🧪 Tests ({}):", tests.len())?; for rel in tests { writeln!( writer, " {} → {}", rel.source.display(), rel.target.display() )?; } writeln!(writer)?; } if !coupled.is_empty() { writeln!(writer, "🔗 Coupled Changes ({}):", coupled.len())?; for rel in coupled { writeln!( writer, " {} ↔ {}", rel.source.display(), rel.target.display() )?; } writeln!(writer)?; } // Summary writeln!(writer, "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")?; writeln!(writer, "Total relationships: {}", relations.len())?; if let Some(focus_file) = &self.focus { writeln!(writer, "Focused on: {}", focus_file.display())?; } else { writeln!(writer, "Files analyzed: {}", root_path.display())?; } 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