Changeset bc5e856


Ignore:
Timestamp:
Aug 1, 2009, 9:38:37 PM (12 years ago)
Author:
David Benjamin <davidben@mit.edu>
Branches:
master, release-1.4, release-1.5, release-1.6, release-1.7, release-1.8, release-1.9
Children:
bd25f30
Parents:
7940ac2
git-author:
David Benjamin <davidben@mit.edu> (08/01/09 21:30:10)
git-committer:
David Benjamin <davidben@mit.edu> (08/01/09 21:38:37)
Message:
Add completer for filter expressions

It parses the incomplete input to figure out what keywords, etc., you
can add next.

Signed-off-by: David Benjamin <davidben@mit.edu>
File:
1 edited

Legend:

Unmodified
Added
Removed
  • perl/lib/BarnOwl/Complete/Client.pm

    r7940ac2 rbc5e856  
    4545sub complete_variable {}        # stub
    4646
     47my %filter_cmds = (
     48    sender    => \&BarnOwl::Complete::Zephyr::complete_user,
     49    recipient => \&BarnOwl::Complete::Zephyr::complete_user,
     50    class     => \&BarnOwl::Complete::Zephyr::complete_class,
     51    instance  => \&BarnOwl::Complete::Zephyr::complete_instance,
     52    opcode    => \&BarnOwl::Complete::Zephyr::complete_opcode,
     53    realm     => \&BarnOwl::Complete::Zephyr::complete_realm,
     54    body      => undef,
     55    hostname  => undef,
     56    type      => sub { qw(zephyr aim admin); },
     57    direction => sub { qw(in out none); },
     58    login     => sub { qw(login logout none); },
     59    filter    => \&complete_filter_name,
     60    perl      => undef,
     61);
     62
     63# Returns:
     64# - where to look next after pulling out an expression
     65# - $INCOMPLETE if this cannot form a complete expression (or w/e)
     66# - pushes to completion list as it finds valid completions
     67
     68my $INCOMPLETE = -1;
     69sub _complete_filter_expr {
     70    # Takes as arguments context and the index into $ctx->words where the
     71    # filter expression starts
     72    my $ctx = shift;
     73    my $start = shift;
     74    my $o_comp = shift;
     75    my $end = $ctx->word;
     76
     77    # Grab an expression; we don't allow empty
     78    my $i = $start;
     79    $i = _complete_filter_primitive_expr($ctx, $start, $o_comp);
     80    return $INCOMPLETE if $start == $INCOMPLETE;
     81
     82    while ($i <= $end) {
     83        if ($i == $end) {
     84            # We could and/or another clause
     85            push @$o_comp, qw(and or);
     86            return $end; # Or we could let the parent do his thing
     87        }
     88
     89        if ($ctx->words->[$i] ne 'and' && $ctx->words->[$i] ne 'or') {
     90            return $i; # We're done. Let the parent do his thing
     91        }
     92
     93        # Eat the and/or
     94        $i++;
     95
     96        # Grab an expression
     97        $i = _complete_filter_primitive_expr($ctx, $i, $o_comp);
     98        return $INCOMPLETE if $i == $INCOMPLETE;
     99    }
     100   
     101    return $i; # Well, it looks like we're happy
     102    # (Actually, I'm pretty sure this never happens...)
     103}
     104
     105sub _complete_filter_primitive_expr {
     106    my $ctx = shift;
     107    my $start = shift;
     108    my $o_comp = shift;
     109    my $end = $ctx->word;
     110
     111    if ($start >= $end) {
     112        push @$o_comp, "(";
     113        push @$o_comp, qw(true false not);
     114        push @$o_comp, keys %filter_cmds;
     115        return $INCOMPLETE;
     116    }
     117
     118    my $word = $ctx->words->[$start];
     119    if ($word eq "(") {
     120        $start = _complete_filter_expr($ctx, $start+1, $o_comp);
     121        return $INCOMPLETE if $start == $INCOMPLETE;
     122
     123        # Now, we expect a ")"
     124        if ($start >= $end) {
     125            push @$o_comp, ")";
     126            return $INCOMPLETE;
     127        }
     128        if ($ctx->words->[$start] ne ')') {
     129            # User is being confusing. Give up.
     130            return $INCOMPLETE;
     131        }
     132        return $start+1; # Eat the )
     133    } elsif ($word eq "not") {
     134        # We just want another primitive expression
     135        return _complete_filter_primitive_expr($ctx, $start+1, $o_comp);
     136    } elsif ($word eq "true" || $word eq "false") {
     137        # No arguments
     138        return $start+1; # Eat the boolean. Mmmm, tasty.
     139    } else {
     140        # It's of the form 'CMD ARG'
     141        return $start+2 if ($start+1 < $end); # The user supplied the argument
     142
     143        # complete the argument
     144        my $arg_func = $filter_cmds{$word};
     145        push @$o_comp, ($arg_func ? ($arg_func->()) : ());
     146        return $INCOMPLETE;
     147    }
     148}
     149
     150sub complete_filter_expr {
     151    my $ctx = shift;
     152    my $start = shift;
     153    my @completions = ();
     154    _complete_filter_expr($ctx, $start, \@completions);
     155    # Get rid of duplicates and sort
     156    my %hash = ();
     157    @hash{@completions} = ();
     158    @completions = sort keys %hash;
     159    return @completions;
     160}
     161
    47162sub complete_filter_args {
    48163    my $ctx = shift;
    49164    my $arg = shift;
    50     return if $arg;
    51     return complete_filter_name();
     165    return complete_filter_name() unless $arg;
     166    my $idx = 2; # skip the filter name
     167    while ($idx < $ctx->word) {
     168        last unless ($ctx->words->[$idx] =~ m{^-});
     169        $idx += 2; # skip the flag and the argument
     170    }
     171    return complete_filter_expr($ctx, $idx);
    52172}
    53173
Note: See TracChangeset for help on using the changeset viewer.