gobby-code 1.3.3

Fast Rust CLI for Gobby's code index — AST-aware search, symbol navigation, and dependency graph
Documentation
use std::collections::BTreeMap;
use std::path::Path;

use crate::config::Context;
use crate::db;
use crate::output::{self, Format};
use crate::visibility;

pub fn repo_outline(ctx: &Context, format: Format) -> anyhow::Result<()> {
    let mut conn = db::connect_readonly(&ctx.database_url)?;

    let files: Vec<serde_json::Value> = visibility::visible_tree(&mut conn, ctx)?
        .into_iter()
        .map(|file| {
            serde_json::json!({
                "file_path": file.file_path,
                "language": file.language,
                "symbol_count": file.symbol_count,
            })
        })
        .collect();

    let mut dirs: BTreeMap<String, Vec<&serde_json::Value>> = BTreeMap::new();
    for f in &files {
        let fp = f["file_path"].as_str().unwrap_or("");
        let dir = Path::new(fp)
            .parent()
            .and_then(|p| {
                let path = p.to_string_lossy();
                if path.is_empty() {
                    None
                } else {
                    Some(path.to_string())
                }
            })
            .unwrap_or_else(|| ".".to_string());
        dirs.entry(dir).or_default().push(f);
    }

    match format {
        Format::Json => output::print_json(&dirs),
        Format::Text => {
            let mut text = String::new();
            for (dir, dir_files) in &dirs {
                let total_syms: i64 = dir_files
                    .iter()
                    .map(|f| f["symbol_count"].as_i64().unwrap_or(0))
                    .sum();
                text.push_str(&format!(
                    "{dir}/ ({} files, {total_syms} symbols)\n",
                    dir_files.len()
                ));
            }
            output::print_text(text.trim_end())
        }
    }
}