ctucx.git: nimstagit

[nimlang] incomplete reimplementation of stagit

commit ad62fd652e3f3507df20863e32c931ececb82ad7
parent cb0e968e2672912f853cd35be9fe8441a4c6d00b
Author: Leah (ctucx) <leah@ctu.cx>
Date: Tue, 23 Mar 2021 20:38:49 +0100

show diff on commits
3 files changed, 124 insertions(+), 18 deletions(-)
M
src/assets/repoCommit.html
|
19
++++++++++++++++++-
M
src/assets/style.css
|
7
+++++++
M
src/repoGenerator.nim
|
116
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
diff --git a/src/assets/repoCommit.html b/src/assets/repoCommit.html
@@ -32,7 +32,24 @@
 				author: {{authorName}}<br>
 				committer: {{committerName}}<br><br>
 				<pre>{{message}}</pre>
-			</div>			
+			</div>
+			<div class="event">
+				<pre>{{filesChanged}} files changed, {{insertions}} insertions, {{deletions}} deletions
+
+{{#files}}
+{{status}} <a href="/{{repoUrl}}/tree/{{oldFileUrl}}.html">{{oldFile}}</a>
+{{/files}}</pre>
+			</div>
+			{{#files}}
+			<div class="event">
+<pre>{{status}} {{oldFile}} => {{newFile}}
+{{#hunks}}
+{{header}}
+{{#lines}}<span class="{{type}}">{{prefix}}{{content}}</span>{{/lines}}
+{{/hunks}}
+</pre>
+			</div>
+			{{/files}}
 		</div>
 		</main>
 		<footer>Generated on {{generated}}</footer>
diff --git a/src/assets/style.css b/src/assets/style.css
@@ -164,6 +164,13 @@ footer {
     z-index: 0;
 }
 
+.insertion {
+	color: #080;
+}
+
+.deletion {
+	color: #800;
+}
 
 
 /***
diff --git a/src/repoGenerator.nim b/src/repoGenerator.nim
@@ -70,23 +70,104 @@ proc generateCommitPage (path: string, templateContext: JsonNode, commit: GitCom
         for id in commit.parentIds:
             parents.add($id)
 
+    var commitTemplateContext = %* {
+            "id":                id,
+            "shortId":           commit.shortId,
+            "when":              relativeTimeFromNow(commit.time.time),
+            "message":           commit.message,
+            "committerIsAuthor": (committer.email == author.email),
+            "committerName":     committer.name,
+            "committerMail":     committer.email,
+            "authorName":        author.name,
+            "authorMail":        author.email,
+            "parents":           parents
+        }
+
+    let repo       = commit.owner
+    let tree       = commit.tree
+
+    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)
+
+    var diff: GitDiff
+    if commit.parentCount != 0:
+        let parent     = repo.lookupCommit(commit.parentIds[0])
+        let parentTree = repo.lookupTree(parent.treeId)
+
+        diff = repo.diffTrees(parentTree, tree, diffopts)
+
+        free(parentTree)
+        free(parent)
+    else:
+        let treeId     = fromString("4b825dc642cb6eb9a060e54bf8d69288fbee4904")
+        let parentTree = repo.lookupTree(treeId)
+
+        diff = repo.diffTrees(parentTree, tree, diffopts)
+
+        free(parentTree)
+        free(treeId)
+
+    diff.findSimilar(findopts)
+
+    free(tree)
+
+    let diffStats = diff.stats
+
+    commitTemplateContext["filesChanged"] = %diffStats.filesChanged
+    commitTemplateContext["insertions"]   = %diffStats.insertions
+    commitTemplateContext["deletions"]    = %diffStats.deletions
+
+    commitTemplateContext["files"] = newJArray()
+    for deltaIndex, delta in diff.deltas:
+        let patch = diff.patch(deltaIndex)
+        var hunks = newJArray()
+
+        for hunkIndex, hunk in patch.hunks():
+            var lines = newJArray()
+            for lineIndex, line in patch.lines(hunkIndex):
+                var lineJson = newJObject()
+
+                if line.old_lineno == -1:
+                    lineJson["type"]   = %"insertion"
+                    lineJson["prefix"] = %"+"
+                elif line.new_lineno == -1:
+                    lineJson["type"]   = %"deletion"
+                    lineJson["prefix"] = %"-"
+                else:
+                    lineJson["prefix"] = %" "
+
+                var content = newString(line.content_len)
+                copyMem(content.cstring, line.content, line.content_len)
+                lineJson["content"] = %content
+                lines.add(lineJson)
+
+            var header = newString(hunk.header_len)
+            copyMem(header.cstring, hunk.header[0].unsafeAddr, hunk.header_len)
+            hunks.add(%* {
+                    "header": header,
+                    "lines":  lines
+                })
+
+        commitTemplateContext["files"].add(%* {
+                "status":     delta.statusChar,
+                "newFile":    $delta.new_file.path,
+                "newFileUrl": encodeUrl($delta.new_file.path),
+                "oldFile":    $delta.old_file.path,
+                "oldFileUrl": encodeUrl($delta.old_file.path),
+                "hunks":      hunks
+            })
+
+        free(patch)
+
 
     writeFile(
         joinPath(joinPath(path, id & ".html")),
         render(
             templateRepoCommit,
-            mergeJson(templateContext, %* {
-                "id":                id,
-                "shortId":           commit.shortId,
-                "when":              relativeTimeFromNow(commit.time.time),
-                "message":           commit.message,
-                "committerIsAuthor": (committer.email == author.email),
-                "committerName":     committer.name,
-                "committerMail":     committer.email,
-                "authorName":        author.name,
-                "authorMail":        author.email,
-                "parents":           parents
-            })
+            mergeJson(templateContext, commitTemplateContext)
         )
     )
 

@@ -95,11 +176,12 @@ proc generateRepoBlobPage (path: string, pathSeq: seq[PathObj], templateContext:
     let content = blob.content
 
     var blobData = %*{
-            "path":     pathSeq,
-            "id":       $entry.id,
-            "filename": entry.name,
-            "filesize": formatSize(blob.size),
-            "isBinary": blob.isBinary
+            "path":        pathSeq,
+            "id":          $entry.id,
+            "filename":    entry.name,
+            "filenameUrl": encodeUrl(entry.name),
+            "filesize":    formatSize(blob.size),
+            "isBinary":    blob.isBinary
         }
 
     if not blob.isBinary: