codeaide / codeaide / modes / completer.py

from codeaide.base import *


class CompleterModel(QAbstractListModel):


    def __init__(self):
        QAbstractListModel.__init__(self)
        self.items = ["Foo", "Bar", "Bla", "Blub"]


    def data(self, index, role):
        if index.isValid() and role in (Qt.DisplayRole, Qt.EditRole):
            return QVariant(self.items[index.row()])
        else:
            return QVariant()


    def rowCount(self, parent=QModelIndex()):
        return len(self.items)



class CompleterBase(ModeBase):
    """
    Autocompletion based on "Custom Completer Example" in Qt docs 
    and looking at the qbzr implementation.
    """


    def init(self, eow="~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-=", 
                 min_length=2, sensitivity=Qt.CaseSensitive):
        self.widget = QCompleter(self.textedit)
        self.eow = QString(eow)
        self.min_length = min_length

        self.widget.setWidget(self.textedit)
        self.widget.setCaseSensitivity(sensitivity)
        self.widget.connect(self.widget, SIGNAL("activated(QString)"), self.insertCompletion)
        self.model = CompleterModel()
        self.widget.setModel(self.model)
        self.init_completer()


    def init_completer(self):
        pass


    def textUnderCursor(self):
        tc = self.textedit.textCursor()
        tc.select(QTextCursor.WordUnderCursor)
        return tc.selectedText()


    def insertCompletion(self, completion):
        tc = self.textedit.textCursor()
        c = self.widget
        extra = completion.length() - c.completionPrefix().length()
        tc.movePosition(QTextCursor.Left)
        tc.movePosition(QTextCursor.EndOfWord)
        tc.insertText(completion.right(extra))
        self.textedit.setTextCursor(tc)


    def check_popup_visible(self, event, key, modifiers, text):
        if self.widget.popup().isVisible():
            # key will be handled by completer popup
            event.ignore()
            return True


    def shortcut_pressed(self, event, key, modifiers, text):
        ctrlOrShift = modifiers & (Qt.ControlModifier | Qt.ShiftModifier)
        if ctrlOrShift and text.isEmpty():
            print "transparency switched on"
            self.widget.popup().setWindowOpacity(0.5)
            return False

        c = self.widget
        hasModifier = (modifiers != Qt.NoModifier) and not ctrlOrShift
        completionPrefix = self.textUnderCursor()
        if  (hasModifier or text.isEmpty()
             or self.eow.contains(text.right(1)) or 
             completionPrefix.length() < self.min_length):
            c.popup().hide()
            return False

        if completionPrefix != c.completionPrefix():
            c.setCompletionPrefix(completionPrefix)
            c.popup().setCurrentIndex(c.completionModel().index(0, 0))

        cr = self.textedit.cursorRect()
        cr.setWidth(c.popup().sizeHintForColumn(0) +
                    c.popup().verticalScrollBar().sizeHint().width())
        c.complete(cr)
        return True


    keyboard_hooks = {
        Qt.Key_Enter: check_popup_visible,
        Qt.Key_Return: check_popup_visible,
        Qt.Key_Escape: check_popup_visible,
        Qt.Key_Tab: check_popup_visible,
        Qt.Key_Backtab: check_popup_visible,
        (Qt.Key_Space, Qt.ControlModifier): shortcut_pressed,
        }



class CompleterThread(QThread):


    def __init__(self, completer, interval=2):
        QThread.__init__(self)
        self.completer = completer
        self.textedit = completer.textedit
        self.interval = interval


    def run(self):
        completer = self.completer
        #popup = completer.widget.popup()
        while True:
            if True: #not popup.isVisible():
                words = self.find_completitions(
                    unicode(self.textedit.toPlainText()))
                completer.model.items = words
            self.sleep(self.interval)




split_words = lambda s: re.split(re.compile("[^\w_]+", re.UNICODE), s)


class TextCompleterThread(CompleterThread):


    def find_completitions(self, text):
        words = set(split_words(text))
        return sorted([w for w in words if len(w) > 2])


    

class TextCompleter(CompleterBase):


    def init_completer(self):
        self.thread = TextCompleterThread(self)
        self.thread.start()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.