Skip to content

Commit

Permalink
add sketch but_core::UnifiedDiff to obtain patches of content chang…
Browse files Browse the repository at this point in the history
…es suitable for consumption.
  • Loading branch information
Byron committed Jan 21, 2025
1 parent f5456db commit 791c5b6
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 1 deletion.
28 changes: 28 additions & 0 deletions crates/but-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,34 @@ use bstr::BString;
/// Functions related to a Git worktree, i.e. the files checked out from a repository.
pub mod worktree;

///
pub mod unified_diff;

/// A patch in unified diff format to show how a resource changed or now looks like (in case it was newly added),
/// or how it previously looked like in case of a deletion.
pub enum UnifiedDiff {
/// The resource was a binary and couldn't be diffed.
Binary,
/// The file was too large and couldn't be diffed.
TooLarge {
/// The size of the file on disk that made it too large.
size_in_bytes: u64,
},
/// A patch that if applied to the previous state of the resource would yield the current state.
Patch {
/// All non-overlapping hunks, including their context lines.
hunks: Vec<unified_diff::DiffHunk>,
},
}

/// The patch that turns the previous version of a resource into the current one.
pub struct BlobDiff {
/// The worktree-relative path at which the diffed blob lives, in the working tree and/or in the repository.
pub path: BString,
/// All patches along with their context lines, or `None` if the patch could not be created as the content
pub hunks: Option<Vec<()>>,
}

/// An entry in the worktree that changed and thus is eligible to being committed.
///
/// It either lives (or lived) in the in `.git/index`, or in the `worktree`.
Expand Down
50 changes: 50 additions & 0 deletions crates/but-core/src/unified_diff.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use super::UnifiedDiff;
use bstr::BString;

/// A hunk as used in a [UnifiedDiff].
#[derive(Debug, Clone)]
pub struct DiffHunk {
/// The 1-based line number at which the previous version of the file started.
pub old_start: u32,
/// The non-zero amount of lines included in the previous version of the file.
pub old_lines: u32,
/// The 1-based line number at which the new version of the file started.
pub new_start: u32,
/// The non-zero amount of lines included in the new version of the file.
pub new_lines: u32,
/// A unified-diff formatted patch like:
///
/// ```diff
/// @@ -1,6 +1,8 @@
/// This is the first line of the original text.
/// -Line to be removed.
/// +Line that has been replaced.
/// This is another line in the file.
/// +This is a new line added at the end.
/// ```
///
/// The line separator is the one used in the original file and may be `LF` or `CRLF`.
/// Note that the file-portion of the header isn't used here.
pub diff: BString,
}

impl UnifiedDiff {
/// Given a worktree-relative `path` to a resource already tracked in Git, or one that is currently untracked,
/// create a patch in unified diff format that turns `previous_state` into `current_state_or_null` with the given
/// amount of `context_lines`.
/// `current_state_or_null` is either the hash of the state we know the resource currently has, or is a null-hash
/// if the current state lives in the filesystem of the current worktree.
/// If it is `None`, then there is no current state, and as long as a previous state is given, this will produce a
/// unified diff for a deletion.
/// `previous_state`, if `None`, indicates the file is new so there is nothing to compare to.
/// Otherwise, it's the hash of the previously known state. It is never the null-hash.
pub fn compute(
repo: &gix::Repository,
path: BString,
current_state_or_null: impl Into<Option<gix::ObjectId>>,
previous_state: impl Into<Option<gix::ObjectId>>,
context_lines: usize,
) -> anyhow::Result<Self> {
todo!()
}
}
1 change: 1 addition & 0 deletions crates/but-core/tests/core/main.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
mod unified_diff;
mod worktree;
29 changes: 29 additions & 0 deletions crates/but-core/tests/core/unified_diff.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use but_core::worktree::changes;
use but_core::UnifiedDiff;

#[test]
fn untracked_in_unborn() -> anyhow::Result<()> {
let repo = crate::worktree::repo("untracked-unborn")?;
UnifiedDiff::compute(
&repo,
"untracked".into(),
repo.object_hash().null(),
None,
3,
)?;
let actual = changes(&repo)?;
insta::assert_debug_snapshot!(actual, @r#"
[
WorktreeChange {
path: "untracked",
status: Untracked {
state: ChangeState {
id: Sha1(0000000000000000000000000000000000000000),
kind: Blob,
},
},
},
]
"#);
Ok(())
}
2 changes: 1 addition & 1 deletion crates/but-core/tests/core/worktree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,7 @@ fn modified_in_index_and_workingtree() -> Result<()> {
Ok(())
}

fn repo(fixture_name: &str) -> anyhow::Result<gix::Repository> {
pub fn repo(fixture_name: &str) -> anyhow::Result<gix::Repository> {
let root = gix_testtools::scripted_fixture_read_only("worktree-changes.sh")
.map_err(anyhow::Error::from_boxed)?;
let worktree_root = root.join(fixture_name);
Expand Down

0 comments on commit 791c5b6

Please sign in to comment.