#! perl # mandatory depends=doclet our $TOPIC; our %DOCLET; our $HELP_CHANNEL = { id => "help", title => "Help", reply => "help ", tooltip => "Online Help", }; # considerable duplication between load_doclets and load_topics sub load_doclets { %DOCLET = (); my @command_list; for ( [0, "command_help"], [1, "emote_help"], [2, "dmcommand_help"], ) { my ($type, $path) = @$_; my $paragraphs = cf::pod::load_pod "$PODDIR/$path.pod" or die "unable to load $path"; my $level = 1e9; my $rpar; for my $par (@$paragraphs) { if ($par->{type} eq "head2") { # this code taken almost verbatim from DC/Protocol.pm if ($par->{markup} =~ /^(\S+) (?:\s+ \( ([^\)]*) \) )?/x) { my $cmd = $1; my @args = split /\|/, $2; @args = (".*") unless @args; $_ = $_ eq ".*" ? "" : " $_" for @args; my @variants = map "$cmd$_", sort { (length $a) <=> (length $b) } @args; $rpar = \($DOCLET{$cmd} = &cf::pod::as_cfpod ([$par])); push @command_list, [$type, \@variants]; $level = $par->{level}; } else { cf::error "$par->{markup}: unparsable command heading"; } } elsif ($par->{level} > $level) { $$rpar .= &cf::pod::as_cfpod ([$par]); } cf::cede_to_tick; } } @command_list = sort { $a->[0] <=> $b->[0] or $a->[1] cmp $b->[1] } @command_list; cf::cede_to_tick; cf::face::set "res/command_list" => cf::FT_RSRC, JSON::XS->new->utf8->encode (\@command_list); } our $DOCLET_HANDLER = ext::doclet::register command => sub { my ($pl, $category, $command) = @_; my $guard = cf::lock_acquire "ext::help::loading"; $DOCLET{$command} || "B" }; sub load_topics($$) { my ($type, $path) = @_; my $paragraphs = cf::pod::load_pod "$PODDIR/$path.pod" or die "unable to load $path"; my @topics; my $level = 1e9; for my $par (@$paragraphs) { cf::cede_to_tick; if ($par->{type} eq "head2") { if ($par->{markup} =~ /^(\S+)/) { push @topics, $1 => [$type => $par]; $level = $par->{level}; } } elsif ($par->{level} > $level) { push @{ $topics[-1] }, $par; } } @topics } sub reload() { my $guard1 = cf::lock_acquire "ext::help::loading"; my $guard2 = cf::lock_acquire "ext::resource"; local $Coro::current->{desc} = "help loader"; $TOPIC = { (load_topics "DM Commands" => "dmcommand_help"), (load_topics "Emotes" => "emote_help"), (load_topics "Commands" => "command_help"), (load_topics "Generic Help Topics" => "generic_help"), }; load_doclets; () } cf::post_init { cf::async_ext { reload }; Coro::cede; # make sure reload acquires the lock(s) }; cf::register_command help => sub { my ($pl, $topic) = @_; if (cf::lock_active "ext::help::loading") { $pl->send_msg ($HELP_CHANNEL => "help files are being loaded currently, try again in a few seconds.", cf::NDI_REPLY | cf::NDI_CLEAR); return; } $topic = $1 if $topic =~ /(\S+)/; if (!length $topic) { # sort.. my %topics; while (my ($k, $v) = each %$TOPIC) { push @{$topics{$v->[0]}}, $k; } my $res; while (my ($k, $v) = each %topics) { $res .= "T<$k:>\n\n" . (join " ", sort @$v) . "\n\n"; } $pl->send_msg ($HELP_CHANNEL => $res, cf::NDI_REPLY | cf::NDI_CLEAR); } elsif (my $item = $TOPIC->{$topic}) { my ($type, @pars) = @$item; $pl->send_msg ($HELP_CHANNEL => (cf::pod::as_cfpod \@pars), cf::NDI_REPLY | cf::NDI_CLEAR); } else { $pl->send_msg ($HELP_CHANNEL => "'$topic' no such help topic, try just 'help' to get a list of topics.", cf::NDI_REPLY); } };