syntext 1.0.5

Hybrid code search index for agent workflows
Documentation
//! Free-standing helper functions used by the index subsystem.

#[cfg(not(target_arch = "wasm32"))]
use std::path::Path;
#[cfg(not(target_arch = "wasm32"))]
use std::process::Command;

#[cfg(not(target_arch = "wasm32"))]
use crate::index::overlay::OverlayView;
#[cfg(not(target_arch = "wasm32"))]
use crate::index::snapshot::IndexSnapshot;
#[cfg(not(target_arch = "wasm32"))]
use crate::IndexError;

#[cfg(not(target_arch = "wasm32"))]
pub(super) fn current_repo_head(repo_root: &Path) -> Result<Option<String>, IndexError> {
    let canonical_root = std::fs::canonicalize(repo_root)?;
    let output = match Command::new(crate::git_util::resolve_git_binary())
        .arg("-C")
        .arg(&canonical_root)
        .args(["rev-parse", "--verify", "HEAD"])
        .output()
    {
        Ok(output) => output,
        Err(_) => return Ok(None),
    };

    if !output.status.success() {
        return Ok(None);
    }

    let head = String::from_utf8_lossy(&output.stdout).trim().to_string();
    if head.is_empty() {
        Ok(None)
    } else {
        Ok(Some(head))
    }
}

/// Opens the directory-level lock file (`lock`) with consistent options across
/// all call sites: read+write, create-if-absent, no truncation. The caller is
/// responsible for calling `try_lock_exclusive` or `try_lock_shared` afterward.
#[cfg(not(target_arch = "wasm32"))]
pub(super) fn open_dir_lock_file(index_dir: &Path) -> std::io::Result<std::fs::File> {
    std::fs::OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .truncate(false)
        .open(index_dir.join("lock"))
}

#[cfg(feature = "fs2")]
pub(super) fn acquire_writer_lock(index_dir: &Path) -> Result<std::fs::File, IndexError> {
    use fs2::FileExt;
    let write_lock_path = index_dir.join("write.lock");
    let write_lock = std::fs::OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .truncate(false)
        .open(&write_lock_path)?;
    write_lock
        .try_lock_exclusive()
        .map_err(|_| IndexError::LockConflict(index_dir.to_path_buf()))?;
    Ok(write_lock)
}

#[cfg(not(target_arch = "wasm32"))]
pub(super) fn projected_overlay_doc_count(
    old_overlay: &OverlayView,
    visible_changed: &std::collections::HashSet<std::path::PathBuf>,
    removed_paths: &std::collections::HashSet<std::path::PathBuf>,
) -> usize {
    old_overlay
        .docs
        .iter()
        .filter(|doc| !visible_changed.contains(&doc.path) && !removed_paths.contains(&doc.path))
        .count()
        + visible_changed
            .iter()
            .filter(|p| !removed_paths.contains(*p))
            .count()
}

#[cfg(not(target_arch = "wasm32"))]
pub(super) fn base_doc_id_limit(snapshot: &IndexSnapshot) -> Result<u32, IndexError> {
    let mut max_limit: u32 = 0;
    for (seg_idx, seg) in snapshot.base_segments().iter().enumerate() {
        if let Some(&base) = snapshot.segment_base_ids().get(seg_idx) {
            let limit = base
                .checked_add(seg.doc_count)
                .ok_or(IndexError::DocIdOverflow {
                    base_doc_count: base,
                    overlay_docs: seg.doc_count as usize,
                })?;
            if limit > max_limit {
                max_limit = limit;
            }
        }
    }
    Ok(max_limit)
}