bug-readline
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Bug-readline] partial word completion


From: David Fang
Subject: Re: [Bug-readline] partial word completion
Date: Mon, 23 Feb 2009 20:05:01 -0500 (EST)

Hi Chet,
Your suggestion worked, thanks for your help! I just provided my own display hook that transformed the string pointers by munching up to the common prefix of the hierarchical name, and passed that to the standard display-matches function. I had to append a call to rl_forced_update_display() to restore the line buffer. (code pasted below)

The standard readline mechanism for multiple completions is an array of
matches, where matches[0] contains the common prefix, and matches[1..n]
contain the possible completions, including the common prefix.  This
allows readline to sort, eliminate duplicates, and so on.

Ahh, I didn't about matches[0] being special before.
That explains a few things... :)

I would like this to behave similarly to directory completion:
% cd foo/bar/x<TAB>
% cd foo/bar/xx

You need to handle the display of possible completions yourself.
The way to do that is to `register' a function to display matches by
assigning its address to rl_completion_display_matches_hook.  That
function receives the list of matches in the form described above, the
number of matches in the list, and the length in characters of the
longest entry.

Your code can manipulate the list of matches to remove the common
prefix, if you'd like, but make sure that you keep any new common prefix
in matches[0].  Readline provides a convenience function to display
the contents of the array, rl_display_match_list(), which you can call
with your modified array and the same two additional arguments your
function received, modified appropriately.

For anyone interested, my display hook function looks like this:

// candidate matches can look like (hierarchical prefix always match):
// for set:
// x. x.foo x.bar x.baz
//
// desired behavior:
// prompt> x.<TAB>
// foo bar baz
// prompt> x.
// prompt> x.b<TAB>
// prompt> x.ba<TAB>
// bar baz

void
my_display_matches_hook(char** matches, int len, int max) {
if (len) {
        // find the last '.', if any
        char* tail = strrchr(matches[0], '.');
        if (tail) {
                const int dist = tail -matches[0] +1;   // past '.'
                std::vector<char*> mod_matches;
                mod_matches.reserve(len+1);
                mod_matches.push_back(matches[0]);
                int i=1;
                for ( ; i<=len; ++i) {
                        // remove common prefix
                        assert(matches[i]);
                        const size_t ml = strlen(matches[i]);
                        assert(ml > size_t(dist));
                        mod_matches.push_back(matches[i] +dist);
                }
                assert(max > dist);
                rl_display_match_list(&mod_matches[0], len, max -dist);
        } else {
                // use default printer
                rl_display_match_list(matches, len, max);
        }
        rl_forced_update_display();     // refresh prompt, line-buffer
}
}


Fang

David Fang
http://www.csl.cornell.edu/~fang/
http://www.achronix.com/





reply via email to

[Prev in Thread] Current Thread [Next in Thread]