source: perl/lib/BarnOwl/Completion/Context.pm @ f987504

release-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since f987504 was 7be5d8b, checked in by Nelson Elhage <nelhage@mit.edu>, 15 years ago
Completion::Context: Fix behavior if point is at end after whitespace. We should add an empty word on the end, and need to get the word limits correct.
  • Property mode set to 100644
File size: 3.4 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                                word_start word_end));
45
46sub new {
47    my $class = shift;
48    my $before_point = shift;
49    my $after_point = shift;
50
51    my $line  = $before_point . $after_point;
52    my $point = length ($before_point);
53    my ($words, $word, $word_point,
54        $word_start, $word_end) = tokenize($line, $point);
55
56    my $self = {
57        line  => $line,
58        point => $point,
59        words => $words,
60        word  => $word,
61        word_point => $word_point,
62        word_start => $word_start,
63        word_end   => $word_end
64       };
65    return bless($self, $class);
66}
67
68=for doc
69
70Ideally, this should use the same codepath we use to /actually/
71tokenize commands, but for now, make sure this is kept in sync with
72owl_parseline in util.c
73
74Unlike owl_parseline, we always return a result, even in the presence
75of parse errors, since we may be called on incomplete command-lines.
76
77The owl_parseline rules are:
78
79* Tokenize on ' ' and '\t'
80* ' and " are quote characters
81* \ has no effect
82
83=cut
84
85my $boring = qr{[^'" \t]};
86my $quote  = qr{['"]};
87my $space  = qr{[ \t]};
88
89sub tokenize {
90    my $line = shift;
91    my $point = shift;
92
93    my @words = ();
94    my $cword = 0;
95    my $cword_start;
96    my $cword_end;
97    my $word_point;
98
99    my $word = '';
100    my $wstart = 0;
101    my $skipped = 0;
102
103    pos($line) = 0;
104    while(pos($line) < length($line)) {
105        if($line =~ m{\G ($boring+) }gcx) {
106            $word .= $1;
107        } elsif ($line =~ m{\G ($quote)}gcx) {
108            my $chr = $1;
109            $skipped++ if pos($line) > $point;
110            if($line =~ m{\G ([^$chr]*) $chr}gcx) {
111                $word .= $1;
112                $skipped++ if pos($line) > $point;
113            } else {
114                $word .= substr($line, pos($line));
115                pos($line) = length($line);
116            }
117        }
118
119        if ($line =~ m{\G ($space+|$)}gcx) {
120            my $wend = pos($line) - length($1);
121            push @words, $word;
122            $cword++ unless $wend >= $point;
123            if(($wend >= $point) && !defined($word_point)) {
124                $word_point = length($word) - ($wend - $point) + $skipped;
125                $cword_start = $wstart;
126                $cword_end   = $wend;
127            }
128            $word = '';
129            $wstart = pos($line);
130            $skipped = 0;
131        }
132    }
133
134    if(length($word)) { die("Internal error, leftover=$word"); }
135
136    unless(defined($word_point)) {
137        $word_point = 0;
138        $cword_start = $cword_end = $point;
139        push @words, '' if $point > 0;
140    }
141
142    return (\@words, $cword, $word_point, $cword_start, $cword_end);
143}
144
1451;
Note: See TracBrowser for help on using the repository browser.