sculblog 0.1.9

project xanadu revivalism
Documentation
use crate::maps::MapsCache;
use crate::serve::BuildContentResult;
use crate::SNAPSHOT_INTERVAL;
use std::fs;
use std::path::{Path, PathBuf};

/// Resolve snapshot offset and build content for a given xvuid.
/// If `requested_offset` is None, uses the latest entry from the maps cache.
pub fn serve_xvuid(
    cache: &MapsCache,
    repo_path: &Path,
    xvuid: &str,
    requested_offset: Option<usize>,
    debug: bool,
) -> Option<BuildContentResult> {
    let (target_offset, snapshot_offset) = if let Some(off) = requested_offset {
        let si = (off / SNAPSHOT_INTERVAL) * SNAPSHOT_INTERVAL;
        (Some(off), cache.lookup_snapshot_offset(xvuid, si))
    } else if let Some((latest_index, latest_snapshot_offset)) = cache.lookup_latest(xvuid) {
        (Some(latest_index), Some(latest_snapshot_offset))
    } else {
        (None, None)
    };

    let dif_path = repo_path.join(format!("{}.dif", xvuid));
    crate::serve::build_content_from_snapshot_offset(&dif_path, target_offset, snapshot_offset, debug)
}

pub fn load_config(target_key: &str) -> PathBuf {
    let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string());
    let rc_path = PathBuf::from(home).join(".sculblogrc");

    if !rc_path.exists() {
        eprintln!("Error: ~/.sculblogrc not found! Please create it and define {}.", target_key);
        std::process::exit(1);
    }

    let content = fs::read_to_string(&rc_path).expect("Failed to read ~/.sculblogrc");
    let prefix = format!("{}=", target_key);
    for line in content.lines() {
        let line = line.trim();
        if line.starts_with(&prefix) {
            let dir = line.trim_start_matches(&prefix).trim();
            let dir = dir.trim_matches('"').trim_matches('\'');
            return PathBuf::from(dir);
        }
    }

    eprintln!("Error: {} not defined in ~/.sculblogrc", target_key);
    std::process::exit(1);
}

/// Filter out lines from a tab-separated map file where the path column matches `exclude_path`.
pub fn filter_filename_map(content: &str, exclude_path: &str) -> String {
    let filtered: Vec<&str> = content
        .lines()
        .filter(|line| {
            line.split_once('\t')
                .map(|(p, _)| p != exclude_path)
                .unwrap_or(true)
        })
        .collect();
    let mut out = filtered.join("\n");
    if !out.is_empty() {
        out.push('\n');
    }
    out
}