source: perl/lib/BarnOwl/Completion.pm @ 4fde21c

release-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 4fde21c was c4efb46, checked in by Nelson Elhage <nelhage@mit.edu>, 15 years ago
Completion: Fix a min/max confusion. This could cause completion to insert a completion in some situations even if it was not unique.
  • Property mode set to 100644
File size: 2.9 KB
Line 
1use warnings;
2use strict;
3
4=head1 NAME
5
6BarnOwl::Completion
7
8=head1 DESCRIPTION
9
10Hooks for tab-completion support in BarnOwl.
11
12=cut
13
14package BarnOwl::Completion;
15
16use BarnOwl::Completion::Context;
17use BarnOwl::Editwin qw(save_excursion text_before_point text_after_point
18                        point_move replace_region);
19
20use List::Util qw(min first);
21
22our %completers = ();
23
24sub do_complete {
25    my $cmd = shift;
26    my $before = text_before_point();
27    my $after  = text_after_point();
28    BarnOwl::debug("Completing: $before-|-$after");
29    my $ctx = BarnOwl::Completion::Context->new($before, $after);
30
31    my @words = get_completions($ctx);
32    return unless @words;
33    my $prefix = common_prefix(@words);
34
35    if($prefix) {
36        insert_completion($ctx, $prefix, scalar @words == 1);
37    }
38
39    if(scalar @words > 1) {
40        show_completions(@words);
41    } else {
42        BarnOwl::message('');
43    }
44}
45
46sub insert_completion {
47    my $ctx = shift;
48    my $completion = BarnOwl::quote(shift);
49    my $unique = shift;
50
51    if($unique) {
52        $completion .= " ";
53    }
54
55    save_excursion {
56        point_move($ctx->word_start - $ctx->point);
57        BarnOwl::Editwin::set_mark();
58        point_move($ctx->word_end - $ctx->word_start);
59        replace_region($completion);
60    };
61    if(!length($ctx->words->[$ctx->word])) {
62        point_move(length($completion));
63    }
64}
65
66sub show_completions {
67    my @words = @_;
68    my $all = join(" ", map {BarnOwl::quote($_)} @words);
69    my $width = BarnOwl::getnumcols();
70    if (length($all) > $width-1) {
71        $all = substr($all, 0, $width-4) . "...";
72    }
73    BarnOwl::message($all);
74}
75
76sub common_prefix {
77    my @words = @_;
78    my $len   = min(map {length($_)} @words);
79    my $pfx = '';
80    for my $i (1..$len) {
81        $pfx = substr($words[0], 0, $i);
82        if(first {substr($_, 0, $i) ne $pfx} @words) {
83            $pfx = substr($pfx, 0, $i-1);
84            last;
85        }
86    }
87
88    return $pfx;
89}
90
91
92sub get_completions {
93    my $ctx = shift;
94    my @words = ();
95    if($ctx->word == 0) {
96        return complete_command($ctx->words->[0]);
97    } else {
98        my $cmd = $ctx->words->[0];
99        my $word = $ctx->words->[$ctx->word];
100        if(exists($completers{$cmd})) {
101            return grep {$_ =~ m{^\Q$word\E}} $completers{$cmd}->($ctx);
102        }
103        return;
104    }
105}
106
107sub complete_command {
108    my $cmd = shift;
109    return grep {$_ =~ m{^\Q$cmd\E}} @BarnOwl::all_commands;
110}
111
112sub register_completer {
113    my $cmd = shift;
114    my $completer = shift;
115    $completers{$cmd} = $completer;
116}
117
118sub load_completers {
119    opendir(my $dh, BarnOwl::get_data_dir() . "/" . "lib/BarnOwl/Complete/") or return;
120    while(my $name = readdir($dh)) {
121        next if $name =~ m{^\.};
122        next unless $name =~ m{[.]pm$};
123        $name =~ s{[.]pm$}{};
124        eval "use BarnOwl::Complete::$name";
125    }
126}
127
128$BarnOwl::Hooks::startup->add("BarnOwl::Completion::load_completers");
129
1301;
Note: See TracBrowser for help on using the repository browser.