Ignore:
File:
1 edited

Legend:

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

    rd5ccf4e8 ra3a9eb7  
    77
    88use BarnOwl::Completion::Util qw(complete_flags);
     9use BarnOwl::Complete::Filter qw(complete_filter_name complete_filter_expr);
    910
    1011my @all_colors = qw(default
     
    4243sub complete_command { return sort @BarnOwl::all_commands; }
    4344sub complete_color { return @all_colors; }
    44 sub complete_filter_name { return @{BarnOwl::all_filters()}; }
    4545sub complete_variable    { return @{BarnOwl::all_variables()}; }
    4646sub complete_style       { return @{BarnOwl::all_styles()}; }
    47 
    48 my %filter_cmds = (
    49     sender    => \&BarnOwl::Complete::Zephyr::complete_user,
    50     recipient => \&BarnOwl::Complete::Zephyr::complete_user,
    51     class     => \&BarnOwl::Complete::Zephyr::complete_class,
    52     instance  => \&BarnOwl::Complete::Zephyr::complete_instance,
    53     opcode    => \&BarnOwl::Complete::Zephyr::complete_opcode,
    54     realm     => \&BarnOwl::Complete::Zephyr::complete_realm,
    55     body      => undef,
    56     hostname  => undef,
    57     type      => sub { qw(zephyr aim admin); },
    58     direction => sub { qw(in out none); },
    59     login     => sub { qw(login logout none); },
    60     filter    => \&complete_filter_name,
    61     perl      => undef,
    62 );
    63 
    64 # Returns:
    65 # - where to look next after pulling out an expression
    66 # - $INCOMPLETE if this cannot form a complete expression (or w/e)
    67 # - pushes to completion list as it finds valid completions
    68 
    69 my $INCOMPLETE = -1;
    70 sub _complete_filter_expr {
    71     # Takes as arguments context and the index into $ctx->words where the
    72     # filter expression starts
    73     my $ctx = shift;
    74     my $start = shift;
    75     my $o_comp = shift;
    76     my $end = $ctx->word;
    77 
    78     # Grab an expression; we don't allow empty
    79     my $i = $start;
    80     $i = _complete_filter_primitive_expr($ctx, $start, $o_comp);
    81     return $INCOMPLETE if $start == $INCOMPLETE;
    82 
    83     while ($i <= $end) {
    84         if ($i == $end) {
    85             # We could and/or another clause
    86             push @$o_comp, qw(and or);
    87             return $end; # Or we could let the parent do his thing
    88         }
    89 
    90         if ($ctx->words->[$i] ne 'and' && $ctx->words->[$i] ne 'or') {
    91             return $i; # We're done. Let the parent do his thing
    92         }
    93 
    94         # Eat the and/or
    95         $i++;
    96 
    97         # Grab an expression
    98         $i = _complete_filter_primitive_expr($ctx, $i, $o_comp);
    99         return $INCOMPLETE if $i == $INCOMPLETE;
    100     }
    101    
    102     return $i; # Well, it looks like we're happy
    103     # (Actually, I'm pretty sure this never happens...)
    104 }
    105 
    106 sub _complete_filter_primitive_expr {
    107     my $ctx = shift;
    108     my $start = shift;
    109     my $o_comp = shift;
    110     my $end = $ctx->word;
    111 
    112     if ($start >= $end) {
    113         push @$o_comp, "(";
    114         push @$o_comp, qw(true false not);
    115         push @$o_comp, keys %filter_cmds;
    116         return $INCOMPLETE;
    117     }
    118 
    119     my $word = $ctx->words->[$start];
    120     if ($word eq "(") {
    121         $start = _complete_filter_expr($ctx, $start+1, $o_comp);
    122         return $INCOMPLETE if $start == $INCOMPLETE;
    123 
    124         # Now, we expect a ")"
    125         if ($start >= $end) {
    126             push @$o_comp, ")";
    127             return $INCOMPLETE;
    128         }
    129         if ($ctx->words->[$start] ne ')') {
    130             # User is being confusing. Give up.
    131             return $INCOMPLETE;
    132         }
    133         return $start+1; # Eat the )
    134     } elsif ($word eq "not") {
    135         # We just want another primitive expression
    136         return _complete_filter_primitive_expr($ctx, $start+1, $o_comp);
    137     } elsif ($word eq "true" || $word eq "false") {
    138         # No arguments
    139         return $start+1; # Eat the boolean. Mmmm, tasty.
    140     } else {
    141         # It's of the form 'CMD ARG'
    142         return $start+2 if ($start+1 < $end); # The user supplied the argument
    143 
    144         # complete the argument
    145         my $arg_func = $filter_cmds{$word};
    146         push @$o_comp, ($arg_func ? ($arg_func->()) : ());
    147         return $INCOMPLETE;
    148     }
    149 }
    150 
    151 sub complete_filter_expr {
    152     my $ctx = shift;
    153     my $start = shift;
    154     my @completions = ();
    155     _complete_filter_expr($ctx, $start, \@completions);
    156     # Get rid of duplicates and sort
    157     my %hash = ();
    158     @hash{@completions} = ();
    159     @completions = sort keys %hash;
    160     return @completions;
    161 }
    162 
    163 sub complete_filter_args {
    164     my $ctx = shift;
    165     my $arg = shift;
    166     return complete_filter_name() unless $arg;
    167     my $idx = 2; # skip the filter name
    168     while ($idx < $ctx->word) {
    169         last unless ($ctx->words->[$idx] =~ m{^-});
    170         $idx += 2; # skip the flag and the argument
    171     }
    172     return complete_filter_expr($ctx, $idx);
    173 }
    17447
    17548sub complete_help {
     
    19467sub complete_filter {
    19568    my $ctx = shift;
     69    # Syntax: filter FILTERNAME FLAGS EXPR
     70
     71    # FILTERNAME
     72    return complete_filter_name() if $ctx->word == 1;
     73
     74    # FLAGS
     75    $ctx = $ctx->shift_words(1); # complete_flags starts at the second word
    19676    return complete_flags($ctx,
    19777        [qw()],
     
    20080           "-b" => \&complete_color,
    20181        },
    202          \&complete_filter_args
     82        # EXPR
     83        sub {
     84            my $ctx = shift;
     85            my $arg = shift;
     86
     87            # We pass stop_at_nonflag, so we can rewind to the start
     88            my $idx = $ctx->word - $arg;
     89            $ctx = $ctx->shift_words($idx);
     90            return complete_filter_expr($ctx);
     91        },
     92        stop_at_nonflag => 1
    20393        );
    20494}
     
    213103    }
    214104    if ($ctx->words->[1] eq "-d") {
    215         return complete_filter_expr($ctx, 2);
     105        $ctx = $ctx->shift_words(2);
     106        return complete_filter_expr($ctx);
    216107    }
    217108    if ($ctx->words->[1] eq "-s") {
     
    243134}
    244135
     136sub complete_startup {
     137    my $ctx = shift;
     138    my $new_ctx = $ctx->shift_words(1);
     139    return BarnOwl::Completion::get_completions($new_ctx);
     140}
     141
    245142BarnOwl::Completion::register_completer(help    => \&complete_help);
    246143BarnOwl::Completion::register_completer(filter  => \&complete_filter);
     
    250147BarnOwl::Completion::register_completer(set     => \&complete_set);
    251148BarnOwl::Completion::register_completer(unset   => \&complete_set);
     149BarnOwl::Completion::register_completer(startup => \&complete_startup);
    252150
    2531511;
Note: See TracChangeset for help on using the changeset viewer.