Continued implementing a viewer for source code documentation extracted by providers to be implemented by plug-ins (like rope and jedi).

Sun, 15 Oct 2017 19:40:26 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 15 Oct 2017 19:40:26 +0200
changeset 5905
f31960634997
parent 5904
2ff6078532c0
child 5906
fef02b3fdc32

Continued implementing a viewer for source code documentation extracted by providers to be implemented by plug-ins (like rope and jedi).

Preferences/__init__.py file | annotate | diff | comparison | revisions
QScintilla/Editor.py file | annotate | diff | comparison | revisions
UI/CodeDocumentationViewer.py file | annotate | diff | comparison | revisions
UI/Previewers/PreviewerHTML.py file | annotate | diff | comparison | revisions
UI/UserInterface.py file | annotate | diff | comparison | revisions
ViewManager/ViewManager.py file | annotate | diff | comparison | revisions
--- a/Preferences/__init__.py	Sun Oct 15 17:21:51 2017 +0200
+++ b/Preferences/__init__.py	Sun Oct 15 19:40:26 2017 +0200
@@ -428,7 +428,7 @@
         "CallTipsScintillaOnFail": False,
         # show QScintilla calltips, if plug-in fails
         
-        "ShowInfoOnOpenBracket": True,
+        "ShowInfoOnOpenParenthesis": True,
         # TODO: add to editor configuration page
         
         "AutoCheckSyntax": True,
@@ -1463,6 +1463,13 @@
         "HeaderColor": QColor(237, 237, 190),
         "BadWhitespaceColor": QColor(255, 0, 0, 192),
     }
+    
+    # defaults for Code Documentation Viewer
+    docuViewerDefaults = {
+        "ShowInfoAsMarkdown": False,
+        "Provider": "disabled",
+    }
+    # TODO: add to new configuration page to editor section
 
 
 def readToolGroups(prefClass=Prefs):
@@ -3532,7 +3539,7 @@
     
     @param key the key of the value to get
     @param prefClass preferences class used as the storage area
-    @return the requested editor colour
+    @return the requested diff colour
     """
     col = prefClass.settings.value("Diff/" + key)
     if col is not None:
@@ -3560,6 +3567,35 @@
     prefClass.settings.setValue("Diff/" + key, val)
 
 
+def getDocuViewer(key, prefClass=Prefs):
+    """
+    Module function to retrieve the Code Documentation Viewer related settings.
+    
+    @param key the key of the value to get
+    @param prefClass preferences class used as the storage area
+    @return the requested editor colour
+    """
+    if key in ["ShowInfoAsMarkdown"]:
+        return toBool(prefClass.settings.value(
+            "CodeDocumentationViewer/" + key,
+            prefClass.docuViewerDefaults[key]))
+    else:
+        return prefClass.settings.value(
+            "CodeDocumentationViewer/" + key,
+            prefClass.docuViewerDefaults[key])
+    
+
+def setDocuViewer(key, value, prefClass=Prefs):
+    """
+    Module function to store the Code Documentation Viewer related settings.
+    
+    @param key the key of the setting to be set
+    @param value the value to be set
+    @param prefClass preferences class used as the storage area
+    """
+    prefClass.settings.setValue("CodeDocumentationViewer/" + key, value)
+
+
 def getGeometry(key, prefClass=Prefs):
     """
     Module function to retrieve the display geometry.
--- a/QScintilla/Editor.py	Sun Oct 15 17:21:51 2017 +0200
+++ b/QScintilla/Editor.py	Sun Oct 15 19:40:26 2017 +0200
@@ -4553,6 +4553,7 @@
     ## auto-completion hook interfaces
     #################################################################
     
+    # TODO: document this hook in chapter 6.2 of plug-in document
     def addCompletionListHook(self, key, func, async=False):
         """
         Public method to set an auto-completion list provider.
@@ -4591,6 +4592,7 @@
         else:
             self.__completionListHookFunctions[key] = func
     
+    # TODO: document this hook in chapter 6.2 of plug-in document
     def removeCompletionListHook(self, key):
         """
         Public method to remove a previously registered completion list
