- Add ArticleFeed component for article-based channels - Implement ArticleComposer with draft persistence - Add Newspaper icon for article room type - Update ChannelPage to conditionally render article feed vs message view - Add article-related API endpoints and models - Reset thread view when switching rooms - Add room type check in channel sidebar - Update CSS to hide scrollbars globally - Add gRPC message size limit configuration - Fix git diff tree handling
104 lines
3.4 KiB
Rust
104 lines
3.4 KiB
Rust
use gix::bstr::ByteSlice;
|
|
|
|
use crate::{
|
|
bare::GitBare,
|
|
cmd::{
|
|
diff::{
|
|
DiffOptions, DiffStats,
|
|
diff_tree_to_tree::{matches_pathspec, peel_to_tree},
|
|
},
|
|
oid::ObjectId,
|
|
},
|
|
errors::{GitError, GitResult},
|
|
};
|
|
|
|
impl GitBare {
|
|
pub fn diff_stats(
|
|
&self,
|
|
old_commit: ObjectId,
|
|
new_commit: ObjectId,
|
|
opts: Option<DiffOptions>,
|
|
) -> GitResult<DiffStats> {
|
|
let repo = self.gix_repo()?;
|
|
let options = opts.unwrap_or_default();
|
|
|
|
let old_tree_obj = peel_to_tree(&repo, old_commit)?;
|
|
let new_tree_obj = peel_to_tree(&repo, new_commit)?;
|
|
let mut platform = old_tree_obj
|
|
.changes()
|
|
.map_err(|e| GitError::Gix(e.to_string()))?;
|
|
platform.options(|opts| {
|
|
opts.track_rewrites(None);
|
|
});
|
|
|
|
let gix_stats = platform
|
|
.stats(&new_tree_obj)
|
|
.map_err(|e| GitError::Gix(e.to_string()))?;
|
|
if options.pathspec.is_empty() {
|
|
Ok(DiffStats {
|
|
files_changed: gix_stats.files_changed as usize,
|
|
insertions: gix_stats.lines_added as usize,
|
|
deletions: gix_stats.lines_removed as usize,
|
|
})
|
|
} else {
|
|
let changes = repo
|
|
.diff_tree_to_tree(&old_tree_obj, &new_tree_obj, None)
|
|
.map_err(|e| GitError::Gix(e.to_string()))?;
|
|
|
|
let mut resource_cache =
|
|
repo.diff_resource_cache_for_tree_diff()
|
|
.map_err(|e| GitError::Gix(e.to_string()))?;
|
|
|
|
let mut stats = DiffStats {
|
|
files_changed: 0,
|
|
insertions: 0,
|
|
deletions: 0,
|
|
};
|
|
|
|
for change in &changes {
|
|
let location = change.location().to_str().unwrap_or("");
|
|
if !matches_pathspec(&options.pathspec, location) {
|
|
continue;
|
|
}
|
|
|
|
// Skip directories — only diff blobs
|
|
if change.entry_mode().is_tree() {
|
|
continue;
|
|
}
|
|
|
|
resource_cache
|
|
.set_resource_by_change(change.to_ref(), &repo.objects)
|
|
.map_err(|e| GitError::Gix(e.to_string()))?;
|
|
|
|
{
|
|
use gix::diff::blob::platform::prepare_diff::Operation;
|
|
|
|
let prep = resource_cache
|
|
.prepare_diff()
|
|
.map_err(|e| GitError::Gix(e.to_string()))?;
|
|
|
|
if let Operation::InternalDiff { algorithm } =
|
|
prep.operation
|
|
{
|
|
let input = prep.interned_input();
|
|
let diff = gix::diff::blob::diff_with_slider_heuristics(
|
|
algorithm, &input,
|
|
);
|
|
stats.files_changed += 1;
|
|
stats.insertions += diff.count_additions() as usize;
|
|
stats.deletions += diff.count_removals() as usize;
|
|
} else if let Operation::SourceOrDestinationIsBinary =
|
|
prep.operation
|
|
{
|
|
stats.files_changed += 1;
|
|
}
|
|
}
|
|
|
|
resource_cache.clear_resource_cache_keep_allocation();
|
|
}
|
|
|
|
Ok(stats)
|
|
}
|
|
}
|
|
}
|