+#!/usr/bin/perl
+
+# Copyright (C) 2014 Steven McDonald <steven@steven-mcdonald.id.au>
+#
+# This program is free software. It comes without any warranty, to the
+# extent permitted by applicable law. You can redistribute it and/or
+# modify it under the terms of the Do What The Fuck You Want To Public
+# License, Version 2, as published by Sam Hocevar. See the COPYING file
+# or visit http://www.wtfpl.net/ for more details.
+
+use strict;
+use warnings;
+
+sub print_tree;
+
+my $tree = {};
+my %name_to_node = (root => $tree);
+my $show_detached = 0;
+
+for (@ARGV) {
+ $show_detached = 1 if /^(-d|--show-detached)$/;
+}
+
+while (<STDIN>) {
+ if (/^(\w+) at (\w+):?\s(.*?["(<])?([^"()<>\n]+)?/) {
+ my $node_prettyname;
+ if ($4) {
+ $node_prettyname = "$1 ($4)";
+ } else {
+ $node_prettyname = $1;
+ }
+
+ my $new_node = {};
+ $name_to_node{$2}{$node_prettyname} = $new_node;
+ $name_to_node{$1} = $new_node;
+ } elsif (/^(\w+) detached$/ and my $node = $name_to_node{$1}) {
+ $node->{_is_detached} = 1;
+ }
+}
+
+print "root\n";
+print_tree $tree;
+exit;
+
+sub print_tree {
+ my $tree = shift;
+ my $prev_indent = shift || "";
+ my $indent = $prev_indent . " |";
+ my $count = 0;
+ my @keys = keys $tree;
+
+ for (sort @keys) {
+ my $name = $_;
+ if (delete $tree->{$_}->{_is_detached}) {
+ next unless $show_detached;
+ $name = "$name [DETACHED]";
+ }
+
+ print $indent . "-$name\n";
+ $indent = $prev_indent . " " if $count eq $#keys;
+ print_tree $tree->{$_}, $indent;
+ $count++;
+ }
+}