source: perl/lib/BarnOwl/Complete/Client.pm @ 6035008

release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 6035008 was 6035008, checked in by David Benjamin <davidben@mit.edu>, 12 years ago
Drop start argument to complete_filter_expr Use context slicing instead. For now, the private functions will retain the index for efficiency and to avoid complexity. They're private, so we don't need to conform to any interface. Signed-off-by: David Benjamin <davidben@mit.edu>
  • Property mode set to 100644
File size: 7.3 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
154    my @completions = ();
155    _complete_filter_expr($ctx, 0, \@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            $ctx = $ctx->shift_words($idx);
205            return complete_filter_expr($ctx);
206        },
207        stop_at_nonflag => 1
208        );
209}
210
211sub complete_view {
212    my $ctx = shift;
213    if ($ctx->word == 1) {
214        return ("--home", "-d", "-r", "-s", complete_filter_name());
215    }
216    if ($ctx->words->[1] eq "--home") {
217        return;
218    }
219    if ($ctx->words->[1] eq "-d") {
220        $ctx = $ctx->shift_words(2);
221        return complete_filter_expr($ctx);
222    }
223    if ($ctx->words->[1] eq "-s") {
224        return complete_style();
225    }
226    return;
227}
228
229sub complete_getvar {
230    my $ctx = shift;
231    return unless ($ctx->word == 1);
232    return complete_variable();
233}
234
235sub complete_set {
236    my $ctx = shift;
237    return complete_flags($ctx,
238        [qw(-q)],
239        {
240        },
241         \&complete_set_args
242        );
243}
244sub complete_set_args {
245    my $ctx = shift;
246    my $arg = shift;
247    return if $arg;
248    return complete_variable();
249}
250
251sub complete_startup {
252    my $ctx = shift;
253    my $new_ctx = $ctx->shift_words(1);
254    return BarnOwl::Completion::get_completions($new_ctx);
255}
256
257BarnOwl::Completion::register_completer(help    => \&complete_help);
258BarnOwl::Completion::register_completer(filter  => \&complete_filter);
259BarnOwl::Completion::register_completer(view    => \&complete_view);
260BarnOwl::Completion::register_completer(show    => \&complete_show);
261BarnOwl::Completion::register_completer(getvar  => \&complete_getvar);
262BarnOwl::Completion::register_completer(set     => \&complete_set);
263BarnOwl::Completion::register_completer(unset   => \&complete_set);
264BarnOwl::Completion::register_completer(startup => \&complete_startup);
265
2661;
Note: See TracBrowser for help on using the repository browser.