RefactoringRope/CodeAssistServer.py

changeset 283
d98e971d9e4c
parent 280
45f0a0511acd
child 285
247d62c682dc
equal deleted inserted replaced
282:ccb5c268df65 283:d98e971d9e4c
19 19
20 from .JsonServer import JsonServer 20 from .JsonServer import JsonServer
21 21
22 import Globals 22 import Globals
23 import Preferences 23 import Preferences
24 import Utilities
24 25
25 26
26 class CodeAssistServer(JsonServer): 27 class CodeAssistServer(JsonServer):
27 """ 28 """
28 Class implementing the autocompletion interface to rope. 29 Class implementing the autocompletion interface to rope.
29 """ 30 """
31 IdProject = "Project"
32
30 def __init__(self, plugin, parent=None): 33 def __init__(self, plugin, parent=None):
31 """ 34 """
32 Constructor 35 Constructor
33 36
34 @param plugin reference to the plugin object 37 @param plugin reference to the plugin object
40 "CodeAssistServer", multiplex=True, parent=parent) 43 "CodeAssistServer", multiplex=True, parent=parent)
41 44
42 self.__plugin = plugin 45 self.__plugin = plugin
43 self.__ui = parent 46 self.__ui = parent
44 self.__vm = e5App().getObject("ViewManager") 47 self.__vm = e5App().getObject("ViewManager")
48 self.__e5project = e5App().getObject("Project")
45 49
46 self.__editorLanguageMapping = {} 50 self.__editorLanguageMapping = {}
47 self.__clientConfigs = {} 51 self.__clientConfigs = {}
48 self.__editors = {} 52 self.__editors = {}
49 53
97 elif name == "Python3": 101 elif name == "Python3":
98 self.__editorLanguageMapping.update({ 102 self.__editorLanguageMapping.update({
99 "Python3": "Python3", 103 "Python3": "Python3",
100 "Pygments|Python 3": "Python3", 104 "Pygments|Python 3": "Python3",
101 }) 105 })
106
107 def isSupportedLanguage(self, language):
108 """
109 Public method to check, if the given language is supported.
110
111 @param language editor programming language to check
112 @type str
113 @return flag indicating the support status
114 @rtype bool
115 """
116 return language in self.__editorLanguageMapping
117
118 def __idString(self, editor):
119 """
120 Private method to determine the ID string for the back-end.
121
122 @param editor reference to the editor to determine the ID string for
123 @type QScintilla.Editor
124 @return ID string
125 @rtype str
126 """
127 idString = ""
128
129 language = editor.getLanguage()
130 if self.__e5project.isOpen() and \
131 self.__e5project.getProjectLanguage() == language:
132 filename = editor.getFileName()
133 if self.__e5project.isProjectSource(filename):
134 idString = CodeAssistServer.IdProject
135
136 if not idString and language in self.__editorLanguageMapping:
137 idString = self.__editorLanguageMapping[language]
138
139 return idString
102 140
103 def __getConfigs(self): 141 def __getConfigs(self):
104 """ 142 """
105 Private method to get the configurations of all connected clients. 143 Private method to get the configurations of all connected clients.
106 """ 144 """
168 self.__ui, 206 self.__ui,
169 self.tr("Configure Rope"), 207 self.tr("Configure Rope"),
170 self.tr("""The Rope configuration file '{0}' does""" 208 self.tr("""The Rope configuration file '{0}' does"""
171 """ not exist.""").format(configfile)) 209 """ not exist.""").format(configfile))
172 210
173 def isSupportedLanguage(self, language):
174 """
175 Public method to check, if the given language is supported.
176
177 @param language editor programming language to check
178 @type str
179 @return flag indicating the support status
180 @rtype bool
181 """
182 return language in self.__editorLanguageMapping
183
184 def getCompletions(self, editor, context): 211 def getCompletions(self, editor, context):
185 """ 212 """
186 Public method to calculate the possible completions. 213 Public method to calculate the possible completions.
187 214
188 Note: This is the synchronous variant for eric6 before 17.11. 215 Note: This is the synchronous variant for eric6 before 17.11.
195 @rtype list of str 222 @rtype list of str
196 """ 223 """
197 # reset the completions buffer 224 # reset the completions buffer
198 self.__completions = None 225 self.__completions = None
199 226
200 language = editor.getLanguage() 227 if not self.__idString(editor):
201 if language not in self.__editorLanguageMapping:
202 return [] 228 return []
203 229
204 self.requestCompletions(editor, context, "") 230 self.requestCompletions(editor, context, "")
205 231
206 # emulate the synchronous behaviour 232 # emulate the synchronous behaviour
224 @param context flag indicating to autocomplete a context 250 @param context flag indicating to autocomplete a context
225 @type bool 251 @type bool
226 @param acText text to be completed 252 @param acText text to be completed
227 @type str 253 @type str
228 """ 254 """
229 language = editor.getLanguage() 255 idString = self.__idString(editor)
230 if language not in self.__editorLanguageMapping: 256 if not idString:
231 return 257 return
232 idString = self.__editorLanguageMapping[language]
233 258
234 filename = editor.getFileName() 259 filename = editor.getFileName()
235 line, index = editor.getCursorPosition() 260 line, index = editor.getCursorPosition()
236 source = editor.text() 261 source = editor.text()
237 offset = len("".join(source.splitlines(True)[:line])) + index 262 offset = len("".join(source.splitlines(True)[:line])) + index
282 @rtype list of str 307 @rtype list of str
283 """ 308 """
284 # reset the calltips buffer 309 # reset the calltips buffer
285 self.__calltips = None 310 self.__calltips = None
286 311
287 language = editor.getLanguage() 312 idString = self.__idString(editor)
288 if language not in self.__editorLanguageMapping: 313 if not idString:
289 return [] 314 return []
290 idString = self.__editorLanguageMapping[language]
291 315
292 filename = editor.getFileName() 316 filename = editor.getFileName()
293 source = editor.text() 317 source = editor.text()
294 line, index = editor.lineIndexFromPosition(pos) 318 line, index = editor.lineIndexFromPosition(pos)
295 offset = len("".join(source.splitlines(True)[:line])) + index 319 offset = len("".join(source.splitlines(True)[:line])) + index
334 @param oldSource source code before the change 358 @param oldSource source code before the change
335 @type str 359 @type str
336 """ 360 """
337 editor = self.__vm.getOpenEditor(filename) 361 editor = self.__vm.getOpenEditor(filename)
338 if editor is not None: 362 if editor is not None:
339 language = editor.getLanguage() 363 idString = self.__idString(editor)
340 if language in self.__editorLanguageMapping: 364 if idString:
341 idString = self.__editorLanguageMapping[language]
342
343 self.__ensureActive(idString) 365 self.__ensureActive(idString)
344 self.sendJson("reportChanged", { 366 self.sendJson("reportChanged", {
345 "FileName": filename, 367 "FileName": filename,
346 "OldSource": oldSource, 368 "OldSource": oldSource,
347 }, idString=idString) 369 }, idString=idString)
357 """ 379 """
358 if self.__documentationViewer is None: 380 if self.__documentationViewer is None:
359 return 381 return
360 382
361 language = editor.getLanguage() 383 language = editor.getLanguage()
362 if language not in self.__editorLanguageMapping: 384 if not self.isSupportedLanguage(language):
363 if Preferences.getDocuViewer("ShowInfoAsRichText"): 385 if Preferences.getDocuViewer("ShowInfoAsRichText"):
364 warning = self.tr("Language <b>{0}</b> is not supported.")\ 386 warning = self.tr("Language <b>{0}</b> is not supported.")\
365 .format(language) 387 .format(language)
366 else: 388 else:
367 warning = self.tr("Language '{0}' is not supported.")\ 389 warning = self.tr("Language '{0}' is not supported.")\
368 .format(language) 390 .format(language)
369 self.__documentationViewer.documentationReady( 391 self.__documentationViewer.documentationReady(
370 warning, isWarning=True) 392 warning, isWarning=True)
371 return 393 return
372 394
373 idString = self.__editorLanguageMapping[language] 395 idString = self.__idString(editor)
396 if not idString:
397 return
374 398
375 filename = editor.getFileName() 399 filename = editor.getFileName()
376 source = editor.text() 400 source = editor.text()
377 line, index = editor.getCursorPosition() 401 line, index = editor.getCursorPosition()
378 offset = len("".join(source.splitlines(True)[:line])) + index 402 offset = len("".join(source.splitlines(True)[:line])) + index
494 @rtype bool 518 @rtype bool
495 """ 519 """
496 ok = False 520 ok = False
497 521
498 if interpreter: 522 if interpreter:
499 configDir = os.path.join(Globals.getConfigDir(), "rope", idString) 523 if idString == CodeAssistServer.IdProject:
524 configDir = self.__e5project.getProjectPath()
525 else:
526 configDir = os.path.join(Globals.getConfigDir(), "rope",
527 idString)
500 if not os.path.exists(configDir): 528 if not os.path.exists(configDir):
501 os.makedirs(configDir) 529 os.makedirs(configDir)
502 530
503 client = os.path.join(os.path.dirname(__file__), 531 client = os.path.join(os.path.dirname(__file__),
504 "CodeAssistClient.py") 532 "CodeAssistClient.py")
529 @rtype bool 557 @rtype bool
530 """ 558 """
531 ok = idString in self.connectionNames() 559 ok = idString in self.connectionNames()
532 if not ok: 560 if not ok:
533 # client is not running 561 # client is not running
534 try: 562 if idString == CodeAssistServer.IdProject:
535 # new code using virtual environments 563 interpreter = self.__interpreterForProject()
536 venvManager = e5App().getObject("VirtualEnvManager") 564 else:
537 if idString == "Python2": 565 interpreter = ""
538 # Python 2 566 venvName = ""
539 venvName = Preferences.getDebugger("Python2VirtualEnv") 567 try:
540 if not venvName and sys.version_info[0] == 2: 568 # new code using virtual environments
541 try: 569 venvManager = e5App().getObject("VirtualEnvManager")
542 venvName, _ = venvManager.getDefaultEnvironment() 570 if idString == "Python2":
543 except AttributeError: 571 # Python 2
544 # ignore for eric6 < 18.10 572 venvName = Preferences.getDebugger("Python2VirtualEnv")
545 pass 573 if not venvName and sys.version_info[0] == 2:
546 elif idString == "Python3": 574 try:
547 # Python 3 575 venvName, _ = \
548 venvName = Preferences.getDebugger("Python3VirtualEnv") 576 venvManager.getDefaultEnvironment()
549 if not venvName and sys.version_info[0] == 3: 577 except AttributeError:
550 try: 578 # ignore for eric6 < 18.10
551 venvName, _ = venvManager.getDefaultEnvironment() 579 pass
552 except AttributeError: 580 elif idString == "Python3":
553 # ignore for eric6 < 18.10 581 # Python 3
554 pass 582 venvName = Preferences.getDebugger("Python3VirtualEnv")
555 else: 583 if not venvName and sys.version_info[0] == 3:
556 venvName = "" 584 try:
557 if venvName: 585 venvName, _ = \
558 interpreter = e5App().getObject("VirtualEnvManager")\ 586 venvManager.getDefaultEnvironment()
559 .getVirtualenvInterpreter(venvName) 587 except AttributeError:
560 else: 588 # ignore for eric6 < 18.10
561 interpreter = "" 589 pass
562 except KeyError: 590 if venvName:
563 # backward compatibility (eric <18.07) 591 interpreter = \
564 if idString == "Python2": 592 venvManager.getVirtualenvInterpreter(venvName)
565 # Python 2 593 except KeyError:
566 interpreter = Preferences.getDebugger("PythonInterpreter") 594 # backward compatibility (eric <18.07)
567 elif idString == "Python3": 595 if idString == "Python2":
568 # Python 3 596 # Python 2
569 interpreter = Preferences.getDebugger("Python3Interpreter") 597 interpreter = \
570 else: 598 Preferences.getDebugger("PythonInterpreter")
571 interpreter = "" 599 elif idString == "Python3":
600 # Python 3
601 interpreter = \
602 Preferences.getDebugger("Python3Interpreter")
572 if interpreter: 603 if interpreter:
573 ok = self.__startCodeAssistClient(interpreter, idString) 604 ok = self.__startCodeAssistClient(interpreter, idString)
574 else: 605 else:
575 ok = False 606 ok = False
576 return ok 607 return ok
608
609 def __interpreterForProject(self):
610 """
611 Private method to determine the interpreter for the current project.
612
613 @return interpreter of the current project
614 @rtype str
615 """
616 interpreter = ""
617 projectLanguage = self.__e5project.getProjectLanguage()
618
619 if projectLanguage.startswith("Python"):
620 try:
621 # new code using virtual environments
622 venvManager = e5App().getObject("VirtualEnvManager")
623
624 # get virtual environment from project first
625 venvName = self.__e5project.getDebugProperty("VIRTUALENV")
626 if not venvName:
627 # get it from debugger settings next
628 if projectLanguage == "Python2":
629 # Python 2
630 venvName = Preferences.getDebugger("Python2VirtualEnv")
631 if not venvName and sys.version_info[0] == 2:
632 try:
633 venvName, _ = \
634 venvManager.getDefaultEnvironment()
635 except AttributeError:
636 # ignore for eric6 < 18.10
637 pass
638 elif projectLanguage == "Python3":
639 # Python 3
640 venvName = Preferences.getDebugger("Python3VirtualEnv")
641 if not venvName and sys.version_info[0] == 3:
642 try:
643 venvName, _ = \
644 venvManager.getDefaultEnvironment()
645 except AttributeError:
646 # ignore for eric6 < 18.10
647 pass
648 else:
649 venvName = ""
650 if venvName:
651 interpreter = \
652 venvManager.getVirtualenvInterpreter(venvName)
653 except KeyError:
654 # backward compatibility (eric < 18.07)
655 # get interpreter from project first
656 interpreter = self.__e5project.getDebugProperty("INTERPRETER")
657 if not interpreter or not Utilities.isinpath(interpreter):
658 # get it from debugger settings second
659 if projectLanguage == "Python2":
660 interpreter = Preferences.getDebugger(
661 "PythonInterpreter")
662 elif projectLanguage == "Python3":
663 interpreter = Preferences.getDebugger(
664 "Python3Interpreter")
665
666 return interpreter
577 667
578 @pyqtSlot() 668 @pyqtSlot()
579 def handleNewConnection(self): 669 def handleNewConnection(self):
580 """ 670 """
581 Public slot for new incoming connections from a client. 671 Public slot for new incoming connections from a client.
597 "rope", self.tr("Rope"), self.requestCodeDocumentation, 687 "rope", self.tr("Rope"), self.requestCodeDocumentation,
598 self.isSupportedLanguage) 688 self.isSupportedLanguage)
599 except AttributeError: 689 except AttributeError:
600 # eric6 before 17.11 doesn't have this 690 # eric6 before 17.11 doesn't have this
601 pass 691 pass
692
693 self.__e5project.projectClosed.connect(self.__projectClosed)
602 694
603 def deactivate(self): 695 def deactivate(self):
604 """ 696 """
605 Public method to deactivate the code assist server. 697 Public method to deactivate the code assist server.
606 """ 698 """
611 self.__documentationViewer.unregisterProvider("rope") 703 self.__documentationViewer.unregisterProvider("rope")
612 704
613 for idString in self.connectionNames(): 705 for idString in self.connectionNames():
614 self.sendJson("closeProject", {}, flush=True, idString=idString) 706 self.sendJson("closeProject", {}, flush=True, idString=idString)
615 707
708 try:
709 self.__e5project.projectClosed.disconnect(self.__projectClosed)
710 except TypeError:
711 # ignore it, the signal may be disconnected already
712 pass
713
616 self.stopAllClients() 714 self.stopAllClients()
715
716 @pyqtSlot()
717 def __projectClosed(self):
718 """
719 Private slot to handle the projectClosed signal.
720 """
721 self.stopClient(idString=CodeAssistServer.IdProject)
617 722
618 ####################################################################### 723 #######################################################################
619 ## Methods below handle setting/unsetting the hook methods 724 ## Methods below handle setting/unsetting the hook methods
620 ####################################################################### 725 #######################################################################
621 726

eric ide

mercurial