← back to jdx__fnox

Function bodies 391 total

All specs Real LLM only Function bodies
parse_key_value function · rust · L314-L334 (21 LOC)
src/commands/import.rs
    fn parse_key_value(&self, line: &str, secrets: &mut HashMap<String, String>) -> Result<()> {
        if let Some((key, value)) = line.split_once('=') {
            let key = key.trim();
            let value = value.trim();

            // Handle quoted values
            let value = if (value.starts_with('"') && value.ends_with('"'))
                || (value.starts_with('\'') && value.ends_with('\''))
            {
                value[1..value.len() - 1].to_string()
            } else {
                value.to_string()
            };

            if !key.is_empty() {
                secrets.insert(key.to_string(), value);
            }
        }
        Ok(())
    }
parse_json function · rust · L335-L348 (14 LOC)
src/commands/import.rs
    fn parse_json(&self, input: &str, source_name: &str) -> Result<HashMap<String, String>> {
        let data: serde_json::Value = serde_json::from_str(input).map_err(|e| {
            // serde_json provides line and column
            let offset = self.offset_from_line_col(input, e.line(), e.column());
            FnoxError::ImportParseErrorWithSource {
                format: "JSON".to_string(),
                details: e.to_string(),
                src: Arc::new(NamedSource::new(source_name, Arc::new(input.to_string()))),
                span: SourceSpan::new(offset.into(), 1usize),
            }
        })?;
        self.extract_string_values(&data)
    }
parse_yaml function · rust · L349-L367 (19 LOC)
src/commands/import.rs
    fn parse_yaml(&self, input: &str, source_name: &str) -> Result<HashMap<String, String>> {
        let data: serde_yaml::Value = serde_yaml::from_str(input).map_err(|e| {
            // serde_yaml provides location via e.location()
            // Note: serde_yaml uses 0-indexed line/column, so we add 1 for our 1-indexed function
            if let Some(loc) = e.location() {
                let offset = self.offset_from_line_col(input, loc.line() + 1, loc.column() + 1);
                FnoxError::ImportParseErrorWithSource {
                    format: "YAML".to_string(),
                    details: e.to_string(),
                    src: Arc::new(NamedSource::new(source_name, Arc::new(input.to_string()))),
                    span: SourceSpan::new(offset.into(), 1usize),
                }
            } else {
                FnoxError::Config(format!("Failed to parse YAML: {}", e))
            }
        })?;
        self.extract_string_values(&data)
    }
parse_toml function · rust · L368-L384 (17 LOC)
src/commands/import.rs
    fn parse_toml(&self, input: &str, source_name: &str) -> Result<HashMap<String, String>> {
        let data: serde_json::Value = toml_edit::de::from_str(input).map_err(|e| {
            // toml_edit provides span via e.span()
            if let Some(span) = e.span() {
                FnoxError::ImportParseErrorWithSource {
                    format: "TOML".to_string(),
                    details: e.to_string(),
                    src: Arc::new(NamedSource::new(source_name, Arc::new(input.to_string()))),
                    span: SourceSpan::new(span.start.into(), span.end - span.start),
                }
            } else {
                FnoxError::Config(format!("Failed to parse TOML: {}", e))
            }
        })?;
        self.extract_string_values(&data)
    }
