3
0
mirror of https://github.com/pragma-/pbot.git synced 2024-10-05 02:48:50 +02:00

Factoids: add %(a|b|c) syntax to select a random item

This commit is contained in:
Pragmatic Software 2020-06-02 22:25:09 -07:00
parent 4b1c36bca2
commit a3a7319497

View File

@ -451,72 +451,12 @@ sub expand_special_vars {
return validate_string($action, $self->{pbot}->{registry}->get_value('factoids', 'max_content_length'));
}
sub expand_factoid_vars {
my ($self, $context, @exclude) = @_;
my $from = length $context->{ref_from} ? $context->{ref_from} : $context->{from};
my $nick = $context->{nick};
my $root_keyword = $context->{keyword_override} ? $context->{keyword_override} : $context->{root_keyword};
my $action = $context->{action};
my $depth = 0;
if ($action =~ m/^\/call --keyword-override=([^ ]+)/i) { $root_keyword = $1; }
while (1) {
last if ++$depth >= 1000;
my $offset = 0;
my $matches = 0;
my $expansions = 0;
$action =~ s/(?<!\\)\$0/$root_keyword/g;
my $const_action = $action;
while ($const_action =~ /(\ba\s*|\ban\s*)?(?<!\\)\$(?:(\{[a-zA-Z0-9_#]+(?::[a-zA-Z0-9_(),.#:+-]+)?\}|[a-zA-Z0-9_#]+(?::[a-zA-Z0-9_(),.#:+-]+)?))/gi) {
my ($indefinite_article, $v) = ($1, $2);
$indefinite_article = '' if not defined $indefinite_article;
next if not defined $v;
my $original_v = $v;
my $test_v = $v;
$test_v =~ s/(.):$/$1/; # remove trailing : only if at least one character precedes it
next if $test_v =~ m/^_/; # special character prefix skipped for shell/code-factoids/etc
next if $test_v =~ m/^(?:nick|channel|randomnick|arglen|args|arg\[.+\]|[_0])(?:\:json)*$/i; # don't override special variables
next if @exclude && grep { $test_v =~ m/^\Q$_\E$/i } @exclude;
last if ++$depth >= 1000;
$matches++;
$test_v =~ s/\{(.+)\}/$1/;
my $modifier = '';
if ($test_v =~ s/(:.*)$//) { $modifier = $1; }
if ($modifier =~ m/^:(#[^:]+|global)/i) {
$from = $1;
$from = '.*' if lc $from eq 'global';
}
my $recurse = 0;
ALIAS:
my @factoids = $self->find_factoid($from, $test_v, exact_channel => 2, exact_trigger => 2);
next if not @factoids or not $factoids[0];
my ($var_chan, $var) = ($factoids[0]->[0], $factoids[0]->[1]);
if ($self->{factoids}->get_data($var_chan, $var, 'action') =~ m{^/call (.*)}ms) {
$test_v = $1;
next if ++$recurse > 100;
goto ALIAS;
}
if ($self->{factoids}->get_data($var_chan, $var, 'type') eq 'text') {
my $change = $self->{factoids}->get_data($var_chan, $var, 'action');
my @list = $self->{pbot}->{interpreter}->split_line($change);
sub select_item {
my ($self, $list, $modifier) = @_;
my %settings;
$self->{pbot}->{logger}->log("Picking from list (" . (join ', ', @$list) . ") with modifier [$modifier]\n");
foreach my $mod (split /:/, $modifier) {
next if not length $mod;
if ($mod =~ s/([,.#:-]+)$//) {
@ -581,20 +521,20 @@ sub expand_factoid_vars {
}
}
my $replacement;
my $item;
if (exists $settings{'index'}) {
my $index = $settings{'index'};
$index = $#list - -$index if $index < 0;
$index = $#$list - -$index if $index < 0;
$index = 0 if $index < 0;
$index = $#list if $index > $#list;
$replacement = $list[$index];
$index = $#$list if $index > $#$list;
$item = $list->[$index];
# strip outer quotes
if (not $replacement =~ s/^"(.*)"$/$1/) { $replacement =~ s/^'(.*)'$/$1/; }
if (not $item =~ s/^"(.*)"$/$1/) { $item =~ s/^'(.*)'$/$1/; }
} elsif ($settings{'pick'}) {
my $min = $settings{'pick_min'};
my $max = $settings{'pick_max'};
$max = @list if $max > @list;
$max = @$list if $max > @$list;
$min = $max if $min > $max;
my $count = $max;
@ -604,11 +544,11 @@ sub expand_factoid_vars {
my @choices;
while ($count-- > 0) {
my $index = int rand @list;
my $choice = $list[$index];
my $index = int rand @$list;
my $choice = $list->[$index];
if ($settings{'unique'}) {
splice @list, $index, 1;
splice @$list, $index, 1;
}
# strip outer quotes
@ -624,22 +564,164 @@ sub expand_factoid_vars {
@choices = sort { $b cmp $a } @choices;
}
return @choices if wantarray;
if ($settings{'enumerate'} or $settings{'comma'}) {
$replacement = join ', ', @choices;
$replacement =~ s/(.*), /$1 and / if $settings{'enumerate'};
$item = join ', ', @choices;
$item =~ s/(.*), /$1 and / if $settings{'enumerate'};
} else {
$replacement = "@choices";
$item = "@choices";
}
} else {
$replacement = $list[rand @list];
$item = $list->[rand @$list];
# strip outer quotes
if (not $replacement =~ s/^"(.*)"$/$1/) { $replacement =~ s/^'(.*)'$/$1/; }
if (not $item =~ s/^"(.*)"$/$1/) { $item =~ s/^'(.*)'$/$1/; }
}
if ($settings{'trailing-punct'}) {
$replacement .= $settings{'trailing-punct'};
$item .= $settings{'trailing-punct'};
}
foreach my $mod (split /:/, $modifier) {
next if not length $mod;
$mod =~ s/,$//;
given ($mod) {
when ('uc') { $item = uc $item; }
when ('lc') { $item = lc $item; }
when ('ucfirst') { $item = ucfirst $item; }
when ('title') {
$item = ucfirst lc $item;
$item =~ s/ (\w)/' ' . uc $1/ge;
}
when ('json') { $item = $self->escape_json($item); }
}
}
if (wantarray) {
my @items = ($item);
return @items;
}
return $item;
}
sub expand_factoid_selectors {
my ($self, $context, $action) = @_;
my $result = '';
while (1) {
if ($action =~ /(.*?)(?<!\\)%\s*\(.*\)/) {
$result .= $1;
} else {
last;
}
my ($extracted, $rest) = $self->{pbot}->{interpreter}->extract_bracketed($action, '(', ')', '%', 1);
last if not length $extracted;
my $modifier = '';
if ($rest =~ s/^(:[^ ]+)//) {
$modifier = $1;
}
my @list;
foreach my $item (split /\s*\|\s*/, $extracted) {
$item =~ s/^\s+|\s+$//g;
my @items = $self->expand_factoid_vars($context, $item);
push @list, @items;
}
my $item = $self->select_item(\@list, $modifier);
$result .= $item;
$action = $rest;
}
$result .= $action;
return $result;
}
sub expand_factoid_vars {
my ($self, $context, $action, @exclude) = @_;
my $from = length $context->{ref_from} ? $context->{ref_from} : $context->{from};
my $nick = $context->{nick};
my $root_keyword = $context->{keyword_override} ? $context->{keyword_override} : $context->{root_keyword};
$action = defined $action ? $action : $context->{action};
$action = $self->expand_factoid_selectors($context, $action);
my $depth = 0;
if ($action =~ m/^\/call --keyword-override=([^ ]+)/i) { $root_keyword = $1; }
while (1) {
last if ++$depth >= 1000;
my $offset = 0;
my $matches = 0;
my $expansions = 0;
$action =~ s/(?<!\\)\$0/$root_keyword/g;
my $const_action = $action;
while ($const_action =~ /(\ba\s*|\ban\s*)?(?<!\\)\$(?:(\{[a-zA-Z0-9_#]+(?::[a-zA-Z0-9_(),.#:+-]+)?\}|[a-zA-Z0-9_#]+(?::[a-zA-Z0-9_(),.#:+-]+)?))/gi) {
my ($indefinite_article, $v) = ($1, $2);
$indefinite_article = '' if not defined $indefinite_article;
next if not defined $v;
my $original_v = $v;
my $test_v = $v;
$test_v =~ s/(.):$/$1/; # remove trailing : only if at least one character precedes it
next if $test_v =~ m/^_/; # special character prefix skipped for shell/code-factoids/etc
next if $test_v =~ m/^(?:nick|channel|randomnick|arglen|args|arg\[.+\]|[_0])(?:\:json)*$/i; # don't override special variables
next if @exclude && grep { $test_v =~ m/^\Q$_\E$/i } @exclude;
last if ++$depth >= 1000;
$matches++;
$test_v =~ s/\{(.+)\}/$1/;
my $modifier = '';
if ($test_v =~ s/(:.*)$//) { $modifier = $1; }
if ($modifier =~ m/^:(#[^:]+|global)/i) {
$from = $1;
$from = '.*' if lc $from eq 'global';
}
my $recurse = 0;
ALIAS:
my @factoids = $self->find_factoid($from, $test_v, exact_channel => 2, exact_trigger => 2);
next if not @factoids or not $factoids[0];
my ($var_chan, $var) = ($factoids[0]->[0], $factoids[0]->[1]);
if ($self->{factoids}->get_data($var_chan, $var, 'action') =~ m{^/call (.*)}ms) {
$test_v = $1;
next if ++$recurse > 100;
goto ALIAS;
}
if ($self->{factoids}->get_data($var_chan, $var, 'type') eq 'text') {
my $change = $self->{factoids}->get_data($var_chan, $var, 'action');
my @list = $self->{pbot}->{interpreter}->split_line($change);
my @replacements;
if (wantarray) {
@replacements = $self->select_item(\@list, $modifier);
} else {
push @replacements, scalar $self->select_item(\@list, $modifier);
}
foreach my $replacement (@replacements) {
foreach my $mod (split /:/, $modifier) {
next if not length $mod;
$mod =~ s/,$//;
@ -675,6 +757,13 @@ sub expand_factoid_vars {
$fixed_article = ucfirst $fixed_article if $indefinite_article =~ m/^A/;
$replacement = "$fixed_article $replacement";
}
}
if (wantarray) {
return @replacements;
}
my $replacement = "@replacements";
$original_v = quotemeta $original_v;
$original_v =~ s/\\:/:/g;