<html dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style id="owaParaStyle" type="text/css">P {margin-top:0;margin-bottom:0;}</style>
</head>
<body ocsi="0" fpstyle="1">
<div style="direction: ltr; font-family: Tahoma; color: rgb(0, 0, 0); font-size: 13px;">
<div style="">Hello,<br>
<br>
I'm helping build a cross-platform custom tab completer for a Python research project, and I'm using Pyreadline to substitute for the the lack of readline on Windows. However, upon installation, despite trying to set-up the custom tab completion through the
 use of readline's set_completer function, pyreadline automatically uses the completer under basemode.py, shown when it printed out a list of files in the directory when I tabbed despite changing the custom tab complete function to raise an exception instead.
 When I ran through the code using the Python Debugger, I saw that set_completer(completer.complete) was clearly called under rlmain.py, yet the custom tab complete function wasn't implemented in the readline somehow.<br>
<br>
I'm using version 1.5 of Pyreadline, installed under a custom directory of the research project that essentially uses Python 2.5. I'm testing all this through Windows command prompt. I might have overlooked some details since I'm still fairly new to Python,
 but any help would be much appreciated.<br>
<br>
For reference, I didn't write the TabCompleter code, and it works when 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>
&nbsp; import readline<br>
except ImportError:<br>
&nbsp; print &quot;Auto tab completion is off, because it is not available on your operating system.&quot;<br>
&nbsp; tabcompletion = False<br>
.<br>
.<br>
.<br>
&nbsp; # Set up the tab completion environment<br>
&nbsp; if tabcompletion:<br>
&nbsp;&nbsp;&nbsp; completer = TabCompleter()<br>
&nbsp;&nbsp;&nbsp; readline.parse_and_bind(&quot;tab: complete&quot;)<br>
&nbsp;&nbsp;&nbsp; readline.set_completer_delims(&quot; &quot;)<br>
&nbsp;&nbsp;&nbsp; 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>
&nbsp; # Constructor that initializes all the private variables<br>
&nbsp; def __init__(self):<br>
<br>
&nbsp;&nbsp;&nbsp; # list of files that match the directory of the given prefix<br>
&nbsp;&nbsp;&nbsp; self._words = []<br>
<br>
&nbsp;&nbsp;&nbsp; # list of files that match the given prefix<br>
&nbsp;&nbsp;&nbsp; self._matching_words = []<br>
<br>
&nbsp;&nbsp;&nbsp; self._prefix = None<br>
<br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp; # Returns the path from a given prefix, by extracting the string up to the<br>
&nbsp; # last forward slash in the prefix. If no forward slash is found, returns an<br>
&nbsp; # empty string.<br>
&nbsp; def _getpath(self, prefix):<br>
<br>
&nbsp;&nbsp;&nbsp; slashpos = prefix.rfind(&quot;/&quot;)<br>
&nbsp;&nbsp;&nbsp; currentpath = &quot;&quot;<br>
&nbsp;&nbsp;&nbsp; if slashpos &gt; -1:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; currentpath = prefix[0 : slashpos&#43;1]<br>
<br>
&nbsp;&nbsp;&nbsp; return currentpath<br>
<br>
<br>
&nbsp; # Returns the file name, or a part of the file name, from a given prefix, by<br>
&nbsp; # extracting the string after the last forward slash in the prefix. If no<br>
&nbsp; # forward slash is found, returns an empty string.<br>
&nbsp; def _getfilename(self, prefix):<br>
<br>
&nbsp;&nbsp;&nbsp; # Find the last occurrence of the slash (if any), as it separates the path<br>
&nbsp;&nbsp;&nbsp; # and the file name.<br>
&nbsp;&nbsp;&nbsp; slashpos = prefix.rfind(&quot;/&quot;)<br>
&nbsp;&nbsp;&nbsp; filename = &quot;&quot;<br>
<br>
&nbsp;&nbsp;&nbsp; # If slash exists and there are characters after the last slash, then the<br>
&nbsp;&nbsp;&nbsp; # file name is whatever that follows the last slash.<br>
&nbsp;&nbsp;&nbsp; if slashpos &gt; -1 and slashpos&#43;1 &lt;= len(prefix)-1:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filename = prefix[slashpos&#43;1:]<br>
<br>
&nbsp;&nbsp;&nbsp; # If no slash is found, then we assume that the entire user input is the<br>
&nbsp;&nbsp;&nbsp; # prefix of a file name because it does not contain a directory<br>
&nbsp;&nbsp;&nbsp; elif slashpos == -1:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filename = prefix<br>
<br>
&nbsp;&nbsp;&nbsp; # If both cases fail, then the entire user input is the name of a<br>
&nbsp;&nbsp;&nbsp; # directory. Thus, we return the file name as an empty string.<br>
<br>
&nbsp;&nbsp;&nbsp; return filename<br>
<br>
<br>
&nbsp; # Returns a list of file names that start with the given prefix.<br>
&nbsp; def _listfiles(self, prefix):<br>
<br>
&nbsp;&nbsp;&nbsp; # Find the directory specified by the prefix<br>
&nbsp;&nbsp;&nbsp; currentpath = self._getpath(prefix)<br>
&nbsp;&nbsp;&nbsp; if not currentpath:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; currentpath = &quot;./&quot;<br>
&nbsp;&nbsp;&nbsp; filelist = []<br>
<br>
&nbsp;&nbsp;&nbsp; # Attempt to list files from the directory<br>
&nbsp;&nbsp;&nbsp; try:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; currentpath = os.path.expanduser(currentpath)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filelist = os.listdir(currentpath)<br>
<br>
&nbsp;&nbsp;&nbsp; except:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # We are silently dropping all exceptions because the directory specified<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # by the prefix may be incorrect. In this case, we're returning an empty<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # list, similar to what you would get when you TAB a wrong name in the<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Unix shell.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pass<br>
<br>
&nbsp;&nbsp;&nbsp; finally:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return filelist<br>
<br>
<br>
&nbsp; # The completer function required as a callback by the readline module. See<br>
&nbsp; # also http://docs.python.org/library/readline.html#readline.set_completer<br>
&nbsp; def complete(self, prefix, index):<br>
<br>
&nbsp;&nbsp;&nbsp; # If the user updates the prefix, then we list files that start with the<br>
&nbsp;&nbsp;&nbsp; # prefix.<br>
&nbsp;&nbsp;&nbsp; if prefix != self._prefix:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self._words = self._listfiles(prefix)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fn = self._getfilename(prefix)<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Find the files that match the prefix<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self._matching_words = []<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for word in self._words:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if word.startswith(fn):<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self._matching_words.append(word)<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self._prefix = prefix<br>
<br>
&nbsp;&nbsp;&nbsp; try:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self._getpath(prefix) &#43; self._matching_words[index]<br>
<br>
&nbsp;&nbsp;&nbsp; except IndexError:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return None<br>
<br>
</div>
</div>
</body>
</html>