offset_from_line_col function · rust · L395-L437 (43 LOC)
src/commands/import.rs
    fn offset_from_line_col(&self, input: &str, line: usize, col: usize) -> usize {
        // Handle invalid 0-indexed values (serde_json can return 0,0 for some errors)
        if line == 0 || col == 0 {
            return 0;
        }

        let mut current_line = 1;
        let mut line_start_byte = 0;

        // Find the byte offset of the target line by scanning for newlines
        for (byte_idx, c) in input.char_indices() {
            if current_line == line {
                // Found the start of target line
                line_start_byte = byte_idx;
                break;
            }
            if c == '\n' {
                current_line += 1;
                // Set line_start_byte to byte after newline for next iteration
                line_start_byte = byte_idx + 1;
            }
        }

        // If requested line is beyond the file, return end of input
        if current_line < line {
            return input.len();
        }

        // Defensive: clamp line
extract_string_values function · rust · L438-L466 (29 LOC)
src/commands/import.rs
    fn extract_string_values<V>(&self, data: &V) -> Result<HashMap<String, String>>
    where
        V: serde::Serialize,
    {
        let json_value = serde_json::to_value(data)?;

        let mut secrets = HashMap::new();

        if let serde_json::Value::Object(map) = json_value {
            for (key, value) in map {
                match value {
                    serde_json::Value::String(s) => {
                        secrets.insert(key, s);
                    }
                    serde_json::Value::Null
                    | serde_json::Value::Bool(_)
                    | serde_json::Value::Number(_) => {
                        secrets.insert(key, value.to_string());
                    }
                    _ => {
                        tracing::warn!("Skipping non-string value for key '{}'", key);
                    }
                }
            }
        }

        Ok(secrets)
    }
run function · rust · L26-L85 (60 LOC)
src/commands/init.rs
    pub async fn run(&self, cli: &Cli) -> Result<()> {
        // Determine the target config path
        let config_path = if self.global {
            Config::global_config_path()
        } else {
            cli.config.clone()
        };

        tracing::debug!(
            "Initializing new fnox configuration at '{}'",
            config_path.display()
        );

        if config_path.exists() && !self.force {
            return Err(FnoxError::Config(format!(
                "Configuration file '{}' already exists. Use --force to overwrite.",
                config_path.display()
            )));
        }

        // Create parent directory if it doesn't exist (for global config)
        if self.global
            && let Some(parent) = config_path.parent()
        {
            std::fs::create_dir_all(parent).map_err(|e| {
                FnoxError::Config(format!(
                    "Failed to create config directory '{}': {}",
                    parent.display(),
         
Repobility — same analyzer, your code, free for public repos · /scan/
run_wizard function · rust · L86-L161 (76 LOC)
src/commands/init.rs
    async fn run_wizard(&self) -> Result<Config> {
        println!("\n🔐 Welcome to fnox setup wizard!\n");
        println!("This will help you configure your first secret provider.\n");

        // Ask if they want to set up a provider
        let setup_provider = Confirm::new("Would you like to set up a provider now?")
            .affirmative("Yes")
            .negative("No, I'll configure it later")
            .run()
            .map_err(|e| FnoxError::Config(format!("Wizard cancelled: {}", e)))?;

        if !setup_provider {
            println!("\n✓ Creating minimal configuration file.");
            return Ok(Config::new());
        }

        // Select provider category
        let category = self.select_category()?;

        // Get providers for that category
        let providers = ProviderConfig::wizard_info_by_category(category);

        // Select specific provider
        let provider_info = self.select_provider(&providers)?;

        // Print setup instructions
    
select_category function · rust · L164-L189 (26 LOC)
src/commands/init.rs
    fn select_category(&self) -> Result<WizardCategory> {
        let mut select = Select::new("What type of provider do you want to use?")
            .description("Choose a category based on your security and convenience needs")
            .filterable(false);

        for category in WizardCategory::all() {
            select = select.option(
                DemandOption::new(category.display_name())
                    .label(category.display_name())
                    .description(category.description()),
            );
        }

        let selected = select
            .run()
            .map_err(|e| FnoxError::Config(format!("Wizard cancelled: {}", e)))?;

        // Map the display name back to the category
        for category in WizardCategory::all() {
            if category.display_name() == selected {
                return Ok(*category);
            }
        }

        Err(FnoxError::Config("Unknown provider category".to_string()))
    }
select_provider function · rust · L192-L215 (24 LOC)
src/commands/init.rs
    fn select_provider(&self, providers: &[&'static WizardInfo]) -> Result<&'static WizardInfo> {
        let mut select = Select::new("Select provider:").filterable(false);

        for info in providers {
            select = select.option(
                DemandOption::new(info.provider_type)
                    .label(info.display_name)
                    .description(info.description),
            );
        }

        let selected = select
            .run()
            .map_err(|e| FnoxError::Config(format!("Wizard cancelled: {}", e)))?;

        // Find the selected provider info
        for info in providers {
            if info.provider_type == selected {
                return Ok(info);
            }
        }

        Err(FnoxError::Config("Unknown provider".to_string()))
    }
collect_fields function · rust · L218-L238 (21 LOC)
src/commands/init.rs
    fn collect_fields(&self, info: &WizardInfo) -> Result<HashMap<String, String>> {
        let mut fields = HashMap::new();

        for field in info.fields {
            let result = Input::new(field.label).placeholder(field.placeholder).run();

            match result {
                Ok(value) => {
                    if value.is_empty() && field.required {
                        return Err(FnoxError::Config(format!("{} is required", field.name)));
                    }
                    fields.insert(field.name.to_string(), value);
                }
                Err(e) => {
                    return Err(FnoxError::Config(format!("Wizard cancelled: {}", e)));
                }
            }
        }

        Ok(fields)
    }
get_provider_name function · rust · L241-L253 (13 LOC)
src/commands/init.rs
    fn get_provider_name(&self, default: &str) -> Result<String> {
        Input::new("Provider name:")
            .placeholder(default)
            .run()
            .map(|name| {
                if name.is_empty() {
                    default.to_string()
                } else {
                    name
                }
            })
            .map_err(|e| FnoxError::Config(format!("Wizard cancelled: {}", e)))
    }
test_provider_connection function · rust · L256-L283 (28 LOC)
src/commands/init.rs
    async fn test_provider_connection(&self, provider_config: &ProviderConfig) {
        println!("\n🔍 Testing provider connection...");

        // Wizard-created configs always have literal values, so we can use try_to_resolved
        match provider_config.try_to_resolved() {
            Ok(resolved) => match get_provider_from_resolved(&resolved) {
                Ok(provider) => match provider.test_connection().await {
                    Ok(()) => {
                        println!("✓ Provider connection successful!\n");
                    }
                    Err(e) => {
                        println!("⚠️  Provider connection test failed: {}", e);
                        println!(
                            "   You can still save the configuration and fix the issue later.\n"
                        );
                    }
                },
                Err(e) => {
                    println!("⚠️  Could not create provider: {}", e);
                    println!("   You 
run function · rust · L90-L137 (48 LOC)
src/commands/list.rs
    pub async fn run(&self, cli: &Cli, config: Config) -> Result<()> {
        let profile = Config::get_profile(cli.profile.as_deref());
        tracing::debug!("Listing secrets in profile '{}'", profile);

        // Get the profile secrets
        let profile_secrets = config.get_secrets(&profile)?;

        if profile_secrets.is_empty() {
            if !self.complete {
                println!("No secrets defined in profile '{}'", profile);
            }
            return Ok(());
        }

        // Preserve insertion order from IndexMap
        let keys: Vec<_> = profile_secrets.keys().collect();

        // Handle completion mode
        if self.complete {
            for key in keys {
                println!("{}", key);
            }
            return Ok(());
        }

        // Resolve secrets if values are requested
        let resolved_values = if self.values {
            Some(resolve_secrets_batch(&config, &profile, &profile_secrets).await?)
        } else {
       
get_source_type_and_provider_key function · rust · L138-L166 (29 LOC)
src/commands/list.rs
    fn get_source_type_and_provider_key(
        &self,
        secret_config: &crate::config::SecretConfig,
    ) -> (String, String) {
        let (base_type, provider_key) = if let Some(provider) = secret_config.provider() {
            let pk = secret_config.value().unwrap_or("");
            let pk_display = if !self.full && pk.len() > 40 {
                format!("{}...", &pk[..37])
            } else {
                pk.to_string()
            };
            (format!("provider ({})", provider), pk_display)
        } else if secret_config.value().is_some() {
            ("stored value".to_string(), String::new())
        } else if secret_config.default.is_some() {
            ("default value".to_string(), String::new())
        } else {
            ("env var".to_string(), String::new())
        };

        let source_type = if secret_config.as_file {
            format!("{} [file]", base_type)
        } else {
            base_type
        };

        (source_type, provider_key
Same scanner, your repo: https://repobility.com — Repobility
display_basic function · rust · L167-L193 (27 LOC)
src/commands/list.rs
    fn display_basic(
        &self,
        keys: &[&String],
        profile_secrets: &indexmap::IndexMap<String, crate::config::SecretConfig>,
    ) -> Result<()> {
        let mut rows = Vec::new();
        for key in keys {
            let secret_config = &profile_secrets[*key];
            let (source_type, provider_key_str) =
                self.get_source_type_and_provider_key(secret_config);
            let description_str = secret_config
                .description
                .as_deref()
                .unwrap_or("")
                .to_string();

            rows.push(SecretRow {
                key: (*key).clone(),
                source_type,
                provider_key: provider_key_str,
                description: description_str,
            });
        }

        self.display_table(rows)
    }
display_with_sources function · rust · L194-L226 (33 LOC)
src/commands/list.rs
    fn display_with_sources(
        &self,
        keys: &[&String],
        profile_secrets: &indexmap::IndexMap<String, crate::config::SecretConfig>,
    ) -> Result<()> {
        let mut rows = Vec::new();
        for key in keys {
            let secret_config = &profile_secrets[*key];
            let (source_type, provider_key_str) =
                self.get_source_type_and_provider_key(secret_config);
            let description_str = secret_config
                .description
                .as_deref()
                .unwrap_or("")
                .to_string();
            let source_file = secret_config
                .source_path
                .as_ref()
                .map(|p| p.display().to_string())
                .unwrap_or_else(|| "unknown".to_string());

            rows.push(SecretRowWithSources {
                key: (*key).clone(),
                source_type,
                source_file,
                provider_key: provider_key_str,
                descript
display_with_values function · rust · L227-L262 (36 LOC)
src/commands/list.rs
    fn display_with_values(
        &self,
        keys: &[&String],
        profile_secrets: &indexmap::IndexMap<String, crate::config::SecretConfig>,
        resolved_values: &IndexMap<String, Option<String>>,
    ) -> Result<()> {
        let mut rows = Vec::new();
        for key in keys {
            let secret_config = &profile_secrets[*key];
            let (source_type, provider_key_str) =
                self.get_source_type_and_provider_key(secret_config);
            let description_str = secret_config
                .description
                .as_deref()
                .unwrap_or("")
                .to_string();

            // Use the resolved value if available, otherwise show placeholder
            let value_str = resolved_values
                .get(*key)
                .and_then(|v| v.as_ref())
                .cloned()
                .unwrap_or_else(|| "<not available>".to_string());

            rows.push(SecretRowWithValues {
                key: (*key).clo
display_with_values_and_sources function · rust · L263-L304 (42 LOC)
src/commands/list.rs
    fn display_with_values_and_sources(
        &self,
        keys: &[&String],
        profile_secrets: &indexmap::IndexMap<String, crate::config::SecretConfig>,
        resolved_values: &IndexMap<String, Option<String>>,
    ) -> Result<()> {
        let mut rows = Vec::new();
        for key in keys {
            let secret_config = &profile_secrets[*key];
            let (source_type, provider_key_str) =
                self.get_source_type_and_provider_key(secret_config);
            let description_str = secret_config
                .description
                .as_deref()
                .unwrap_or("")
                .to_string();
            let source_file = secret_config
                .source_path
                .as_ref()
                .map(|p| p.display().to_string())
                .unwrap_or_else(|| "unknown".to_string());

            // Use the resolved value if available, otherwise show placeholder
            let value_str = resolved_values
                .g
display_table function · rust · L305-L326 (22 LOC)
src/commands/list.rs
    fn display_table<T: tabled::Tabled>(&self, rows: Vec<T>) -> Result<()> {
        let mut table = Table::new(rows);
        table.with(Style::empty());

        // Apply colors only if enabled
        if console::colors_enabled() {
            table.with(
                Modify::new(Rows::first())
                    .with(Color::FG_BRIGHT_BLUE)
                    .with(Format::content(|s| format!("\x1b[1m{}\x1b[0m", s))),
            );
        }

        if !self.full {
            // Apply width constraints for description and provider key columns
            table.with(Modify::new(Columns::last()).with(Width::wrap(40)));
        }

        println!("{}", table);
        Ok(())
    }
run function · rust · L150-L189 (40 LOC)
src/commands/mod.rs
    pub async fn run(&self, cli: &Cli) -> Result<()> {
        match self {
            // Commands that don't need config
            Commands::Version(cmd) => cmd.run(cli).await,
            Commands::Init(cmd) => cmd.run(cli).await,
            Commands::Completion(cmd) => cmd.run(cli).await,
            Commands::ConfigFiles(cmd) => cmd.run(cli).await,
            Commands::Schema(cmd) => cmd.run(cli).await,
            Commands::Usage(cmd) => cmd.run(cli).await,
            Commands::Activate(cmd) => cmd
                .run()
                .await
                .map_err(|e| FnoxError::Config(e.to_string())),
            Commands::Deactivate(cmd) => cmd
                .run(cli, Config::new())
                .await
                .map_err(|e| FnoxError::Config(e.to_string())),
            Commands::HookEnv(cmd) => cmd
                .run()
                .await
                .map_err(|e| FnoxError::Config(e.to_string())),

            // Commands that need config
        
run function · rust · L15-L35 (21 LOC)
src/commands/profiles.rs
    pub async fn run(&self, _cli: &Cli, config: Config) -> Result<()> {
        let mut profile_names = vec!["default".to_string()];
        profile_names.extend(config.profiles.keys().cloned());
        profile_names.sort();
        profile_names.dedup();

        if self.complete {
            // Output for completion
            for name in profile_names {
                println!("{}", name);
            }
        } else {
            // Normal output
            println!("Available profiles:");
            for name in profile_names {
                let secret_count = config.get_secrets(&name).map(|s| s.len()).unwrap_or(0);
                println!("  {} ({} secrets)", name, secret_count);
            }
        }
        Ok(())
    }
run function · rust · L25-L145 (121 LOC)
src/commands/provider/add.rs
    pub async fn run(&self, cli: &Cli) -> Result<()> {
        tracing::debug!(
            "Adding provider '{}' of type '{}'",
            self.provider,
            self.provider_type
        );

        // Determine the target config file
        let target_path = if self.global {
            let global_path = Config::global_config_path();
            // Create parent directory if it doesn't exist
            if let Some(parent) = global_path.parent() {
                std::fs::create_dir_all(parent).map_err(|e| {
                    FnoxError::Config(format!(
                        "Failed to create config directory '{}': {}",
                        parent.display(),
                        e
                    ))
                })?;
            }
            global_path
        } else {
            let current_dir = std::env::current_dir().map_err(|e| {
                FnoxError::Config(format!("Failed to get current directory: {}", e))
            })?;
            current_di
Open data scored by Repobility · https://repobility.com
run function · rust · L15-L30 (16 LOC)
src/commands/provider/list.rs
    pub async fn run(&self, _cli: &Cli, config: Config) -> Result<()> {
        tracing::debug!("Listing providers");

        if config.providers.is_empty() {
            return Ok(());
        }

        // Always just output provider names, one per line
        let mut names: Vec<_> = config.providers.keys().collect();
        names.sort();
        for name in names {
            println!("{}", name);
        }

        Ok(())
    }
run function · rust · L87-L95 (9 LOC)
src/commands/provider/mod.rs
    pub async fn run(&self, cli: &Cli, config: Config) -> Result<()> {
        match &self.action {
            None => ListCommand { complete: false }.run(cli, config).await,
            Some(ProviderAction::List(cmd)) => cmd.run(cli, config).await,
            Some(ProviderAction::Add(cmd)) => cmd.run(cli).await,
            Some(ProviderAction::Remove(cmd)) => cmd.run(cli).await,
            Some(ProviderAction::Test(cmd)) => cmd.run(cli, config).await,
        }
    }
run function · rust · L18-L53 (36 LOC)
src/commands/provider/remove.rs
    pub async fn run(&self, cli: &Cli) -> Result<()> {
        tracing::debug!("Removing provider '{}'", self.provider);

        // Determine the target config file
        let target_path = if self.global {
            Config::global_config_path()
        } else {
            let current_dir = std::env::current_dir().map_err(|e| {
                FnoxError::Config(format!("Failed to get current directory: {}", e))
            })?;
            current_dir.join(&cli.config)
        };

        // Load the target config file directly
        if !target_path.exists() {
            return Err(FnoxError::Config(format!(
                "Config file '{}' not found",
                target_path.display()
            )));
        }

        let mut config = Config::load(&target_path)?;

        if config.providers.shift_remove(&self.provider).is_some() {
            config.save(&target_path)?;
            let global_suffix = if self.global { " (global)" } else { "" };
            println!("✓ 
run function · rust · L18-L31 (14 LOC)
src/commands/provider/test.rs
    pub async fn run(&self, cli: &Cli, config: Config) -> Result<()> {
        let profile = Config::get_profile(cli.profile.as_deref());

        if self.all {
            self.test_all_providers(cli, &config, &profile).await
        } else if let Some(ref provider_name) = self.provider {
            self.test_single_provider(&config, &profile, provider_name)
                .await
        } else {
            Err(FnoxError::Config(
                "Please specify a provider name or use --all to test all providers".to_string(),
            ))?
        }
    }
test_single_provider function · rust · L32-L62 (31 LOC)
src/commands/provider/test.rs
    async fn test_single_provider(
        &self,
        config: &Config,
        profile: &str,
        provider_name: &str,
    ) -> Result<()> {
        tracing::debug!("Testing provider '{}'", provider_name);

        let provider_config = config
            .providers
            .get(provider_name)
            .ok_or_else(|| FnoxError::Config(format!("Provider '{}' not found", provider_name)))?;

        // Create the provider instance (resolving any secret refs in config)
        let provider = crate::providers::get_provider_resolved(
            config,
            profile,
            provider_name,
            provider_config,
        )
        .await?;

        // Test the connection
        provider.test_connection().await?;

        let check = console::style("✓").green();
        let styled_provider = console::style(provider_name).cyan();
        println!("{check} Provider {styled_provider} connection successful");
        Ok(())
    }
test_all_providers function · rust · L63-L158 (96 LOC)
src/commands/provider/test.rs
    async fn test_all_providers(&self, cli: &Cli, config: &Config, profile: &str) -> Result<()> {
        let providers = config.get_providers(profile);

        if providers.is_empty() {
            println!("No providers configured");
            return Ok(());
        }

        println!(
            "Testing {} provider{}...\n",
            providers.len(),
            if providers.len() == 1 { "" } else { "s" }
        );

        let mut passed = 0;
        let mut failed = 0;
        let mut errors: Vec<(String, String)> = Vec::new();

        for (provider_name, provider_config) in providers {
            let styled_provider = console::style(&provider_name).cyan();
            print!("  {} ", styled_provider);

            match crate::providers::get_provider_resolved(
                config,
                profile,
                &provider_name,
                &provider_config,
            )
            .await
            {
                Ok(provider) => match provider.te
run function · rust · L22-L96 (75 LOC)
src/commands/remove.rs
    pub async fn run(&self, cli: &Cli) -> Result<()> {
        let profile = Config::get_profile(cli.profile.as_deref());
        tracing::debug!("Removing secret '{}' from profile '{}'", self.key, profile);

        // Determine the target config file
        let target_path = if self.global {
            Config::global_config_path()
        } else {
            let current_dir = std::env::current_dir().map_err(|e| {
                FnoxError::Config(format!("Failed to get current directory: {}", e))
            })?;
            current_dir.join(&cli.config)
        };

        // Load the target config file directly (not the merged config)
        if !target_path.exists() {
            return Err(FnoxError::ConfigFileNotFound {
                path: target_path.clone(),
            });
        }

        // Check the secret exists before attempting removal
        let config = Config::load(&target_path)?;
        let profile_secrets = config.get_secrets(&profile)?;

        if !profi
run function · rust · L25-L42 (18 LOC)
src/commands/scan.rs
    pub async fn run(&self, _cli: &Cli, _config: Config) -> Result<()> {
        println!("Scanning directory: {}", self.dir.display());

        // TODO: Implement file scanning logic
        // - Walk through directory recursively
        // - Skip .git directory and hidden files
        // - Check for secret patterns in text files
        // - Use regex patterns to detect potential secrets
        // - Report findings

        if self.quiet {
            println!("Scan completed (quiet mode).");
        } else {
            println!("Scan completed. No implementation yet.");
        }

        Ok(())
    }
Repobility · severity-and-effort ranking · https://repobility.com
run function · rust · L10-L15 (6 LOC)
src/commands/schema.rs
    pub async fn run(&self, _cli: &Cli) -> Result<()> {
        let schema = schemars::schema_for!(Config);
        let json = serde_json::to_string_pretty(&schema)?;
        println!("{json}");
        Ok(())
    }
run function · rust · L28-L76 (49 LOC)
src/commands/tui.rs
    pub async fn run(&self, cli: &Cli, config: Config) -> Result<()> {
        let profile = Config::get_profile(cli.profile.as_deref());

        // Install panic hook to restore terminal on panic
        install_panic_hook();

        // Initialize terminal
        let mut terminal = enter_terminal().map_err(|e| {
            crate::error::FnoxError::Config(format!("Failed to initialize terminal: {}", e))
        })?;

        // Create guard to ensure terminal cleanup on any exit (error or success)
        let _guard = TerminalGuard;

        // Create app state
        let mut app = App::new(config, profile)?;

        // Create event handler
        let mut events = EventHandler::new(Duration::from_millis(250));

        // Store event tx for refresh operations
        app.set_event_tx(events.message_tx());

        // Spawn initial secret resolution
        app.spawn_resolve_secrets(events.message_tx());

        // Main event loop
        while app.running {
            // Rende
run function · rust · L9-L19 (11 LOC)
src/commands/usage.rs
    pub async fn run(&self, _cli: &Cli) -> Result<()> {
        use clap::CommandFactory;
        let cmd = Cli::command();
        let spec: usage::Spec = cmd.into();

        let min_version = r#"min_usage_version "1.3""#;
        let extra = include_str!("../assets/fnox-extras.usage.kdl").trim();

        println!("{min_version}\n{}\n{extra}", spec.to_string().trim());
        Ok(())
    }
all_config_filenames function · rust · L21-L30 (10 LOC)
src/config.rs
pub fn all_config_filenames(profile: Option<&str>) -> Vec<String> {
    let mut files = vec!["fnox.toml".to_string(), ".fnox.toml".to_string()];
    if let Some(p) = profile.filter(|p| *p != "default") {
        files.push(format!("fnox.{p}.toml"));
        files.push(format!(".fnox.{p}.toml"));
    }
    files.push("fnox.local.toml".to_string());
    files.push(".fnox.local.toml".to_string());
    files
}
load_smart function · rust · L165-L186 (22 LOC)
src/config.rs
    pub fn load_smart<P: AsRef<Path>>(path: P) -> Result<Self> {
        let path_ref = path.as_ref();

        // If the path is one of the default config filenames, use recursive loading
        let default_filenames = all_config_filenames(None);
        if default_filenames.iter().any(|f| path_ref == Path::new(f)) {
            Self::load_with_recursion(path_ref)
        } else {
            // For explicit paths, resolve relative paths against current directory first
            let resolved_path = if path_ref.is_relative() {
                env::current_dir()
                    .map_err(|e| {
                        FnoxError::Config(format!("Failed to get current directory: {}", e))
                    })?
                    .join(path_ref)
            } else {
                path_ref.to_path_buf()
            };
            // For explicit paths, use direct loading
            Self::load(resolved_path)
        }
    }
load function · rust · L189-L222 (34 LOC)
src/config.rs
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
        use miette::{NamedSource, SourceSpan};

        let path = path.as_ref();
        let content = fs::read_to_string(path).map_err(|source| FnoxError::ConfigReadFailed {
            path: path.to_path_buf(),
            source,
        })?;

        // Register the source for error reporting
        source_registry::register(path, content.clone());

        let mut config: Config = toml_edit::de::from_str(&content).map_err(|e| {
            // Try to create a source-aware error with span highlighting
            if let Some(span) = e.span() {
                FnoxError::ConfigParseErrorWithSource {
                    message: e.message().to_string(),
                    src: Arc::new(NamedSource::new(
                        path.display().to_string(),
                        Arc::new(content),
                    )),
                    span: SourceSpan::new(span.start.into(), span.end - span.start),
                }
  
load_with_recursion function · rust · L225-L244 (20 LOC)
src/config.rs
    fn load_with_recursion<P: AsRef<Path>>(_start_path: P) -> Result<Self> {
        // Start from current working directory and search upwards
        let current_dir = env::current_dir()
            .map_err(|e| FnoxError::Config(format!("Failed to get current directory: {}", e)))?;

        match Self::load_recursive(&current_dir, false) {
            Ok((_config, found)) if !found => {
                // No config file was found anywhere in the directory tree
                Err(FnoxError::ConfigNotFound {
                    message: format!(
                        "No configuration file found in {} or any parent directory",
                        current_dir.display()
                    ),
                    help: "Run 'fnox init' to create a configuration file".to_string(),
                })
            }
            Ok((config, _)) => Ok(config),
            Err(e) => Err(e),
        }
    }
load_recursive function · rust · L248-L303 (56 LOC)
src/config.rs
    fn load_recursive(dir: &Path, found_any: bool) -> Result<(Self, bool)> {
        // Get current profile from Settings (respects: CLI flag > Env var > Default)
        let profile = crate::settings::Settings::get().profile.clone();
        let filenames = all_config_filenames(Some(&profile));

        // Load all existing config files in order (later files override earlier ones)
        let mut config = Self::new();
        let mut found = found_any;

        for filename in &filenames {
            let path = dir.join(filename);
            if path.exists() {
                let file_config = Self::load(&path)?;
                config = Self::merge_configs(config, file_config)?;
                found = true;
            }
        }

        // If this config marks root, stop recursion but still load global config
        if config.root {
            // Load imports if any
            for import_path in &config.import.clone() {
                let import_config = Self::load_import(i
Repobility — same analyzer, your code, free for public repos · /scan/
load_global function · rust · L312-L325 (14 LOC)
src/config.rs
    fn load_global() -> Result<(Self, bool)> {
        let global_config_path = Self::global_config_path();

        if global_config_path.exists() {
            tracing::debug!(
                "Loading global config from {}",
                global_config_path.display()
            );
            let config = Self::load(&global_config_path)?;
            Ok((config, true))
        } else {
            Ok((Self::new(), false))
        }
    }
load_import function · rust · L328-L346 (19 LOC)
src/config.rs
    fn load_import(import_path: &str, base_dir: &Path) -> Result<Self> {
        let path = PathBuf::from(import_path);

        // Handle relative paths - they're relative to the base config's directory
        let absolute_path = if path.is_absolute() {
            path
        } else {
            base_dir.join(path)
        };

        if !absolute_path.exists() {
            return Err(FnoxError::Config(format!(
                "Import file not found: {}",
                absolute_path.display()
            )));
        }

        Self::load(&absolute_path)
    }
merge_configs function · rust · L349-L434 (86 LOC)
src/config.rs
    fn merge_configs(base: Config, overlay: Config) -> Result<Config> {
        let mut merged = base;

        // Merge imports (overlay takes precedence, but keep unique paths)
        for import_path in overlay.import {
            if !merged.import.contains(&import_path) {
                merged.import.push(import_path);
            }
        }

        // root flag: if either is true, result is true
        merged.root = merged.root || overlay.root;

        // Merge age_key_file (overlay takes precedence)
        if overlay.age_key_file.is_some() {
            merged.age_key_file = overlay.age_key_file;
        }

        // Merge if_missing (overlay takes precedence)
        if overlay.if_missing.is_some() {
            merged.if_missing = overlay.if_missing;
        }

        // Merge prompt_auth (overlay takes precedence)
        if overlay.prompt_auth.is_some() {
            merged.prompt_auth = overlay.prompt_auth;
        }

        // Merge default_provider and its source
save function · rust · L439-L464 (26 LOC)
src/config.rs
    pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()> {
        // Clone and clean up empty profiles before saving
        let mut clean_config = self.clone();
        clean_config
            .profiles
            .retain(|_, profile| !profile.is_empty());

        // First serialize with to_string_pretty to get proper structure
        let pretty_string = toml_edit::ser::to_string_pretty(&clean_config)?;

        // Parse it back as a document so we can modify it
        let mut doc = pretty_string
            .parse::<toml_edit::DocumentMut>()
            .map_err(|e| FnoxError::Config(format!("Failed to parse TOML: {}", e)))?;

        // Convert secrets to inline tables
        Self::convert_secrets_to_inline(&mut doc)?;

        fs::write(path.as_ref(), doc.to_string()).map_err(|source| {
            FnoxError::ConfigWriteFailed {
                path: path.as_ref().to_path_buf(),
                source,
            }
        })?;
        Ok(())
    }
convert_secrets_to_inline function · rust · L467-L524 (58 LOC)
src/config.rs
    fn convert_secrets_to_inline(doc: &mut toml_edit::DocumentMut) -> Result<()> {
        use toml_edit::{InlineTable, Item};

        // Convert top-level [secrets]
        if let Some(secrets_item) = doc.get_mut("secrets")
            && let Some(secrets_table) = secrets_item.as_table_mut()
        {
            let keys: Vec<String> = secrets_table.iter().map(|(k, _)| k.to_string()).collect();
            for key in keys {
                if let Some(item) = secrets_table.get_mut(&key)
                    && let Some(table) = item.as_table()
                {
                    let mut inline = InlineTable::new();
                    for (k, v) in table.iter() {
                        if let Some(value) = v.as_value() {
                            inline.insert(k, value.clone());
                        }
                    }
                    inline.fmt();
                    *item = Item::Value(toml_edit::Value::InlineTable(inline));
                }
            }
        }
save_secret_to_source function · rust · L533-L601 (69 LOC)
src/config.rs
    pub fn save_secret_to_source(
        &self,
        secret_name: &str,
        secret_config: &SecretConfig,
        profile: &str,
        default_target: &Path,
    ) -> Result<()> {
        use toml_edit::{DocumentMut, Item, Value};

        let target_file = default_target.to_path_buf();

        // Load existing document or create new one (preserves comments)
        let mut doc = if target_file.exists() {
            let content =
                fs::read_to_string(&target_file).map_err(|source| FnoxError::ConfigReadFailed {
                    path: target_file.clone(),
                    source,
                })?;
            content.parse::<DocumentMut>().map_err(|e| {
                FnoxError::Config(format!(
                    "Failed to parse TOML in {}: {}",
                    target_file.display(),
                    e
                ))
            })?
        } else {
            DocumentMut::new()
        };

        // Get or create the secrets table
     
remove_secret_from_source function · rust · L607-L654 (48 LOC)
src/config.rs
    pub fn remove_secret_from_source(
        secret_name: &str,
        profile: &str,
        target_file: &Path,
    ) -> Result<bool> {
        use toml_edit::DocumentMut;

        let content =
            fs::read_to_string(target_file).map_err(|source| FnoxError::ConfigReadFailed {
                path: target_file.to_path_buf(),
                source,
            })?;
        let mut doc = content.parse::<DocumentMut>().map_err(|e| {
            FnoxError::Config(format!(
                "Failed to parse TOML in {}: {}",
                target_file.display(),
                e
            ))
        })?;

        // Navigate to the secrets table
        let removed = if profile == "default" {
            doc.get_mut("secrets")
                .and_then(|s| s.as_table_mut())
                .map(|t| t.remove(secret_name).is_some())
                .unwrap_or(false)
        } else {
            doc.get_mut("profiles")
                .and_then(|p| p.as_table_mut())
             
save_secrets_to_source function · rust · L659-L732 (74 LOC)
src/config.rs
    pub fn save_secrets_to_source(
        secrets: &IndexMap<String, SecretConfig>,
        profile: &str,
        target_file: &Path,
    ) -> Result<()> {
        use toml_edit::{DocumentMut, Item, Value};

        // Load existing document or create new one (preserves comments)
        let mut doc = if target_file.exists() {
            let content =
                fs::read_to_string(target_file).map_err(|source| FnoxError::ConfigReadFailed {
                    path: target_file.to_path_buf(),
                    source,
                })?;
            content.parse::<DocumentMut>().map_err(|e| {
                FnoxError::Config(format!(
                    "Failed to parse TOML in {}: {}",
                    target_file.display(),
                    e
                ))
            })?
        } else {
            DocumentMut::new()
        };

        // Get or create the secrets table
        let secrets_table = if profile == "default" {
            if doc.get("secrets").i
Same scanner, your repo: https://repobility.com — Repobility
new function · rust · L735-L750 (16 LOC)
src/config.rs
    pub fn new() -> Self {
        Self {
            import: Vec::new(),
            root: false,
            providers: IndexMap::new(),
            default_provider: None,
            secrets: IndexMap::new(),
            profiles: IndexMap::new(),
            age_key_file: None,
            if_missing: None,
            prompt_auth: None,
            provider_sources: HashMap::new(),
            secret_sources: HashMap::new(),
            default_provider_source: None,
        }
    }
get_profile function · rust · L753-L758 (6 LOC)
src/config.rs
    pub fn get_profile(profile_flag: Option<&str>) -> String {
        profile_flag
            .map(String::from)
            .or_else(|| (*env::FNOX_PROFILE).clone())
            .unwrap_or_else(|| "default".to_string())
    }
should_prompt_auth function · rust · L763-L771 (9 LOC)
src/config.rs
    pub fn should_prompt_auth(&self) -> bool {
        // Check env var first
        let enabled = (*env::FNOX_PROMPT_AUTH)
            .or(self.prompt_auth)
            .unwrap_or(true);

        // Only prompt if enabled AND we're in a TTY
        enabled && atty::is(atty::Stream::Stdin)
    }
‹ prevpage 2 / 8next ›