Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tab completion in Python's raw_input()

i know i can do this to get the effect of tab completion in python sure.

import readline COMMANDS = ['extra', 'extension', 'stuff', 'errors',             'email', 'foobar', 'foo']  def complete(text, state):     for cmd in COMMANDS:         if cmd.startswith(text):             if not state:                 return cmd             else:                 state -= 1  readline.parse_and_bind("tab: complete") readline.set_completer(complete) raw_input('Enter section name: ') 

I am now interested in doing tab completion with directories. (/home/user/doc >tab)

How would i go about doing such a task?

like image 298
John Riselvato Avatar asked Apr 12 '11 14:04

John Riselvato


People also ask

What is tab completion in Python?

Tab Completion and History Editing. Completion of variable and module names is automatically enabled at interpreter startup so that the Tab key invokes the completion function; it looks at Python statement names, the current local variables, and the available module names.

How do you use the Tab key in Python?

The action of the tab key depends on the Editor > Keyboard > Personality preference, the file type being edited, and the position within the file. To insert a real tab character, press Ctrl-T.


2 Answers

Here is a quick example of how to perform incremental completion of file system paths. I've modified your example, organizing it into a class where methods named complete_[name] indicate top-level commands.

I've switched the completion function to use the internal readline buffer to determine the state of the overall completion, which makes the state logic a bit simpler. The path completion is in the _complete_path(path) method, and I've hooked up the extra command to perform path completions on its arguments.

I'm sure the code could be further simplified but it should provide you a decent starting point:

import os import re import readline  COMMANDS = ['extra', 'extension', 'stuff', 'errors',             'email', 'foobar', 'foo'] RE_SPACE = re.compile('.*\s+$', re.M)  class Completer(object):      def _listdir(self, root):         "List directory 'root' appending the path separator to subdirs."         res = []         for name in os.listdir(root):             path = os.path.join(root, name)             if os.path.isdir(path):                 name += os.sep             res.append(name)         return res      def _complete_path(self, path=None):         "Perform completion of filesystem path."         if not path:             return self._listdir('.')         dirname, rest = os.path.split(path)         tmp = dirname if dirname else '.'         res = [os.path.join(dirname, p)                 for p in self._listdir(tmp) if p.startswith(rest)]         # more than one match, or single match which does not exist (typo)         if len(res) > 1 or not os.path.exists(path):             return res         # resolved to a single directory, so return list of files below it         if os.path.isdir(path):             return [os.path.join(path, p) for p in self._listdir(path)]         # exact file match terminates this completion         return [path + ' ']      def complete_extra(self, args):         "Completions for the 'extra' command."         if not args:             return self._complete_path('.')         # treat the last arg as a path and complete it         return self._complete_path(args[-1])      def complete(self, text, state):         "Generic readline completion entry point."         buffer = readline.get_line_buffer()         line = readline.get_line_buffer().split()         # show all commands         if not line:             return [c + ' ' for c in COMMANDS][state]         # account for last argument ending in a space         if RE_SPACE.match(buffer):             line.append('')         # resolve command to the implementation function         cmd = line[0].strip()         if cmd in COMMANDS:             impl = getattr(self, 'complete_%s' % cmd)             args = line[1:]             if args:                 return (impl(args) + [None])[state]             return [cmd + ' '][state]         results = [c + ' ' for c in COMMANDS if c.startswith(cmd)] + [None]         return results[state]  comp = Completer() # we want to treat '/' as part of a word, so override the delimiters readline.set_completer_delims(' \t\n;') readline.parse_and_bind("tab: complete") readline.set_completer(comp.complete) raw_input('Enter section name: ') 

Usage:

% python complete.py  Enter section name: ext<tab> extension extra Enter section name: extra foo<tab> foo.py foo.txt foo/ Enter section name: extra foo/<tab> foo/bar.txt foo/baz.txt Enter section name: extra foo/bar.txt 

Update It will complete paths from the root if the user types /:

% python complete.py Enter section name: extra /Use<tab> /Users/.localized  /Users/Shared/  /Users/user1 /Users/user2 Enter section name: extra /Users/use<tab> /Users/user1  /Users/user2 
like image 119
samplebias Avatar answered Sep 20 '22 01:09

samplebias


This is enough to enable built in directory tab completion with raw_input():

import readline readline.parse_and_bind("tab: complete") 
like image 35
AsksAnyway Avatar answered Sep 20 '22 01:09

AsksAnyway