eric7/JediInterface/AssistantJedi.py

Mon, 14 Feb 2022 19:01:43 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Mon, 14 Feb 2022 19:01:43 +0100
branch
eric7
changeset 8949
bab82fd15a6b
parent 8881
54e42bc2437a
permissions
-rw-r--r--

Implemented a workaround for an action disconnect issue.

# -*- coding: utf-8 -*-

# Copyright (c) 2015 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing the Jedi assistant plug-in.
"""

import contextlib

from PyQt6.QtCore import pyqtSlot, QObject
from PyQt6.QtWidgets import QMenu

import Preferences


class AssistantJedi(QObject):
    """
    Class implementing the Jedi assistant interface.
    """
    def __init__(self, ui, viewManager, project):
        """
        Constructor
        
        @param ui reference to the user interface object
        @type UserInterface
        @param viewManager reference to the viewmanager object
        @type ViewManager
        @param project reference to the project object
        @type Project
        """
        super().__init__(ui)
        self.__ui = ui
        self.__vm = viewManager
        
        self.__jediServer = None
        self.__editors = []
        self.__menuActions = {}
        
        from .JediServer import JediServer
        self.__jediServer = JediServer(self.__vm, project, self.__ui)
        self.__jediServer.activate()
        
        self.__ui.preferencesChanged.connect(self.__preferencesChanged)
        
        self.__initRefactoringMenu()
        
        self.__vm.editorOpenedEd.connect(self.__editorOpened)
        self.__vm.editorClosedEd.connect(self.__editorClosed)
    
    @pyqtSlot()
    def __preferencesChanged(self):
        """
        Private slot handling changes of the Disassembly viewer settings.
        """
        for editor in self.__editors:
            self.__disconnectMouseClickHandler(editor)
            self.__connectMouseClickHandler(editor)
    
    def __determineLanguage(self):
        """
        Private method to determine the valid language strings.
        
        @return list of valid language strings
        @rtype list of str
        """
        return ["Python3", "MicroPython",
                "Pygments|Python", "Pygments|Python 2.x",
                "Cython"]
    
    def __editorOpened(self, editor):
        """
        Private slot called, when a new editor was opened.
        
        @param editor reference to the new editor
        @type Editor
        """
        languages = self.__determineLanguage()
        
        if editor.getLanguage() in languages:
            self.__connectEditor(editor)
        
        editor.languageChanged.connect(self.__editorLanguageChanged)
        self.__editors.append(editor)
    
    def __editorClosed(self, editor):
        """
        Private slot called, when an editor was closed.
        
        @param editor reference to the editor
        @type Editor
        """
        if editor in self.__editors:
            editor.languageChanged.disconnect(self.__editorLanguageChanged)
            self.__disconnectEditor(editor)
            self.__editors.remove(editor)
    
    def __editorLanguageChanged(self, language):
        """
        Private slot to handle the language change of an editor.
        
        @param language programming language of the editor
        @type str
        """
        editor = self.sender()
        languages = self.__determineLanguage()
        
        self.__disconnectEditor(editor)
        if language in languages:
            self.__connectEditor(editor)
    
    def __connectEditor(self, editor):
        """
        Private method to connect an editor.
        
        @param editor reference to the editor
        @type Editor
        """
        self.__setAutoCompletionHook(editor)
        self.__setCalltipsHook(editor)
        
        self.__connectMouseClickHandler(editor)
        
        editor.registerMouseHoverHelpFunction(
            self.__jediServer.hoverHelp)
        
        menu = editor.getMenu("Main")
        if menu is not None:
            checkAction = editor.getMenu("Checks").menuAction()
            act = menu.insertMenu(checkAction, self.__menu)
            sep = menu.insertSeparator(checkAction)
            self.__menuActions[editor] = [act, sep]
        editor.showMenu.connect(self.__editorShowMenu)
    
    def __disconnectEditor(self, editor):
        """
        Private method to disconnect an editor.
        
        @param editor reference to the editor
        @type Editor
        """
        self.__unsetAutoCompletionHook(editor)
        self.__unsetCalltipsHook(editor)
        
        self.__disconnectMouseClickHandler(editor)
        
        editor.unregisterMouseHoverHelpFunction(
            self.__jediServer.hoverHelp)
        
        with contextlib.suppress(TypeError):
            editor.showMenu.disconnect(self.__editorShowMenu)
        menu = editor.getMenu("Main")
        if menu is not None and editor in self.__menuActions:
            for act in self.__menuActions[editor]:
                with contextlib.suppress(RuntimeError):
                    menu.removeAction(act)
            del self.__menuActions[editor]
    
    def __connectMouseClickHandler(self, editor):
        """
        Private method to connect the mouse click handler to an editor.
        
        @param editor reference to the editor
        @type Editor
        """
        if Preferences.getJedi("MouseClickGotoButton"):
            editor.setMouseClickHandler(
                "jedi",
                Preferences.getJedi("MouseClickGotoModifiers"),
                Preferences.getJedi("MouseClickGotoButton"),
                self.__jediServer.gotoDefinition
            )
    
    def __disconnectMouseClickHandler(self, editor):
        """
        Private method to disconnect the mouse click handler from an editor.
        
        @param editor reference to the editor
        @type Editor
        """
        editor.removeMouseClickHandlers("jedi")
    
    def __setAutoCompletionHook(self, editor):
        """
        Private method to set the autocompletion hook.
        
        @param editor reference to the editor
        @type Editor
        """
        editor.addCompletionListHook(
            "jedi", self.__jediServer.requestCompletions, True)
    
    def __unsetAutoCompletionHook(self, editor):
        """
        Private method to unset the autocompletion hook.
        
        @param editor reference to the editor
        @type Editor
        """
        editor.removeCompletionListHook("jedi")
    
    def __setCalltipsHook(self, editor):
        """
        Private method to set the calltip hook.
        
        @param editor reference to the editor
        @type Editor
        """
        editor.addCallTipHook("jedi", self.__jediServer.getCallTips)
    
    def __unsetCalltipsHook(self, editor):
        """
        Private method to unset the calltip hook.
        
        @param editor reference to the editor
        @type Editor
        """
        editor.removeCallTipHook("jedi")
    
    def __initRefactoringMenu(self):
        """
        Private method to initialize the Refactoring menu.
        """
        self.__menu = QMenu(self.tr("Refactoring"))
        self.__menu.addAction(
            self.tr("Rename Variable"),
            self.__jediServer.refactoringRenameVariable)
        self.__menu.addAction(
            self.tr("Extract Variable"),
            self.__jediServer.refactoringExtractNewVariable)
        self.__menu.addAction(
            self.tr("Inline Variable"),
            self.__jediServer.refactoringInlineVariable)
        self.__menu.addSeparator()
        self.__menu.addAction(
            self.tr("Extract Function"),
            self.__jediServer.refactoringExtractFunction)
    
    def __editorShowMenu(self, menuName, menu, editor):
        """
        Private slot called, when the the editor context menu or a submenu is
        about to be shown.
        
        @param menuName name of the menu to be shown
        @type str
        @param menu reference to the menu
        @type QMenu
        @param editor reference to the editor
        @type Editor
        """
        if menuName == "Main":
            self.__menu.setEnabled(editor.hasSelectedText())

eric ide

mercurial