@@ -4611,6 +4613,7 @@
                 self.setAutoCompletionThreshold(
                     Preferences.getEditor("AutoCompletionThreshold"))
     
+    # TODO: document this hook in chapter 6.2 of plug-in document
     def getCompletionListHook(self, key):
         """
         Public method to get the registered completion list provider.
@@ -4683,6 +4686,7 @@
                     self, context)
                 self.completionsListReady(completions, self.__acText)
     
+    # TODO: document this hook in chapter 6.2 of plug-in document
     def completionsListReady(self, completions, acText):
         """
         Public method to show the completions determined by a completions
@@ -4780,6 +4784,70 @@
                 bool(self.__completionListHookFunctions) or
                 bool(self.__completionListAsyncHookFunctions))
     
+    #################################################################
+    ## call-tip hook interfaces
+    #################################################################
+    
+    # TODO: document this hook in chapter 6.2 of plug-in document
+    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
+    
+    # TODO: document this hook in chapter 6.2 of plug-in document
+    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.__ctHookFunctions:
+            del self.__ctHookFunctions[key]
+    
+    # TODO: document this hook in chapter 6.2 of plug-in document
+    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
+                bool(self.__ctHookFunctions))
     def callTip(self):
         """
         Public method to show calltips.
@@ -4909,67 +4977,6 @@
                 ct = ct - ctshift
         return ct
     
-    #################################################################
-    ## call-tip hook interfaces
-    #################################################################
-    
-    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.__ctHookFunctions:
-            del self.__ctHookFunctions[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
-                bool(self.__ctHookFunctions))
     
     #################################################################
     ## Methods needed by the code documentation viewer
@@ -4985,7 +4992,7 @@
         @param charNumber value of the character entered (integer)
         """
         char = chr(charNumber)
-        if char == "(" and Preferences.getEditor("ShowInfoOnOpenBracket"):
+        if char == "(" and Preferences.getEditor("ShowInfoOnOpenParenthesis"):
             self.vm.showEditorInfo(self)
     
     #################################################################
--- a/UI/CodeDocumentationViewer.py	Sun Oct 15 17:21:51 2017 +0200
+++ b/UI/CodeDocumentationViewer.py	Sun Oct 15 19:40:26 2017 +0200
@@ -35,6 +35,8 @@
         super(CodeDocumentationViewer, self).__init__(parent)
         self.setupUi(self)
         
+        self.searchWidget.attachTextEdit(self.contents)
+        
         self.__ui = parent
         
         self.__providers = {}
@@ -44,26 +46,34 @@
         self.__shuttingDown = False
         self.__startingUp = True
         
+        self.__lastDocumentation = None
+        
+        self.__showMarkdown = Preferences.getDocuViewer("ShowInfoAsMarkdown")
+        
         self.__noDocumentationString = self.tr("No documentation available")
         self.__disabledString = self.tr(
             "No source code documentation provider has been registered or"
             " this function has been disabled.")
         
         self.providerComboBox.addItem(self.tr("<disabled>"), "disabled")
+        
+        font = Preferences.getEditorOtherFonts("MonospacedFont")
+        self.contents.setFontFamily(font.family())
+        self.contents.setFontPointSize(font.pointSize())
     
     def finalizeSetup(self):
         """
         Public method to finalize the setup of the documentation viewer.
         """
         self.__startingUp = False
-        provider = Preferences.Prefs.settings.value(
-            "CodeDocumentationViewer/Provider", "disabled")
+        provider = Preferences.getDocuViewer("Provider")
         if provider in self.__providers:
             index = self.providerComboBox.findData(provider)
         else:
             index = 0
         self.providerComboBox.setCurrentIndex(index)
     
