diffctx 1.12.1

Selects the minimum code an LLM needs to review a git diff: walks the dependency graph outward from changed lines and stops when extra context stops paying for itself
Documentation
use std::path::{Path, PathBuf};

use once_cell::sync::Lazy;
use regex::Regex;
use rustc_hash::{FxHashMap, FxHashSet};

use crate::config::weights::EDGE_WEIGHTS;
use crate::types::{Fragment, FragmentId};

use super::super::EdgeDict;
use super::super::base::{self, EdgeBuilder, FragmentIndex, add_edge, link_by_name};

static WORKSPACE_MEMBERS_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(?s)\[workspace\][^\[]*?members\s*=\s*\[(.*?)\]").unwrap());
static PATH_DEP_RE: Lazy<Regex> = Lazy::new(|| {
    Regex::new(r##"(?m)^\s*(\w[\w-]{0,100})\s*=\s*\{[^}]*?path\s*=\s*["']([^"']{1,300})["']"##)
        .unwrap()
});
static FEATURES_SECTION_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(?ms)^\[features\]\s*\n(.+?)(?:\n\[|\z)").unwrap());
static FEATURE_DEP_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r##"["'](\w[\w-]{0,100})(?:/[^"']*)?["']"##).unwrap());
static STRING_ITEM_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r##"["']([^"']{1,300})["']"##).unwrap());
static BIN_SECTION_RE: Lazy<Regex> = Lazy::new(|| {
    Regex::new(r##"(?s)\[\[bin\]\][^\[]*?path\s*=\s*["']([^"']{1,300})["']"##).unwrap()
});
static LIB_SECTION_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r##"(?s)\[lib\][^\[]*?path\s*=\s*["']([^"']{1,300})["']"##).unwrap());

fn is_cargo_toml(path: &Path) -> bool {
    path.file_name()
        .map(|n| n.to_string_lossy().to_lowercase() == "cargo.toml")
        .unwrap_or(false)
}

fn is_rust_source(path: &Path) -> bool {
    base::file_ext(path) == ".rs"
}

fn extract_workspace_members(content: &str) -> Vec<String> {
    WORKSPACE_MEMBERS_RE
        .captures(content)
        .map(|c| {
            STRING_ITEM_RE
                .captures_iter(&c[1])
                .map(|m| m[1].to_string())
                .collect()
        })
        .unwrap_or_default()
}

fn extract_path_deps(content: &str) -> Vec<(String, String)> {
    PATH_DEP_RE
        .captures_iter(content)
        .map(|c| (c[1].to_string(), c[2].to_string()))
        .collect()
}

fn extract_feature_deps(content: &str) -> FxHashSet<String> {
    FEATURES_SECTION_RE
        .captures(content)
        .map(|c| {
            FEATURE_DEP_RE
                .captures_iter(&c[1])
                .map(|m| m[1].to_string())
                .collect()
        })
        .unwrap_or_default()
}

fn extract_entry_points(content: &str) -> Vec<String> {
    let mut entries: Vec<String> = BIN_SECTION_RE
        .captures_iter(content)
        .map(|c| c[1].to_string())
        .collect();
    if let Some(c) = LIB_SECTION_RE.captures(content) {
        entries.push(c[1].to_string());
    }
    for default in ["src/lib.rs", "src/main.rs"] {
        if !entries.iter().any(|e| e == default) {
            entries.push(default.to_string());
        }
    }
    entries
}

pub struct CargoEdgeBuilder;

impl EdgeBuilder for CargoEdgeBuilder {
    fn build(&self, fragments: &[Fragment], repo_root: Option<&Path>) -> EdgeDict {
        let cargo_frags: Vec<&Fragment> = fragments
            .iter()
            .filter(|f| is_cargo_toml(Path::new(f.path())))
            .collect();
        if cargo_frags.is_empty() {
            return FxHashMap::default();
        }

        let ws_w = EDGE_WEIGHTS["cargo_workspace"].forward;
        let dep_w = EDGE_WEIGHTS["cargo_path_dep"].forward;
        let entry_w = EDGE_WEIGHTS["cargo_entry_point"].forward;
        let rev = EDGE_WEIGHTS["cargo_workspace"].reverse_factor;

        let idx = FragmentIndex::new(fragments, repo_root);
        let mut edges: EdgeDict = FxHashMap::default();

        let mut cargo_by_dir: FxHashMap<String, Vec<FragmentId>> = FxHashMap::default();
        for f in &cargo_frags {
            let dir = Path::new(f.path())
                .parent()
                .map(|p| p.to_string_lossy().to_string())
                .unwrap_or_default();
            cargo_by_dir.entry(dir).or_default().push(f.id.clone());
        }

        let mut rs_by_path: FxHashMap<String, FragmentId> = FxHashMap::default();
        for f in fragments {
            if is_rust_source(Path::new(f.path())) {
                rs_by_path.insert(f.path().to_string(), f.id.clone());
            }
        }

        for cf in &cargo_frags {
            let parent = Path::new(cf.path()).parent().unwrap_or(Path::new(""));

            for entry in extract_entry_points(&cf.content) {
                let entry_path = parent.join(&entry).to_string_lossy().to_string();
                if let Some(fid) = rs_by_path.get(&entry_path) {
                    if fid != &cf.id {
                        add_edge(&mut edges, &cf.id, fid, entry_w, rev);
                    }
                }
            }

            for (_, rel_path) in extract_path_deps(&cf.content) {
                let dep_dir = parent.join(&rel_path).to_string_lossy().to_string();
                if let Some(fids) = cargo_by_dir.get(&dep_dir) {
                    for fid in fids {
                        if fid != &cf.id {
                            add_edge(&mut edges, &cf.id, fid, dep_w, rev);
                        }
                    }
                }
            }

            for member in extract_workspace_members(&cf.content) {
                let member_dir = parent.join(&member).to_string_lossy().to_string();
                if let Some(fids) = cargo_by_dir.get(&member_dir) {
                    for fid in fids {
                        if fid != &cf.id {
                            add_edge(&mut edges, &cf.id, fid, ws_w, rev);
                        }
                    }
                }
                link_by_name(
                    &cf.id,
                    &format!("{}/Cargo.toml", member),
                    &idx,
                    &mut edges,
                    ws_w,
                    rev,
                );
            }

            let feature_deps = extract_feature_deps(&cf.content);
            let path_deps = extract_path_deps(&cf.content);
            for dep_name in &feature_deps {
                for (name, rel_path) in &path_deps {
                    if name != dep_name {
                        continue;
                    }
                    let dep_dir = parent.join(rel_path).to_string_lossy().to_string();
                    if let Some(fids) = cargo_by_dir.get(&dep_dir) {
                        for fid in fids {
                            if fid != &cf.id {
                                add_edge(&mut edges, &cf.id, fid, dep_w, rev);
                            }
                        }
                    }
                }
            }
        }
        edges
    }

    fn discover_related_files(
        &self,
        changed: &[PathBuf],
        candidates: &[PathBuf],
        repo_root: Option<&Path>,
        file_cache: Option<&FxHashMap<PathBuf, String>>,
    ) -> Vec<PathBuf> {
        let cargo_changed: Vec<&PathBuf> = changed.iter().filter(|p| is_cargo_toml(p)).collect();
        if cargo_changed.is_empty() {
            return vec![];
        }

        let mut refs = FxHashSet::default();

        for cf in &cargo_changed {
            let content = match base::read_file_cached(cf, file_cache) {
                Some(c) => c,
                None => continue,
            };
            let parent = cf.parent().unwrap_or(Path::new(""));

            for entry in extract_entry_points(&content) {
                refs.insert(parent.join(&entry).to_string_lossy().to_string());
            }
            for (_, rel_path) in extract_path_deps(&content) {
                refs.insert(
                    parent
                        .join(&rel_path)
                        .join("Cargo.toml")
                        .to_string_lossy()
                        .to_string(),
                );
            }
            for member in extract_workspace_members(&content) {
                refs.insert(
                    parent
                        .join(&member)
                        .join("Cargo.toml")
                        .to_string_lossy()
                        .to_string(),
                );
            }
        }

        base::discover_files_by_refs(&refs, changed, candidates, repo_root)
    }

    fn category_label(&self) -> Option<&str> {
        Some("semantic")
    }
}