<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>
import readline<br>
except ImportError:<br>
print "Auto tab completion is off, because it is not available on your operating system."<br>
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 the<br>
# last forward slash in the prefix. If no forward slash is found, returns an<br>
# 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 prefix, by<br>
# extracting the string after the last forward slash in the prefix. If no<br>
# 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 the path<br>
# and the file name.<br>
slashpos = prefix.rfind("/")<br>
filename = ""<br>
<br>
# If slash exists and there are characters after the last slash, then the<br>
# 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 the<br>
# 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 specified<br>
# by the prefix may be incorrect. In this case, we're returning an empty<br>
# list, similar to what you would get when you TAB a wrong name in the<br>
# Unix shell.<br>
pass<br>
<br>
finally:<br>
return filelist<br>
<br>
<br>
# The completer function required as a callback by the readline module. See<br>
# also http://docs.python.org/library/readline.html#readline.set_completer<br>
def complete(self, prefix, index):<br>
<br>
# If the user updates the prefix, then we list files that start with the<br>
# 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>
</div>
</div>
</body>
</html>