+    # TODO: document this hook in the plug-in document
     def registerProvider(self, providerName, providerDisplay, provider):
         """
         Public method register a source docu provider.
@@ -84,6 +94,7 @@
         self.__providers[providerName] = provider
         self.providerComboBox.addItem(providerDisplay, providerName)
     
+    # TODO: document this hook in the plug-in document
     def unregisterProvider(self, providerName):
         """
         Public method register a source docu provider.
@@ -106,10 +117,18 @@
         @param editor reference to the editor to request code docu for
         @type Editor
         """
+        line, index = editor.getCursorPosition()
+        word = editor.getWord(line, index)
+        if not word:
+            # try again one index before
+            word = editor.getWord(line,  index - 1)
+        self.objectLineEdit.setText(word)
+        
         if self.__selectedProvider != self.__disabledProvider:
             self.contents.clear()
             self.__providers[self.__selectedProvider](editor)
     
+    # TODO: document this hook in the plug-in document
     def documentationReady(self, documentationInfo):
         """
         Public method to provide the documentation info to the viewer.
@@ -128,27 +147,42 @@
         """
         self.__ui.activateCodeDocumentationViewer(switchFocus=False)
         
+        self.__lastDocumentation = documentationInfo
+        
         if not documentationInfo:
             fullText = self.__noDocumentationString
         elif isinstance(documentationInfo, str):
             fullText = documentationInfo
         elif isinstance(documentationInfo, dict):
+            # format the text with markdown syntax
             name = documentationInfo["name"]
             if name:
-                title = "".join(["=" * len(name), "\n", name, "\n",
+                title = "".join([name, "\n",
                                  "=" * len(name), "\n\n"])
             else:
                 title = ""
 
             if documentationInfo["argspec"]:
-                definition = self.tr("Definition: {0}{1}\n").format(
-                    name, documentationInfo["argspec"])
+                if self.__showMarkdown:
+                    definition = self.tr("**Definition**: {0}{1}\n",
+                                         "string with markdown syntax").format(
+                        name, documentationInfo["argspec"])
+                else:
+                    definition = self.tr("Definition: {0}{1}\n",
+                                         "string as plain text").format(
+                        name, documentationInfo["argspec"])
             else:
                 definition = ''
 
             if documentationInfo["note"]:
-                note = self.tr("Info: {0}\n\n----\n\n").format(
-                    documentationInfo["note"])
+                if self.__showMarkdown:
+                    note = self.tr("**Info**: _{0}_\n\n----\n\n",
+                                   "string with markdown syntax").format(
+                        documentationInfo["note"])
+                else:
+                    note = self.tr("Info: {0}\n\n----\n\n",
+                                   "string as plain text").format(
+                        documentationInfo["note"])
             else:
                 note = ""
 
@@ -170,8 +204,7 @@
             if provider == self.__disabledProvider:
                 self.documentationReady(self.__disabledString)
             elif provider in self.__providers:
-                Preferences.Prefs.settings.setValue(
-                    "CodeDocumentationViewer/Provider", provider)
+                Preferences.setDocuViewer("Provider", provider)
             self.__selectedProvider = provider
     
     def shutdown(self):
@@ -179,5 +212,24 @@
         Public method to perform shutdown actions.
         """
         self.__shuttingDown = True
-        Preferences.Prefs.settings.setValue(
-            "CodeDocumentationViewer/Provider", self.__selectedProvider)
+        Preferences.setDocuViewer("Provider", self.__selectedProvider)
+    
+    def preferencesChanged(self):
+        """
+        Public slot to handle a change of preferences.
+        """
+        showMarkdown = Preferences.getDocuViewer("ShowInfoAsMarkdown")
+        if showMarkdown != self.__showMarkdown:
+            self.__showMarkdown = showMarkdown
+            self.documentationReady(self.__lastDocumentation)
+        
+        provider = Preferences.getDocuViewer("Provider")
+        if provider != self.__selectedProvider:
+            index = self.providerComboBox.findData(provider)
+            if index < 0:
+                index = 0
+            self.providerComboBox.setCurrentIndex(index)
+        
+        font = Preferences.getEditorOtherFonts("MonospacedFont")
+        self.contents.setFontFamily(font.family())
+        self.contents.setFontPointSize(font.pointSize())
--- a/UI/Previewers/PreviewerHTML.py	Sun Oct 15 17:21:51 2017 +0200
+++ b/UI/Previewers/PreviewerHTML.py	Sun Oct 15 19:40:26 2017 +0200
@@ -682,7 +682,8 @@
         try:
             import mdx_mathjax  # __IGNORE_EXCEPTION__ __IGNORE_WARNING__
         except ImportError:
