source: perl/lib/BarnOwl/Complete/Client.pm @ 76e0e4a

release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 76e0e4a was 76e0e4a, checked in by David Benjamin <davidben@mit.edu>, 12 years ago
Reimplement complete_filter using shift_words Fixes bug with -c and -b appearing in completion suggestions. Signed-off-by: David Benjamin <davidben@mit.edu>
  • Property mode set to 100644
File size: 7.2 KB
Line 
1use strict;
2use warnings;
3
4# Completers for client state
5
6package BarnOwl::Complete::Client;
7
8use BarnOwl::Completion::Util qw(complete_flags);
9
10my @all_colors = qw(default
11                    black
12                    blue
13                    cyan
14                    green
15                    magenta
16                    red
17                    white
18                    yellow);
19
20my %show = (
21    information => undef,
22    colors      => undef,
23    commands    => undef,
24    command     => \&complete_command,
25    filters     => undef,
26    filter      => \&complete_filter_name,
27    license     => undef,
28    quickstart  => undef,
29    startup     => undef,
30    status      => undef,
31    styles      => undef,
32    subscriptions       => undef,
33    subs        => undef,
34    terminal    => undef,
35    variables   => undef,
36    variable    => \&complete_variable,
37    version     => undef,
38    view        => undef,
39    zpunts      => undef,
40   );
41
42sub complete_command { return sort @BarnOwl::all_commands; }
43sub complete_color { return @all_colors; }
44sub complete_filter_name { return @{BarnOwl::all_filters()}; }
45sub complete_variable    { return @{BarnOwl::all_variables()}; }
46sub complete_style       { return @{BarnOwl::all_styles()}; }
47
48my %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
69my $INCOMPLETE = -1;
70sub _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
106sub _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
151sub 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
163sub complete_help {
164    my $ctx = shift;
165    if($ctx->word == 1) {
166        return complete_command();
167    }
168}
169
170sub complete_show {
171    my $ctx = shift;
172    if($ctx->word == 1) {
173        return keys %show;
174    } elsif ($ctx->word == 2) {
175        my $cmd = $show{$ctx->words->[1]};
176        if($cmd) {
177            return $cmd->($ctx);
178        }
179    }
180}
181
182sub complete_filter {
183    my $ctx = shift;
184    # Syntax: filter FILTERNAME FLAGS EXPR
185
186    # FILTERNAME
187    return complete_filter_name() if $ctx->word == 1;
188
189    # FLAGS
190    $ctx = $ctx->shift_words(1); # complete_flags starts at the second word
191    return complete_flags($ctx,
192        [qw()],
193        {
194           "-c" => \&complete_color,
195           "-b" => \&complete_color,
196        },
197        # EXPR
198        sub {
199            my $ctx = shift;
200            my $arg = shift;
201
202            # We pass stop_at_nonflag, so we can rewind to the start
203            my $idx = $ctx->word - $arg;
204            return complete_filter_expr($ctx, $idx);
205        },
206        stop_at_nonflag => 1
207        );
208}
209
210sub complete_view {
211    my $ctx = shift;
212    if ($ctx->word == 1) {
213        return ("--home", "-d", "-r", "-s", complete_filter_name());
214    }
215    if ($ctx->words->[1] eq "--home") {
216        return;
217    }
218    if ($ctx->words->[1] eq "-d") {
219        return complete_filter_expr($ctx, 2);
220    }
221    if ($ctx->words->[1] eq "-s") {
222        return complete_style();
223    }
224    return;
225}
226
227sub complete_getvar {
228    my $ctx = shift;
229    return unless ($ctx->word == 1);
230    return complete_variable();
231}
232
233sub complete_set {
234    my $ctx = shift;
235    return complete_flags($ctx,
236        [qw(-q)],
237        {
238        },
239         \&complete_set_args
240        );
241}
242sub complete_set_args {
243    my $ctx = shift;
244    my $arg = shift;
245    return if $arg;
246    return complete_variable();
247}
248
249sub complete_startup {
250    my $ctx = shift;
251    my $new_ctx = $ctx->shift_words(1);
252    return BarnOwl::Completion::get_completions($new_ctx);
253}
254
255BarnOwl::Completion::register_completer(help    => \&complete_help);
256BarnOwl::Completion::register_completer(filter  => \&complete_filter);
257BarnOwl::Completion::register_completer(view    => \&complete_view);
258BarnOwl::Completion::register_completer(show    => \&complete_show);
259BarnOwl::Completion::register_completer(getvar  => \&complete_getvar);
260BarnOwl::Completion::register_completer(set     => \&complete_set);
261BarnOwl::Completion::register_completer(unset   => \&complete_set);
262BarnOwl::Completion::register_completer(startup => \&complete_startup);
263
2641;
Note: See TracBrowser for help on using the repository browser.