QScintilla/Editor.py

changeset 4271
480434472ac1
parent 4227
8a39c8b968f4
child 4272
169835cdf784
--- a/QScintilla/Editor.py	Sat May 30 20:16:47 2015 +0200
+++ b/QScintilla/Editor.py	Sun May 31 17:30:12 2015 +0200
@@ -366,10 +366,11 @@
         self.__setTextDisplay()
         
         # set the autocompletion and calltips function
-        # TODO: make this work with multiple providers
         self.__acHookFunction = None
+        self.__completionListHookFunctions = {}
         self.__setAutoCompletion()
         self.__ctHookFunction = None
+        self.__ctHookFunctions = {}
         self.__setCallTips()
         
         sh = self.sizeHint()
@@ -4264,7 +4265,8 @@
         else:
             self.setAutoCompletionSource(QsciScintilla.AcsAll)
         if Preferences.getEditor("AutoCompletionEnabled"):
-            if self.__acHookFunction is None:
+            if self.__acHookFunction is None or \
+                    not self.__completionListHookFunctions:
                 self.setAutoCompletionThreshold(
                     Preferences.getEditor("AutoCompletionThreshold"))
             else:
@@ -4414,6 +4416,10 @@
         
         return False
     
+    #####################################################
+    ## old auto-completion hook interfaces (before 6.1.0)
+    #####################################################
+    
     def setAutoCompletionHook(self, func):
         """
         Public method to set an autocompletion hook.
@@ -4455,6 +4461,69 @@
         """
         return self.__acHookFunction
     
+    ########################################################
+    ## new auto-completion hook interfaces (6.1.0 and later)
+    ########################################################
+    
+    def addCompletionListHook(self, key, func):
+        """
+        Public method to set an auto-completion list provider.
+        
+        @param key name of the provider
+        @type str
+        @param func function providing completion list. func
+            should be a function taking a reference to the editor and
+            a boolean indicating to complete a context. It should return
+            the possible completions as a list of strings.
+        @type function(editor, bool) -> list of str
+        """
+        if key in self.__completionListHookFunctions:
+            # it was already registered
+            E5MessageBox.warning(
+                self,
+                self.tr("Auto-Completion Provider"),
+                self.tr("""The completion list provider '{0}' was already"""
+                        """ registered. Ignoring duplicate request.""")
+                .format(key))
+            return
+        
+        if not self.__completionListHookFunctions:
+            if self.autoCompletionThreshold() > 0:
+                self.setAutoCompletionThreshold(0)
+            self.SCN_CHARADDED.connect(self.__charAdded)
+        self.__completionListHookFunctions[key] = func
+    
+    def removeCompletionListHook(self, key):
+        """
+        Public method to remove a previously registered completion list
+        provider.
+        
+        @param key name of the provider
+        @type str
+        """
+        if key in self.__completionListHookFunctions:
+            del self.__completionListHookFunctions[key]
+        
+        if not self.__completionListHookFunctions:
+            self.SCN_CHARADDED.disconnect(self.__charAdded)
+            if self.autoCompletionThreshold() == 0:
+                self.setAutoCompletionThreshold(
+                    Preferences.getEditor("AutoCompletionThreshold"))
+    
+    def getCompletionListHook(self, key):
+        """
+        Public method to get the registered completion list provider.
+        
+        @param key name of the provider
+        @type str
+        @return function providing completion list
+        @rtype function or None
+        """
+        if key in self.__completionListHookFunctions:
+            return self.__completionListHookFunctions[key]
+        else:
+            return None
+    
     def autoComplete(self, auto=False, context=True):
         """
         Public method to start autocompletion.
@@ -4467,18 +4536,77 @@
             # autocompletion is disabled
             return
         
-        if self.__acHookFunction is not None:
+        if self.__completionListHookFunctions:
+            if self.isListActive():
+                self.cancelList()
+            completionsList = []
+            for key in self.__completionListHookFunctions:
+                completionsList.extend(
+                    self.__completionListHookFunctions[key](self, context))
+            completionsList = list(set(completionsList))
+            if len(completionsList) == 0 and \
+                Preferences.getEditor("AutoCompletionScintillaOnFail") and \
+                (self.autoCompletionSource() != QsciScintilla.AcsNone or
+                 not auto):
+                self.autoCompleteQScintilla()
+            else:
+                completionsList.sort()
+                self.showUserList(EditorAutoCompletionListID,
+                                  completionsList)
+        elif self.__acHookFunction is not None:
+            # for backward compatibility
             self.__acHookFunction(self, context)
         elif not auto:
             self.autoCompleteQScintilla()
         elif self.autoCompletionSource() != QsciScintilla.AcsNone:
             self.autoCompleteQScintilla()
     
+    def __completionListSelected(self, id, txt):
+        """
+        Private slot to handle the selection from the completion list.
+        
+        @param id the ID of the user list (should be 1) (integer)
+        @param txt the selected text (string)
+        """
+        if id == EditorAutoCompletionListID:
+            lst = txt.split()
+            if len(lst) > 1:
+                txt = lst[0]
+            
+            if Preferences.getEditor("AutoCompletionReplaceWord"):
+                self.selectCurrentWord()
+                self.removeSelectedText()
+                line, col = self.getCursorPosition()
+            else:
+                line, col = self.getCursorPosition()
+                wLeft = self.getWordLeft(line, col)
+                if not txt.startswith(wLeft):
+                    self.selectCurrentWord()
+                    self.removeSelectedText()
+                    line, col = self.getCursorPosition()
+                elif wLeft:
+                    txt = txt[len(wLeft):]
+            self.insert(txt)
+            self.setCursorPosition(line, col + len(txt))
+        elif id == TemplateCompletionListID:
+            self.__applyTemplate(txt, self.getLanguage())
+    
+    def canProvideDynamicAutoCompletion(self):
+        """
+        Public method to test the dynamic auto-completion availability.
+        
+        @return flag indicating the availability of dynamic auto-completion
+            (boolean)
+        """
+        return (self.acAPI or
+                self.__acHookFunction is not None or
+                bool(self.__completionListHookFunctions))
+    
     def callTip(self):
         """
         Public method to show calltips.
         """
-        if self.__ctHookFunction is not None:
+        if bool(self.__ctHookFunctions) or self.__ctHookFunction is not None:
             self.__callTip()
         else:
             super(Editor, self).callTip()
@@ -4522,11 +4650,15 @@
         if not found:
             return
         
-        try:
+        if self.__ctHookFunctions:
+            callTips = []
+            for key in self.__ctHookFunctions:
+                callTips.extend(self.__ctHookFunctions[key](self, pos, commas))
+            callTips = list(set(callTips))
+            callTips.sort()
+        else:
+            # for backward compatibility
             callTips = self.__ctHookFunction(self, pos, commas)
-        except TypeError:
-            # for backward compatibility
-            callTips = self.__ctHookFunction(self, pos)
         if len(callTips) == 0:
             if Preferences.getEditor("CallTipsScintillaOnFail"):
                 # try QScintilla calltips
@@ -4602,6 +4734,10 @@
                 ct = ct - ctshift
         return ct
     
+    ##############################################
+    ## old calltips hook interfaces (before 6.1.0)
+    ##############################################
+    
     def setCallTipHook(self, func):
         """
         Public method to set a calltip hook.