-            #mathjax doesn't require import statement if installed as extension
+            # mathjax doesn't require import statement if installed
+            # as extension
             pass
         
         if convertNewLineToBreak:
--- a/UI/UserInterface.py	Sun Oct 15 17:21:51 2017 +0200
+++ b/UI/UserInterface.py	Sun Oct 15 19:40:26 2017 +0200
@@ -455,6 +455,8 @@
         self.preferencesChanged.connect(self.cooperation.preferencesChanged)
         self.preferencesChanged.connect(
             self.backgroundService.preferencesOrProjectChanged)
+        self.preferencesChanged.connect(
+            self.codeDocumentationViewer.preferencesChanged)
         
         self.viewmanager.editorSaved.connect(self.project.repopulateItem)
         self.viewmanager.lastEditorClosed.connect(self.__lastEditorClosed)
--- a/ViewManager/ViewManager.py	Sun Oct 15 17:21:51 2017 +0200
+++ b/ViewManager/ViewManager.py	Sun Oct 15 19:40:26 2017 +0200
@@ -84,7 +84,6 @@
         super(QuickSearchLineEdit, self).focusInEvent(evt)   # pass it on
 
 
-# TODO: add an action to show code info for the object under the cursor (Ctrl-Alt-I)
 class ViewManager(QWidget):
     """
     Base class inherited by all specific viewmanager classes.
@@ -1379,6 +1378,24 @@
         self.calltipsAct.triggered.connect(self.__editShowCallTips)
         self.editActions.append(self.calltipsAct)
         
+        self.codeInfoAct = E5Action(
+            QCoreApplication.translate('ViewManager', 'Code Info'),
+            UI.PixmapCache.getIcon("codeDocuViewer.png"),
+            QCoreApplication.translate('ViewManager', 'Code Info'),
+            QKeySequence(QCoreApplication.translate(
+                'ViewManager', "Ctrl+Alt+I", "Edit|Code Info")),
+            0,
+            self.editActGrp, 'vm_edit_codeinfo')
+        self.codeInfoAct.setStatusTip(QCoreApplication.translate(
+            'ViewManager', 'Show Code Info'))
+        self.codeInfoAct.setWhatsThis(QCoreApplication.translate(
+            'ViewManager',
+            """<b>Code Info</b>"""
+            """<p>Show code information based on the cursor position.</p>"""
+        ))
+        self.codeInfoAct.triggered.connect(self.__editShowCodeInfo)
+        self.editActions.append(self.codeInfoAct)
+        
         self.sortAct = E5Action(
             QCoreApplication.translate('ViewManager', 'Sort'),
             QCoreApplication.translate('ViewManager', 'Sort'),
@@ -5434,6 +5451,12 @@
         """
         self.activeWindow().callTip()
     
+    def __editShowCodeInfo(self):
+        """
+        Private method to handle the code info action.
+        """
+        self.showEditorInfo(self.activeWindow())
+    
     ##################################################################
     ## Below are the action and utility methods for the search menu
     ##################################################################
@@ -6790,7 +6813,6 @@
         @param editor editor to show information text for
         @type Editor
         """
-        # TODO: implement CodeDocumentationViewer
         self.ui.documentationViewer().showInfo(editor)
     
     ##################################################################

eric ide

mercurial