diff --git a/LibGit2Sharp/BlameHunkCollection.cs b/LibGit2Sharp/BlameHunkCollection.cs index 869daf527..6176c3730 100644 --- a/LibGit2Sharp/BlameHunkCollection.cs +++ b/LibGit2Sharp/BlameHunkCollection.cs @@ -11,10 +11,13 @@ namespace LibGit2Sharp /// /// The result of a blame operation. /// - public class BlameHunkCollection : IEnumerable + public class BlameHunkCollection : IEnumerable, IDisposable { private readonly IRepository repo; private readonly List hunks = new List(); + private readonly RepositoryHandle repoHandle; + private readonly BlameHandle referenceHandle; + private readonly bool shouldDisposeHandle; /// /// For easy mocking @@ -49,17 +52,29 @@ internal unsafe BlameHunkCollection(Repository repo, RepositoryHandle repoHandle } } - using (var blameHandle = Proxy.git_blame_file(repoHandle, path, rawopts)) + referenceHandle = Proxy.git_blame_file(repoHandle, path, rawopts); + shouldDisposeHandle = true; + this.PopulateHunks(this.referenceHandle); + } + + private unsafe BlameHunkCollection(IRepository repo, RepositoryHandle repoHandle, BlameHandle reference, byte[] buffer) + { + this.repo = repo; + this.repoHandle = repoHandle; + this.referenceHandle = reference; + this.shouldDisposeHandle = false; + + using (var blameHandle = Proxy.git_blame_buffer(repoHandle, reference, buffer)) { - var numHunks = NativeMethods.git_blame_get_hunk_count(blameHandle); - for (uint i = 0; i < numHunks; ++i) - { - var rawHunk = Proxy.git_blame_get_hunk_byindex(blameHandle, i); - hunks.Add(new BlameHunk(this.repo, rawHunk)); - } + this.PopulateHunks(blameHandle); } } + public BlameHunkCollection FromBuffer(byte[] buffer) + { + return new BlameHunkCollection(repo, repoHandle, this.referenceHandle, buffer); + } + /// /// Access blame hunks by index. /// @@ -100,5 +115,23 @@ IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + + private unsafe void PopulateHunks(BlameHandle blameHandle) + { + var numHunks = NativeMethods.git_blame_get_hunk_count(blameHandle); + for (uint i = 0; i < numHunks; ++i) + { + var rawHunk = Proxy.git_blame_get_hunk_byindex(blameHandle, i); + hunks.Add(new BlameHunk(this.repo, rawHunk)); + } + } + + public void Dispose() + { + if (shouldDisposeHandle) + { + this.referenceHandle.Dispose(); + } + } } } diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index f5d45f3cf..44ecc9599 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -190,6 +190,13 @@ internal static extern unsafe int git_blame_file( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string path, git_blame_options options); + [DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)] + internal static extern unsafe int git_blame_buffer( + out git_blame* blame, + git_blame* reference, + IntPtr buffer, + UIntPtr len); + [DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)] internal static extern unsafe void git_blame_free(git_blame* blame); diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs index 50cefc0df..050dfe305 100644 --- a/LibGit2Sharp/Core/Proxy.cs +++ b/LibGit2Sharp/Core/Proxy.cs @@ -35,6 +35,27 @@ public static unsafe BlameHandle git_blame_file( return NativeMethods.git_blame_get_hunk_byindex(blame, idx); } + public static unsafe BlameHandle git_blame_buffer( + RepositoryHandle repo, + BlameHandle reference, + byte[] buffer) + { + git_blame* ptr; + int res; + + unsafe + { + fixed (byte* p = buffer) + { + res = NativeMethods.git_blame_buffer(out ptr, reference, (IntPtr)p, (UIntPtr)buffer.Length); + } + } + + Ensure.ZeroResult(res); + + return new BlameHandle(ptr, true); + } + #endregion #region git_blob_