src/eric7/JediInterface/JediServer.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9264
18a7312cfdb3
child 9287
ce3ceb47300c
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
29 29
30 class JediServer(EricJsonServer): 30 class JediServer(EricJsonServer):
31 """ 31 """
32 Class implementing the interface to the jedi library. 32 Class implementing the interface to the jedi library.
33 """ 33 """
34
34 IdProject = "Project" 35 IdProject = "Project"
35 36
36 PictureIDs = { 37 PictureIDs = {
37 "class": "?{0}".format(Editor.ClassID), 38 "class": "?{0}".format(Editor.ClassID),
38 "_class": "?{0}".format(Editor.ClassProtectedID), 39 "_class": "?{0}".format(Editor.ClassProtectedID),
39 "__class": "?{0}".format(Editor.ClassPrivateID), 40 "__class": "?{0}".format(Editor.ClassPrivateID),
40 "instance": "?{0}".format(Editor.ClassID), 41 "instance": "?{0}".format(Editor.ClassID),
53 "_statement": "?{0}".format(Editor.AttributeProtectedID), 54 "_statement": "?{0}".format(Editor.AttributeProtectedID),
54 "__statement": "?{0}".format(Editor.AttributePrivateID), 55 "__statement": "?{0}".format(Editor.AttributePrivateID),
55 "import": "", 56 "import": "",
56 "None": "", 57 "None": "",
57 } 58 }
58 59
59 def __init__(self, viewManager, project, ui): 60 def __init__(self, viewManager, project, ui):
60 """ 61 """
61 Constructor 62 Constructor
62 63
63 @param viewManager reference to the viewmanager object 64 @param viewManager reference to the viewmanager object
64 @type ViewManager 65 @type ViewManager
65 @param project reference to the project object 66 @param project reference to the project object
66 @type Project 67 @type Project
67 @param ui reference to the user interface 68 @param ui reference to the user interface
68 @type UserInterface 69 @type UserInterface
69 """ 70 """
70 super().__init__( 71 super().__init__("JediServer", multiplex=True, parent=ui)
71 "JediServer", multiplex=True, parent=ui) 72
72
73 self.__ui = ui 73 self.__ui = ui
74 self.__vm = viewManager 74 self.__vm = viewManager
75 self.__ericProject = project 75 self.__ericProject = project
76 76
77 self.__editorLanguageMapping = {} 77 self.__editorLanguageMapping = {}
78 78
79 self.__documentationViewer = None 79 self.__documentationViewer = None
80 80
81 # attributes to store the resuls of the client side 81 # attributes to store the resuls of the client side
82 self.__completions = None 82 self.__completions = None
83 self.__calltips = None 83 self.__calltips = None
84 84
85 self.__methodMapping = { 85 self.__methodMapping = {
86 "CompletionsResult": self.__processCompletionsResult, 86 "CompletionsResult": self.__processCompletionsResult,
87 "CallTipsResult": self.__processCallTipsResult, 87 "CallTipsResult": self.__processCallTipsResult,
88 "DocumentationResult": self.__processDocumentationResult, 88 "DocumentationResult": self.__processDocumentationResult,
89 "HoverHelpResult": self.__processHoverHelpResult, 89 "HoverHelpResult": self.__processHoverHelpResult,
90 "GotoDefinitionResult": self.__processGotoDefinitionResult, 90 "GotoDefinitionResult": self.__processGotoDefinitionResult,
91 "GotoReferencesResult": self.__processGotoReferencesResult, 91 "GotoReferencesResult": self.__processGotoReferencesResult,
92
93 "RefactoringDiff": self.__showRefactoringDiff, 92 "RefactoringDiff": self.__showRefactoringDiff,
94 "RefactoringApplyResult": self.__checkRefactoringResult, 93 "RefactoringApplyResult": self.__checkRefactoringResult,
95
96 "ClientException": self.__processClientException, 94 "ClientException": self.__processClientException,
97 } 95 }
98 96
99 # temporary store for editor references indexed by Uuid 97 # temporary store for editor references indexed by Uuid
100 self.__editors = {} 98 self.__editors = {}
101 99
102 # Python 3 100 # Python 3
103 self.__ensureActive("Python3") 101 self.__ensureActive("Python3")
104 102
105 def __updateEditorLanguageMapping(self): 103 def __updateEditorLanguageMapping(self):
106 """ 104 """
107 Private method to update the editor language to connection mapping. 105 Private method to update the editor language to connection mapping.
108 """ 106 """
109 self.__editorLanguageMapping = {} 107 self.__editorLanguageMapping = {}
110 for name in self.connectionNames(): 108 for name in self.connectionNames():
111 if name == "Python3": 109 if name == "Python3":
112 self.__editorLanguageMapping.update({ 110 self.__editorLanguageMapping.update(
113 "Python3": "Python3", 111 {
114 "MicroPython": "Python3", 112 "Python3": "Python3",
115 "Pygments|Python": "Python3", 113 "MicroPython": "Python3",
116 "Pygments|Python 2.x": "Python3", 114 "Pygments|Python": "Python3",
117 "Cython": "Python3", 115 "Pygments|Python 2.x": "Python3",
118 }) 116 "Cython": "Python3",
119 117 }
118 )
119
120 def isSupportedLanguage(self, language): 120 def isSupportedLanguage(self, language):
121 """ 121 """
122 Public method to check, if the given language is supported. 122 Public method to check, if the given language is supported.
123 123
124 @param language editor programming language to check 124 @param language editor programming language to check
125 @type str 125 @type str
126 @return flag indicating the support status 126 @return flag indicating the support status
127 @rtype bool 127 @rtype bool
128 """ 128 """
129 return language in self.__editorLanguageMapping 129 return language in self.__editorLanguageMapping
130 130
131 def __idString(self, editor): 131 def __idString(self, editor):
132 """ 132 """
133 Private method to determine the ID string for the back-end. 133 Private method to determine the ID string for the back-end.
134 134
135 @param editor reference to the editor to determine the ID string for 135 @param editor reference to the editor to determine the ID string for
136 @type Editor 136 @type Editor
137 @return ID string 137 @return ID string
138 @rtype str 138 @rtype str
139 """ 139 """
140 idString = "" 140 idString = ""
141 141
142 language = editor.getLanguage() 142 language = editor.getLanguage()
143 if ( 143 if (
144 self.__ericProject.isOpen() and 144 self.__ericProject.isOpen()
145 self.__ericProject.getProjectLanguage() == language 145 and self.__ericProject.getProjectLanguage() == language
146 ): 146 ):
147 filename = editor.getFileName() 147 filename = editor.getFileName()
148 if self.__ericProject.isProjectSource(filename): 148 if self.__ericProject.isProjectSource(filename):
149 idString = JediServer.IdProject 149 idString = JediServer.IdProject
150 150
151 if not idString and language in self.__editorLanguageMapping: 151 if not idString and language in self.__editorLanguageMapping:
152 idString = self.__editorLanguageMapping[language] 152 idString = self.__editorLanguageMapping[language]
153 153
154 return idString 154 return idString
155 155
156 def __prepareData(self, editor): 156 def __prepareData(self, editor):
157 """ 157 """
158 Private method to gather data about current cursor position. 158 Private method to gather data about current cursor position.
159 159
160 @param editor reference to the editor object, that called this method 160 @param editor reference to the editor object, that called this method
161 @type Editor 161 @type Editor
162 @return tuple of filename, line, index, source 162 @return tuple of filename, line, index, source
163 @rtype tuple (str, int, int, str) 163 @rtype tuple (str, int, int, str)
164 """ 164 """
165 filename = editor.getFileName() 165 filename = editor.getFileName()
166 line, index = editor.getCursorPosition() 166 line, index = editor.getCursorPosition()
167 line += 1 # jedi line numbers are 1 based 167 line += 1 # jedi line numbers are 1 based
168 source = editor.text() 168 source = editor.text()
169 return filename, line, index, source 169 return filename, line, index, source
170 170
171 def requestCompletions(self, editor, context, acText): 171 def requestCompletions(self, editor, context, acText):
172 """ 172 """
173 Public method to request a list of possible completions. 173 Public method to request a list of possible completions.
174 174
175 @param editor reference to the editor object, that called this method 175 @param editor reference to the editor object, that called this method
176 @type Editor 176 @type Editor
177 @param context flag indicating to autocomplete a context 177 @param context flag indicating to autocomplete a context
178 @type bool 178 @type bool
179 @param acText text to be completed 179 @param acText text to be completed
180 @type str 180 @type str
181 """ 181 """
182 if not Preferences.getJedi("JediCompletionsEnabled"): 182 if not Preferences.getJedi("JediCompletionsEnabled"):
183 return 183 return
184 184
185 idString = self.__idString(editor) 185 idString = self.__idString(editor)
186 if not idString: 186 if not idString:
187 return 187 return
188 188
189 filename, line, index, source = self.__prepareData(editor) 189 filename, line, index, source = self.__prepareData(editor)
190 fuzzy = Preferences.getJedi("JediFuzzyCompletionsEnabled") 190 fuzzy = Preferences.getJedi("JediFuzzyCompletionsEnabled")
191 191
192 self.__ensureActive(idString) 192 self.__ensureActive(idString)
193 193
194 self.sendJson("getCompletions", { 194 self.sendJson(
195 "FileName": filename, 195 "getCompletions",
196 "Source": source, 196 {
197 "Line": line, 197 "FileName": filename,
198 "Index": index, 198 "Source": source,
199 "Fuzzy": fuzzy, 199 "Line": line,
200 "CompletionText": acText, 200 "Index": index,
201 }, idString=idString) 201 "Fuzzy": fuzzy,
202 202 "CompletionText": acText,
203 },
204 idString=idString,
205 )
206
203 def __processCompletionsResult(self, result): 207 def __processCompletionsResult(self, result):
204 """ 208 """
205 Private method to process the completions sent by the client. 209 Private method to process the completions sent by the client.
206 210
207 @param result dictionary containing the result sent by the client 211 @param result dictionary containing the result sent by the client
208 @type dict 212 @type dict
209 """ 213 """
210 names = [] 214 names = []
211 for completion in result["Completions"]: 215 for completion in result["Completions"]:
212 name = completion['Name'] 216 name = completion["Name"]
213 context = completion['FullName'] 217 context = completion["FullName"]
214 if context: 218 if context:
215 if context.endswith(".{0}".format(name)): 219 if context.endswith(".{0}".format(name)):
216 context = context.rsplit(".", 1)[0] 220 context = context.rsplit(".", 1)[0]
217 name = "{0} ({1})".format(name, context) 221 name = "{0} ({1})".format(name, context)
218 222
219 name += JediServer.PictureIDs.get(completion['CompletionType'], '') 223 name += JediServer.PictureIDs.get(completion["CompletionType"], "")
220 names.append(name) 224 names.append(name)
221 225
222 if "Error" not in result: 226 if "Error" not in result:
223 editor = self.__vm.getOpenEditor(result["FileName"]) 227 editor = self.__vm.getOpenEditor(result["FileName"])
224 if editor is not None: 228 if editor is not None:
225 editor.completionsListReady(names, 229 editor.completionsListReady(names, result["CompletionText"])
226 result["CompletionText"]) 230
227
228 def getCallTips(self, editor, pos, commas): 231 def getCallTips(self, editor, pos, commas):
229 """ 232 """
230 Public method to calculate calltips. 233 Public method to calculate calltips.
231 234
232 @param editor reference to the editor object, that called this method 235 @param editor reference to the editor object, that called this method
233 @type Editor 236 @type Editor
234 @param pos position in the text for the calltip 237 @param pos position in the text for the calltip
235 @type int 238 @type int
236 @param commas minimum number of commas contained in the calltip 239 @param commas minimum number of commas contained in the calltip
238 @return list of possible calltips 241 @return list of possible calltips
239 @rtype list of str 242 @rtype list of str
240 """ 243 """
241 if not Preferences.getJedi("JediCalltipsEnabled"): 244 if not Preferences.getJedi("JediCalltipsEnabled"):
242 return [] 245 return []
243 246
244 # reset the calltips buffer 247 # reset the calltips buffer
245 self.__calltips = None 248 self.__calltips = None
246 249
247 idString = self.__idString(editor) 250 idString = self.__idString(editor)
248 if not idString: 251 if not idString:
249 return [] 252 return []
250 253
251 filename, line, index, source = self.__prepareData(editor) 254 filename, line, index, source = self.__prepareData(editor)
252 255
253 self.__ensureActive(idString) 256 self.__ensureActive(idString)
254 self.sendJson("getCallTips", { 257 self.sendJson(
255 "FileName": filename, 258 "getCallTips",
256 "Source": source, 259 {
257 "Line": line, 260 "FileName": filename,
258 "Index": index, 261 "Source": source,
259 }, idString=idString) 262 "Line": line,
260 263 "Index": index,
264 },
265 idString=idString,
266 )
267
261 # emulate the synchronous behaviour 268 # emulate the synchronous behaviour
262 timer = QTimer() 269 timer = QTimer()
263 timer.setSingleShot(True) 270 timer.setSingleShot(True)
264 timer.start(5000) # 5s timeout 271 timer.start(5000) # 5s timeout
265 while self.__calltips is None and timer.isActive(): 272 while self.__calltips is None and timer.isActive():
266 QCoreApplication.processEvents() 273 QCoreApplication.processEvents()
267 QThread.msleep(100) 274 QThread.msleep(100)
268 275
269 return [] if self.__calltips is None else self.__calltips 276 return [] if self.__calltips is None else self.__calltips
270 277
271 def __processCallTipsResult(self, result): 278 def __processCallTipsResult(self, result):
272 """ 279 """
273 Private method to process the calltips sent by the client. 280 Private method to process the calltips sent by the client.
274 281
275 @param result dictionary containing the result sent by the client 282 @param result dictionary containing the result sent by the client
276 @type dict 283 @type dict
277 """ 284 """
278 if "Error" in result: 285 if "Error" in result:
279 self.__calltips = [] 286 self.__calltips = []
280 else: 287 else:
281 self.__calltips = result["CallTips"] 288 self.__calltips = result["CallTips"]
282 289
283 def requestCodeDocumentation(self, editor): 290 def requestCodeDocumentation(self, editor):
284 """ 291 """
285 Public method to request source code documentation for the given 292 Public method to request source code documentation for the given
286 editor. 293 editor.
287 294
288 @param editor reference to the editor to get source code documentation 295 @param editor reference to the editor to get source code documentation
289 for 296 for
290 @type Editor 297 @type Editor
291 """ 298 """
292 if self.__documentationViewer is None: 299 if self.__documentationViewer is None:
293 return 300 return
294 301
295 idString = self.__idString(editor) 302 idString = self.__idString(editor)
296 303
297 if not idString: 304 if not idString:
298 language = editor.getLanguage() 305 language = editor.getLanguage()
299 warning = ( 306 warning = self.tr("Language <b>{0}</b> is not supported.").format(language)
300 self.tr("Language <b>{0}</b> is not supported.") 307 self.__documentationViewer.documentationReady(warning, isWarning=True)
301 .format(language)
302 )
303 self.__documentationViewer.documentationReady(
304 warning, isWarning=True)
305 return 308 return
306 309
307 filename, line, index, source = self.__prepareData(editor) 310 filename, line, index, source = self.__prepareData(editor)
308 sourceLines = source.splitlines() 311 sourceLines = source.splitlines()
309 # Correct index if cursor is standing after an opening bracket 312 # Correct index if cursor is standing after an opening bracket
310 if line > 0 and index > 0 and sourceLines[line - 1][index - 1] == '(': 313 if line > 0 and index > 0 and sourceLines[line - 1][index - 1] == "(":
311 index -= 1 314 index -= 1
312 315
313 self.__ensureActive(idString) 316 self.__ensureActive(idString)
314 self.sendJson("getDocumentation", { 317 self.sendJson(
315 "FileName": filename, 318 "getDocumentation",
316 "Source": source, 319 {
317 "Line": line, 320 "FileName": filename,
318 "Index": index, 321 "Source": source,
319 }, idString=idString) 322 "Line": line,
320 323 "Index": index,
324 },
325 idString=idString,
326 )
327
321 def __processDocumentationResult(self, result): 328 def __processDocumentationResult(self, result):
322 """ 329 """
323 Private method to process the documentation sent by the client. 330 Private method to process the documentation sent by the client.
324 331
325 @param result dictionary containing the result sent by the client 332 @param result dictionary containing the result sent by the client
326 @type dict with keys 'name', 'module', 'argspec', 'docstring' 333 @type dict with keys 'name', 'module', 'argspec', 'docstring'
327 """ 334 """
328 if self.__documentationViewer is None: 335 if self.__documentationViewer is None:
329 return 336 return
330 337
331 docu = None 338 docu = None
332 339
333 if "Error" not in result: 340 if "Error" not in result:
334 docu = result["DocumentationDict"] 341 docu = result["DocumentationDict"]
335 docu["note"] = ( 342 docu["note"] = self.tr("Present in <i>{0}</i> module").format(
336 self.tr("Present in <i>{0}</i> module") 343 docu["module"]
337 .format(docu["module"])) 344 )
338 345
339 if docu is None: 346 if docu is None:
340 msg = self.tr("No documentation available.") 347 msg = self.tr("No documentation available.")
341 self.__documentationViewer.documentationReady( 348 self.__documentationViewer.documentationReady(msg, isDocWarning=True)
342 msg, isDocWarning=True)
343 else: 349 else:
344 self.__documentationViewer.documentationReady(docu) 350 self.__documentationViewer.documentationReady(docu)
345 351
346 def gotoDefinition(self, editor): 352 def gotoDefinition(self, editor):
347 """ 353 """
348 Public slot to find the definition for the word at the cursor position 354 Public slot to find the definition for the word at the cursor position
349 and go to it. 355 and go to it.
350 356
351 Note: This is executed upon a mouse click sequence. 357 Note: This is executed upon a mouse click sequence.
352 358
353 @param editor reference to the calling editor 359 @param editor reference to the calling editor
354 @type Editor 360 @type Editor
355 """ 361 """
356 if not Preferences.getJedi("MouseClickEnabled"): 362 if not Preferences.getJedi("MouseClickEnabled"):
357 return 363 return
358 364
359 idString = self.__idString(editor) 365 idString = self.__idString(editor)
360 if not idString: 366 if not idString:
361 return 367 return
362 368
363 filename, line, index, source = self.__prepareData(editor) 369 filename, line, index, source = self.__prepareData(editor)
364 370
365 self.__ensureActive(idString) 371 self.__ensureActive(idString)
366 372
367 euuid = str(uuid.uuid4()) 373 euuid = str(uuid.uuid4())
368 self.__editors[euuid] = editor 374 self.__editors[euuid] = editor
369 375
370 self.sendJson("gotoDefinition", { 376 self.sendJson(
371 "FileName": filename, 377 "gotoDefinition",
372 "Source": source, 378 {
373 "Line": line, 379 "FileName": filename,
374 "Index": index, 380 "Source": source,
375 "Uuid": euuid, 381 "Line": line,
376 }, idString=idString) 382 "Index": index,
377 383 "Uuid": euuid,
384 },
385 idString=idString,
386 )
387
378 def __processGotoDefinitionResult(self, result): 388 def __processGotoDefinitionResult(self, result):
379 """ 389 """
380 Private method callback for the goto definition result. 390 Private method callback for the goto definition result.
381 391
382 @param result dictionary containing the result data 392 @param result dictionary containing the result data
383 @type dict 393 @type dict
384 """ 394 """
385 euuid = result["Uuid"] 395 euuid = result["Uuid"]
386 if "Error" not in result: 396 if "Error" not in result:
387 # ignore errors silently 397 # ignore errors silently
388 location = result["GotoDefinitionDict"] 398 location = result["GotoDefinitionDict"]
389 if location: 399 if location:
390 self.__vm.openSourceFile(location["ModulePath"], 400 self.__vm.openSourceFile(
391 location["Line"], 401 location["ModulePath"], location["Line"], addNext=True
392 addNext=True) 402 )
393 else: 403 else:
394 ericApp().getObject("UserInterface").statusBar().showMessage( 404 ericApp().getObject("UserInterface").statusBar().showMessage(
395 self.tr('Jedi: No definition found'), 5000) 405 self.tr("Jedi: No definition found"), 5000
396 406 )
407
397 with contextlib.suppress(KeyError): 408 with contextlib.suppress(KeyError):
398 del self.__editors[euuid] 409 del self.__editors[euuid]
399 410
400 def __processGotoReferencesResult(self, result): 411 def __processGotoReferencesResult(self, result):
401 """ 412 """
402 Private method callback for the goto references result. 413 Private method callback for the goto references result.
403 414
404 @param result dictionary containing the result data 415 @param result dictionary containing the result data
405 @type dict 416 @type dict
406 """ 417 """
407 euuid = result["Uuid"] 418 euuid = result["Uuid"]
408 with contextlib.suppress(ImportError): 419 with contextlib.suppress(ImportError):
409 from QScintilla.Editor import ReferenceItem 420 from QScintilla.Editor import ReferenceItem
410 421
411 if "Error" not in result: 422 if "Error" not in result:
412 # ignore errors silently 423 # ignore errors silently
413 references = result["GotoReferencesList"] 424 references = result["GotoReferencesList"]
414 if references: 425 if references:
415 try: 426 try:
421 ReferenceItem( 432 ReferenceItem(
422 modulePath=ref["ModulePath"], 433 modulePath=ref["ModulePath"],
423 codeLine=ref["Code"], 434 codeLine=ref["Code"],
424 line=ref["Line"], 435 line=ref["Line"],
425 column=ref["Column"], 436 column=ref["Column"],
426 ) for ref in references 437 )
438 for ref in references
427 ] 439 ]
428 editor.gotoReferenceHandler(referenceItemsList) 440 editor.gotoReferenceHandler(referenceItemsList)
429 441
430 with contextlib.suppress(KeyError): 442 with contextlib.suppress(KeyError):
431 del self.__editors[euuid] 443 del self.__editors[euuid]
432 444
433 def hoverHelp(self, editor, line, index): 445 def hoverHelp(self, editor, line, index):
434 """ 446 """
435 Public method to initiate the display of mouse hover help. 447 Public method to initiate the display of mouse hover help.
436 448
437 @param editor reference to the calling editor 449 @param editor reference to the calling editor
438 @type Editor 450 @type Editor
439 @param line line number (zero based) 451 @param line line number (zero based)
440 @type int 452 @type int
441 @param index index within the line (zero based) 453 @param index index within the line (zero based)
442 @type int 454 @type int
443 """ 455 """
444 idString = self.__idString(editor) 456 idString = self.__idString(editor)
445 if not idString: 457 if not idString:
446 return 458 return
447 459
448 filename = editor.getFileName() 460 filename = editor.getFileName()
449 line += 1 # jedi line numbers are 1 based 461 line += 1 # jedi line numbers are 1 based
450 source = editor.text() 462 source = editor.text()
451 463
452 self.__ensureActive(idString) 464 self.__ensureActive(idString)
453 465
454 euuid = str(uuid.uuid4()) 466 euuid = str(uuid.uuid4())
455 self.__editors[euuid] = editor 467 self.__editors[euuid] = editor
456 468
457 self.sendJson("hoverHelp", { 469 self.sendJson(
458 "FileName": filename, 470 "hoverHelp",
459 "Source": source, 471 {
460 "Line": line, 472 "FileName": filename,
461 "Index": index, 473 "Source": source,
462 "Uuid": euuid, 474 "Line": line,
463 }, idString=idString) 475 "Index": index,
464 476 "Uuid": euuid,
477 },
478 idString=idString,
479 )
480
465 def __processHoverHelpResult(self, result): 481 def __processHoverHelpResult(self, result):
466 """ 482 """
467 Private method callback for the goto definition result. 483 Private method callback for the goto definition result.
468 484
469 @param result dictionary containing the result data 485 @param result dictionary containing the result data
470 @type dict 486 @type dict
471 """ 487 """
472 euuid = result["Uuid"] 488 euuid = result["Uuid"]
473 if "Error" not in result: 489 if "Error" not in result:
474 # ignore errors silently 490 # ignore errors silently
475 helpText = result["HoverHelp"] 491 helpText = result["HoverHelp"]
476 if helpText: 492 if helpText:
477 with contextlib.suppress(KeyError): 493 with contextlib.suppress(KeyError):
478 self.__editors[euuid].showMouseHoverHelpData( 494 self.__editors[euuid].showMouseHoverHelpData(
479 result["Line"] - 1, 495 result["Line"] - 1, result["Index"], helpText
480 result["Index"],
481 helpText
482 ) 496 )
483 else: 497 else:
484 ericApp().getObject("UserInterface").statusBar().showMessage( 498 ericApp().getObject("UserInterface").statusBar().showMessage(
485 self.tr('Jedi: No mouse hover help found'), 5000) 499 self.tr("Jedi: No mouse hover help found"), 5000
486 500 )
501
487 with contextlib.suppress(KeyError): 502 with contextlib.suppress(KeyError):
488 del self.__editors[euuid] 503 del self.__editors[euuid]
489 504
490 ####################################################################### 505 #######################################################################
491 ## Refactoring methods below 506 ## Refactoring methods below
492 ####################################################################### 507 #######################################################################
493 508
494 @pyqtSlot() 509 @pyqtSlot()
495 def refactoringRenameVariable(self): 510 def refactoringRenameVariable(self):
496 """ 511 """
497 Public slot to rename the selected variable. 512 Public slot to rename the selected variable.
498 """ 513 """
499 editor = self.__vm.activeWindow() 514 editor = self.__vm.activeWindow()
500 if editor: 515 if editor:
501 idString = self.__idString(editor) 516 idString = self.__idString(editor)
502 if not idString: 517 if not idString:
503 return 518 return
504 519
505 newName, ok = QInputDialog.getText( 520 newName, ok = QInputDialog.getText(
506 None, 521 None,
507 self.tr("Rename Variable"), 522 self.tr("Rename Variable"),
508 self.tr("Enter the new name for the variable:"), 523 self.tr("Enter the new name for the variable:"),
509 QLineEdit.EchoMode.Normal, 524 QLineEdit.EchoMode.Normal,
510 editor.selectedText() 525 editor.selectedText(),
511 ) 526 )
512 527
513 if ok and newName and self.__vm.checkAllDirty(): 528 if ok and newName and self.__vm.checkAllDirty():
514 filename = editor.getFileName() 529 filename = editor.getFileName()
515 line, index = editor.getCursorPosition() 530 line, index = editor.getCursorPosition()
516 source = editor.text() 531 source = editor.text()
517 532
518 self.__ensureActive(idString) 533 self.__ensureActive(idString)
519 534
520 euuid = str(uuid.uuid4()) 535 euuid = str(uuid.uuid4())
521 self.__editors[euuid] = editor 536 self.__editors[euuid] = editor
522 537
523 self.sendJson("renameVariable", { 538 self.sendJson(
524 "FileName": filename, 539 "renameVariable",
525 "Source": source, 540 {
526 "Line": line + 1, 541 "FileName": filename,
527 "Index": index, 542 "Source": source,
528 "Uuid": euuid, 543 "Line": line + 1,
529 "NewName": newName, 544 "Index": index,
530 }, idString=idString) 545 "Uuid": euuid,
531 546 "NewName": newName,
547 },
548 idString=idString,
549 )
550
532 @pyqtSlot() 551 @pyqtSlot()
533 def refactoringExtractNewVariable(self): 552 def refactoringExtractNewVariable(self):
534 """ 553 """
535 Public slot to extract a statement to a new variable. 554 Public slot to extract a statement to a new variable.
536 """ 555 """
537 editor = self.__vm.activeWindow() 556 editor = self.__vm.activeWindow()
538 if editor: 557 if editor:
539 idString = self.__idString(editor) 558 idString = self.__idString(editor)
540 if not idString: 559 if not idString:
541 return 560 return
542 561
543 newName, ok = QInputDialog.getText( 562 newName, ok = QInputDialog.getText(
544 None, 563 None,
545 self.tr("Extract Variable"), 564 self.tr("Extract Variable"),
546 self.tr("Enter the name for the new variable:"), 565 self.tr("Enter the name for the new variable:"),
547 QLineEdit.EchoMode.Normal 566 QLineEdit.EchoMode.Normal,
548 ) 567 )
549 568
550 if ok and newName and editor.checkDirty(): 569 if ok and newName and editor.checkDirty():
551 filename = editor.getFileName() 570 filename = editor.getFileName()
552 sLine, sIndex, eLine, eIndex = editor.getSelection() 571 sLine, sIndex, eLine, eIndex = editor.getSelection()
553 source = editor.text() 572 source = editor.text()
554 573
555 self.__ensureActive(idString) 574 self.__ensureActive(idString)
556 575
557 euuid = str(uuid.uuid4()) 576 euuid = str(uuid.uuid4())
558 self.__editors[euuid] = editor 577 self.__editors[euuid] = editor
559 578
560 self.sendJson("extractVariable", { 579 self.sendJson(
561 "FileName": filename, 580 "extractVariable",
562 "Source": source, 581 {
563 "Line": sLine + 1, 582 "FileName": filename,
564 "Index": sIndex, 583 "Source": source,
565 "EndLine": eLine + 1, 584 "Line": sLine + 1,
566 "EndIndex": eIndex, 585 "Index": sIndex,
567 "Uuid": euuid, 586 "EndLine": eLine + 1,
568 "NewName": newName, 587 "EndIndex": eIndex,
569 }, idString=idString) 588 "Uuid": euuid,
570 589 "NewName": newName,
590 },
591 idString=idString,
592 )
593
571 @pyqtSlot() 594 @pyqtSlot()
572 def refactoringInlineVariable(self): 595 def refactoringInlineVariable(self):
573 """ 596 """
574 Public slot to inline the selected variable. 597 Public slot to inline the selected variable.
575 598
576 Note: This is the opposite to Extract New Variable. 599 Note: This is the opposite to Extract New Variable.
577 """ 600 """
578 editor = self.__vm.activeWindow() 601 editor = self.__vm.activeWindow()
579 if editor: 602 if editor:
580 idString = self.__idString(editor) 603 idString = self.__idString(editor)
581 if not idString: 604 if not idString:
582 return 605 return
583 606
584 if editor.checkDirty(): 607 if editor.checkDirty():
585 filename = editor.getFileName() 608 filename = editor.getFileName()
586 line, index = editor.getCursorPosition() 609 line, index = editor.getCursorPosition()
587 source = editor.text() 610 source = editor.text()
588 611
589 self.__ensureActive(idString) 612 self.__ensureActive(idString)
590 613
591 euuid = str(uuid.uuid4()) 614 euuid = str(uuid.uuid4())
592 self.__editors[euuid] = editor 615 self.__editors[euuid] = editor
593 616
594 self.sendJson("inlineVariable", { 617 self.sendJson(
595 "FileName": filename, 618 "inlineVariable",
596 "Source": source, 619 {
597 "Line": line + 1, 620 "FileName": filename,
598 "Index": index, 621 "Source": source,
599 "Uuid": euuid, 622 "Line": line + 1,
600 }, idString=idString) 623 "Index": index,
601 624 "Uuid": euuid,
625 },
626 idString=idString,
627 )
628
602 @pyqtSlot() 629 @pyqtSlot()
603 def refactoringExtractFunction(self): 630 def refactoringExtractFunction(self):
604 """ 631 """
605 Public slot to extract an expression to a function. 632 Public slot to extract an expression to a function.
606 """ 633 """
607 editor = self.__vm.activeWindow() 634 editor = self.__vm.activeWindow()
608 if editor: 635 if editor:
609 idString = self.__idString(editor) 636 idString = self.__idString(editor)
610 if not idString: 637 if not idString:
611 return 638 return
612 639
613 newName, ok = QInputDialog.getText( 640 newName, ok = QInputDialog.getText(
614 None, 641 None,
615 self.tr("Extract Function"), 642 self.tr("Extract Function"),
616 self.tr("Enter the name for the function:"), 643 self.tr("Enter the name for the function:"),
617 QLineEdit.EchoMode.Normal 644 QLineEdit.EchoMode.Normal,
618 ) 645 )
619 646
620 if ok and newName and editor.checkDirty(): 647 if ok and newName and editor.checkDirty():
621 filename = editor.getFileName() 648 filename = editor.getFileName()
622 sLine, sIndex, eLine, eIndex = editor.getSelection() 649 sLine, sIndex, eLine, eIndex = editor.getSelection()
623 source = editor.text() 650 source = editor.text()
624 651
625 self.__ensureActive(idString) 652 self.__ensureActive(idString)
626 653
627 euuid = str(uuid.uuid4()) 654 euuid = str(uuid.uuid4())
628 self.__editors[euuid] = editor 655 self.__editors[euuid] = editor
629 656
630 self.sendJson("extractFunction", { 657 self.sendJson(
631 "FileName": filename, 658 "extractFunction",
632 "Source": source, 659 {
633 "Line": sLine + 1, 660 "FileName": filename,
634 "Index": sIndex, 661 "Source": source,
635 "EndLine": eLine + 1, 662 "Line": sLine + 1,
636 "EndIndex": eIndex, 663 "Index": sIndex,
637 "Uuid": euuid, 664 "EndLine": eLine + 1,
638 "NewName": newName, 665 "EndIndex": eIndex,
639 }, idString=idString) 666 "Uuid": euuid,
640 667 "NewName": newName,
668 },
669 idString=idString,
670 )
671
641 def __showRefactoringDiff(self, result): 672 def __showRefactoringDiff(self, result):
642 """ 673 """
643 Private method to show the diff of a refactoring. 674 Private method to show the diff of a refactoring.
644 675
645 @param result dictionary containing the result data 676 @param result dictionary containing the result data
646 @type dict 677 @type dict
647 """ 678 """
648 if "Error" not in result: 679 if "Error" not in result:
649 euuid = result["Uuid"] 680 euuid = result["Uuid"]
655 self.__cancelRefactoring(euuid) 686 self.__cancelRefactoring(euuid)
656 else: 687 else:
657 EricMessageBox.critical( 688 EricMessageBox.critical(
658 None, 689 None,
659 self.tr("Refactoring"), 690 self.tr("Refactoring"),
660 self.tr("<p>The refactoring could not be performed.</p>" 691 self.tr(
661 "<p>Reason: {0}</p>").format(result["ErrorString"]) 692 "<p>The refactoring could not be performed.</p>"
662 ) 693 "<p>Reason: {0}</p>"
663 694 ).format(result["ErrorString"]),
695 )
696
664 def __applyRefactoring(self, uid): 697 def __applyRefactoring(self, uid):
665 """ 698 """
666 Private method to apply a given refactoring. 699 Private method to apply a given refactoring.
667 700
668 @param uid UID of the calculated refactoring 701 @param uid UID of the calculated refactoring
669 @type str 702 @type str
670 """ 703 """
671 with contextlib.suppress(KeyError): 704 with contextlib.suppress(KeyError):
672 editor = self.__editors[uid] 705 editor = self.__editors[uid]
673 idString = self.__idString(editor) 706 idString = self.__idString(editor)
674 707
675 self.sendJson("applyRefactoring", { 708 self.sendJson(
676 "Uuid": uid, 709 "applyRefactoring",
677 }, idString=idString) 710 {
678 711 "Uuid": uid,
712 },
713 idString=idString,
714 )
715
679 del self.__editors[uid] 716 del self.__editors[uid]
680 717
681 def __cancelRefactoring(self, uid): 718 def __cancelRefactoring(self, uid):
682 """ 719 """
683 Private method to cancel a given refactoring. 720 Private method to cancel a given refactoring.
684 721
685 @param uid UID of the calculated refactoring 722 @param uid UID of the calculated refactoring
686 @type str 723 @type str
687 """ 724 """
688 with contextlib.suppress(KeyError): 725 with contextlib.suppress(KeyError):
689 editor = self.__editors[uid] 726 editor = self.__editors[uid]
690 idString = self.__idString(editor) 727 idString = self.__idString(editor)
691 728
692 self.sendJson("cancelRefactoring", { 729 self.sendJson(
693 "Uuid": uid, 730 "cancelRefactoring",
694 }, idString=idString) 731 {
695 732 "Uuid": uid,
733 },
734 idString=idString,
735 )
736
696 del self.__editors[uid] 737 del self.__editors[uid]
697 738
698 def __checkRefactoringResult(self, result): 739 def __checkRefactoringResult(self, result):
699 """ 740 """
700 Private method to check the refactoring result for errors. 741 Private method to check the refactoring result for errors.
701 742
702 @param result dictionary containing the result data 743 @param result dictionary containing the result data
703 @type dict 744 @type dict
704 """ 745 """
705 if "Error" in result: 746 if "Error" in result:
706 EricMessageBox.critical( 747 EricMessageBox.critical(
707 None, 748 None,
708 self.tr("Apply Refactoring"), 749 self.tr("Apply Refactoring"),
709 self.tr("<p>The refactoring could not be applied.</p>" 750 self.tr(
710 "<p>Reason: {0}</p>").format(result["ErrorString"]) 751 "<p>The refactoring could not be applied.</p>" "<p>Reason: {0}</p>"
711 ) 752 ).format(result["ErrorString"]),
712 753 )
754
713 ####################################################################### 755 #######################################################################
714 ## Methods below handle the network connection 756 ## Methods below handle the network connection
715 ####################################################################### 757 #######################################################################
716 758
717 def handleCall(self, method, params): 759 def handleCall(self, method, params):
718 """ 760 """
719 Public method to handle a method call from the client. 761 Public method to handle a method call from the client.
720 762
721 @param method requested method name 763 @param method requested method name
722 @type str 764 @type str
723 @param params dictionary with method specific parameters 765 @param params dictionary with method specific parameters
724 @type dict 766 @type dict
725 """ 767 """
726 self.__methodMapping[method](params) 768 self.__methodMapping[method](params)
727 769
728 def __processClientException(self, params): 770 def __processClientException(self, params):
729 """ 771 """
730 Private method to handle exceptions of the refactoring client. 772 Private method to handle exceptions of the refactoring client.
731 773
732 @param params dictionary containing the exception data 774 @param params dictionary containing the exception data
733 @type dict 775 @type dict
734 """ 776 """
735 if params["ExceptionType"] == "ProtocolError": 777 if params["ExceptionType"] == "ProtocolError":
736 self.__ui.appendToStderr( 778 self.__ui.appendToStderr(
737 self.tr("The data received from the Jedi server could not be" 779 self.tr(
738 " decoded. Please report this issue with the received" 780 "The data received from the Jedi server could not be"
739 " data to the eric bugs email address.\n" 781 " decoded. Please report this issue with the received"
740 "Error: {0}\n" 782 " data to the eric bugs email address.\n"
741 "Data:\n{1}\n").format( 783 "Error: {0}\n"
742 params["ExceptionValue"], 784 "Data:\n{1}\n"
743 params["ProtocolData"])) 785 ).format(params["ExceptionValue"], params["ProtocolData"])
786 )
744 else: 787 else:
745 self.__ui.appendToStderr( 788 self.__ui.appendToStderr(
746 self.tr("An exception happened in the Jedi client. Please" 789 self.tr(
747 " report it to the eric bugs email address.\n" 790 "An exception happened in the Jedi client. Please"
748 "Exception: {0}\n" 791 " report it to the eric bugs email address.\n"
749 "Value: {1}\n" 792 "Exception: {0}\n"
750 "Traceback: {2}\n").format( 793 "Value: {1}\n"
794 "Traceback: {2}\n"
795 ).format(
751 params["ExceptionType"], 796 params["ExceptionType"],
752 params["ExceptionValue"], 797 params["ExceptionValue"],
753 params["Traceback"])) 798 params["Traceback"],
754 799 )
800 )
801
755 def __startJediClient(self, interpreter, idString, clientEnv): 802 def __startJediClient(self, interpreter, idString, clientEnv):
756 """ 803 """
757 Private method to start the Jedi client with the given interpreter. 804 Private method to start the Jedi client with the given interpreter.
758 805
759 @param interpreter interpreter to be used for the Jedi client 806 @param interpreter interpreter to be used for the Jedi client
760 @type str 807 @type str
761 @param idString id of the client to be started 808 @param idString id of the client to be started
762 @type str 809 @type str
763 @param clientEnv dictionary with environment variables to run the 810 @param clientEnv dictionary with environment variables to run the
765 @type dict 812 @type dict
766 @return flag indicating a successful start of the client 813 @return flag indicating a successful start of the client
767 @rtype bool 814 @rtype bool
768 """ 815 """
769 ok = False 816 ok = False
770 817
771 if interpreter: 818 if interpreter:
772 client = os.path.join(os.path.dirname(__file__), 819 client = os.path.join(os.path.dirname(__file__), "JediClient.py")
773 "JediClient.py")
774 ok, exitCode = self.startClient( 820 ok, exitCode = self.startClient(
775 interpreter, client, 821 interpreter,
822 client,
776 [Globals.getPythonLibraryDirectory()], 823 [Globals.getPythonLibraryDirectory()],
777 idString=idString, environment=clientEnv) 824 idString=idString,
825 environment=clientEnv,
826 )
778 if not ok: 827 if not ok:
779 if exitCode == 42: 828 if exitCode == 42:
780 self.__ui.appendToStderr("JediServer: " + self.tr( 829 self.__ui.appendToStderr(
781 "The jedi and/or parso library is not installed.\n" 830 "JediServer: "
782 )) 831 + self.tr("The jedi and/or parso library is not installed.\n")
832 )
783 else: 833 else:
784 self.__ui.appendToStderr("JediServer: " + self.tr( 834 self.__ui.appendToStderr(
785 "'{0}' is not supported because the configured" 835 "JediServer: "
786 " interpreter could not be started.\n" 836 + self.tr(
787 ).format(idString)) 837 "'{0}' is not supported because the configured"
838 " interpreter could not be started.\n"
839 ).format(idString)
840 )
788 else: 841 else:
789 self.__ui.appendToStderr("JediServer: " + self.tr( 842 self.__ui.appendToStderr(
790 "'{0}' is not supported because no suitable interpreter is" 843 "JediServer: "
791 " configured.\n" 844 + self.tr(
792 ).format(idString)) 845 "'{0}' is not supported because no suitable interpreter is"
793 846 " configured.\n"
847 ).format(idString)
848 )
849
794 return ok 850 return ok
795 851
796 def __ensureActive(self, idString): 852 def __ensureActive(self, idString):
797 """ 853 """
798 Private method to ensure, that the requested client is active. 854 Private method to ensure, that the requested client is active.
799 855
800 A non-active client will be started. 856 A non-active client will be started.
801 857
802 @param idString id of the client to be checked 858 @param idString id of the client to be checked
803 @type str 859 @type str
804 @return flag indicating an active client 860 @return flag indicating an active client
805 @rtype bool 861 @rtype bool
806 """ 862 """
820 if idString == "Python3": 876 if idString == "Python3":
821 venvName = Preferences.getDebugger("Python3VirtualEnv") 877 venvName = Preferences.getDebugger("Python3VirtualEnv")
822 if not venvName: 878 if not venvName:
823 venvName, _ = venvManager.getDefaultEnvironment() 879 venvName, _ = venvManager.getDefaultEnvironment()
824 if venvName: 880 if venvName:
825 interpreter = venvManager.getVirtualenvInterpreter( 881 interpreter = venvManager.getVirtualenvInterpreter(venvName)
826 venvName)
827 execPath = venvManager.getVirtualenvExecPath(venvName) 882 execPath = venvManager.getVirtualenvExecPath(venvName)
828 883
829 # build a suitable environment 884 # build a suitable environment
830 if execPath: 885 if execPath:
831 if "PATH" in clientEnv: 886 if "PATH" in clientEnv:
832 clientEnv["PATH"] = os.pathsep.join( 887 clientEnv["PATH"] = os.pathsep.join(
833 [execPath, clientEnv["PATH"]]) 888 [execPath, clientEnv["PATH"]]
889 )
834 else: 890 else:
835 clientEnv["PATH"] = execPath 891 clientEnv["PATH"] = execPath
836 if interpreter: 892 if interpreter:
837 ok = self.__startJediClient(interpreter, idString, clientEnv) 893 ok = self.__startJediClient(interpreter, idString, clientEnv)
838 else: 894 else:
839 ok = False 895 ok = False
840 return ok 896 return ok
841 897
842 def __interpreterForProject(self): 898 def __interpreterForProject(self):
843 """ 899 """
844 Private method to determine the interpreter for the current project and 900 Private method to determine the interpreter for the current project and
845 the environment to run it. 901 the environment to run it.
846 902
847 @return tuple containing the interpreter of the current project and the 903 @return tuple containing the interpreter of the current project and the
848 environment variables 904 environment variables
849 @rtype tuple of (str, dict) 905 @rtype tuple of (str, dict)
850 """ 906 """
851 projectLanguage = self.__ericProject.getProjectLanguage() 907 projectLanguage = self.__ericProject.getProjectLanguage()
852 interpreter = "" 908 interpreter = ""
853 clientEnv = os.environ.copy() 909 clientEnv = os.environ.copy()
854 if "PATH" in clientEnv: 910 if "PATH" in clientEnv:
855 clientEnv["PATH"] = self.__ui.getOriginalPathString() 911 clientEnv["PATH"] = self.__ui.getOriginalPathString()
856 912
857 if projectLanguage in ("Python3", "MicroPython", "Cython"): 913 if projectLanguage in ("Python3", "MicroPython", "Cython"):
858 interpreter = self.__ericProject.getProjectInterpreter( 914 interpreter = self.__ericProject.getProjectInterpreter(resolveGlobal=False)
859 resolveGlobal=False)
860 if interpreter: 915 if interpreter:
861 execPath = self.__ericProject.getProjectExecPath() 916 execPath = self.__ericProject.getProjectExecPath()
862 917
863 # build a suitable environment 918 # build a suitable environment
864 if execPath: 919 if execPath:
865 if "PATH" in clientEnv: 920 if "PATH" in clientEnv:
866 clientEnv["PATH"] = os.pathsep.join( 921 clientEnv["PATH"] = os.pathsep.join(
867 [execPath, clientEnv["PATH"]]) 922 [execPath, clientEnv["PATH"]]
923 )
868 else: 924 else:
869 clientEnv["PATH"] = execPath 925 clientEnv["PATH"] = execPath
870 926
871 return interpreter, clientEnv 927 return interpreter, clientEnv
872 928
873 @pyqtSlot() 929 @pyqtSlot()
874 def handleNewConnection(self): 930 def handleNewConnection(self):
875 """ 931 """
876 Public slot for new incoming connections from a client. 932 Public slot for new incoming connections from a client.
877 """ 933 """
878 super().handleNewConnection() 934 super().handleNewConnection()
879 935
880 self.__updateEditorLanguageMapping() 936 self.__updateEditorLanguageMapping()
881 937
882 def activate(self): 938 def activate(self):
883 """ 939 """
884 Public method to activate the Jedi server. 940 Public method to activate the Jedi server.
885 """ 941 """
886 self.__documentationViewer = self.__ui.documentationViewer() 942 self.__documentationViewer = self.__ui.documentationViewer()
887 if self.__documentationViewer is not None: 943 if self.__documentationViewer is not None:
888 self.__documentationViewer.registerProvider( 944 self.__documentationViewer.registerProvider(
889 "jedi", self.tr("Jedi"), self.requestCodeDocumentation, 945 "jedi",
890 self.isSupportedLanguage) 946 self.tr("Jedi"),
891 947 self.requestCodeDocumentation,
948 self.isSupportedLanguage,
949 )
950
892 self.__ericProject.projectOpened.connect(self.__projectOpened) 951 self.__ericProject.projectOpened.connect(self.__projectOpened)
893 self.__ericProject.projectClosed.connect(self.__projectClosed) 952 self.__ericProject.projectClosed.connect(self.__projectClosed)
894 953
895 def deactivate(self): 954 def deactivate(self):
896 """ 955 """
897 Public method to deactivate the code assist server. 956 Public method to deactivate the code assist server.
898 """ 957 """
899 """ 958 """
900 Public method to shut down the code assist server. 959 Public method to shut down the code assist server.
901 """ 960 """
902 if self.__documentationViewer is not None: 961 if self.__documentationViewer is not None:
903 self.__documentationViewer.unregisterProvider("jedi") 962 self.__documentationViewer.unregisterProvider("jedi")
904 963
905 with contextlib.suppress(TypeError): 964 with contextlib.suppress(TypeError):
906 self.__ericProject.projectOpened.disconnect(self.__projectOpened) 965 self.__ericProject.projectOpened.disconnect(self.__projectOpened)
907 self.__ericProject.projectClosed.disconnect(self.__projectClosed) 966 self.__ericProject.projectClosed.disconnect(self.__projectClosed)
908 967
909 self.stopAllClients() 968 self.stopAllClients()
910 969
911 @pyqtSlot() 970 @pyqtSlot()
912 def __projectOpened(self): 971 def __projectOpened(self):
913 """ 972 """
914 Private slot to handle the projectOpened signal. 973 Private slot to handle the projectOpened signal.
915 """ 974 """
916 self.__ensureActive(JediServer.IdProject) 975 self.__ensureActive(JediServer.IdProject)
917 self.sendJson("openProject", { 976 self.sendJson(
918 "ProjectPath": self.__ericProject.getProjectPath(), 977 "openProject",
919 }, idString=JediServer.IdProject) 978 {
920 979 "ProjectPath": self.__ericProject.getProjectPath(),
980 },
981 idString=JediServer.IdProject,
982 )
983
921 @pyqtSlot() 984 @pyqtSlot()
922 def __projectClosed(self): 985 def __projectClosed(self):
923 """ 986 """
924 Private slot to handle the projectClosed signal. 987 Private slot to handle the projectClosed signal.
925 """ 988 """
926 self.__ensureActive(JediServer.IdProject) 989 self.__ensureActive(JediServer.IdProject)
927 self.sendJson("closeProject", {}, idString=JediServer.IdProject) 990 self.sendJson("closeProject", {}, idString=JediServer.IdProject)
928 991
929 self.stopClient(idString=JediServer.IdProject) 992 self.stopClient(idString=JediServer.IdProject)

eric ide

mercurial