8 calltips system. |
8 calltips system. |
9 """ |
9 """ |
10 |
10 |
11 import re |
11 import re |
12 |
12 |
13 from PyQt4.QtCore import * |
13 from PyQt4.QtCore import QRegExp, QObject |
14 |
14 |
15 from E5Gui.E5Application import e5App |
15 from E5Gui.E5Application import e5App |
16 |
16 |
17 from .APIsManager import APIsManager, ApisNameProject |
17 from .APIsManager import APIsManager, ApisNameProject |
18 |
18 |
19 from QScintilla.Editor import Editor |
19 from QScintilla.Editor import Editor |
20 |
20 |
21 import Preferences |
21 import Preferences |
22 |
22 |
23 AcsAPIs = 0x0001 |
23 AcsAPIs = 0x0001 |
24 AcsDocument = 0x0002 |
24 AcsDocument = 0x0002 |
25 AcsProject = 0x0004 |
25 AcsProject = 0x0004 |
26 AcsOther = 0x1000 |
26 AcsOther = 0x1000 |
|
27 |
27 |
28 |
28 class Assistant(QObject): |
29 class Assistant(QObject): |
29 """ |
30 """ |
30 Class implementing the autocompletion and calltips system. |
31 Class implementing the autocompletion and calltips system. |
31 """ |
32 """ |
32 def __init__(self, plugin, newStyle, parent = None): |
33 def __init__(self, plugin, parent=None): |
33 """ |
34 """ |
34 Constructor |
35 Constructor |
35 |
36 |
36 @param plugin reference to the plugin object |
37 @param plugin reference to the plugin object |
37 @param newStyle flag indicating usage of new style signals (bool) |
|
38 @param parent parent (QObject) |
38 @param parent parent (QObject) |
39 """ |
39 """ |
40 QObject.__init__(self, parent) |
40 QObject.__init__(self, parent) |
41 |
41 |
42 self.__plugin = plugin |
42 self.__plugin = plugin |
43 self.__newStyle = newStyle |
|
44 self.__ui = parent |
43 self.__ui = parent |
45 self.__project = e5App().getObject("Project") |
44 self.__project = e5App().getObject("Project") |
46 self.__viewmanager = e5App().getObject("ViewManager") |
45 self.__viewmanager = e5App().getObject("ViewManager") |
47 self.__pluginManager = e5App().getObject("PluginManager") |
46 self.__pluginManager = e5App().getObject("PluginManager") |
48 |
47 |
49 self.__apisManager = APIsManager(self.__newStyle, self) |
48 self.__apisManager = APIsManager(self) |
50 |
49 |
51 self.__editors = [] |
50 self.__editors = [] |
52 self.__completingContext = False |
51 self.__completingContext = False |
53 self.__lastContext = None |
52 self.__lastContext = None |
54 self.__lastFullContext = None |
53 self.__lastFullContext = None |
57 |
56 |
58 def activate(self): |
57 def activate(self): |
59 """ |
58 """ |
60 Public method to perform actions upon activation. |
59 Public method to perform actions upon activation. |
61 """ |
60 """ |
62 if self.__newStyle: |
61 self.__pluginManager.shutdown.connect(self.__shutdown) |
63 self.__pluginManager.shutdown.connect(self.__shutdown) |
62 |
64 |
63 self.__ui.preferencesChanged.connect(self.__preferencesChanged) |
65 self.__ui.preferencesChanged.connect(self.__preferencesChanged) |
64 |
66 |
65 self.__viewmanager.editorOpenedEd.connect(self.__editorOpened) |
67 self.__viewmanager.editorOpenedEd.connect(self.__editorOpened) |
66 self.__viewmanager.editorClosedEd.connect(self.__editorClosed) |
68 self.__viewmanager.editorClosedEd.connect(self.__editorClosed) |
|
69 else: |
|
70 self.connect(self.__pluginManager, SIGNAL("shutdown()"), |
|
71 self.__shutdown) |
|
72 |
|
73 self.connect(self.__ui, SIGNAL('preferencesChanged'), |
|
74 self.__preferencesChanged) |
|
75 |
|
76 self.connect(self.__viewmanager, SIGNAL("editorOpenedEd"), |
|
77 self.__editorOpened) |
|
78 self.connect(self.__viewmanager, SIGNAL("editorClosedEd"), |
|
79 self.__editorClosed) |
|
80 |
67 |
81 # preload the project APIs object |
68 # preload the project APIs object |
82 self.__apisManager.getAPIs(ApisNameProject) |
69 self.__apisManager.getAPIs(ApisNameProject) |
83 |
70 |
84 for editor in self.__viewmanager.getOpenEditors(): |
71 for editor in self.__viewmanager.getOpenEditors(): |
86 |
73 |
87 def deactivate(self): |
74 def deactivate(self): |
88 """ |
75 """ |
89 Public method to perform actions upon deactivation. |
76 Public method to perform actions upon deactivation. |
90 """ |
77 """ |
91 if self.__newStyle: |
78 self.__pluginManager.shutdown.disconnect(self.__shutdown) |
92 self.__pluginManager.shutdown.disconnect(self.__shutdown) |
79 |
93 |
80 self.__ui.preferencesChanged.disconnect(self.__preferencesChanged) |
94 self.__ui.preferencesChanged.disconnect(self.__preferencesChanged) |
81 |
95 |
82 self.__viewmanager.editorOpenedEd.disconnect(self.__editorOpened) |
96 self.__viewmanager.editorOpenedEd.disconnect(self.__editorOpened) |
83 self.__viewmanager.editorClosedEd.disconnect(self.__editorClosed) |
97 self.__viewmanager.editorClosedEd.disconnect(self.__editorClosed) |
|
98 else: |
|
99 self.disconnect(self.__pluginManager, SIGNAL("shutdown()"), |
|
100 self.__shutdown) |
|
101 |
|
102 self.disconnect(self.__ui, SIGNAL('preferencesChanged'), |
|
103 self.__preferencesChanged) |
|
104 |
|
105 self.disconnect(self.__viewmanager, SIGNAL("editorOpenedEd"), |
|
106 self.__editorOpened) |
|
107 self.disconnect(self.__viewmanager, SIGNAL("editorClosedEd"), |
|
108 self.__editorClosed) |
|
109 |
84 |
110 self.__shutdown() |
85 self.__shutdown() |
111 |
86 |
112 def __shutdown(self): |
87 def __shutdown(self): |
113 """ |
88 """ |
139 """ |
114 """ |
140 if self.__plugin.getPreferences("AutoCompletionEnabled"): |
115 if self.__plugin.getPreferences("AutoCompletionEnabled"): |
141 self.__setAutoCompletionHook(editor) |
116 self.__setAutoCompletionHook(editor) |
142 if self.__plugin.getPreferences("CalltipsEnabled"): |
117 if self.__plugin.getPreferences("CalltipsEnabled"): |
143 self.__setCalltipsHook(editor) |
118 self.__setCalltipsHook(editor) |
144 if self.__newStyle: |
119 editor.editorSaved.connect( |
145 editor.editorSaved.connect( |
120 self.__apisManager.getAPIs(ApisNameProject).editorSaved) |
146 self.__apisManager.getAPIs(ApisNameProject).editorSaved) |
|
147 else: |
|
148 self.connect(editor, SIGNAL("editorSaved"), |
|
149 self.__apisManager.getAPIs(ApisNameProject).editorSaved) |
|
150 self.__editors.append(editor) |
121 self.__editors.append(editor) |
151 |
122 |
152 # preload the api to give the manager a chance to prepare the database |
123 # preload the api to give the manager a chance to prepare the database |
153 language = editor.getLanguage() |
124 language = editor.getLanguage() |
154 if language == "": |
125 if language == "": |
160 Private slot called, when an editor was closed. |
131 Private slot called, when an editor was closed. |
161 |
132 |
162 @param editor reference to the editor (QScintilla.Editor) |
133 @param editor reference to the editor (QScintilla.Editor) |
163 """ |
134 """ |
164 if editor in self.__editors: |
135 if editor in self.__editors: |
165 if self.__newStyle: |
136 editor.editorSaved.disconnect( |
166 editor.editorSaved.disconnect( |
137 self.__apisManager.getAPIs(ApisNameProject).editorSaved) |
167 self.__apisManager.getAPIs(ApisNameProject).editorSaved) |
|
168 else: |
|
169 self.disconnect(editor, SIGNAL("editorSaved"), |
|
170 self.__apisManager.getAPIs(ApisNameProject).editorSaved) |
|
171 self.__editors.remove(editor) |
138 self.__editors.remove(editor) |
172 if editor.autoCompletionHook() == self.autocomplete: |
139 if editor.autoCompletionHook() == self.autocomplete: |
173 self.__unsetAutoCompletionHook(editor) |
140 self.__unsetAutoCompletionHook(editor) |
174 if editor.callTipHook() == self.calltips: |
141 if editor.callTipHook() == self.calltips: |
175 self.__unsetCalltipsHook(editor) |
142 self.__unsetCalltipsHook(editor) |
201 return "", pos |
168 return "", pos |
202 |
169 |
203 return ch, pos |
170 return ch, pos |
204 |
171 |
205 ################################# |
172 ################################# |
206 ## autocompletion methods below |
173 ## autocompletion methods below |
207 ################################# |
174 ################################# |
208 |
175 |
209 def __completionListSelected(self, id, txt): |
176 def __completionListSelected(self, id, txt): |
210 """ |
177 """ |
211 Private slot to handle the selection from the completion list. |
178 Private slot to handle the selection from the completion list. |
244 """ |
211 """ |
245 Private method to set the autocompletion hook. |
212 Private method to set the autocompletion hook. |
246 |
213 |
247 @param editor reference to the editor (QScintilla.Editor) |
214 @param editor reference to the editor (QScintilla.Editor) |
248 """ |
215 """ |
249 if self.__newStyle: |
216 editor.userListActivated.connect(self.__completionListSelected) |
250 editor.userListActivated.connect(self.__completionListSelected) |
|
251 else: |
|
252 self.connect(editor, SIGNAL('userListActivated(int, const QString)'), |
|
253 self.__completionListSelected) |
|
254 editor.setAutoCompletionHook(self.autocomplete) |
217 editor.setAutoCompletionHook(self.autocomplete) |
255 |
218 |
256 def __unsetAutoCompletionHook(self, editor): |
219 def __unsetAutoCompletionHook(self, editor): |
257 """ |
220 """ |
258 Private method to unset the autocompletion hook. |
221 Private method to unset the autocompletion hook. |
259 |
222 |
260 @param editor reference to the editor (QScintilla.Editor) |
223 @param editor reference to the editor (QScintilla.Editor) |
261 """ |
224 """ |
262 editor.unsetAutoCompletionHook() |
225 editor.unsetAutoCompletionHook() |
263 if self.__newStyle: |
226 editor.userListActivated.disconnect(self.__completionListSelected) |
264 editor.userListActivated.disconnect(self.__completionListSelected) |
|
265 else: |
|
266 self.disconnect(editor, SIGNAL('userListActivated(int, const QString)'), |
|
267 self.__completionListSelected) |
|
268 |
227 |
269 def autocomplete(self, editor, context): |
228 def autocomplete(self, editor, context): |
270 """ |
229 """ |
271 Public method to determine the autocompletion proposals. |
230 Public method to determine the autocompletion proposals. |
272 |
231 |
362 @return list of possible completions (list of strings) |
321 @return list of possible completions (list of strings) |
363 """ |
322 """ |
364 completionsList = [] |
323 completionsList = [] |
365 if api is not None: |
324 if api is not None: |
366 if context: |
325 if context: |
367 completions = api.getCompletions(context = word) |
326 completions = api.getCompletions(context=word) |
368 for completion in completions: |
327 for completion in completions: |
369 entry = completion["completion"] |
328 entry = completion["completion"] |
370 if completion["pictureId"]: |
329 if completion["pictureId"]: |
371 entry += "?{0}".format(completion["pictureId"]) |
330 entry += "?{0}".format(completion["pictureId"]) |
372 if entry not in completionsList: |
331 if entry not in completionsList: |
373 completionsList.append(entry) |
332 completionsList.append(entry) |
374 else: |
333 else: |
375 completions = api.getCompletions(start = word) |
334 completions = api.getCompletions(start=word) |
376 for completion in completions: |
335 for completion in completions: |
377 if not completion["context"]: |
336 if not completion["context"]: |
378 entry = completion["completion"] |
337 entry = completion["completion"] |
379 else: |
338 else: |
380 entry = "{0} ({1})".format( |
339 entry = "{0} ({1})".format( |
381 completion["completion"], |
340 completion["completion"], |
382 completion["context"] |
341 completion["context"] |
383 ) |
342 ) |
384 if entry in completionsList: |
343 if entry in completionsList: |
385 completionsList.remove(entry) |
344 completionsList.remove(entry) |
386 if completion["pictureId"]: |
345 if completion["pictureId"]: |
415 |
374 |
416 if editor.isUtf8(): |
375 if editor.isUtf8(): |
417 sword = word.encode("utf-8") |
376 sword = word.encode("utf-8") |
418 else: |
377 else: |
419 sword = word |
378 sword = word |
420 res = editor.findFirstTarget(sword, False, |
379 res = editor.findFirstTarget(sword, False, |
421 editor.autoCompletionCaseSensitivity(), |
380 editor.autoCompletionCaseSensitivity(), |
422 False, begline = 0, begindex = 0, ws_ = True) |
381 False, begline=0, begindex=0, ws_=True) |
423 while res: |
382 while res: |
424 start, length = editor.getFoundTarget() |
383 start, length = editor.getFoundTarget() |
425 pos = start + length |
384 pos = start + length |
426 if pos != currentPos: |
385 if pos != currentPos: |
427 if context: |
386 if context: |
428 completion = "" |
387 completion = "" |
429 else: |
388 else: |
430 completion = word |
389 completion = word |
431 line, index = editor.lineIndexFromPosition(pos) |
390 line, index = editor.lineIndexFromPosition(pos) |
432 curWord = editor.getWord(line, index, useWordChars = False) |
391 curWord = editor.getWord(line, index, useWordChars=False) |
433 completion += curWord[len(completion):] |
392 completion += curWord[len(completion):] |
434 if completion and completion not in completionsList: |
393 if completion and completion not in completionsList: |
435 completionsList.append( |
394 completionsList.append( |
436 "{0}?{1}".format(completion, self.__fromDocumentID)) |
395 "{0}?{1}".format(completion, self.__fromDocumentID)) |
437 |
396 |
439 |
398 |
440 completionsList.sort() |
399 completionsList.sort() |
441 return completionsList |
400 return completionsList |
442 |
401 |
443 ########################### |
402 ########################### |
444 ## calltips methods below |
403 ## calltips methods below |
445 ########################### |
404 ########################### |
446 |
405 |
447 def __setCalltipsHook(self, editor): |
406 def __setCalltipsHook(self, editor): |
448 """ |
407 """ |
449 Private method to set the calltip hook. |
408 Private method to set the calltip hook. |
486 projectCalltips = [] |
445 projectCalltips = [] |
487 |
446 |
488 if self.__plugin.getPreferences("AutoCompletionSource") & AcsAPIs: |
447 if self.__plugin.getPreferences("AutoCompletionSource") & AcsAPIs: |
489 api = self.__apisManager.getAPIs(language) |
448 api = self.__apisManager.getAPIs(language) |
490 if api is not None: |
449 if api is not None: |
491 apiCalltips = api.getCalltips(word, commas, self.__lastContext, |
450 apiCalltips = api.getCalltips(word, commas, self.__lastContext, |
492 self.__lastFullContext, |
451 self.__lastFullContext, |
493 self.__plugin.getPreferences("CallTipsContextShown")) |
452 self.__plugin.getPreferences("CallTipsContextShown")) |
494 |
453 |
495 if self.__plugin.getPreferences("AutoCompletionSource") & AcsProject: |
454 if self.__plugin.getPreferences("AutoCompletionSource") & AcsProject: |
496 api = self.__apisManager.getAPIs(ApisNameProject) |
455 api = self.__apisManager.getAPIs(ApisNameProject) |
497 projectCalltips = api.getCalltips(word, commas, self.__lastContext, |
456 projectCalltips = api.getCalltips(word, commas, self.__lastContext, |
498 self.__lastFullContext, |
457 self.__lastFullContext, |
499 self.__plugin.getPreferences("CallTipsContextShown")) |
458 self.__plugin.getPreferences("CallTipsContextShown")) |
500 |
459 |
501 return sorted(set(apiCalltips).union(set(projectCalltips))) |
460 return sorted(set(apiCalltips).union(set(projectCalltips))) |