Dependency graph

I’ve kind of given up on the graph.
Instead, I modified the script to generate HTML, which could be a log option like --output-format html.
This shows both directions of the dependencies.
(this script inherited the function parentheses, which could probably be removed)
Direct the output to a .htm file.
Edit: I added code to output list of files for each change.
Edit: I convert < to &lt; in the message and description.

#!/bin/bash
# arguments are reserved for passing directly to the pijul log command
LEN=10
PROJECT=$(pwd)
PROJECT=$(basename "$PROJECT")
CHANNEL=$(pijul channel | grep \*)

(
echo "<!DOCTYPE html> <html><head><title>$PROJECT $CHANNEL</title>"
echo "<style>.descript,.depend,.neededby,.file{font-size:0.9em;margin-inline-start:2em}[id]{margin-bottom:0.6em;scroll-margin-top: 2ex}"
echo ":target{background-color:honeydew;border: 1px solid}::marker{font-size:smaller;color:gray}"
echo "body{background:white linear-gradient(to bottom,transparent 15%,aliceblue 40%,lightyellow 65%,pink 90%);color:black}"
echo ".descript[open] summary {opacity: 0.5}.descript[open]{background:rgba(88,88,100,0.05)}</style>"
echo "<script>function expandAll(sel){document.querySelectorAll(sel).forEach(function(el){el.setAttribute('open','');})};"
echo "function collapseAll(sel){document.querySelectorAll(sel).forEach(function(el){el.removeAttribute('open');})};</script></head>"
echo "<body><h2>$PROJECT $CHANNEL</h2>"
echo "<div><button onclick=\"expandAll('details.descript')\">Expand descriptions</button>"
echo "<button onclick=\"collapseAll('details.descript')\">Collapse descriptions</button>"
echo " &nbsp; <button onclick=\"expandAll('details.depend')\">Expand dependencies</button>"
echo "<button onclick=\"collapseAll('details.depend')\">Collapse dependencies</button>"
echo " &nbsp; <button onclick=\"expandAll('details.neededby')\">Expand needed by</button>"
echo "<button onclick=\"collapseAll('details.neededby')\">Collapse needed by</button>"
echo " &nbsp; <button onclick=\"expandAll('details.file')\">Expand files</button>"
echo "<button onclick=\"collapseAll('details.file')\">Collapse files</button><br>"
echo "<small><em>in-page search will not find hidden text</em></small></div>"
echo "<ol class=\"log\" reversed>"

pijul log --hash-only "$@" | while read ID; do
    pijul change "$ID" | awk -v oid="$ID" -v idlen="$LEN" '
/^message =/ { msg = substr($0, index($0, $3));
	gsub( /"/, "", msg );
	gsub(/</, "&lt;", msg);
	print "\n<li id=\"" substr(oid,1,idlen) "\">" substr(oid,1,idlen) " : " msg "<br>"; 
}  
/^timestamp =/ {
  before = indesc ? "" : "<div class=\"descript\">"; 
  print before "<time datetime=" $3 ">" $3 "</time>" (before?"</div>":"</small></details>");
  indesc = 0;  
}
indesc { gsub(/</,"&lt;"); print $0 "<br>"; }  
/^description =/ { indesc = 1; print "<details class=\"descript\"><summary>Description</summary><small>";}
/^# Dependencies/ {
  FS="]";
  print "<details class=\"depend\"><summary>Dependencies</summary>";
  getline;
  while (substr($2,1,1) == " " ) {
    print "<a href=\"#" substr($2,2,idlen) "\">" substr($0,1,idlen+6) "</a><br>";
    getline;
  } 
  print "</details>"; 
}
/^# Hunks/ { 
  FS="\""; 
  print "<details class=\"file\"><summary>Files</summary>";
  err=getline;
  while (err > 0) {
    if (match($0, /^[0-9]+/)) {
      if ($2 == "\\") gsub(/\\"/,"")
      names[(NF>1?$2:$0)]=1
    }
    err=getline;
  } 
  for (n in names) print n "<br>";
  print "</details></li>"; 
}
'
done
echo "</ol><script>(function() {
var allIDs=document.querySelectorAll('[id]');
allIDs.forEach(function(item, i){
  const id=item.getAttribute('id');
  let needed=document.querySelectorAll('.depend [href=\"#'+id+'\"]');
  if (needed.length) {
    let neededBy='';
    needed.forEach(function(el, i){
      let byid=el.parentNode.parentNode.getAttribute('id');
      neededBy +='<a href=\"#'+byid+'\">'+byid+'</a><br>'
    });
    item.innerHTML+='<details class=\"neededby\"><summary>Needed By</summary>'+neededBy+'</details>';
  }
});
})();
</script>"
echo '</body></html>'
) 
2 Likes