Adding File Completion to the Entry Widget

May 19, 1998 | Fredrik Lundh

 
from Tkinter import *

import os

#
# completion entry baseclass.

class CompletionEntry(Entry):

    def __init__(self, master, **kw):

        apply(Entry.__init__, (self, master), kw)

        self.bind("<Tab>", self.__tab)

        self.__state = None, None, None

    def __tab(self, event):

        index = self.index(INSERT)
        value = self.get()
        prefix, suffix = value[:index], value[index:]

        # check state
        state, old_index, old_prefix = self.__state
        if index != old_index or prefix != old_prefix:
            state = 0

        try:

            # get next completion
            match = self.complete(state, prefix, suffix)

            if match:

                # insert completion
                if self.select_present():
                    self.delete(SEL_FIRST, SEL_LAST)
                self.insert(index, match)
                self.select_range(index, index+len(match))
                self.icursor(index)

                self.__state = state+1, index, prefix

            else:

                self.__state = 0, index, prefix

        except IndexError:
            pass

        return "break"

    def complete(self, state, prefix, suffix):
        return None # override

#
# file completion

class FileEntry(CompletionEntry):

    def complete(self, state, prefix, suffix):

        # workaround os.path.isdir buglet
        path = prefix
        if path[-1:] in ("/", os.sep):
            path = path[:-1]

        # get directory and file prefix
        if os.path.isdir(path):
            path, prefix = prefix, ""
        else:
            path, prefix = os.path.split(prefix)

        if state == 0:

            try:

                # look for matching files in directory
                prefix = os.path.normcase(prefix)
                length = len(prefix)

                self.__files = []
                for file in os.listdir(path):
                    file = os.path.normcase(file)
                    if file[:length] == prefix:
                        if os.path.isdir(os.path.join(path, file)):
                            file = file + os.sep
                        self.__files.append(file)

            except os.error:
                self.__files = []

        # return next match
        return self.__files[state][len(prefix):]

A Django site. rendered by a django application. hosted by webfaction.