use std::path::Path;
use objects::{
object::{ContentHash, FileChangeSet, diff_trees},
store::ObjectStore,
worktree::WorktreeStatus,
};
use super::{diff_helpers::TreeBlobContentLoader, diff_options::SemanticDiffOptions};
use crate::{
cache::SemanticParseCache,
diff::{
diff_engine::SemanticEngine,
diff_types::{SemanticCheckOnlyResult, SemanticDiffResult, SemanticSummaryResult},
},
};
pub fn semantic_check_only<S: ObjectStore + ?Sized>(
store: &S,
from_tree_hash: &ContentHash,
to_tree_hash: &ContentHash,
options: &SemanticDiffOptions,
) -> Result<SemanticCheckOnlyResult, anyhow::Error> {
semantic_check_only_with_cache(
store,
from_tree_hash,
to_tree_hash,
options,
SemanticParseCache::shared(),
)
}
pub fn semantic_check_only_with_cache<S: ObjectStore + ?Sized>(
store: &S,
from_tree_hash: &ContentHash,
to_tree_hash: &ContentHash,
options: &SemanticDiffOptions,
cache: &SemanticParseCache,
) -> Result<SemanticCheckOnlyResult, anyhow::Error> {
let file_changes = diff_trees(store, from_tree_hash, to_tree_hash)?;
let old_loader = TreeBlobContentLoader::new(store, *from_tree_hash);
let new_loader = TreeBlobContentLoader::new(store, *to_tree_hash);
SemanticEngine::new(
file_changes,
|path| old_loader.load_content(path),
|path| new_loader.load_content(path),
options,
cache,
)
.check_only()
}
pub fn semantic_check_only_worktree<S: ObjectStore + ?Sized>(
store: &S,
from_tree_hash: &ContentHash,
worktree_root: &Path,
status: &WorktreeStatus,
options: &SemanticDiffOptions,
) -> Result<SemanticCheckOnlyResult, anyhow::Error> {
semantic_check_only_worktree_with_cache(
store,
from_tree_hash,
worktree_root,
status,
options,
SemanticParseCache::shared(),
)
}
pub fn semantic_check_only_worktree_with_cache<S: ObjectStore + ?Sized>(
store: &S,
from_tree_hash: &ContentHash,
worktree_root: &Path,
status: &WorktreeStatus,
options: &SemanticDiffOptions,
cache: &SemanticParseCache,
) -> Result<SemanticCheckOnlyResult, anyhow::Error> {
let old_loader = TreeBlobContentLoader::new(store, *from_tree_hash);
SemanticEngine::new(
file_changes_from_status(status),
|path| old_loader.load_content(path),
|path| load_worktree_blob_content(worktree_root, path),
options,
cache,
)
.check_only()
}
pub fn semantic_diff_summary<S: ObjectStore + ?Sized>(
store: &S,
from_tree_hash: &ContentHash,
to_tree_hash: &ContentHash,
options: &SemanticDiffOptions,
) -> Result<SemanticSummaryResult, anyhow::Error> {
semantic_diff_summary_with_cache(
store,
from_tree_hash,
to_tree_hash,
options,
SemanticParseCache::shared(),
)
}
pub fn semantic_diff_summary_with_cache<S: ObjectStore + ?Sized>(
store: &S,
from_tree_hash: &ContentHash,
to_tree_hash: &ContentHash,
options: &SemanticDiffOptions,
cache: &SemanticParseCache,
) -> Result<SemanticSummaryResult, anyhow::Error> {
let file_changes = diff_trees(store, from_tree_hash, to_tree_hash)?;
let old_loader = TreeBlobContentLoader::new(store, *from_tree_hash);
let new_loader = TreeBlobContentLoader::new(store, *to_tree_hash);
SemanticEngine::new(
file_changes,
|path| old_loader.load_content(path),
|path| new_loader.load_content(path),
options,
cache,
)
.summary()
}
pub fn semantic_diff_summary_worktree<S: ObjectStore + ?Sized>(
store: &S,
from_tree_hash: &ContentHash,
worktree_root: &Path,
status: &WorktreeStatus,
options: &SemanticDiffOptions,
) -> Result<SemanticSummaryResult, anyhow::Error> {
semantic_diff_summary_worktree_with_cache(
store,
from_tree_hash,
worktree_root,
status,
options,
SemanticParseCache::shared(),
)
}
pub fn semantic_diff_summary_worktree_with_cache<S: ObjectStore + ?Sized>(
store: &S,
from_tree_hash: &ContentHash,
worktree_root: &Path,
status: &WorktreeStatus,
options: &SemanticDiffOptions,
cache: &SemanticParseCache,
) -> Result<SemanticSummaryResult, anyhow::Error> {
let old_loader = TreeBlobContentLoader::new(store, *from_tree_hash);
SemanticEngine::new(
file_changes_from_status(status),
|path| old_loader.load_content(path),
|path| load_worktree_blob_content(worktree_root, path),
options,
cache,
)
.summary()
}
pub fn semantic_diff<S: ObjectStore + ?Sized>(
store: &S,
from_tree_hash: &ContentHash,
to_tree_hash: &ContentHash,
options: &SemanticDiffOptions,
) -> Result<SemanticDiffResult, anyhow::Error> {
semantic_diff_with_cache(
store,
from_tree_hash,
to_tree_hash,
options,
SemanticParseCache::shared(),
)
}
pub fn semantic_diff_with_cache<S: ObjectStore + ?Sized>(
store: &S,
from_tree_hash: &ContentHash,
to_tree_hash: &ContentHash,
options: &SemanticDiffOptions,
cache: &SemanticParseCache,
) -> Result<SemanticDiffResult, anyhow::Error> {
let file_changes = diff_trees(store, from_tree_hash, to_tree_hash)?;
let old_loader = TreeBlobContentLoader::new(store, *from_tree_hash);
let new_loader = TreeBlobContentLoader::new(store, *to_tree_hash);
SemanticEngine::new(
file_changes,
|path| old_loader.load_content(path),
|path| new_loader.load_content(path),
options,
cache,
)
.full()
}
pub fn semantic_diff_worktree<S: ObjectStore + ?Sized>(
store: &S,
from_tree_hash: &ContentHash,
worktree_root: &Path,
status: &WorktreeStatus,
options: &SemanticDiffOptions,
) -> Result<SemanticDiffResult, anyhow::Error> {
semantic_diff_worktree_with_cache(
store,
from_tree_hash,
worktree_root,
status,
options,
SemanticParseCache::shared(),
)
}
pub fn semantic_diff_worktree_with_cache<S: ObjectStore + ?Sized>(
store: &S,
from_tree_hash: &ContentHash,
worktree_root: &Path,
status: &WorktreeStatus,
options: &SemanticDiffOptions,
cache: &SemanticParseCache,
) -> Result<SemanticDiffResult, anyhow::Error> {
let old_loader = TreeBlobContentLoader::new(store, *from_tree_hash);
SemanticEngine::new(
file_changes_from_status(status),
|path| old_loader.load_content(path),
|path| load_worktree_blob_content(worktree_root, path),
options,
cache,
)
.full()
}
fn file_changes_from_status(status: &WorktreeStatus) -> FileChangeSet {
let mut file_changes = FileChangeSet::with_capacity(status.change_count());
for path in &status.deleted {
file_changes.push_deleted(path.display().to_string());
}
for path in &status.added {
file_changes.push_added(path.display().to_string());
}
for path in &status.modified {
file_changes.push_modified(path.display().to_string());
}
file_changes
}
fn load_worktree_blob_content(
worktree_root: &Path,
path: &Path,
) -> Result<Option<String>, anyhow::Error> {
let worktree_path = worktree_root.join(path);
match std::fs::read_to_string(&worktree_path) {
Ok(content) => Ok(Some(content)),
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(None),
Err(err) => Err(err.into()),
}
}