use strict; use warnings; ############################# OP data # dummy items to play with my @animals = (qw( cow camel dog cat )); my @foods = (qw( fish pasture meat )); my @places = (qw( wood sea desert )); # commands my $commands = { select => { completion_list => \@animals, commands => { give => { completion_list => \@foods, }, take_to => { completion_list => \@places, }, }, }, kill => { completion_list => \@animals, } }; ############################# my $branch = { commands => $commands }; my @path; BRANCH: { if ( exists $branch-> { completion_list }) { my $choice = choose( @{ $branch-> { completion_list }}); push @path, $choice } if ( exists $branch-> { commands }) { my $choice = choose( sort keys %{ $branch-> { commands }}); push @path, $choice; $branch = $branch-> { commands }{ $choice }; redo BRANCH } } sub choose { $_[ 0 ]} print "Excellent choice! ===> [ @path ]\n"; #### Excellent choice! ===> [ kill cow ] #### sub choose { my @list = @_; use Term::Completion; STDOUT-> autoflush( 1 ); my $tc = Term::Completion-> new( prompt => "Choose (@list): ", choices => \@list, columns => 80, validation => 'nonempty fromchoices', ); return $tc-> complete } #### --- Completion.pm.orig Sat Feb 23 18:39:15 2013 +++ Completion.pm Mon Feb 13 15:06:00 2023 @@ -179,19 +179,24 @@ # (TAB) attempt completion $_ =~ $this->{tab} && do { + last GETC if grep /^$return$/, $this->get_choices($return); if($tab_pressed++) { - $this->show_choices($return); - redo LOOP; +# $this->show_choices($return); +# redo LOOP; } my @match = $this->get_choices($return); if (@match == 0) { + $this->show_choices($return); + redo LOOP; # sound bell if there is no match - $this->bell(); +# $this->bell(); } else { my $l = length(my $test = shift(@match)); if(@match) { + $this->show_choices($return); + redo LOOP; # sound bell if multiple choices - $this->bell(); +# $this->bell(); } elsif($this->{delim}) { $test .= $this->{delim}; @@ -361,7 +366,7 @@ { my __PACKAGE__ $this = shift; my $return = shift; - unless($this->{validate}) { + unless($this->{validation}) { return $return; } elsif(ref $this->{validate}) { @@ -376,7 +381,7 @@ } # we may have several validation options - my @vals = split(/[\s,]+/, $this->{validate}); + my @vals = split(/[\s,]+/, $this->{validation}); VALIDATE_OPTIONS: foreach my $val (@vals) { #### Choose (kill select): # TAB (for choices) kill select Choose (kill select): select # sTAB (to complete) + TAB or ENTER Choose (cow camel dog cat): c # cTAB (for choices) cow camel cat Choose (cow camel dog cat): ca # aTAB (for choices) camel cat Choose (cow camel dog cat): camel # mTAB (to complete) + TAB or ENTER Choose (give take_to): take_to # tTAB (to complete) + TAB or ENTER Choose (wood sea desert): desert # dTAB (to complete) + TAB or ENTER Excellent choice! ===> [ select camel take_to desert ]