source: perl/lib/BarnOwl/Completion/Context.pm @ 8eac1a5

release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 8eac1a5 was 8eac1a5, checked in by Nelson Elhage <nelhage@mit.edu>, 12 years ago
Implement and test BarnOwl::Completion::Context. This is the class responsible for tokenizing the command-line for tab-completion.
  • Property mode set to 100644
File size: 2.9 KB
Line 
1use warnings;
2use strict;
3
4=head1 NAME
5
6BarnOwl::Completion::Context
7
8=head1 DESCRIPTION
9
10BarnOwl::Completion::Context is the context that is passed to a
11completion function by BarnOwl. It contains information on the text
12being completed.
13
14=head1 METHODS
15
16=head2 line
17
18The entire command-line currently being completed.
19
20=head2 point
21
22The index of the cursor in C<line>, in the range C<[0,len($line)]>.
23
24=head2 words
25
26The current command-line, tokenized according to BarnOwl's
27tokenization rules, as an array reference.
28
29=head2 word
30
31The current word the point is sitting in, as an index into C<words>.
32
33=head2 word_point
34
35The index of the point within C<$words->[$word]>.
36
37=cut
38
39package BarnOwl::Completion::Context;
40
41use base qw(Class::Accessor::Fast);
42
43__PACKAGE__->mk_ro_accessors(qw(line point words word word_point));
44
45sub new {
46    my $class = shift;
47    my $before_point = shift;
48    my $after_point = shift;
49
50    my $line  = $before_point . $after_point;
51    my $point = length ($before_point);
52    my ($words, $word, $word_point) = tokenize($line, $point);
53
54    my $self = {
55        line  => $line,
56        point => $point,
57        words => $words,
58        word  => $word,
59        word_point => $word_point
60       };
61    return bless($self, $class);
62}
63
64=for doc
65
66Ideally, this should use the same codepath we use to /actually/
67tokenize commands, but for now, make sure this is kept in sync with
68owl_parseline in util.c
69
70Unlike owl_parseline, we always return a result, even in the presence
71of parse errors, since we may be called on incomplete command-lines.
72
73The owl_parseline rules are:
74
75* Tokenize on ' ' and '\t'
76* ' and " are quote characters
77* \ has no effect
78
79=cut
80
81my $boring = qr{[^'" \t]};
82my $quote  = qr{['"]};
83my $space  = qr{[ \t]};
84
85sub tokenize {
86    my $line = shift;
87    my $point = shift;
88
89    my @words = ();
90    my $cword = 0;
91    my $word_point;
92
93    my $word = '';
94    my $skipped = 0;
95
96    pos($line) = 0;
97    while(pos($line) < length($line)) {
98        if($line =~ m{\G ($boring+) }gcx) {
99            $word .= $1;
100        } elsif ($line =~ m{\G ($quote)}gcx) {
101            my $chr = $1;
102            $skipped++ if pos($line) > $point;
103            if($line =~ m{\G ([^$chr]*) $chr}gcx) {
104                $word .= $1;
105                $skipped++ if pos($line) > $point;
106            } else {
107                $word .= substr($line, pos($line));
108                pos($line) = length($line);
109            }
110        }
111
112        if ($line =~ m{\G ($space+|$)}gcx) {
113            my $wend = pos($line) - length($1);
114            push @words, $word;
115            $cword++ unless $wend >= $point;
116            if ($wend >= $point && !defined($word_point)) {
117                $word_point = length($word) - ($wend - $point) + $skipped;
118            }
119            $word = '';
120            $skipped = 0;
121        }
122    }
123
124    if(length($word)) { die("Internal error, leftover=$word"); }
125
126    $word_point = 0 unless defined($word_point);
127
128    return (\@words, $cword, $word_point);
129}
130
1311;
Note: See TracBrowser for help on using the repository browser.