24 |
24 |
25 class Assistant(QObject): |
25 class Assistant(QObject): |
26 """ |
26 """ |
27 Class implementing the autocompletion and calltips system. |
27 Class implementing the autocompletion and calltips system. |
28 """ |
28 """ |
|
29 |
29 def __init__(self, plugin, parent=None): |
30 def __init__(self, plugin, parent=None): |
30 """ |
31 """ |
31 Constructor |
32 Constructor |
32 |
33 |
33 @param plugin reference to the plugin object |
34 @param plugin reference to the plugin object |
34 @type AssistantEricPlugin |
35 @type AssistantEricPlugin |
35 @param parent parent |
36 @param parent parent |
36 @type QObject |
37 @type QObject |
37 """ |
38 """ |
38 QObject.__init__(self, parent) |
39 QObject.__init__(self, parent) |
39 |
40 |
40 self.__plugin = plugin |
41 self.__plugin = plugin |
41 self.__ui = parent |
42 self.__ui = parent |
42 self.__project = ericApp().getObject("Project") |
43 self.__project = ericApp().getObject("Project") |
43 self.__viewmanager = ericApp().getObject("ViewManager") |
44 self.__viewmanager = ericApp().getObject("ViewManager") |
44 self.__pluginManager = ericApp().getObject("PluginManager") |
45 self.__pluginManager = ericApp().getObject("PluginManager") |
45 |
46 |
46 self.__apisManager = APIsManager(self.__ui, self) |
47 self.__apisManager = APIsManager(self.__ui, self) |
47 |
48 |
48 self.__editors = [] |
49 self.__editors = [] |
49 self.__lastContext = None |
50 self.__lastContext = None |
50 self.__lastFullContext = None |
51 self.__lastFullContext = None |
51 |
52 |
52 from QScintilla.Editor import Editor |
53 from QScintilla.Editor import Editor |
|
54 |
53 self.__fromDocumentID = Editor.FromDocumentID |
55 self.__fromDocumentID = Editor.FromDocumentID |
54 |
56 |
55 def activate(self): |
57 def activate(self): |
56 """ |
58 """ |
57 Public method to perform actions upon activation. |
59 Public method to perform actions upon activation. |
58 """ |
60 """ |
59 self.__pluginManager.shutdown.connect(self.__shutdown) |
61 self.__pluginManager.shutdown.connect(self.__shutdown) |
60 |
62 |
61 self.__ui.preferencesChanged.connect(self.__preferencesChanged) |
63 self.__ui.preferencesChanged.connect(self.__preferencesChanged) |
62 |
64 |
63 self.__viewmanager.editorOpenedEd.connect(self.__editorOpened) |
65 self.__viewmanager.editorOpenedEd.connect(self.__editorOpened) |
64 self.__viewmanager.editorClosedEd.connect(self.__editorClosed) |
66 self.__viewmanager.editorClosedEd.connect(self.__editorClosed) |
65 |
67 |
66 # preload the project APIs object |
68 # preload the project APIs object |
67 self.__apisManager.getAPIs(ApisNameProject) |
69 self.__apisManager.getAPIs(ApisNameProject) |
68 |
70 |
69 for editor in self.__viewmanager.getOpenEditors(): |
71 for editor in self.__viewmanager.getOpenEditors(): |
70 self.__editorOpened(editor) |
72 self.__editorOpened(editor) |
71 |
73 |
72 def deactivate(self): |
74 def deactivate(self): |
73 """ |
75 """ |
74 Public method to perform actions upon deactivation. |
76 Public method to perform actions upon deactivation. |
75 """ |
77 """ |
76 self.__pluginManager.shutdown.disconnect(self.__shutdown) |
78 self.__pluginManager.shutdown.disconnect(self.__shutdown) |
77 |
79 |
78 self.__ui.preferencesChanged.disconnect(self.__preferencesChanged) |
80 self.__ui.preferencesChanged.disconnect(self.__preferencesChanged) |
79 |
81 |
80 self.__viewmanager.editorOpenedEd.disconnect(self.__editorOpened) |
82 self.__viewmanager.editorOpenedEd.disconnect(self.__editorOpened) |
81 self.__viewmanager.editorClosedEd.disconnect(self.__editorClosed) |
83 self.__viewmanager.editorClosedEd.disconnect(self.__editorClosed) |
82 |
84 |
83 self.__shutdown() |
85 self.__shutdown() |
84 |
86 |
85 def __shutdown(self): |
87 def __shutdown(self): |
86 """ |
88 """ |
87 Private slot to handle the shutdown signal. |
89 Private slot to handle the shutdown signal. |
88 """ |
90 """ |
89 for editor in self.__editors[:]: |
91 for editor in self.__editors[:]: |
90 self.__editorClosed(editor) |
92 self.__editorClosed(editor) |
91 |
93 |
92 self.__apisManager.deactivate() |
94 self.__apisManager.deactivate() |
93 |
95 |
94 def setEnabled(self, key, enabled): |
96 def setEnabled(self, key, enabled): |
95 """ |
97 """ |
96 Public method to enable or disable a feature. |
98 Public method to enable or disable a feature. |
97 |
99 |
98 @param key feature to set |
100 @param key feature to set |
99 @type str |
101 @type str |
100 @param enabled flag indicating the status |
102 @param enabled flag indicating the status |
101 @type bool |
103 @type bool |
102 """ |
104 """ |
103 for editor in self.__editors[:]: |
105 for editor in self.__editors[:]: |
104 self.__editorClosed(editor) |
106 self.__editorClosed(editor) |
105 for editor in self.__viewmanager.getOpenEditors(): |
107 for editor in self.__viewmanager.getOpenEditors(): |
106 self.__editorOpened(editor) |
108 self.__editorOpened(editor) |
107 |
109 |
108 def __editorOpened(self, editor): |
110 def __editorOpened(self, editor): |
109 """ |
111 """ |
110 Private slot called, when a new editor was opened. |
112 Private slot called, when a new editor was opened. |
111 |
113 |
112 @param editor reference to the new editor |
114 @param editor reference to the new editor |
113 @type Editor |
115 @type Editor |
114 """ |
116 """ |
115 if self.__plugin.getPreferences("AutoCompletionEnabled"): |
117 if self.__plugin.getPreferences("AutoCompletionEnabled"): |
116 self.__setAutoCompletionHook(editor) |
118 self.__setAutoCompletionHook(editor) |
117 if self.__plugin.getPreferences("CalltipsEnabled"): |
119 if self.__plugin.getPreferences("CalltipsEnabled"): |
118 self.__setCalltipsHook(editor) |
120 self.__setCalltipsHook(editor) |
119 editor.editorSaved.connect( |
121 editor.editorSaved.connect( |
120 self.__apisManager.getAPIs(ApisNameProject).editorSaved) |
122 self.__apisManager.getAPIs(ApisNameProject).editorSaved |
|
123 ) |
121 self.__editors.append(editor) |
124 self.__editors.append(editor) |
122 |
125 |
123 # preload the api to give the manager a chance to prepare the database |
126 # preload the api to give the manager a chance to prepare the database |
124 language = editor.getApiLanguage() |
127 language = editor.getApiLanguage() |
125 if language: |
128 if language: |
126 projectType = self.__getProjectType(editor) |
129 projectType = self.__getProjectType(editor) |
127 self.__apisManager.getAPIs(language, projectType=projectType) |
130 self.__apisManager.getAPIs(language, projectType=projectType) |
128 |
131 |
129 def __editorClosed(self, editor): |
132 def __editorClosed(self, editor): |
130 """ |
133 """ |
131 Private slot called, when an editor was closed. |
134 Private slot called, when an editor was closed. |
132 |
135 |
133 @param editor reference to the editor |
136 @param editor reference to the editor |
134 @type Editor |
137 @type Editor |
135 """ |
138 """ |
136 if editor in self.__editors: |
139 if editor in self.__editors: |
137 editor.editorSaved.disconnect( |
140 editor.editorSaved.disconnect( |
138 self.__apisManager.getAPIs(ApisNameProject).editorSaved) |
141 self.__apisManager.getAPIs(ApisNameProject).editorSaved |
|
142 ) |
139 self.__editors.remove(editor) |
143 self.__editors.remove(editor) |
140 if editor.getCompletionListHook("Assistant"): |
144 if editor.getCompletionListHook("Assistant"): |
141 self.__unsetAutoCompletionHook(editor) |
145 self.__unsetAutoCompletionHook(editor) |
142 if editor.getCallTipHook("Assistant"): |
146 if editor.getCallTipHook("Assistant"): |
143 self.__unsetCalltipsHook(editor) |
147 self.__unsetCalltipsHook(editor) |
144 |
148 |
145 def __preferencesChanged(self): |
149 def __preferencesChanged(self): |
146 """ |
150 """ |
147 Private method to handle a change of the global configuration. |
151 Private method to handle a change of the global configuration. |
148 """ |
152 """ |
149 self.__apisManager.reloadAPIs() |
153 self.__apisManager.reloadAPIs() |
150 |
154 |
151 def __getProjectType(self, editor): |
155 def __getProjectType(self, editor): |
152 """ |
156 """ |
153 Private method to determine the project type to be used. |
157 Private method to determine the project type to be used. |
154 |
158 |
155 @param editor reference to the editor to check |
159 @param editor reference to the editor to check |
156 @type Editor |
160 @type Editor |
157 @return project type |
161 @return project type |
158 @rtype str |
162 @rtype str |
159 """ |
163 """ |
160 filename = editor.getFileName() |
164 filename = editor.getFileName() |
161 projectType = ( |
165 projectType = ( |
162 self.__project.getProjectType() |
166 self.__project.getProjectType() |
163 if (self.__project.isOpen() and |
167 if ( |
164 filename and |
168 self.__project.isOpen() |
165 self.__project.isProjectFile(filename)) else |
169 and filename |
166 "" |
170 and self.__project.isProjectFile(filename) |
|
171 ) |
|
172 else "" |
167 ) |
173 ) |
168 |
174 |
169 return projectType |
175 return projectType |
170 |
176 |
171 ################################# |
177 ################################# |
172 ## auto-completion methods below |
178 ## auto-completion methods below |
173 ################################# |
179 ################################# |
174 |
180 |
175 def __recordSelectedContext(self, userListId, txt): |
181 def __recordSelectedContext(self, userListId, txt): |
176 """ |
182 """ |
177 Private slot to handle the selection from the completion list to |
183 Private slot to handle the selection from the completion list to |
178 record the selected completion context. |
184 record the selected completion context. |
179 |
185 |
180 @param userListId the ID of the user list (should be 1) |
186 @param userListId the ID of the user list (should be 1) |
181 @type int |
187 @type int |
182 @param txt the selected text |
188 @param txt the selected text |
183 @type str |
189 @type str |
184 """ |
190 """ |
185 from QScintilla.Editor import EditorAutoCompletionListID |
191 from QScintilla.Editor import EditorAutoCompletionListID |
186 |
192 |
187 if userListId == EditorAutoCompletionListID: |
193 if userListId == EditorAutoCompletionListID: |
188 lst = txt.split() |
194 lst = txt.split() |
189 if len(lst) > 1: |
195 if len(lst) > 1: |
190 self.__lastFullContext = lst[1][1:].split(")")[0] |
196 self.__lastFullContext = lst[1][1:].split(")")[0] |
191 else: |
197 else: |
192 self.__lastFullContext = None |
198 self.__lastFullContext = None |
193 |
199 |
194 def __setAutoCompletionHook(self, editor): |
200 def __setAutoCompletionHook(self, editor): |
195 """ |
201 """ |
196 Private method to set the autocompletion hook. |
202 Private method to set the autocompletion hook. |
197 |
203 |
198 @param editor reference to the editor |
204 @param editor reference to the editor |
199 @type Editor |
205 @type Editor |
200 """ |
206 """ |
201 editor.userListActivated.connect(self.__recordSelectedContext) |
207 editor.userListActivated.connect(self.__recordSelectedContext) |
202 editor.addCompletionListHook("Assistant", self.getCompletionsList) |
208 editor.addCompletionListHook("Assistant", self.getCompletionsList) |
203 |
209 |
204 def __unsetAutoCompletionHook(self, editor): |
210 def __unsetAutoCompletionHook(self, editor): |
205 """ |
211 """ |
206 Private method to unset the autocompletion hook. |
212 Private method to unset the autocompletion hook. |
207 |
213 |
208 @param editor reference to the editor |
214 @param editor reference to the editor |
209 @type Editor |
215 @type Editor |
210 """ |
216 """ |
211 editor.userListActivated.disconnect(self.__recordSelectedContext) |
217 editor.userListActivated.disconnect(self.__recordSelectedContext) |
212 editor.removeCompletionListHook("Assistant") |
218 editor.removeCompletionListHook("Assistant") |
213 |
219 |
214 def getCompletionsList(self, editor, context): |
220 def getCompletionsList(self, editor, context): |
215 """ |
221 """ |
216 Public method to get a list of possible completions. |
222 Public method to get a list of possible completions. |
217 |
223 |
218 @param editor reference to the editor object, that called this method |
224 @param editor reference to the editor object, that called this method |
219 @type Editor |
225 @type Editor |
220 @param context flag indicating to autocomplete a context |
226 @param context flag indicating to autocomplete a context |
221 @type bool |
227 @type bool |
222 @return list of possible completions |
228 @return list of possible completions |
223 @rtype list of str |
229 @rtype list of str |
224 """ |
230 """ |
225 language = editor.getApiLanguage() |
231 language = editor.getApiLanguage() |
226 completeFromDocumentOnly = False |
232 completeFromDocumentOnly = False |
227 if language in ["", "Guessed"] or language.startswith("Pygments|"): |
233 if language in ["", "Guessed"] or language.startswith("Pygments|"): |
228 if ( |
234 if self.__plugin.getPreferences("AutoCompletionSource") & AcsDocument: |
229 self.__plugin.getPreferences("AutoCompletionSource") & |
|
230 AcsDocument |
|
231 ): |
|
232 completeFromDocumentOnly = True |
235 completeFromDocumentOnly = True |
233 else: |
236 else: |
234 return [] |
237 return [] |
235 |
238 |
236 projectType = self.__getProjectType(editor) |
239 projectType = self.__getProjectType(editor) |
237 |
240 |
238 line, col = editor.getCursorPosition() |
241 line, col = editor.getCursorPosition() |
239 sep = "" |
242 sep = "" |
240 if language and context: |
243 if language and context: |
241 wc = re.sub("\w", "", editor.wordCharacters()) |
244 wc = re.sub("\w", "", editor.wordCharacters()) |
242 pat = re.compile("\w{0}".format(re.escape(wc))) |
245 pat = re.compile("\w{0}".format(re.escape(wc))) |
243 text = editor.text(line) |
246 text = editor.text(line) |
244 |
247 |
245 beg = text[:col] |
248 beg = text[:col] |
246 for wsep in editor.getLexer().autoCompletionWordSeparators(): |
249 for wsep in editor.getLexer().autoCompletionWordSeparators(): |
247 if beg.endswith(wsep): |
250 if beg.endswith(wsep): |
248 sep = wsep |
251 sep = wsep |
249 break |
252 break |
250 |
253 |
251 depth = 0 |
254 depth = 0 |
252 while ( |
255 while col > 0 and not pat.match(text[col - 1]): |
253 col > 0 and |
|
254 not pat.match(text[col - 1]) |
|
255 ): |
|
256 ch = text[col - 1] |
256 ch = text[col - 1] |
257 if ch == ')': |
257 if ch == ")": |
258 depth = 1 |
258 depth = 1 |
259 |
259 |
260 # ignore everything back to the start of the |
260 # ignore everything back to the start of the |
261 # corresponding parenthesis |
261 # corresponding parenthesis |
262 col -= 1 |
262 col -= 1 |
263 while col > 0: |
263 while col > 0: |
264 ch = text[col - 1] |
264 ch = text[col - 1] |
265 if ch == ')': |
265 if ch == ")": |
266 depth += 1 |
266 depth += 1 |
267 elif ch == '(': |
267 elif ch == "(": |
268 depth -= 1 |
268 depth -= 1 |
269 if depth == 0: |
269 if depth == 0: |
270 break |
270 break |
271 col -= 1 |
271 col -= 1 |
272 elif ch == '(': |
272 elif ch == "(": |
273 break |
273 break |
274 col -= 1 |
274 col -= 1 |
275 |
275 |
276 word = editor.getWordLeft(line, col) |
276 word = editor.getWordLeft(line, col) |
277 if context and not sep: |
277 if context and not sep: |
278 # no separator was found -> no context completion |
278 # no separator was found -> no context completion |
279 context = False |
279 context = False |
280 if context: |
280 if context: |
281 self.__lastContext = word |
281 self.__lastContext = word |
282 else: |
282 else: |
283 self.__lastContext = None |
283 self.__lastContext = None |
284 |
284 |
285 prefix = "" |
285 prefix = "" |
286 mod = None |
286 mod = None |
287 beg = beg[:col + 1] if context else editor.text(line)[:col] |
287 beg = beg[: col + 1] if context else editor.text(line)[:col] |
288 col = len(beg) |
288 col = len(beg) |
289 wseps = ( |
289 wseps = editor.getLexer().autoCompletionWordSeparators() if language else [] |
290 editor.getLexer().autoCompletionWordSeparators() |
|
291 if language else |
|
292 [] |
|
293 ) |
|
294 if wseps: |
290 if wseps: |
295 wseps.append(" ") |
291 wseps.append(" ") |
296 if col > 0 and beg[col - 1] in wseps: |
292 if col > 0 and beg[col - 1] in wseps: |
297 col -= 1 |
293 col -= 1 |
298 else: |
294 else: |
378 @rtype list of str |
404 @rtype list of str |
379 """ |
405 """ |
380 apiCompletionsList = [] |
406 apiCompletionsList = [] |
381 docCompletionsList = [] |
407 docCompletionsList = [] |
382 projectCompletionList = [] |
408 projectCompletionList = [] |
383 |
409 |
384 if not documentOnly: |
410 if not documentOnly: |
385 if self.__plugin.getPreferences("AutoCompletionSource") & AcsAPIs: |
411 if self.__plugin.getPreferences("AutoCompletionSource") & AcsAPIs: |
386 api = self.__apisManager.getAPIs( |
412 api = self.__apisManager.getAPIs(language, projectType=projectType) |
387 language, projectType=projectType) |
|
388 apiCompletionsList = self.__getApiCompletions( |
413 apiCompletionsList = self.__getApiCompletions( |
389 api, word, context, prefix, module, editor) |
414 api, word, context, prefix, module, editor |
390 |
415 ) |
391 if ( |
416 |
392 self.__plugin.getPreferences("AutoCompletionSource") & |
417 if self.__plugin.getPreferences("AutoCompletionSource") & AcsProject: |
393 AcsProject |
|
394 ): |
|
395 api = self.__apisManager.getAPIs(ApisNameProject) |
418 api = self.__apisManager.getAPIs(ApisNameProject) |
396 projectCompletionList = self.__getApiCompletions( |
419 projectCompletionList = self.__getApiCompletions( |
397 api, word, context, prefix, module, editor) |
420 api, word, context, prefix, module, editor |
398 |
421 ) |
|
422 |
399 if ( |
423 if ( |
400 self.__plugin.getPreferences("AutoCompletionSource") & |
424 self.__plugin.getPreferences("AutoCompletionSource") & AcsDocument |
401 AcsDocument and |
425 and not importCompletion |
402 not importCompletion |
|
403 ): |
426 ): |
404 docCompletionsList = self.__getDocumentCompletions( |
427 docCompletionsList = self.__getDocumentCompletions( |
405 editor, word, context, sep, prefix, module) |
428 editor, word, context, sep, prefix, module |
406 |
429 ) |
|
430 |
407 completionsList = list( |
431 completionsList = list( |
408 set(apiCompletionsList) |
432 set(apiCompletionsList) |
409 .union(set(docCompletionsList)) |
433 .union(set(docCompletionsList)) |
410 .union(set(projectCompletionList)) |
434 .union(set(projectCompletionList)) |
411 ) |
435 ) |
412 return completionsList |
436 return completionsList |
413 |
437 |
414 def __getApiCompletions(self, api, word, context, prefix, module, editor): |
438 def __getApiCompletions(self, api, word, context, prefix, module, editor): |
415 """ |
439 """ |
416 Private method to determine a list of completions from an API object. |
440 Private method to determine a list of completions from an API object. |
417 |
441 |
418 @param api reference to the API object to be used |
442 @param api reference to the API object to be used |
419 @type APIsManager.DbAPIs |
443 @type APIsManager.DbAPIs |
420 @param word word (or wordpart) to complete |
444 @param word word (or wordpart) to complete |
421 @type str |
445 @type str |
422 @param context flag indicating to autocomplete a context |
446 @param context flag indicating to autocomplete a context |
433 completionsList = [] |
457 completionsList = [] |
434 if api is not None: |
458 if api is not None: |
435 if prefix and module and prefix == "self": |
459 if prefix and module and prefix == "self": |
436 line, col = editor.getCursorPosition() |
460 line, col = editor.getCursorPosition() |
437 for cl in module.classes.values(): |
461 for cl in module.classes.values(): |
438 if ( |
462 if line >= cl.lineno and ( |
439 line >= cl.lineno and |
463 cl.endlineno == -1 or line <= cl.endlineno |
440 (cl.endlineno == -1 or line <= cl.endlineno) |
|
441 ): |
464 ): |
442 completions = [] |
465 completions = [] |
443 for superClass in cl.super: |
466 for superClass in cl.super: |
444 if prefix == word: |
467 if prefix == word: |
445 completions.extend( |
468 completions.extend( |
446 api.getCompletions( |
469 api.getCompletions( |
447 context=superClass, |
470 context=superClass, |
448 followHierarchy=self.__plugin |
471 followHierarchy=self.__plugin.getPreferences( |
449 .getPreferences( |
|
450 "AutoCompletionFollowHierarchy" |
472 "AutoCompletionFollowHierarchy" |
451 ) |
473 ), |
452 ) |
474 ) |
453 ) |
475 ) |
454 else: |
476 else: |
455 completions.extend( |
477 completions.extend( |
456 api.getCompletions( |
478 api.getCompletions( |
457 start=word, context=superClass, |
479 start=word, |
458 followHierarchy=self.__plugin |
480 context=superClass, |
459 .getPreferences( |
481 followHierarchy=self.__plugin.getPreferences( |
460 "AutoCompletionFollowHierarchy" |
482 "AutoCompletionFollowHierarchy" |
461 ) |
483 ), |
462 ) |
484 ) |
463 ) |
485 ) |
464 for completion in completions: |
486 for completion in completions: |
465 if not completion["context"]: |
487 if not completion["context"]: |
466 entry = completion["completion"] |
488 entry = completion["completion"] |
467 else: |
489 else: |
468 entry = "{0} ({1})".format( |
490 entry = "{0} ({1})".format( |
469 completion["completion"], |
491 completion["completion"], completion["context"] |
470 completion["context"] |
|
471 ) |
492 ) |
472 if entry in completionsList: |
493 if entry in completionsList: |
473 completionsList.remove(entry) |
494 completionsList.remove(entry) |
474 if completion["pictureId"]: |
495 if completion["pictureId"]: |
475 entry += "?{0}".format(completion["pictureId"]) |
496 entry += "?{0}".format(completion["pictureId"]) |
476 else: |
497 else: |
477 cont = False |
498 cont = False |
478 regexp = re.compile( |
499 regexp = re.compile(re.escape(entry) + r"\?\d{,2}") |
479 re.escape(entry) + r"\?\d{,2}") |
|
480 for comp in completionsList: |
500 for comp in completionsList: |
481 if regexp.fullmatch(comp): |
501 if regexp.fullmatch(comp): |
482 cont = True |
502 cont = True |
483 break |
503 break |
484 if cont: |
504 if cont: |
485 continue |
505 continue |
486 if entry not in completionsList: |
506 if entry not in completionsList: |
487 completionsList.append(entry) |
507 completionsList.append(entry) |
488 |
508 |
489 break |
509 break |
490 elif context: |
510 elif context: |
491 completions = api.getCompletions(context=word) |
511 completions = api.getCompletions(context=word) |
492 for completion in completions: |
512 for completion in completions: |
493 entry = completion["completion"] |
513 entry = completion["completion"] |
651 elif attribute.isProtected(): |
681 elif attribute.isProtected(): |
652 iconID = Editor.AttributeProtectedID |
682 iconID = Editor.AttributeProtectedID |
653 else: |
683 else: |
654 iconID = Editor.AttributeID |
684 iconID = Editor.AttributeID |
655 comps.append((attribute.name, cl.name, iconID)) |
685 comps.append((attribute.name, cl.name, iconID)) |
656 |
686 |
657 if word != prefix: |
687 if word != prefix: |
658 completionsList.extend( |
688 completionsList.extend( |
659 ["{0} ({1})?{2}".format(c[0], c[1], c[2]) |
689 [ |
660 for c in comps if c[0].startswith(word)]) |
690 "{0} ({1})?{2}".format(c[0], c[1], c[2]) |
|
691 for c in comps |
|
692 if c[0].startswith(word) |
|
693 ] |
|
694 ) |
661 else: |
695 else: |
662 completionsList.extend( |
696 completionsList.extend( |
663 ["{0} ({1})?{2}".format(c[0], c[1], c[2]) |
697 ["{0} ({1})?{2}".format(c[0], c[1], c[2]) for c in comps] |
664 for c in comps]) |
698 ) |
665 |
699 |
666 for sup in cl.super: |
700 for sup in cl.super: |
667 if sup in module.classes: |
701 if sup in module.classes: |
668 if word == prefix: |
702 if word == prefix: |
669 nword = sup |
703 nword = sup |
670 else: |
704 else: |
671 nword = word |
705 nword = word |
672 completionsList.extend( |
706 completionsList.extend( |
673 self.__getDocumentCompletions( |
707 self.__getDocumentCompletions( |
674 editor, nword, context, sep, sup, module, |
708 editor, |
675 doHierarchy=True)) |
709 nword, |
676 |
710 context, |
|
711 sep, |
|
712 sup, |
|
713 module, |
|
714 doHierarchy=True, |
|
715 ) |
|
716 ) |
|
717 |
677 if not prefixFound: |
718 if not prefixFound: |
678 currentPos = editor.currentPosition() |
719 currentPos = editor.currentPosition() |
679 if context: |
720 if context: |
680 word += sep |
721 word += sep |
681 |
722 |
682 if editor.isUtf8(): |
723 if editor.isUtf8(): |
683 sword = word.encode("utf-8") |
724 sword = word.encode("utf-8") |
684 else: |
725 else: |
685 sword = word |
726 sword = word |
686 res = editor.findFirstTarget( |
727 res = editor.findFirstTarget( |
687 sword, False, editor.autoCompletionCaseSensitivity(), |
728 sword, |
688 False, begline=0, begindex=0, ws_=True) |
729 False, |
|
730 editor.autoCompletionCaseSensitivity(), |
|
731 False, |
|
732 begline=0, |
|
733 begindex=0, |
|
734 ws_=True, |
|
735 ) |
689 while res: |
736 while res: |
690 start, length = editor.getFoundTarget() |
737 start, length = editor.getFoundTarget() |
691 pos = start + length |
738 pos = start + length |
692 if pos != currentPos: |
739 if pos != currentPos: |
693 if context: |
740 if context: |
694 completion = "" |
741 completion = "" |
695 else: |
742 else: |
696 completion = word |
743 completion = word |
697 line, index = editor.lineIndexFromPosition(pos) |
744 line, index = editor.lineIndexFromPosition(pos) |
698 curWord = editor.getWord(line, index, useWordChars=False) |
745 curWord = editor.getWord(line, index, useWordChars=False) |
699 completion += curWord[len(completion):] |
746 completion += curWord[len(completion) :] |
700 if ( |
747 if ( |
701 completion and |
748 completion |
702 completion not in completionsList and |
749 and completion not in completionsList |
703 completion != word |
750 and completion != word |
704 ): |
751 ): |
705 completionsList.append( |
752 completionsList.append( |
706 "{0}?{1}".format( |
753 "{0}?{1}".format(completion, self.__fromDocumentID) |
707 completion, self.__fromDocumentID)) |
754 ) |
708 |
755 |
709 res = editor.findNextTarget() |
756 res = editor.findNextTarget() |
710 |
757 |
711 completionsList.sort() |
758 completionsList.sort() |
712 return completionsList |
759 return completionsList |
713 |
760 |
714 ########################### |
761 ########################### |
715 ## calltips methods below |
762 ## calltips methods below |
716 ########################### |
763 ########################### |
717 |
764 |
718 def __setCalltipsHook(self, editor): |
765 def __setCalltipsHook(self, editor): |
719 """ |
766 """ |
720 Private method to set the calltip hook. |
767 Private method to set the calltip hook. |
721 |
768 |
722 @param editor reference to the editor |
769 @param editor reference to the editor |
723 @type Editor |
770 @type Editor |
724 """ |
771 """ |
725 editor.addCallTipHook("Assistant", self.calltips) |
772 editor.addCallTipHook("Assistant", self.calltips) |
726 |
773 |
727 def __unsetCalltipsHook(self, editor): |
774 def __unsetCalltipsHook(self, editor): |
728 """ |
775 """ |
729 Private method to unset the calltip hook. |
776 Private method to unset the calltip hook. |
730 |
777 |
731 @param editor reference to the editor |
778 @param editor reference to the editor |
732 @type Editor |
779 @type Editor |
733 """ |
780 """ |
734 editor.removeCallTipHook("Assistant") |
781 editor.removeCallTipHook("Assistant") |
735 |
782 |
736 def calltips(self, editor, pos, commas): |
783 def calltips(self, editor, pos, commas): |
737 """ |
784 """ |
738 Public method to return a list of calltips. |
785 Public method to return a list of calltips. |
739 |
786 |
740 @param editor reference to the editor |
787 @param editor reference to the editor |
741 @type Editor |
788 @type Editor |
742 @param pos position in the text for the calltip |
789 @param pos position in the text for the calltip |
743 @type int |
790 @type int |
744 @param commas minimum number of commas contained in the calltip |
791 @param commas minimum number of commas contained in the calltip |
785 if col >= 0: |
825 if col >= 0: |
786 col -= 1 |
826 col -= 1 |
787 prefix = editor.getWordLeft(line, col) |
827 prefix = editor.getWordLeft(line, col) |
788 if editor.isPyFile(): |
828 if editor.isPyFile(): |
789 from Utilities.ModuleParser import Module |
829 from Utilities.ModuleParser import Module |
|
830 |
790 src = editor.text() |
831 src = editor.text() |
791 fn = editor.getFileName() |
832 fn = editor.getFileName() |
792 if fn is None: |
833 if fn is None: |
793 fn = "" |
834 fn = "" |
794 mod = Module("", fn, imp.PY_SOURCE) |
835 mod = Module("", fn, imp.PY_SOURCE) |
795 mod.scan(src) |
836 mod.scan(src) |
796 |
837 |
797 apiCalltips = [] |
838 apiCalltips = [] |
798 projectCalltips = [] |
839 projectCalltips = [] |
799 documentCalltips = [] |
840 documentCalltips = [] |
800 |
841 |
801 if not completeFromDocumentOnly: |
842 if not completeFromDocumentOnly: |
802 if self.__plugin.getPreferences("AutoCompletionSource") & AcsAPIs: |
843 if self.__plugin.getPreferences("AutoCompletionSource") & AcsAPIs: |
803 api = self.__apisManager.getAPIs( |
844 api = self.__apisManager.getAPIs(language, projectType=projectType) |
804 language, projectType=projectType) |
|
805 if api is not None: |
845 if api is not None: |
806 apiCalltips = self.__getApiCalltips( |
846 apiCalltips = self.__getApiCalltips( |
807 api, word, commas, prefix, mod, editor) |
847 api, word, commas, prefix, mod, editor |
808 |
848 ) |
809 if ( |
849 |
810 self.__plugin.getPreferences("AutoCompletionSource") & |
850 if self.__plugin.getPreferences("AutoCompletionSource") & AcsProject: |
811 AcsProject |
|
812 ): |
|
813 api = self.__apisManager.getAPIs(ApisNameProject) |
851 api = self.__apisManager.getAPIs(ApisNameProject) |
814 projectCalltips = self.__getApiCalltips( |
852 projectCalltips = self.__getApiCalltips( |
815 api, word, commas, prefix, mod, editor) |
853 api, word, commas, prefix, mod, editor |
816 |
854 ) |
|
855 |
817 if self.__plugin.getPreferences("AutoCompletionSource") & AcsDocument: |
856 if self.__plugin.getPreferences("AutoCompletionSource") & AcsDocument: |
818 documentCalltips = self.__getDocumentCalltips( |
857 documentCalltips = self.__getDocumentCalltips(word, prefix, mod, editor) |
819 word, prefix, mod, editor) |
858 |
820 |
|
821 return sorted( |
859 return sorted( |
822 set(apiCalltips) |
860 set(apiCalltips).union(set(projectCalltips)).union(set(documentCalltips)) |
823 .union(set(projectCalltips)) |
|
824 .union(set(documentCalltips)) |
|
825 ) |
861 ) |
826 |
862 |
827 def __getApiCalltips(self, api, word, commas, prefix, module, editor): |
863 def __getApiCalltips(self, api, word, commas, prefix, module, editor): |
828 """ |
864 """ |
829 Private method to determine calltips from APIs. |
865 Private method to determine calltips from APIs. |
830 |
866 |
831 @param api reference to the API object to be used |
867 @param api reference to the API object to be used |
832 @type APIsManager.DbAPIs |
868 @type APIsManager.DbAPIs |
833 @param word function to get calltips for |
869 @param word function to get calltips for |
834 @type str |
870 @type str |
835 @param commas minimum number of commas contained in the calltip |
871 @param commas minimum number of commas contained in the calltip |
890 # prefix can be 'self', 'cls' or a class name |
932 # prefix can be 'self', 'cls' or a class name |
891 sep = editor.getLexer().autoCompletionWordSeparators()[0] |
933 sep = editor.getLexer().autoCompletionWordSeparators()[0] |
892 if prefix in ["self", "cls"]: |
934 if prefix in ["self", "cls"]: |
893 line, col = editor.getCursorPosition() |
935 line, col = editor.getCursorPosition() |
894 for cl in module.classes.values(): |
936 for cl in module.classes.values(): |
895 if ( |
937 if line >= cl.lineno and ( |
896 line >= cl.lineno and |
938 cl.endlineno == -1 or line <= cl.endlineno |
897 (cl.endlineno == -1 or line <= cl.endlineno) |
|
898 ): |
939 ): |
899 if word in cl.methods: |
940 if word in cl.methods: |
900 method = cl.methods[word] |
941 method = cl.methods[word] |
901 if ( |
942 if prefix == "self" or ( |
902 prefix == "self" or |
943 prefix == "cls" and method.modifier == method.Class |
903 (prefix == "cls" and |
|
904 method.modifier == method.Class) |
|
905 ): |
944 ): |
906 calltips.append( |
945 calltips.append( |
907 "{0}{1}{2}({3})".format( |
946 "{0}{1}{2}({3})".format( |
908 cl.name, |
947 cl.name, |
909 sep, |
948 sep, |
910 word, |
949 word, |
911 ', '.join(method.parameters[1:] |
950 ", ".join(method.parameters[1:]), |
912 ))) |
951 ) |
913 |
952 ) |
|
953 |
914 for sup in cl.super: |
954 for sup in cl.super: |
915 calltips.extend(self.__getDocumentCalltips( |
955 calltips.extend( |
916 word, sup, module, editor, |
956 self.__getDocumentCalltips( |
917 doHierarchy=True)) |
957 word, sup, module, editor, doHierarchy=True |
918 |
958 ) |
|
959 ) |
|
960 |
919 break |
961 break |
920 else: |
962 else: |
921 if prefix in module.classes: |
963 if prefix in module.classes: |
922 cl = module.classes[prefix] |
964 cl = module.classes[prefix] |
923 if word in cl.methods: |
965 if word in cl.methods: |
924 method = cl.methods[word] |
966 method = cl.methods[word] |
925 if doHierarchy or method.modifier == method.Class: |
967 if doHierarchy or method.modifier == method.Class: |
926 calltips.append("{0}{1}{2}({3})".format( |
968 calltips.append( |
927 cl.name, |
969 "{0}{1}{2}({3})".format( |
928 sep, |
970 cl.name, |
929 word, |
971 sep, |
930 ', '.join(method.parameters[1:]))) |
972 word, |
931 |
973 ", ".join(method.parameters[1:]), |
|
974 ) |
|
975 ) |
|
976 |
932 for sup in cl.super: |
977 for sup in cl.super: |
933 calltips.extend(self.__getDocumentCalltips( |
978 calltips.extend( |
934 word, sup, module, editor, doHierarchy=True)) |
979 self.__getDocumentCalltips( |
|
980 word, sup, module, editor, doHierarchy=True |
|
981 ) |
|
982 ) |
935 else: |
983 else: |
936 # calltip for a module function or class |
984 # calltip for a module function or class |
937 if word in module.functions: |
985 if word in module.functions: |
938 fun = module.functions[word] |
986 fun = module.functions[word] |
939 calltips.append("{0}({1})".format( |
987 calltips.append("{0}({1})".format(word, ", ".join(fun.parameters))) |
940 word, |
|
941 ', '.join(fun.parameters))) |
|
942 elif word in module.classes: |
988 elif word in module.classes: |
943 cl = module.classes[word] |
989 cl = module.classes[word] |
944 if "__init__" in cl.methods: |
990 if "__init__" in cl.methods: |
945 method = cl.methods["__init__"] |
991 method = cl.methods["__init__"] |
946 calltips.append("{0}({1})".format( |
992 calltips.append( |
947 word, |
993 "{0}({1})".format(word, ", ".join(method.parameters[1:])) |
948 ', '.join(method.parameters[1:]))) |
994 ) |
949 |
995 |
950 return calltips |
996 return calltips |
|
997 |
951 |
998 |
952 # |
999 # |
953 # eflag: noqa = M834, W605 |
1000 # eflag: noqa = M834, W605 |