<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="generator" content="Osso Notes">
<title></title></head>
<body>
<p>Did you try using the completer customization mechanisms that already exist in ipython?
<br><font color="#999999">--</font>
<br><font color="#999999">Sent from my Nokia N900</font>
<br>
<br>----- Original message -----
<br>> Hello,
<br>>
<br>> I'm helping build a cross-platform custom tab completer for a Python
<br>> research project, and I'm using Pyreadline to substitute for the the
<br>> lack of readline on Windows. However, upon installation, despite trying
<br>> to set-up the custom tab completion through the use of readline's
<br>> set_completer function, pyreadline automatically uses the completer
<br>> under basemode.py, shown when it printed out a list of files in the
<br>> directory when I tabbed despite changing the custom tab complete
<br>> function to raise an exception instead. When I ran through the code
<br>> using the Python Debugger, I saw that set_completer(completer.complete)
<br>> was clearly called under rlmain.py, yet the custom tab complete function
<br>> wasn't implemented in the readline somehow.
<br>>
<br>> I'm using version 1.5 of Pyreadline, installed under a custom directory
<br>> of the research project that essentially uses Python 2.5. I'm testing
<br>> all this through Windows command prompt. I might have overlooked some
<br>> details since I'm still fairly new to Python, but any help would be much
<br>> appreciated.
<br>>
<br>> For reference, I didn't write the TabCompleter code, and it works when
<br>> used in a Unix system with their GNU Readline.
<br>>
<br>> Thanks,
<br>> Alan Loh
<br>>
<br>>
<br>>
<br>> This is the code for the custom tab completion part of the project:
<br>>
<br>> tabcompletion = True
<br>> try:
<br>>  import readline
<br>> except ImportError:
<br>>  print "Auto tab completion is off, because it is not available on your
<br>> operating system."  tabcompletion = False
<br>> .
<br>> .
<br>> .
<br>>  # Set up the tab completion environment
<br>>  if tabcompletion:
<br>>  completer = TabCompleter()
<br>>  readline.parse_and_bind("tab: complete")
<br>>  readline.set_completer_delims(" ")
<br>>  readline.set_completer(completer.complete)
<br>>
<br>>
<br>>
<br>> ...and this is the TabCompleter class I'm trying to help implement.
<br>>
<br>>
<br>>
<br>> class TabCompleter:
<br>>
<br>>  # Constructor that initializes all the private variables
<br>>  def __init__(self):
<br>>
<br>>  # list of files that match the directory of the given prefix
<br>>  self._words = []
<br>>
<br>>  # list of files that match the given prefix
<br>>  self._matching_words = []
<br>>
<br>>  self._prefix = None
<br>>
<br>>
<br>>  # Returns the path from a given prefix, by extracting the string up to
<br>> the  # last forward slash in the prefix. If no forward slash is found,
<br>> returns an  # empty string.
<br>>  def _getpath(self, prefix):
<br>>
<br>>  slashpos = prefix.rfind("/")
<br>>  currentpath = ""
<br>>  if slashpos > -1:
<br>>  currentpath = prefix[0 : slashpos+1]
<br>>
<br>>  return currentpath
<br>>
<br>>
<br>>  # Returns the file name, or a part of the file name, from a given
<br>> prefix, by  # extracting the string after the last forward slash in the
<br>> prefix. If no  # forward slash is found, returns an empty string.
<br>>  def _getfilename(self, prefix):
<br>>
<br>>  # Find the last occurrence of the slash (if any), as it separates
<br>> the path  # and the file name.
<br>>  slashpos = prefix.rfind("/")
<br>>  filename = ""
<br>>
<br>>  # If slash exists and there are characters after the last slash,
<br>> then the  # file name is whatever that follows the last slash.
<br>>  if slashpos > -1 and slashpos+1 <= len(prefix)-1:
<br>>  filename = prefix[slashpos+1:]
<br>>
<br>>  # If no slash is found, then we assume that the entire user input is
<br>> the  # prefix of a file name because it does not contain a directory
<br>>  elif slashpos == -1:
<br>>  filename = prefix
<br>>
<br>>  # If both cases fail, then the entire user input is the name of a
<br>>  # directory. Thus, we return the file name as an empty string.
<br>>
<br>>  return filename
<br>>
<br>>
<br>>  # Returns a list of file names that start with the given prefix.
<br>>  def _listfiles(self, prefix):
<br>>
<br>>  # Find the directory specified by the prefix
<br>>  currentpath = self._getpath(prefix)
<br>>  if not currentpath:
<br>>  currentpath = "./"
<br>>  filelist = []
<br>>
<br>>  # Attempt to list files from the directory
<br>>  try:
<br>>  currentpath = os.path.expanduser(currentpath)
<br>>  filelist = os.listdir(currentpath)
<br>>
<br>>  except:
<br>>  # We are silently dropping all exceptions because the directory
<br>> specified  # by the prefix may be incorrect. In this case, we're
<br>> returning an empty  # list, similar to what you would get when you
<br>> TAB a wrong name in the  # Unix shell.
<br>>  pass
<br>>
<br>>  finally:
<br>>  return filelist
<br>>
<br>>
<br>>  # The completer function required as a callback by the readline
<br>> module. See  # also
<br>> <a href="http://docs.python.org/library/readline.html#readline.set_completer ">http://docs.python.org/library/readline.html#readline.set_completer </a>;  def
<br>> complete(self, prefix, index):
<br>>
<br>>  # If the user updates the prefix, then we list files that start with
<br>> the  # prefix.
<br>>  if prefix != self._prefix:
<br>>
<br>>  self._words = self._listfiles(prefix)
<br>>  fn = self._getfilename(prefix)
<br>>
<br>>  # Find the files that match the prefix
<br>>  self._matching_words = []
<br>>  for word in self._words:
<br>>  if word.startswith(fn):
<br>>  self._matching_words.append(word)
<br>>
<br>>  self._prefix = prefix
<br>>
<br>>  try:
<br>>  return self._getpath(prefix) + self._matching_words[index]
<br>>
<br>>  except IndexError:
<br>>  return None
<br>>
<br><br></p>
</body>
</html>