commit ca7f01e88a829023e92d047d7a4537dea2c13a28
parent 0c4ecd37247855fd7e3402cd17d3ec955970684f
Author: Leah (ctucx) <leah@ctu.cx>
Date: Tue, 23 Mar 2021 20:13:56 +0100
parent 0c4ecd37247855fd7e3402cd17d3ec955970684f
Author: Leah (ctucx) <leah@ctu.cx>
Date: Tue, 23 Mar 2021 20:13:56 +0100
add diff-procs
5 files changed, 170 insertions(+), 4 deletions(-)
diff --git a/nimgit.nim b/nimgit.nim @@ -1,5 +1,5 @@ import nimgit2 -import nimgit/[types, free, repository, config, objects, oid, tag, blob, tree, treeEntry, reference, revisionWalker, branch, commit] +import nimgit/[types, free, repository, config, objects, oid, tag, blob, tree, treeEntry, reference, revisionWalker, branch, commit, diff] export nimgit2 -export types, free, repository, config, objects, oid, tag, blob, tree, treeEntry, reference, revisionWalker, branch, commit +export types, free, repository, config, objects, oid, tag, blob, tree, treeEntry, reference, revisionWalker, branch, commit, diff
diff --git a/nimgit/diff.nim b/nimgit/diff.nim @@ -0,0 +1,108 @@ +import nimgit2 +import types, free + +proc initDiffOptions* (): GitDiffOptions = + result = cast[GitDiffOptions](sizeof(git_diff_options).alloc) + discard git_diff_init_options(result, GIT_DIFF_OPTIONS_VERSION) + +proc GitDiffFindOptions* (): GitDiffFindOptions = + result = cast[GitDiffFindOptions](sizeof(git_diff_find_options).alloc) + discard git_diff_find_init_options(result, GIT_DIFF_FIND_OPTIONS_VERSION) + + +proc diffTrees* (repo: GitRepository, newTree: GitTree, oldTree: GitTree, options: GitDiffOptions): GitDiff = + let error = git_diff_tree_to_tree(addr result, repo, newTree, oldTree, options) + + if error != 0: + free(result) + raise newException(CatchableError, "Cannot diff Trees: " & $error.getResultCode) + +proc findSimilar* (diff: GitDiff, options: GitDiffFindOptions) = + let error = git_diff_find_similar(diff, options) + + if error != 0: + raise newException(CatchableError, "Cannot diff find: " & $error.getResultCode) + +proc stats* (diff: GitDiff): GitDiffStats = + var diffStats : ptr git_diff_stats + let error = git_diff_get_stats(addr diffStats, diff) + + if error != 0: + raise newException(CatchableError, "Cannot get diff-stats: " & $error.getResultCode) + + result.filesChanged = cast[int](git_diff_stats_files_changed(diffStats)) + result.deletions = cast[int](git_diff_stats_deletions(diffStats)) + result.insertions = cast[int](git_diff_stats_insertions(diffStats)) + + git_diff_stats_free(diffStats) + +proc len* (delta: GitDiff): int = cast[int](git_diff_num_deltas(delta)) + +proc delta* (delta: GitDiff, id: int): GitDiffDelta = git_diff_get_delta(delta, uint(id)) + +iterator deltas* (diff: GitDiff): (int, GitDiffDelta) = + var counter : int + let diffLen = diff.len + + while counter < diffLen: + yield (counter, diff.delta(counter)) + inc(counter) + +proc statusChar* (delta: GitDiffDelta): string = + case delta.status: + of GIT_DELTA_ADDED: + result = "A" + of GIT_DELTA_COPIED: + result = "C" + of GIT_DELTA_DELETED: + result = "D" + of GIT_DELTA_MODIFIED: + result = "M" + of GIT_DELTA_RENAMED: + result = "R" + of GIT_DELTA_TYPECHANGE: + result = "T" + else: + result = " " + + +proc patch* (diff: GitDiff, id: int): GitPatch = + let error = git_patch_from_diff(addr result, diff, uint(id)) + + if error != 0: + raise newException(CatchableError, "Cannot get patch: " & $error.getResultCode) + + +proc hunksLen* (patch: GitPatch): int = cast[int](git_patch_num_hunks(patch)) + +proc hunk* (patch: GitPatch, id: int): GitDiffHunk = + var linesCount : uint + let error = git_patch_get_hunk(addr result, addr linesCount, patch, uint(id)) + + if error != 0: + raise newException(CatchableError, "Cannot get diff-hunk: " & $error.getResultCode) + +iterator hunks* (patch: GitPatch): (int, GitDiffHunk) = + var counter : int + let hunkLen = patch.hunksLen + + while counter < hunkLen: + yield (counter, patch.hunk(counter)) + inc(counter) + + +proc linesLen* (patch: GitPatch, id: int): int = cast[int](git_patch_num_lines_in_hunk(patch, uint(id))) + +proc line* (patch: GitPatch, hunk: int, line: int): GitDiffLine = + let error = git_patch_get_line_in_hunk(addr result, patch, uint(hunk), uint(line)) + + if error != 0: + raise newException(CatchableError, "Cannot get diff-line: " & $error.getResultCode) + +iterator lines* (patch: GitPatch, hunkId: int): (int, GitDiffLine) = + var counter : int + let lineLen = patch.linesLen(hunkId) + + while counter < lineLen: + yield (counter, patch.line(hunkId, counter)) + inc(counter)+ \ No newline at end of file
diff --git a/nimgit/free.nim b/nimgit/free.nim @@ -8,7 +8,7 @@ type git_strarray | git_object | git_commit | git_status_list | git_annotated_commit | git_tree_entry | git_revwalk | git_buf | git_pathspec | git_tree | git_diff | git_pathspec_match_list | - git_branch_iterator | git_signature | git_blob + git_branch_iterator | git_signature | git_blob | git_patch proc free* [T: NimGitTypes] (point: ptr T) = dealloc(point) @@ -55,3 +55,5 @@ proc free* [T: GitTypes] (point: ptr T) = git_signature_free(point) elif T is git_blob: git_blob_free(point) + elif T is git_patch: + git_patch_free(point)+ \ No newline at end of file
diff --git a/nimgit/types.nim b/nimgit/types.nim @@ -16,6 +16,18 @@ type GitBuffer* = ptr git_buf GitTag* = ptr git_tag GitBlob* = ptr git_blob + GitDiff* = ptr git_diff + GitDiffOptions* = ptr git_diff_options + GitDiffFindOptions* = ptr git_diff_find_options + GitDiffDelta* = ptr git_diff_delta + GitPatch* = ptr git_patch + GitDiffHunk* = ptr git_diff_hunk + GitDiffLine* = ptr git_diff_line + + GitDiffStats* = object + filesChanged* : int + insertions* : int + deletions* : int GitObjectKind* = enum # we have to add 2 here to satisfy nim; discriminants.low must be zero
diff --git a/showLastCommit.nim b/showLastCommit.nim @@ -1,4 +1,4 @@ -import os, times +import os, times, bitops import nimgit if paramCount() == 0: @@ -38,6 +38,48 @@ try: echo "" + if commit.hasParents: + let parent = gitRepository.lookupCommit(commit.parentIds[0]) + let parentTree = gitRepository.lookupTree(parent.treeId) + + let diffopts = initDiffOptions() + diffopts.flags = cast[uint32](GIT_DIFF_DISABLE_PATHSPEC_MATCH) or cast[uint32](GIT_DIFF_IGNORE_SUBMODULES) or cast[uint32](GIT_DIFF_INCLUDE_TYPECHANGE) + + let findopts = GitDiffFindOptions() + findopts.flags = cast[uint32](GIT_DIFF_FIND_RENAMES) or cast[uint32](GIT_DIFF_FIND_COPIES) or cast[uint32](GIT_DIFF_FIND_EXACT_MATCH_ONLY) + + let diff = gitRepository.diffTrees(tree, parentTree, diffopts) + diff.findSimilar(findopts) + + free(parentTree) + free(parent) + + echo diff.len + echo diff.stats + + for deltaIndex, delta in diff.deltas: + echo delta.statusChar & " " & $delta.old_file.path & " " & $delta.new_file.path + + let patch = diff.patch(deltaIndex) + + for hunkIndex, hunk in patch.hunks(): + + echo $hunk.header + + for lineIndex, line in patch.lines(hunkIndex): + var status: string + + if line.old_lineno == -1: + status = "+" + elif line.new_lineno == -1: + status = "-" + else: + status = " " + + echo status & $line.content + + free(patch) + free(tree) free(commit) free(config)