@@ -4638,22 +4774,68 @@
         """
         return self.__ctHookFunction
     
+    ########################################################
+    ## new auto-completion hook interfaces (6.1.0 and later)
+    ########################################################
+    
+    def addCallTipHook(self, key, func):
+        """
+        Public method to set a calltip provider.
+        
+        @param key name of the provider
+        @type str
+        @param func function providing calltips. func
+            should be a function taking a reference to the editor,
+            a position into the text and the amount of commas to the
+            left of the cursor. It should return the possible
+            calltips as a list of strings.
+        @type function(editor, int, int) -> list of str
+        """
+        if key in self.__ctHookFunctions:
+            # it was already registered
+            E5MessageBox.warning(
+                self,
+                self.tr("Call-Tips Provider"),
+                self.tr("""The call-tips provider '{0}' was already"""
+                        """ registered. Ignoring duplicate request.""")
+                .format(key))
+            return
+        
+        self.__ctHookFunctions[key] = func
+    
+    def removeCallTipHook(self, key):
+        """
+        Public method to remove a previously registered calltip provider.
+        
+        @param key name of the provider
+        @type str
+        """
+        if key in self.__completionListHookFunctions:
+            del self.__completionListHookFunctions[key]
+    
+    def getCallTipHook(self, key):
+        """
+        Public method to get the registered calltip provider.
+        
+        @param key name of the provider
+        @type str
+        @return function providing calltips
+        @rtype function or None
+        """
+        if key in self.__ctHookFunctions:
+            return self.__ctHookFunctions[key]
+        else:
+            return None
+    
     def canProvideCallTipps(self):
         """
         Public method to test the calltips availability.
         
         @return flag indicating the availability of calltips (boolean)
         """
-        return self.acAPI or self.__ctHookFunction is not None
-    
-    def canProvideDynamicAutoCompletion(self):
-        """
-        Public method to test the dynamic auto-completion availability.
-        
-        @return flag indicating the availability of dynamic auto-completion
-            (boolean)
-        """
-        return self.acAPI or self.__acHookFunction is not None
+        return (self.acAPI or
+                self.__ctHookFunction is not None or
+                bool(self.__ctHookFunctions))
     
     #################################################################
     ## Methods needed by the context menu
@@ -6714,16 +6896,6 @@
         
         super(Editor, self).editorCommand(cmd)
     
-    def __completionListSelected(self, id, txt):
-        """
-        Private slot to handle the selection from the completion list.
-        
-        @param id the ID of the user list (should be 1) (integer)
-        @param txt the selected text (string)
-        """
-        if id == TemplateCompletionListID:
-            self.__applyTemplate(txt, self.getLanguage())
-    
     def __applyTemplate(self, templateName, language):
         """
         Private method to apply a template by name.

eric ide

mercurial