Wed, 23 Oct 2024 17:45:37 +0200
Adjusted code for eric7 24.10 and newer.
# -*- coding: utf-8 -*- # Copyright (c) 2010 - 2024 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing the Rope refactoring plugin. """ import contextlib import os from PyQt6.QtCore import QCoreApplication, QObject, Qt, QTranslator from PyQt6.QtGui import QPalette from eric7 import Preferences, Utilities from eric7.EricWidgets.EricApplication import ericApp try: from eric7.SystemUtilities.FileSystemUtilities import isRemoteFileName except ImportError: from .RefactoringRope.RopeUtilities import isRemoteFileName # Start-Of-Header name = "Refactoring Rope Plugin" author = "Detlev Offenbach <detlev@die-offenbachs.de>" autoactivate = True deactivateable = True version = "10.7.3" className = "RefactoringRopePlugin" packageName = "RefactoringRope" shortDescription = "Refactoring and Code Assist using the Rope library." longDescription = ( """This plug-in implements refactoring functionality using the Rope""" """ refactoring library. Additionally it implements an auto-completion,""" """ call-tips and code documentation provider as well as a mouse""" """ click handler.""" ) pyqtApi = 2 doNotCompile = True # End-Of-Header error = "" refactoringRopePluginObject = None def createAutoCompletionPage(configDlg): # noqa: U100 """ Module function to create the autocompletion configuration page. @param configDlg reference to the configuration dialog @type ConfigurationWidget @return reference to the configuration page @rtype AutoCompletionRopePage """ from RefactoringRope.ConfigurationPage.AutoCompletionRopePage import ( AutoCompletionRopePage, ) global refactoringRopePluginObject page = AutoCompletionRopePage(refactoringRopePluginObject) return page def createCallTipsPage(configDlg): # noqa: U100 """ Module function to create the calltips configuration page. @param configDlg reference to the configuration dialog @type ConfigurationWidget @return reference to the configuration page @rtype CallTipsRopePage """ from RefactoringRope.ConfigurationPage.CallTipsRopePage import CallTipsRopePage global refactoringRopePluginObject page = CallTipsRopePage(refactoringRopePluginObject) return page def createMouseClickHandlerPage(configDlg): # noqa: U100 """ Module function to create the mouse click handler configuration page. @param configDlg reference to the configuration dialog @type ConfigurationWidget @return reference to the configuration page @rtype MouseClickHandlerRopePage """ from RefactoringRope.ConfigurationPage.MouseClickHandlerRopePage import ( MouseClickHandlerRopePage, ) global refactoringRopePluginObject page = MouseClickHandlerRopePage(refactoringRopePluginObject) return page def getConfigData(): """ Module function returning data as required by the configuration dialog. @return dictionary containing the relevant data @rtype dict """ try: usesDarkPalette = ericApp().usesDarkPalette() except AttributeError: palette = ericApp().palette() lightness = palette.color(QPalette.Window).lightness() usesDarkPalette = lightness <= 128 iconSuffix = "dark" if usesDarkPalette else "light" data = { "ropeAutoCompletionPage": [ QCoreApplication.translate("RefactoringRopePlugin", "Rope"), os.path.join( "RefactoringRope", "ConfigurationPage", "preferences-refactoring-{0}".format(iconSuffix), ), createAutoCompletionPage, "1editorAutocompletionPage", None, ], "ropeCallTipsPage": [ QCoreApplication.translate("RefactoringRopePlugin", "Rope"), os.path.join( "RefactoringRope", "ConfigurationPage", "preferences-refactoring-{0}".format(iconSuffix), ), createCallTipsPage, "1editorCalltipsPage", None, ], "ropeMouseClickHandlerPage": [ QCoreApplication.translate("RefactoringRopePlugin", "Rope"), os.path.join( "RefactoringRope", "ConfigurationPage", "preferences-refactoring-{0}".format(iconSuffix), ), createMouseClickHandlerPage, "1editorMouseClickHandlers", None, ], } return data def prepareUninstall(): """ Module function to prepare for an uninstallation. """ Preferences.Prefs.settings.remove(RefactoringRopePlugin.PreferencesKey) class RefactoringRopePlugin(QObject): """ Class implementing the Rope refactoring plugin. """ PreferencesKey = "RefactoringRope" def __init__(self, ui): """ Constructor @param ui reference to the user interface object @type UserInterface """ QObject.__init__(self, ui) self.__ui = ui self.__initialize() self.__defaults = { "CodeAssistEnabled": False, "MaxFixes": 10, "CodeAssistCalltipsEnabled": False, "CalltipsMaxFixes": 10, "MouseClickEnabled": True, "MouseClickGotoModifiers": ( Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.AltModifier ), "MouseClickGotoButton": Qt.MouseButton.LeftButton, } self.__translator = None self.__loadTranslator() def __initialize(self): """ Private slot to (re)initialize the plugin. """ self.__refactoringServer = None self.__codeAssistServer = None self.__editors = [] self.__currentEditor = None self.__savedEditorName = None self.__oldEditorText = "" def activate(self): """ Public method to activate this plugin. @return tuple of None and activation status @rtype tuple of (None, bool) """ from RefactoringRope.CodeAssistServer import CodeAssistServer from RefactoringRope.RefactoringServer import RefactoringServer global refactoringRopePluginObject refactoringRopePluginObject = self ericApp().getObject("PluginManager").shutdown.connect(self.__shutdown) self.__codeAssistServer = CodeAssistServer(self, parent=self.__ui) self.__codeAssistServer.activate() self.__refactoringServer = RefactoringServer(self, parent=self.__ui) self.__refactoringServer.activate() ericApp().getObject("PluginManager").shutdown.connect(self.__shutdown) ericApp().getObject("ViewManager").editorOpenedEd.connect(self.__editorOpened) ericApp().getObject("ViewManager").editorClosedEd.connect(self.__editorClosed) for editor in ericApp().getObject("ViewManager").getOpenEditors(): self.__editorOpened(editor) return None, True def deactivate(self): """ Public method to deactivate this plugin. """ if self.__refactoringServer: self.__refactoringServer.deactivate() if self.__codeAssistServer: self.__codeAssistServer.deactivate() ericApp().getObject("PluginManager").shutdown.disconnect(self.__shutdown) ericApp().getObject("ViewManager").editorOpenedEd.disconnect( self.__editorOpened ) ericApp().getObject("ViewManager").editorClosedEd.disconnect( self.__editorClosed ) for editor in self.__editors[:]: self.__editorClosed(editor) self.__initialize() def __shutdown(self): """ Private slot handling the shutdown signal of the plug-in manager. """ if self.__codeAssistServer: self.__codeAssistServer.deactivate() def __loadTranslator(self): """ Private method to load the translation file. """ if self.__ui is not None: loc = self.__ui.getLocale() if loc and loc != "C": locale_dir = os.path.join( os.path.dirname(__file__), "RefactoringRope", "i18n" ) translation = "rope_{0}".format(loc) translator = QTranslator(None) loaded = translator.load(translation, locale_dir) if loaded: self.__translator = translator ericApp().installTranslator(self.__translator) else: print( "Warning: translation file '{0}' could not" " be loaded.".format(translation) ) print("Using default.") def getPreferences(self, key): """ Public method to retrieve the various refactoring settings. @param key the key of the value to get @type str @return the requested refactoring setting @rtype Any """ if key in [ "CodeAssistEnabled", "CodeAssistCalltipsEnabled", "MouseClickEnabled", ]: return Preferences.toBool( Preferences.Prefs.settings.value( self.PreferencesKey + "/" + key, self.__defaults[key] ) ) elif key in ["CalltipsMaxFixes", "MaxFixes"]: return int( Preferences.Prefs.settings.value( self.PreferencesKey + "/" + key, self.__defaults[key] ) ) else: return Preferences.Prefs.settings.value( self.PreferencesKey + "/" + key, self.__defaults[key] ) def setPreferences(self, key, value): """ Public method to store the various refactoring settings. @param key the key of the setting to be set @type str @param value the value to be set @type Any """ Preferences.Prefs.settings.setValue(self.PreferencesKey + "/" + key, value) if key in ["MouseClickGotoModifiers", "MouseClickGotoButton"]: for editor in self.__editors: self.__disconnectMouseClickHandler(editor) if not isRemoteFileName(editor.getFileName()): 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 """ if not isRemoteFileName(editor.getFileName()): 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() if not isRemoteFileName(editor.getFileName()): 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 """ editor.editorAboutToBeSaved.connect(self.__editorAboutToBeSaved) editor.editorSaved.connect(self.__editorSaved) self.__setAutoCompletionHook(editor) self.__setCalltipsHook(editor) self.__connectMouseClickHandler(editor) def __disconnectEditor(self, editor): """ Private method to disconnect an editor. @param editor reference to the editor @type Editor """ with contextlib.suppress(TypeError): editor.editorAboutToBeSaved.disconnect(self.__editorAboutToBeSaved) editor.editorSaved.disconnect(self.__editorSaved) self.__unsetAutoCompletionHook(editor) self.__unsetCalltipsHook(editor) self.__disconnectMouseClickHandler(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 self.getPreferences("MouseClickGotoButton"): editor.setMouseClickHandler( "rope", self.getPreferences("MouseClickGotoModifiers"), self.getPreferences("MouseClickGotoButton"), self.__codeAssistServer.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("rope") def __setAutoCompletionHook(self, editor): """ Private method to set the autocompletion hook. @param editor reference to the editor @type Editor """ editor.addCompletionListHook( "rope", self.__codeAssistServer.requestCompletions, True ) def __unsetAutoCompletionHook(self, editor): """ Private method to unset the autocompletion hook. @param editor reference to the editor @type Editor """ editor.removeCompletionListHook("rope") def __setCalltipsHook(self, editor): """ Private method to set the calltip hook. @param editor reference to the editor @type Editor """ editor.addCallTipHook("rope", self.__codeAssistServer.getCallTips) def __unsetCalltipsHook(self, editor): """ Private method to unset the calltip hook. @param editor reference to the editor @type Editor """ editor.removeCallTipHook("rope") def __editorAboutToBeSaved(self, filename): """ Private slot to get the old contents of the named file. @param filename name of the file about to be saved @type str """ if filename and os.path.exists(filename): try: self.__oldEditorText = Utilities.readEncodedFile(filename)[0] except OSError: self.__oldEditorText = "" self.__savedEditorName = filename else: self.__savedEditorName = "" self.__oldEditorText = "" def __editorSaved(self, filename): """ Private slot to activate SOA. @param filename name of the file that was saved @type str """ if filename == self.__savedEditorName and self.__oldEditorText: self.__refactoringServer.reportChanged( self.__savedEditorName, self.__oldEditorText ) self.__codeAssistServer.reportChanged( self.__savedEditorName, self.__oldEditorText ) else: self.__refactoringServer.reportChanged(filename, "") self.__codeAssistServer.reportChanged(filename, "") def getCodeAssistServer(self): """ Public method to get a reference to the code assist server. @return reference to the code assist server @rtype CodeAssistServer """ return self.__codeAssistServer def installDependencies(pipInstall): """ Function to install dependencies of this plug-in. @param pipInstall function to be called with a list of package names. @type function """ try: import rope # __IGNORE_WARNING__ except ImportError: pipInstall(["rope"]) # # eflag: noqa = M801, U200