X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/44863ea2346eea32b3bc8b9b700101bf7ea3b32f..94a51309635b799fd25aeaf60d90fab25939343e:/IkiWiki/Plugin/graphviz.pm

diff --git a/IkiWiki/Plugin/graphviz.pm b/IkiWiki/Plugin/graphviz.pm
index f01fdca85..d4018edaa 100644
--- a/IkiWiki/Plugin/graphviz.pm
+++ b/IkiWiki/Plugin/graphviz.pm
@@ -10,7 +10,8 @@ use IPC::Open2;
 
 sub import {
 	hook(type => "getsetup", id => "graphviz", call => \&getsetup);
-	hook(type => "preprocess", id => "graph", call => \&graph);
+	hook(type => "needsbuild", id => "version", call => \&needsbuild);
+	hook(type => "preprocess", id => "graph", call => \&graph, scan => 1);
 }
 
 sub getsetup () {
@@ -26,33 +27,41 @@ my %graphviz_programs = (
 	"dot" => 1, "neato" => 1, "fdp" => 1, "twopi" => 1, "circo" => 1
 );
 
-my $graphnum=0;
+sub needsbuild {
+	my $needsbuild=shift;
+	foreach my $page (keys %pagestate) {
+		if (exists $pagestate{$page}{graph} &&
+		    exists $pagesources{$page} &&
+		    grep { $_ eq $pagesources{$page} } @$needsbuild) {
+			# remove state, will be re-added if
+			# the graph is still there during the rebuild
+			delete $pagestate{$page}{graph};
+		}
+	}       
+	return $needsbuild;
+}
 
 sub render_graph (\%) {
 	my %params = %{(shift)};
-
-	$graphnum++;
-	my $src = "$params{type} graph$graphnum {\n";
-	$src .= "charset=\"utf-8\";\n";
+	
+	my $src = "charset=\"utf-8\";\n";
 	$src .= "ratio=compress;\nsize=\"".($params{width}+0).", ".($params{height}+0)."\";\n"
 		if defined $params{width} and defined $params{height};
 	$src .= $params{src};
 	$src .= "}\n";
-
-	# Use the sha1 of the graphviz code as part of its filename.
+	
+	# Use the sha1 of the graphviz code as part of its filename,
+	# and as a unique identifier for its imagemap.
 	eval q{use Digest::SHA};
 	error($@) if $@;
-	my $base=$params{page}."/graph-".
-		IkiWiki::possibly_foolish_untaint(Digest::SHA::sha1_hex($src));
-	my $dest=$base.".png";
+	my $sha=IkiWiki::possibly_foolish_untaint(Digest::SHA::sha1_hex($params{type}.$src));
+	$src = "$params{type} graph$sha {\n".$src;
+
+	my $dest=$params{page}."/graph-".$sha.".png";
 	will_render($params{page}, $dest);
 
-	# The imagemap data is stored as a separate file.
-	my $imagemap=$base.".imagemap";
-	will_render($params{page}, $imagemap);
-	
-	my $map;
-	if (! -e "$config{destdir}/$dest" || ! -e "$config{destdir}/$imagemap") {
+	my $map=$pagestate{$params{destpage}}{graph}{$sha};
+	if (! -e "$config{destdir}/$dest" || ! defined $map) {
 		# Use ikiwiki's function to create the image file, this makes
 		# sure needed subdirs are there and does some sanity checking.
 		writefile($dest, $config{destdir}, "");
@@ -70,27 +79,66 @@ sub render_graph (\%) {
 		close OUT;
 
 		local $/ = undef;
-		$map=<IN>;
+		$map=$pagestate{$params{destpage}}{graph}{$sha}=<IN>;
 		close IN;
-		writefile($imagemap, $config{destdir}, $map);
 
 		waitpid $pid, 0;
 		$SIG{PIPE}="DEFAULT";
 		error gettext("failed to run graphviz") if ($sigpipe || $?);
-
-	}
-	else {
-		$map=readfile("$config{destdir}/$imagemap");
 	}
 
 	return "<img src=\"".urlto($dest, $params{destpage}).
-		"\" usemap=\"#graph$graphnum\" />\n".
+		"\" usemap=\"#graph$sha\" />\n".
 		$map;
 }
 
 sub graph (@) {
 	my %params=@_;
-	$params{src} = "" unless defined $params{src};
+
+	# Support wikilinks in the graph source.
+	my $src=$params{src};
+	$src="" unless defined $src;
+	$src=IkiWiki::linkify($params{page}, $params{destpage}, $params{src});
+	return unless defined wantarray; # scan mode short-circuit
+	if ($src ne $params{src}) {
+		# linkify makes html links, but graphviz wants plain
+		# urls. This is, frankly a hack: Process source as html,
+		# throw out everything inside tags that is not a href.
+		my $s;
+		my $nested=0;
+		use HTML::Parser;
+		error $@ if $@;
+		my $p=HTML::Parser->new(api_version => 3);
+		$p->handler(start => sub {
+			my %attrs=%{shift()};
+			if (exists $attrs{href}) {
+				if ($s=~/href\s*=\s*"$/) {
+					$s.=$attrs{href};
+				}
+				elsif ($s=~/href\s*=\s*$/) {
+					$s.="\"$attrs{href}\"";
+				}
+				else {
+					$s.="href=\"$attrs{href}\"";
+				}
+			}
+			$nested++;
+		}, "attr");
+		$p->handler(end => sub {
+			$nested--;
+		});
+		$p->handler(default => sub {
+			$s.=join("", @_) unless $nested;
+		}, "text");
+		$p->parse($src);
+		$p->eof;
+		$s=~s/\[ href= \]//g; # handle self-links
+		$params{src}=$s;
+	}
+	else {
+		$params{src}=$src;
+	}
+
 	$params{type} = "digraph" unless defined $params{type};
 	$params{prog} = "dot" unless defined $params{prog};
 	error gettext("prog not a valid graphviz program") unless $graphviz_programs{$params{prog}};