From 8956d8a4836aaca530e2d04104456a53d9ced208 Mon Sep 17 00:00:00 2001
From: Juerd Waalboer <juerd@tnx.nl>
Date: Thu, 2 Nov 2023 03:15:01 +0100
Subject: [PATCH] Move :Tab introspection from main:: to RevBank::Plugin

- Exposes the introspection as a public method.
- Removes undocumented support for NOABORT special-case.
---
 lib/RevBank/Plugin.pm | 26 ++++++++++++++++++++++++++
 plugins/take          |  2 +-
 revbank               | 29 +++--------------------------
 3 files changed, 30 insertions(+), 27 deletions(-)

diff --git a/lib/RevBank/Plugin.pm b/lib/RevBank/Plugin.pm
index 3eccb05..f356a5a 100644
--- a/lib/RevBank/Plugin.pm
+++ b/lib/RevBank/Plugin.pm
@@ -3,16 +3,42 @@ package RevBank::Plugin;
 use v5.28;
 use warnings;
 use experimental 'signatures';  # stable since v5.36
+use attributes;
 
 require RevBank::Global;
 
 sub new($class) {
     return bless { }, $class;
 }
+
 sub command($self, $cart, $command, @) {
     return RevBank::Global::NEXT();
 }
 
+sub Tab($self, $method) {
+    my %completions;
+
+    my $attr = attributes::get(
+        ref $method ? $method : $self->can($method)
+    ) or return;
+
+    my ($tab) = $attr =~ /Tab \( (.*?) \)/x;
+    for my $keyword (split /\s*,\s*/, $tab) {
+        if ($keyword =~ /^&(.*)/) {
+            my $method = $1;
+            @completions{ $self->$method } = ();
+        } else {
+            $completions{ $keyword }++;
+        }
+    }
+
+    if (delete $completions{USERS}) {
+        $completions{$_}++ for grep !RevBank::Users::is_hidden($_),
+            RevBank::Users::names();
+    }
+
+    return keys %completions;
+}
 
 1;
 
diff --git a/plugins/take b/plugins/take
index d01eb19..781b12c 100644
--- a/plugins/take
+++ b/plugins/take
@@ -43,7 +43,7 @@ sub arg :Tab(USERS) ($self, $cart, $arg, @) {
 }
 
 # finish
-sub reason :Tab(bbq,NOABORT) ($self, $cart, $reason, @) { 
+sub reason :Tab(bbq) ($self, $cart, $reason, @) { 
     return REJECT, "'$reason' is a username, not a description :)."
         if parse_user($reason);
     return REJECT, "'$reason' is an amount, not a description :)."
diff --git a/revbank b/revbank
index bc84776..d2aa41c 100755
--- a/revbank
+++ b/revbank
@@ -5,9 +5,8 @@ use warnings;
 use feature qw(signatures);
 no warnings "experimental::signatures";
 
-use attributes;
 use IO::Select;
-use List::Util ();
+use List::Util qw(uniq);
 use Term::ReadLine;
 require Term::ReadLine::Gnu;  # The other one sucks.
 
@@ -163,30 +162,8 @@ OUTER: for (;;) {
             call_hooks "prompt", $cart, $prompt;
             my $split_input = !ref($method) && $method eq 'command';
 
-            my %completions = qw(abort 1);
-            for my $plugin (@plugins) {
-                my $attr = attributes::get(
-                    ref $method ? $method : $plugin->can($method)
-                ) or next;
-                my ($tab) = $attr =~ /Tab \( (.*?) \)/x;
-                for my $keyword (split /\s*,\s*/, $tab) {
-                    if ($keyword =~ /^&(.*)/) {
-                        my $method = $1;
-                        @completions{ $plugin->$method } = ();
-                    } else {
-                        $completions{ $keyword }++;
-                    }
-                }
-            }
-            if (delete $completions{USERS}) {
-                $completions{$_}++ for grep !RevBank::Users::is_hidden($_),
-                    RevBank::Users::names;
-            }
-            if (delete $completions{NOABORT}) {
-                delete $completions{abort};
-            }
-
-            my $input = prompt $prompt, \@plugins, [ keys %completions ];
+            my @completions = uniq 'abort', map $_->Tab($method), @plugins;
+            my $input = prompt $prompt, \@plugins, \@completions;
 
             call_hooks "input", $cart, $input, $split_input;