--- a/RefactoringRope/CodeAssistServer.py Sun Sep 16 13:17:08 2018 +0200 +++ b/RefactoringRope/CodeAssistServer.py Sun Oct 28 12:30:45 2018 +0100 @@ -21,12 +21,15 @@ import Globals import Preferences +import Utilities class CodeAssistServer(JsonServer): """ Class implementing the autocompletion interface to rope. """ + IdProject = "Project" + def __init__(self, plugin, parent=None): """ Constructor @@ -42,6 +45,7 @@ self.__plugin = plugin self.__ui = parent self.__vm = e5App().getObject("ViewManager") + self.__e5project = e5App().getObject("Project") self.__editorLanguageMapping = {} self.__clientConfigs = {} @@ -100,6 +104,40 @@ "Pygments|Python 3": "Python3", }) + def isSupportedLanguage(self, language): + """ + Public method to check, if the given language is supported. + + @param language editor programming language to check + @type str + @return flag indicating the support status + @rtype bool + """ + return language in self.__editorLanguageMapping + + def __idString(self, editor): + """ + Private method to determine the ID string for the back-end. + + @param editor reference to the editor to determine the ID string for + @type QScintilla.Editor + @return ID string + @rtype str + """ + idString = "" + + language = editor.getLanguage() + if self.__e5project.isOpen() and \ + self.__e5project.getProjectLanguage() == language: + filename = editor.getFileName() + if self.__e5project.isProjectSource(filename): + idString = CodeAssistServer.IdProject + + if not idString and language in self.__editorLanguageMapping: + idString = self.__editorLanguageMapping[language] + + return idString + def __getConfigs(self): """ Private method to get the configurations of all connected clients. @@ -170,17 +208,6 @@ self.tr("""The Rope configuration file '{0}' does""" """ not exist.""").format(configfile)) - def isSupportedLanguage(self, language): - """ - Public method to check, if the given language is supported. - - @param language editor programming language to check - @type str - @return flag indicating the support status - @rtype bool - """ - return language in self.__editorLanguageMapping - def getCompletions(self, editor, context): """ Public method to calculate the possible completions. @@ -197,8 +224,7 @@ # reset the completions buffer self.__completions = None - language = editor.getLanguage() - if language not in self.__editorLanguageMapping: + if not self.__idString(editor): return [] self.requestCompletions(editor, context, "") @@ -226,10 +252,9 @@ @param acText text to be completed @type str """ - language = editor.getLanguage() - if language not in self.__editorLanguageMapping: + idString = self.__idString(editor) + if not idString: return - idString = self.__editorLanguageMapping[language] filename = editor.getFileName() line, index = editor.getCursorPosition() @@ -284,10 +309,9 @@ # reset the calltips buffer self.__calltips = None - language = editor.getLanguage() - if language not in self.__editorLanguageMapping: + idString = self.__idString(editor) + if not idString: return [] - idString = self.__editorLanguageMapping[language] filename = editor.getFileName() source = editor.text() @@ -336,10 +360,8 @@ """ editor = self.__vm.getOpenEditor(filename) if editor is not None: - language = editor.getLanguage() - if language in self.__editorLanguageMapping: - idString = self.__editorLanguageMapping[language] - + idString = self.__idString(editor) + if idString: self.__ensureActive(idString) self.sendJson("reportChanged", { "FileName": filename, @@ -359,7 +381,7 @@ return language = editor.getLanguage() - if language not in self.__editorLanguageMapping: + if not self.isSupportedLanguage(language): if Preferences.getDocuViewer("ShowInfoAsRichText"): warning = self.tr("Language <b>{0}</b> is not supported.")\ .format(language) @@ -370,7 +392,9 @@ warning, isWarning=True) return - idString = self.__editorLanguageMapping[language] + idString = self.__idString(editor) + if not idString: + return filename = editor.getFileName() source = editor.text() @@ -496,7 +520,11 @@ ok = False if interpreter: - configDir = os.path.join(Globals.getConfigDir(), "rope", idString) + if idString == CodeAssistServer.IdProject: + configDir = self.__e5project.getProjectPath() + else: + configDir = os.path.join(Globals.getConfigDir(), "rope", + idString) if not os.path.exists(configDir): os.makedirs(configDir) @@ -531,50 +559,112 @@ ok = idString in self.connectionNames() if not ok: # client is not running - try: - # new code using virtual environments - venvManager = e5App().getObject("VirtualEnvManager") - if idString == "Python2": - # Python 2 - venvName = Preferences.getDebugger("Python2VirtualEnv") - if not venvName and sys.version_info[0] == 2: - try: - venvName, _ = venvManager.getDefaultEnvironment() - except AttributeError: - # ignore for eric6 < 18.10 - pass - elif idString == "Python3": - # Python 3 - venvName = Preferences.getDebugger("Python3VirtualEnv") - if not venvName and sys.version_info[0] == 3: - try: - venvName, _ = venvManager.getDefaultEnvironment() - except AttributeError: - # ignore for eric6 < 18.10 - pass - else: - venvName = "" - if venvName: - interpreter = e5App().getObject("VirtualEnvManager")\ - .getVirtualenvInterpreter(venvName) - else: - interpreter = "" - except KeyError: - # backward compatibility (eric <18.07) - if idString == "Python2": - # Python 2 - interpreter = Preferences.getDebugger("PythonInterpreter") - elif idString == "Python3": - # Python 3 - interpreter = Preferences.getDebugger("Python3Interpreter") - else: - interpreter = "" + if idString == CodeAssistServer.IdProject: + interpreter = self.__interpreterForProject() + else: + interpreter = "" + venvName = "" + try: + # new code using virtual environments + venvManager = e5App().getObject("VirtualEnvManager") + if idString == "Python2": + # Python 2 + venvName = Preferences.getDebugger("Python2VirtualEnv") + if not venvName and sys.version_info[0] == 2: + try: + venvName, _ = \ + venvManager.getDefaultEnvironment() + except AttributeError: + # ignore for eric6 < 18.10 + pass + elif idString == "Python3": + # Python 3 + venvName = Preferences.getDebugger("Python3VirtualEnv") + if not venvName and sys.version_info[0] == 3: + try: + venvName, _ = \ + venvManager.getDefaultEnvironment() + except AttributeError: + # ignore for eric6 < 18.10 + pass + if venvName: + interpreter = \ + venvManager.getVirtualenvInterpreter(venvName) + except KeyError: + # backward compatibility (eric <18.07) + if idString == "Python2": + # Python 2 + interpreter = \ + Preferences.getDebugger("PythonInterpreter") + elif idString == "Python3": + # Python 3 + interpreter = \ + Preferences.getDebugger("Python3Interpreter") if interpreter: ok = self.__startCodeAssistClient(interpreter, idString) else: ok = False return ok + def __interpreterForProject(self): + """ + Private method to determine the interpreter for the current project. + + @return interpreter of the current project + @rtype str + """ + interpreter = "" + projectLanguage = self.__e5project.getProjectLanguage() + + if projectLanguage.startswith("Python"): + try: + # new code using virtual environments + venvManager = e5App().getObject("VirtualEnvManager") + + # get virtual environment from project first + venvName = self.__e5project.getDebugProperty("VIRTUALENV") + if not venvName: + # get it from debugger settings next + if projectLanguage == "Python2": + # Python 2 + venvName = Preferences.getDebugger("Python2VirtualEnv") + if not venvName and sys.version_info[0] == 2: + try: + venvName, _ = \ + venvManager.getDefaultEnvironment() + except AttributeError: + # ignore for eric6 < 18.10 + pass + elif projectLanguage == "Python3": + # Python 3 + venvName = Preferences.getDebugger("Python3VirtualEnv") + if not venvName and sys.version_info[0] == 3: + try: + venvName, _ = \ + venvManager.getDefaultEnvironment() + except AttributeError: + # ignore for eric6 < 18.10 + pass + else: + venvName = "" + if venvName: + interpreter = \ + venvManager.getVirtualenvInterpreter(venvName) + except KeyError: + # backward compatibility (eric < 18.07) + # get interpreter from project first + interpreter = self.__e5project.getDebugProperty("INTERPRETER") + if not interpreter or not Utilities.isinpath(interpreter): + # get it from debugger settings second + if projectLanguage == "Python2": + interpreter = Preferences.getDebugger( + "PythonInterpreter") + elif projectLanguage == "Python3": + interpreter = Preferences.getDebugger( + "Python3Interpreter") + + return interpreter + @pyqtSlot() def handleNewConnection(self): """ @@ -599,6 +689,8 @@ except AttributeError: # eric6 before 17.11 doesn't have this pass + + self.__e5project.projectClosed.connect(self.__projectClosed) def deactivate(self): """ @@ -613,8 +705,21 @@ for idString in self.connectionNames(): self.sendJson("closeProject", {}, flush=True, idString=idString) + try: + self.__e5project.projectClosed.disconnect(self.__projectClosed) + except TypeError: + # ignore it, the signal may be disconnected already + pass + self.stopAllClients() + @pyqtSlot() + def __projectClosed(self): + """ + Private slot to handle the projectClosed signal. + """ + self.stopClient(idString=CodeAssistServer.IdProject) + ####################################################################### ## Methods below handle setting/unsetting the hook methods #######################################################################