tags:

views:

220

answers:

2

I'd like to write small scripts which feature incremental search (find-as-you-type) on the command line.

Use case: I have my mobile phone connected via USB, Using gammu --sendsms TEXT I can write text messages. I have the phonebook as CSV, and want to search-as-i-type on that.

What's the easiest/best way to do it? It might be in bash/zsh/Perl/Python or any other scripting language.

Edit: Solution: Modifying Term::Complete (http://search.cpan.org/~jesse/perl-5.12.0/lib/Term/Complete.pm) did what I want. See below for the answer.

+1  A: 

I get the impression GNU Readline supports this kind of thing. Though, I have not used it myself. Here is a C++ example of custom auto complete, which could easily be done in C too. There is also a Python API for readline.

This StackOverflow question gives examples in Python, one of which is ...

import readline
def completer(text, state):
    options = [x in addrs where x.startswith(text)]
    if state < options.length:
        return options[state]
    else
        return None
readline.set_completer(completer)

this article on Bash autocompletion may help. This article also gives examples of programming bash's auto complete feature.

Aiden Bell
It's an interesting idea to use the bash autocompletion feature. Even more I like the link to readline and ncurses (as I switch between zsh and bash at times). Thanks!
Standard readline requires <TAB> to be completed. I did not find a solution with readline yet which does not require <TAB> key (which searches on the fly).
+2  A: 

Following Aiden Bell's hint, I tried Readline in Perl. Solution 1 using Term::Complete (also used by CPAN, I think):

use Term::Complete;   
my $F; 
open($F,"<","bin/phonebook.csv"); 
my @terms = <$F>; chomp(@terms); 
close($F);


my $input;
while (!defined $input) {
   $input = Complete("Enter a name or number: ",@terms);
   my ($name,$number) = split(/\t/,$input);
   print("Sending SMS to $name ($number).\n");
   system("sudo gammu --sendsms TEXT $number");
}

Press \ to complete, press Ctrl-D to see all possibilities.

Solution 2: Ctrl-D is one keystroke to much, so using standard Term::Readline allows completion and the display off possible completions using only \.

use Term::ReadLine;

my $F;
open($F,"<","bin/phonebook.csv");
my @terms = <$F>; chomp(@terms);
close($F);

my $term = new Term::ReadLine;
$term->Attribs->{completion_function} = sub { return @terms; };

my $prompt = "Enter name or number >> ";

my $OUT = $term->OUT || \*STDOUT;
while ( defined (my $input = $term->readline($prompt)) ) {
   my ($name,$number) = split(/\t/,$input);
   print("Sending SMS to $name ($number).\n");
   system("sudo gammu --sendsms TEXT $number");
}

This solution still needs a for completion.

Edit: Final Solution Modifying Term::Complete (http://search.cpan.org/~jesse/perl-5.12.0/lib/Term/Complete.pm) does give me on the fly completion.

Source code: http://search.cpan.org/CPAN/authors/id/J/JE/JESSE/perl-5.12.0.tar.gz Solution number 1 works with this modification. I will put the whole sample online somewhere else if this can be used by somebody

Modifications of Completion.pm (just reusing it's code for Control-D and \ for each character): ` 170c172,189

my $redo=0;

                @match = grep(/^\Q$return/, @cmp_lst);
                unless ($#match < 0) {
                    $l = length($test = shift(@match));
                    foreach $cmp (@match) {
                        until (substr($cmp, 0, $l) eq substr($test, 0, $l)) {
                            $l--;
                        }
                    }
                    print("\a");
                    print($test = substr($test, $r, $l - $r));
                          $redo = $l - $r == 0;
                          if ($redo) { print(join("\r\n", '', grep(/^\Q$return/, @cmp_lst)), "\r\n"); }
                    $r = length($return .= $test);
                }
                    if ($redo) { redo LOOP; } else { last CASE; }

`

I think you will hard pressed, unless you can hook on all keystrokes. These things need a trigger to call the complete procedure.
Aiden Bell
+1 Nice little hack.
Aiden Bell