PluginRefactoringRope.py

branch
server_client_variant
changeset 191
2af42804bca2
parent 189
2711fdd91925
child 195
5d614a567be3
equal deleted inserted replaced
190:a1b9b4975806 191:2af42804bca2
9 9
10 from __future__ import unicode_literals 10 from __future__ import unicode_literals
11 11
12 import os 12 import os
13 13
14 from PyQt5.QtCore import Qt, QObject, QTranslator, QCoreApplication, QTimer 14 from PyQt5.QtCore import Qt, QObject, QTranslator, QCoreApplication
15 15
16 from E5Gui.E5Application import e5App 16 from E5Gui.E5Application import e5App
17 17
18 import Preferences 18 import Preferences
19 import Utilities 19 import Utilities
20
21 from Preferences.Shortcuts import readShortcuts
22 20
23 # Start-Of-Header 21 # Start-Of-Header
24 name = "Refactoring Rope Plugin" 22 name = "Refactoring Rope Plugin"
25 author = "Detlev Offenbach <detlev@die-offenbachs.de>" 23 author = "Detlev Offenbach <detlev@die-offenbachs.de>"
26 autoactivate = True 24 autoactivate = True
102 "ropeCallTipsPage": [ 100 "ropeCallTipsPage": [
103 QCoreApplication.translate("RefactoringRopePlugin", "Rope"), 101 QCoreApplication.translate("RefactoringRopePlugin", "Rope"),
104 os.path.join("RefactoringRope", "ConfigurationPage", 102 os.path.join("RefactoringRope", "ConfigurationPage",
105 "preferences-refactoring.png"), 103 "preferences-refactoring.png"),
106 createCallTipsPage, "editorCalltipsPage", None], 104 createCallTipsPage, "editorCalltipsPage", None],
107 } 105 "ropeMouseClickHandlerPage": [
108
109 ui = e5App().getObject("UserInterface")
110 if ui.versionIsNewer("6.0.99", "20150627") or ui.versionIsNewer("16.10"):
111 data["ropeMouseClickHandlerPage"] = [
112 QCoreApplication.translate("RefactoringRopePlugin", "Rope"), 106 QCoreApplication.translate("RefactoringRopePlugin", "Rope"),
113 os.path.join("RefactoringRope", "ConfigurationPage", 107 os.path.join("RefactoringRope", "ConfigurationPage",
114 "preferences-refactoring.png"), 108 "preferences-refactoring.png"),
115 createMouseClickHandlerPage, "1editorMouseClickHandlers", None] 109 createMouseClickHandlerPage, "1editorMouseClickHandlers", None],
110 }
116 111
117 return data 112 return data
118 113
119 114
120 def prepareUninstall(): 115 def prepareUninstall():
141 self.__initialize() 136 self.__initialize()
142 137
143 self.__defaults = { 138 self.__defaults = {
144 "CodeAssistEnabled": False, 139 "CodeAssistEnabled": False,
145 "MaxFixes": 10, 140 "MaxFixes": 10,
146 "CodeAssistTimeout": 100,
147 141
148 "CodeAssistCalltipsEnabled": False, 142 "CodeAssistCalltipsEnabled": False,
149 "CalltipsMaxFixes": 10, 143 "CalltipsMaxFixes": 10,
150 144
151 "MouseClickEnabled": True, 145 "MouseClickEnabled": True,
153 "MouseClickGotoButton": int(Qt.LeftButton), 147 "MouseClickGotoButton": int(Qt.LeftButton),
154 } 148 }
155 149
156 self.__translator = None 150 self.__translator = None
157 self.__loadTranslator() 151 self.__loadTranslator()
158
159 self.__acTimer = QTimer(self)
160 self.__acTimer.setSingleShot(True)
161 self.__acTimer.setInterval(self.getPreferences("CodeAssistTimeout"))
162 self.__acTimer.timeout.connect(self.__codeAssist)
163 152
164 def __initialize(self): 153 def __initialize(self):
165 """ 154 """
166 Private slot to (re)initialize the plugin. 155 Private slot to (re)initialize the plugin.
167 """ 156 """
168 self.__object = None 157 self.__refactoringServer = None
169 self.__caObject = None 158 self.__codeAssist = None
170
171 self.__mainAct = None
172 self.__mainMenu = None
173 159
174 self.__editors = [] 160 self.__editors = []
175 161
176 self.__currentEditor = None 162 self.__currentEditor = None
177 self.__savedEditorName = None 163 self.__savedEditorName = None
181 """ 167 """
182 Public method to activate this plugin. 168 Public method to activate this plugin.
183 169
184 @return tuple of None and activation status (boolean) 170 @return tuple of None and activation status (boolean)
185 """ 171 """
186 global error
187 error = "" # clear previous error
188
189 global refactoringRopePluginObject 172 global refactoringRopePluginObject
190 refactoringRopePluginObject = self 173 refactoringRopePluginObject = self
191 174
175 from RefactoringRope.CodeAssist import CodeAssist
176 self.__codeAssist = CodeAssist(self, self)
177
192 from RefactoringRope.RefactoringServer import RefactoringServer 178 from RefactoringRope.RefactoringServer import RefactoringServer
193 from RefactoringRope.CodeAssist import CodeAssist 179 self.__refactoringServer = RefactoringServer(self, self.__ui)
194 180 self.__refactoringServer.activate()
195 self.__caObject = CodeAssist(self, self)
196
197 self.__object = RefactoringServer(self, self.__ui)
198 self.__object.initActions()
199 e5App().registerPluginObject("RefactoringRope", self.__object)
200 try:
201 readShortcuts(pluginName="RefactoringRope")
202 except TypeError:
203 # backwards comaytibility, ignore
204 pass
205
206 self.__mainMenu = self.__object.initMenu()
207 extrasAct = self.__ui.getMenuBarAction("extras")
208 self.__mainAct = self.__ui.menuBar().insertMenu(
209 extrasAct, self.__mainMenu)
210 self.__mainAct.setEnabled(False)
211
212 if e5App().getObject("Project").isOpen():
213 self.__object.projectOpened()
214 181
215 e5App().getObject("ViewManager").editorOpenedEd.connect( 182 e5App().getObject("ViewManager").editorOpenedEd.connect(
216 self.__editorOpened) 183 self.__editorOpened)
217 e5App().getObject("ViewManager").editorClosedEd.connect( 184 e5App().getObject("ViewManager").editorClosedEd.connect(
218 self.__editorClosed) 185 self.__editorClosed)
219 186
220 e5App().getObject("Project").projectOpened.connect(
221 self.__object.projectOpened)
222 e5App().getObject("Project").projectPropertiesChanged.connect(
223 self.__object.projectOpened)
224 e5App().getObject("Project").projectClosed.connect(
225 self.__object.projectClosed)
226 e5App().getObject("Project").newProject.connect(
227 self.__object.projectOpened)
228
229 if e5App().getObject("Project").isOpen(): 187 if e5App().getObject("Project").isOpen():
230 for editor in e5App().getObject("ViewManager").getOpenEditors(): 188 for editor in e5App().getObject("ViewManager").getOpenEditors():
231 self.__editorOpened(editor) 189 self.__editorOpened(editor)
232 190
233 return None, True 191 return None, True
234 192
235 def deactivate(self): 193 def deactivate(self):
236 """ 194 """
237 Public method to deactivate this plugin. 195 Public method to deactivate this plugin.
238 """ 196 """
239 e5App().unregisterPluginObject("RefactoringRope") 197 self.__refactoringServer.deactivate()
240 198
241 e5App().getObject("ViewManager").editorOpenedEd.disconnect( 199 e5App().getObject("ViewManager").editorOpenedEd.disconnect(
242 self.__editorOpened) 200 self.__editorOpened)
243 e5App().getObject("ViewManager").editorClosedEd.disconnect( 201 e5App().getObject("ViewManager").editorClosedEd.disconnect(
244 self.__editorClosed) 202 self.__editorClosed)
245
246 e5App().getObject("Project").projectOpened.disconnect(
247 self.__object.projectOpened)
248 e5App().getObject("Project").projectPropertiesChanged.disconnect(
249 self.__object.projectOpened)
250 e5App().getObject("Project").projectClosed.disconnect(
251 self.__object.projectClosed)
252 e5App().getObject("Project").newProject.disconnect(
253 self.__object.projectOpened)
254
255 self.__ui.menuBar().removeAction(self.__mainAct)
256 203
257 for editor in self.__editors[:]: 204 for editor in self.__editors[:]:
258 self.__editorClosed(editor) 205 self.__editorClosed(editor)
259 206
260 self.__initialize() 207 self.__initialize()
318 self.__editorClosed(editor) 265 self.__editorClosed(editor)
319 elif key in ["MouseClickGotoModifiers", "MouseClickGotoButton"]: 266 elif key in ["MouseClickGotoModifiers", "MouseClickGotoButton"]:
320 for editor in self.__editors: 267 for editor in self.__editors:
321 self.__disconnectMouseClickHandler(editor) 268 self.__disconnectMouseClickHandler(editor)
322 self.__connectMouseClickHandler(editor) 269 self.__connectMouseClickHandler(editor)
323 elif key == "CodeAssistTimeout": 270
324 self.__acTimer.setInterval(value) 271 # TODO: get this info from CodeAssistClient or Server
325
326 def __determineLanguages(self): 272 def __determineLanguages(self):
327 """ 273 """
328 Private method to determine the valid language strings. 274 Private method to determine the valid language strings.
329 275
330 @return list of valid language strings (list of string) 276 @return list of valid language strings (list of string)
339 if interpreter and Utilities.isinpath(interpreter): 285 if interpreter and Utilities.isinpath(interpreter):
340 langs.extend(["Python3", "Pygments|Python 3"]) 286 langs.extend(["Python3", "Pygments|Python 3"])
341 287
342 return langs 288 return langs
343 289
290 # TODO: move this to CodeAssist
344 def __editorOpened(self, editor): 291 def __editorOpened(self, editor):
345 """ 292 """
346 Private slot called, when a new editor was opened. 293 Private slot called, when a new editor was opened.
347 294
348 @param editor reference to the new editor (QScintilla.Editor) 295 @param editor reference to the new editor (QScintilla.Editor)
353 self.__connectEditor(editor) 300 self.__connectEditor(editor)
354 301
355 editor.languageChanged.connect(self.__editorLanguageChanged) 302 editor.languageChanged.connect(self.__editorLanguageChanged)
356 self.__editors.append(editor) 303 self.__editors.append(editor)
357 304
305 # TODO: move this to CodeAssist
358 def __editorClosed(self, editor): 306 def __editorClosed(self, editor):
359 """ 307 """
360 Private slot called, when an editor was closed. 308 Private slot called, when an editor was closed.
361 309
362 @param editor reference to the editor (QScintilla.Editor) 310 @param editor reference to the editor (QScintilla.Editor)
364 if editor in self.__editors: 312 if editor in self.__editors:
365 editor.languageChanged.disconnect(self.__editorLanguageChanged) 313 editor.languageChanged.disconnect(self.__editorLanguageChanged)
366 self.__disconnectEditor(editor) 314 self.__disconnectEditor(editor)
367 self.__editors.remove(editor) 315 self.__editors.remove(editor)
368 316
317 # TODO: move this to CodeAssist
369 def __editorLanguageChanged(self, language): 318 def __editorLanguageChanged(self, language):
370 """ 319 """
371 Private slot to handle the language change of an editor. 320 Private slot to handle the language change of an editor.
372 321
373 @param language programming language of the editor (string) 322 @param language programming language of the editor (string)
374 """ 323 """
375 editor = self.sender() 324 editor = self.sender()
376 langs = self.__determineLanguages() 325 langs = self.__determineLanguages()
377 326
378 if language in langs: 327 if language in langs:
379 try: 328 if editor.getCompletionListHook("rope") is None or \
380 if editor.getCompletionListHook("rope") is None or \ 329 editor.getCallTipHook("rope") is None:
381 editor.getCallTipHook("rope") is None: 330 self.__connectEditor(editor)
382 self.__connectEditor(editor)
383 except AttributeError:
384 # old interface (before 6.1.0)
385 if editor.autoCompletionHook() != self.codeAssist or \
386 editor.callTipHook() != self.codeAssistCallTip:
387 self.__connectEditor(editor)
388 else: 331 else:
389 self.__disconnectEditor(editor) 332 self.__disconnectEditor(editor)
390 333
391 def __connectEditor(self, editor): 334 def __connectEditor(self, editor):
392 """ 335 """
395 @param editor reference to the editor (QScintilla.Editor) 338 @param editor reference to the editor (QScintilla.Editor)
396 """ 339 """
397 editor.editorAboutToBeSaved.connect(self.__editorAboutToBeSaved) 340 editor.editorAboutToBeSaved.connect(self.__editorAboutToBeSaved)
398 editor.editorSaved.connect(self.__editorSaved) 341 editor.editorSaved.connect(self.__editorSaved)
399 342
343 # TODO: move this to CodeAssist
400 if self.getPreferences("CodeAssistEnabled"): 344 if self.getPreferences("CodeAssistEnabled"):
401 self.__setAutoCompletionHook(editor) 345 self.__setAutoCompletionHook(editor)
402 if self.getPreferences("CodeAssistCalltipsEnabled"): 346 if self.getPreferences("CodeAssistCalltipsEnabled"):
403 self.__setCalltipsHook(editor) 347 self.__setCalltipsHook(editor)
404 348
411 Private method to connect the mouse click handler to an editor. 355 Private method to connect the mouse click handler to an editor.
412 356
413 @param editor reference to the editor (QScintilla.Editor) 357 @param editor reference to the editor (QScintilla.Editor)
414 """ 358 """
415 if self.getPreferences("MouseClickGotoButton"): 359 if self.getPreferences("MouseClickGotoButton"):
416 try: 360 editor.setMouseClickHandler(
417 editor.setMouseClickHandler( 361 "rope",
418 "rope", 362 self.getPreferences("MouseClickGotoModifiers"),
419 self.getPreferences("MouseClickGotoModifiers"), 363 self.getPreferences("MouseClickGotoButton"),
420 self.getPreferences("MouseClickGotoButton"), 364 self.__refactoringServer.gotoDefinition
421 self.__object.gotoDefinition 365 )
422 )
423 except AttributeError:
424 # eric versions before 6.1.0 don't support this
425 pass
426 366
427 def __disconnectEditor(self, editor): 367 def __disconnectEditor(self, editor):
428 """ 368 """
429 Private method to disconnect an editor. 369 Private method to disconnect an editor.
430 370
435 editor.editorSaved.disconnect(self.__editorSaved) 375 editor.editorSaved.disconnect(self.__editorSaved)
436 except TypeError: 376 except TypeError:
437 # just ignore it 377 # just ignore it
438 pass 378 pass
439 379
440 try: 380 # TODO: move this to CodeAssist
441 if editor.getCompletionListHook("rope"): 381 if editor.getCompletionListHook("rope"):
442 self.__unsetAutoCompletionHook(editor) 382 self.__unsetAutoCompletionHook(editor)
443 except AttributeError: 383 if editor.getCallTipHook("rope"):
444 # old interface (before 6.1.0) 384 self.__unsetCalltipsHook(editor)
445 if editor.autoCompletionHook() == self.codeAssist:
446 self.__unsetAutoCompletionHook(editor)
447 try:
448 if editor.getCallTipHook("rope"):
449 self.__unsetCalltipsHook(editor)
450 except AttributeError:
451 # old interface (before 6.1.0)
452 if editor.callTipHook() == self.codeAssistCallTip:
453 self.__unsetCalltipsHook(editor)
454 385
455 self.__disconnectMouseClickHandler(editor) 386 self.__disconnectMouseClickHandler(editor)
456 387
388 # TODO: move this to CodeAssist
457 def __disconnectMouseClickHandler(self, editor): 389 def __disconnectMouseClickHandler(self, editor):
458 """ 390 """
459 Private method to disconnect the mouse click handler from an editor. 391 Private method to disconnect the mouse click handler from an editor.
460 392
461 @param editor reference to the editor (QScintilla.Editor) 393 @param editor reference to the editor (QScintilla.Editor)
462 """ 394 """
463 try: 395 editor.removeMouseClickHandlers("rope")
464 editor.removeMouseClickHandlers("rope") 396
465 except AttributeError: 397 # TODO: move this to CodeAssist
466 # eric versions before 6.1.0 don't support this
467 pass
468
469 def __completionListSelected(self, userListId, txt):
470 """
471 Private slot to handle the selection from the completion list.
472
473 @param userListId the ID of the user list (should be 1) (integer)
474 @param txt the selected text (QString)
475 """
476 from QScintilla.Editor import EditorAutoCompletionListID
477
478 editor = self.sender()
479 if userListId == EditorAutoCompletionListID:
480 lst = txt.split()
481 if len(lst) > 1:
482 txt = lst[0]
483
484 if Preferences.getEditor("AutoCompletionReplaceWord"):
485 editor.selectCurrentWord()
486 editor.removeSelectedText()
487 line, col = editor.getCursorPosition()
488 else:
489 line, col = editor.getCursorPosition()
490 wLeft = editor.getWordLeft(line, col)
491 if not txt.startswith(wLeft):
492 editor.selectCurrentWord()
493 editor.removeSelectedText()
494 line, col = editor.getCursorPosition()
495 elif wLeft:
496 txt = txt[len(wLeft):]
497 editor.insert(txt)
498 editor.setCursorPosition(line, col + len(txt))
499
500 def __setAutoCompletionHook(self, editor): 398 def __setAutoCompletionHook(self, editor):
501 """ 399 """
502 Private method to set the autocompletion hook. 400 Private method to set the autocompletion hook.
503 401
504 @param editor reference to the editor (QScintilla.Editor) 402 @param editor reference to the editor (QScintilla.Editor)
505 """ 403 """
506 try: 404 editor.addCompletionListHook("rope", self.getCompletionsList)
507 editor.addCompletionListHook("rope", self.getCompletionsList) 405
508 except AttributeError: 406 # TODO: move this to CodeAssist
509 # old interface (before 6.1.0)
510 editor.userListActivated.connect(self.__completionListSelected)
511 editor.setAutoCompletionHook(self.codeAssist)
512
513 def __unsetAutoCompletionHook(self, editor): 407 def __unsetAutoCompletionHook(self, editor):
514 """ 408 """
515 Private method to unset the autocompletion hook. 409 Private method to unset the autocompletion hook.
516 410
517 @param editor reference to the editor (QScintilla.Editor) 411 @param editor reference to the editor (QScintilla.Editor)
518 """ 412 """
519 try: 413 editor.removeCompletionListHook("rope")
520 editor.removeCompletionListHook("rope") 414
521 except AttributeError: 415 # TODO: move this to CodeAssist
522 # old interface (before 6.1.0)
523 editor.unsetAutoCompletionHook()
524 editor.userListActivated.disconnect(self.__completionListSelected)
525
526 def codeAssist(self, editor, context=False):
527 """
528 Public method to determine the autocompletion proposals.
529
530 @param editor reference to the editor object, that called this method
531 QScintilla.Editor)
532 @param context flag indicating to autocomplete a context (boolean)
533 """
534 self.__currentEditor = editor
535 if self.getPreferences("CodeAssistTimeout"):
536 self.__acTimer.stop()
537 self.__acTimer.start()
538 else:
539 self.__codeAssist()
540
541 def __codeAssist(self):
542 """
543 Private slot to show a list with completion proposals.
544 """
545 from QScintilla.Editor import EditorAutoCompletionListID
546
547 if self.__currentEditor is not None:
548 if self.__currentEditor.isListActive():
549 self.__currentEditor.cancelList()
550 completions = self.getCompletionsList(self.__currentEditor, False)
551 if len(completions) == 0:
552 # try QScintilla autocompletion
553 self.__currentEditor.autoCompleteQScintilla()
554 else:
555 completions.sort()
556 self.__currentEditor.showUserList(EditorAutoCompletionListID,
557 completions)
558
559 def getCompletionsList(self, editor, context): 416 def getCompletionsList(self, editor, context):
560 """ 417 """
561 Public method to get a list of possible completions. 418 Public method to get a list of possible completions.
562 419
563 @param editor reference to the editor object, that called this method 420 @param editor reference to the editor object, that called this method
564 (QScintilla.Editor) 421 (QScintilla.Editor)
565 @param context flag indicating to autocomplete a context (boolean) 422 @param context flag indicating to autocomplete a context (boolean)
566 @return list of possible completions (list of strings) 423 @return list of possible completions (list of strings)
567 """ 424 """
568 completions = self.__caObject.getCompletions(editor) 425 completions = self.__codeAssist.getCompletions(editor)
569 return completions 426 return completions
570 427
571 def __editorAboutToBeSaved(self, filename): 428 def __editorAboutToBeSaved(self, filename):
572 """ 429 """
573 Private slot to get the old contents of the named file. 430 Private slot to get the old contents of the named file.
589 Private slot to activate SOA. 446 Private slot to activate SOA.
590 447
591 @param filename name of the file that was saved (string) 448 @param filename name of the file that was saved (string)
592 """ 449 """
593 if filename == self.__savedEditorName and self.__oldEditorText: 450 if filename == self.__savedEditorName and self.__oldEditorText:
594 self.__object.reportChanged(self.__savedEditorName, 451 self.__refactoringServer.reportChanged(self.__savedEditorName,
595 self.__oldEditorText) 452 self.__oldEditorText)
596 self.__caObject.reportChanged(self.__savedEditorName, 453 self.__codeAssist.reportChanged(self.__savedEditorName,
597 self.__oldEditorText) 454 self.__oldEditorText)
598 else: 455 else:
599 self.__object.reportChanged(filename, "") 456 self.__refactoringServer.reportChanged(filename, "")
600 self.__caObject.reportChanged(filename, "") 457 self.__codeAssist.reportChanged(filename, "")
601 458
459 # TODO: move this to CodeAssist
602 def __setCalltipsHook(self, editor): 460 def __setCalltipsHook(self, editor):
603 """ 461 """
604 Private method to set the calltip hook. 462 Private method to set the calltip hook.
605 463
606 @param editor reference to the editor (QScintilla.Editor) 464 @param editor reference to the editor (QScintilla.Editor)
607 """ 465 """
608 try: 466 editor.addCallTipHook("rope", self.codeAssistCallTip)
609 editor.addCallTipHook("rope", self.codeAssistCallTip) 467
610 except AttributeError: 468 # TODO: move this to CodeAssist
611 # old interface (before 6.1.0)
612 editor.setCallTipHook(self.codeAssistCallTip)
613
614 def __unsetCalltipsHook(self, editor): 469 def __unsetCalltipsHook(self, editor):
615 """ 470 """
616 Private method to unset the calltip hook. 471 Private method to unset the calltip hook.
617 472
618 @param editor reference to the editor (QScintilla.Editor) 473 @param editor reference to the editor (QScintilla.Editor)
619 """ 474 """
620 try: 475 editor.removeCallTipHook("rope")
621 editor.removeCallTipHook("rope") 476
622 except AttributeError: 477 # TODO: move this to CodeAssist
623 # old interface (before 6.1.0)
624 editor.unsetCallTipHook()
625
626 def codeAssistCallTip(self, editor, pos, commas): 478 def codeAssistCallTip(self, editor, pos, commas):
627 """ 479 """
628 Public method to return a list of calltips. 480 Public method to return a list of calltips.
629 481
630 @param editor reference to the editor (QScintilla.Editor) 482 @param editor reference to the editor (QScintilla.Editor)
631 @param pos position in the text for the calltip (integer) 483 @param pos position in the text for the calltip (integer)
632 @param commas minimum number of commas contained in the calltip 484 @param commas minimum number of commas contained in the calltip
633 (integer) 485 (integer)
634 @return list of possible calltips (list of strings) 486 @return list of possible calltips (list of strings)
635 """ 487 """
636 cts = self.__caObject.getCallTips(pos, editor) 488 cts = self.__codeAssist.getCallTips(pos, editor)
637 return cts 489 return cts
638 490
639 # 491 #
640 # eflag: noqa = M801 492 # eflag: noqa = M801

eric ide

mercurial