2016-03-04
Some notes on supporting readline (tab) completion in your Python program
Adding basic readline-style line editing to a Python program that
reads input from the user is very simple; as the readline
module
documentation says,
simply importing the module activates this without you having to call
anything. However, adding completion is less well documented, so here
are some notes about it.
First, you need both a readline completion binding and to register a completion function. The easiest way to get a completion binding is just to set it up explicitly:
readline.parse_and_bind("tab: complete")
You may also want to change the delimiter characters with
readline.set_completer_delims
. In my own code, I reduced the
delimiters to space, tab, and newline. Note that if you have
possible completions that include delimiter characters, nothing
complains and things sort of work, but not entirely.
So, now we get to completion functions. Readline needs a completion function, and it's easiest to show you how a simple one works:
comps = ["abc", "abdef", "charlie", "horse",]def complete(text, state): # generate candidate completion list if text == "": matches = comps else: matches = [x for x in comps if x.startswith(text)] # return current completion match if state > len(matches): return None else: return matches[state] readline.set_completer(complete)
You are passed the current 'word' being completed and a 'state',
which is a 0-based index. Your completion function's job is to
return the state'th completion for the current word, or something
other than a string if you've run out of completions, and you'll
actually be called with ever-increasing state
values until you
declare 'no more'.
As we see here, the list of completions that you return does not
have to be in alphabetical order. Obviously it really should be a
stable order for any particular input word; otherwise things will
probably get confused.
By the way, readline will completely swallow any exceptions raised
by your complete()
function. The only symptom of major errors can
be that you get fewer or no completions than you expect.
Of course it's common to want to be a little smarter about possible completions based on the context. For instance, you might be completing a command line where the first word is a command and then following words are various sorts of arguments, and it'd be nice not to offer as completions things that would actually be errors when entered. To do this, you often want to know what is before the current word being completed:
def get_cur_before(): idx = readline.get_begidx() full = readline.get_line_buffer() return full[:idx]
Because words being completed stop at delimiter characters, anything in this before-the-word text is what readline considers a full word (or words). Otherwise, it would be part of the word currently being completed on. If you want to know what the first complete word of the line is, you can thus do something like:
pref = get_cur_before() n = pref.split() cmd = n[0] if len(n) > 0 else ""
You can then use cmd
to decide what set of completions to use.
Other options are possible with the use of various additional
readline functions, but this is all I've needed to use so far for
the completions in my code.
Given that your complete()
function is being called repeatedly
every time the user hits TAB, and that it does all of this examination
and selection and matching every time it's called, you might worry
about performance here; it sure seems like there's a lot of duplicate
work being done here. The good news is that modern computers are very
fast, so you probably aren't going to notice this.
If you do worry about this, what the rlcompleter module does is that
it generates the list of matches when state
is 0 (and caches it),
and uses the already-cached list whenever state
is non-zero. You
can probably count on this to keep working in the future.
Speaking from personal experience, it was not all that much work to add readline completion to my program once I worked out what I actually needed to do, and having readline tab completion available is surprisingly fun.
(And of course it's handy. There's a reason everyone loves tab-completing things when they can.)
PS: remember to turn off readline completion if and when it's no
longer applicable, such as when you're getting other input from the
user (perhaps a yes/no approval). Otherwise things can get at least
puzzling. This can be done with readline.set_completer(None)
.