aicommit 0.1.141

A CLI tool that generates concise and descriptive git commit messages using LLMs
Documentation
// Utility functions

use std::fs;
use crate::types::*;

// From: 016_function_default_retry_attempts.rs
// Used by serde(default) in types.rs
#[allow(dead_code)]
pub fn default_retry_attempts() -> u32 {
    3
}

// From: 021_function_get_safe_slice_length.rs
pub fn get_safe_slice_length(s: &str, max_len: usize) -> usize {
    if max_len >= s.len() {
        return s.len();
    }
    
    // Find the largest index <= max_len that is a char boundary
    let mut safe_len = max_len;
    while safe_len > 0 && !s.is_char_boundary(safe_len) {
        safe_len -= 1;
    }
    
    safe_len
}

// From: 027_function_parse_duration.rs
pub fn parse_duration(duration_str: &str) -> Result<std::time::Duration, String> {
    let duration_str = duration_str.trim().to_lowercase();
    if duration_str.is_empty() {
        return Err("Duration string is empty".to_string());
    }

    let mut chars = duration_str.chars().peekable();
    let mut number = String::new();
    
    // Collect digits
    while let Some(c) = chars.peek() {
        if c.is_digit(10) {
            number.push(chars.next().unwrap());
        } else {
            break;
        }
    }

    // Get the unit (rest of the string)
    let unit: String = chars.collect();

    if number.is_empty() {
        return Err("No duration value provided".to_string());
    }

    let value = number.parse::<u64>()
        .map_err(|_| format!("Invalid duration number: {}", number))?;

    match unit.as_str() {
        "s" => Ok(std::time::Duration::from_secs(value)),
        "m" => Ok(std::time::Duration::from_secs(value * 60)),
        "h" => Ok(std::time::Duration::from_secs(value * 3600)),
        _ => Err(format!("Invalid duration unit: '{}'. Use s, m, or h", unit)),
    }
}

// From: 045_function_save_simple_free_config.rs
pub fn save_simple_free_config(config: &SimpleFreeOpenRouterConfig) -> Result<(), String> {
    let config_path = dirs::home_dir()
        .ok_or_else(|| "Could not find home directory".to_string())?
        .join(".aicommit.json");
        
    let mut full_config = Config::load()?;
    
    // Update the provider in the full config
    for provider in &mut full_config.providers {
        if let ProviderConfig::SimpleFreeOpenRouter(simple_config) = provider {
            if simple_config.id == config.id {
                *simple_config = config.clone();
                break;
            }
        }
    }
    
    let content = serde_json::to_string_pretty(&full_config)
        .map_err(|e| format!("Failed to serialize config: {}", e))?;
        
    fs::write(&config_path, content)
        .map_err(|e| format!("Failed to write config file: {}", e))?;
    
    Ok(())
}