X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/44863ea2346eea32b3bc8b9b700101bf7ea3b32f..33b39968948f2dcda5c073916d797259e441d1de:/IkiWiki/Plugin/graphviz.pm?ds=inline 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=; + $map=$pagestate{$params{destpage}}{graph}{$sha}=; 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 "\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}};