source: perl/lib/BarnOwl/Completion.pm @ 4815492

release-1.6release-1.7release-1.8release-1.9
Last change on this file since 4815492 was 4815492, checked in by Nelson Elhage <nelhage@mit.edu>, 12 years ago
Completion: Allow for separate display and replacement strings.
  • Property mode set to 100644
File size: 3.7 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(map {completion_value($_)} @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
46=head1 COMPLETIONS
47
48A COMPLETION is either a simple string, or a reference to an array
49containing two or more values.
50
51In the former case, the string use used for both the text to display,
52as well as the result of the completion, and is assumed to be a full
53completion.
54
55An arrayref completion consists of
56
57    [$display_text, $replacement_value].
58
59$display_text will be printed in the case of ambiguous completions,
60$replacement_value will be used to substitute the value in.
61
62=cut
63
64sub completion_text {
65    my $c = shift;
66    return $c unless ref($c) eq 'ARRAY';
67    return $c->[0];
68}
69
70sub completion_value {
71    my $c = shift;
72    return $c unless ref($c) eq 'ARRAY';
73    return $c->[1];
74}
75
76sub insert_completion {
77    my $ctx = shift;
78    my $completion = BarnOwl::quote(completion_value(shift));
79    my $unique = shift;
80
81    if($unique) {
82        $completion .= " ";
83    }
84
85    save_excursion {
86        point_move($ctx->word_start - $ctx->point);
87        BarnOwl::Editwin::set_mark();
88        point_move($ctx->word_end - $ctx->word_start);
89        replace_region($completion);
90    };
91    if(!length($ctx->words->[$ctx->word])) {
92        point_move(length($completion));
93    }
94}
95
96sub show_completions {
97    my @words = @_;
98    my $all = BarnOwl::quote(map {completion_text($_)} @words);
99    my $width = BarnOwl::getnumcols();
100    if (length($all) > $width-1) {
101        $all = substr($all, 0, $width-4) . "...";
102    }
103    BarnOwl::message($all);
104}
105
106sub common_prefix {
107    my @words = @_;
108    my $len   = min(map {length($_)} @words);
109    my $pfx = '';
110    for my $i (1..$len) {
111        $pfx = substr($words[0], 0, $i);
112        if(first {substr($_, 0, $i) ne $pfx} @words) {
113            $pfx = substr($pfx, 0, $i-1);
114            last;
115        }
116    }
117
118    return $pfx;
119}
120
121
122sub get_completions {
123    my $ctx = shift;
124    if($ctx->word == 0) {
125        return complete_command($ctx->words->[0]);
126    } else {
127        my $cmd = $ctx->words->[0];
128        my $word = $ctx->words->[$ctx->word];
129        if(exists($completers{$cmd})) {
130            return grep {completion_value($_) =~ m{^\Q$word\E}} $completers{$cmd}->($ctx);
131        }
132        return;
133    }
134}
135
136sub complete_command {
137    my $cmd = shift;
138    $cmd = "" unless defined($cmd);
139    return grep {$_ =~ m{^\Q$cmd\E}} @BarnOwl::all_commands;
140}
141
142sub register_completer {
143    my $cmd = shift;
144    my $completer = shift;
145    $completers{$cmd} = $completer;
146}
147
148sub load_completers {
149    opendir(my $dh, BarnOwl::get_data_dir() . "/" . "lib/BarnOwl/Complete/") or return;
150    while(my $name = readdir($dh)) {
151        next if $name =~ m{^\.};
152        next unless $name =~ m{[.]pm$};
153        $name =~ s{[.]pm$}{};
154        eval "use BarnOwl::Complete::$name";
155        if($@) {
156            BarnOwl::error("Loading completion module $name:\n$@\n");
157        }
158    }
159}
160
161$BarnOwl::Hooks::startup->add("BarnOwl::Completion::load_completers");
162
1631;
Note: See TracBrowser for help on using the repository browser.