src/eric7/QScintilla/APIsManager.py

branch
eric7
changeset 9209
b99e7fd55fd3
parent 9186
0c28a1670e06
child 9221
bf71ee032bb4
equal deleted inserted replaced
9208:3fc8dfeb6ebe 9209:b99e7fd55fd3
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2007 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the APIsManager.
8 """
9
10 import os
11 import pathlib
12
13 from PyQt6.QtCore import QDir, pyqtSignal, QObject
14 from PyQt6.Qsci import QsciAPIs
15
16 from . import Lexers
17 import Preferences
18 import Globals
19
20
21 class APIs(QObject):
22 """
23 Class implementing an API storage entity.
24
25 @signal apiPreparationFinished() emitted after the API preparation has
26 finished
27 @signal apiPreparationCancelled() emitted after the API preparation has
28 been cancelled
29 @signal apiPreparationStarted() emitted after the API preparation has
30 started
31 """
32 apiPreparationFinished = pyqtSignal()
33 apiPreparationCancelled = pyqtSignal()
34 apiPreparationStarted = pyqtSignal()
35
36 def __init__(self, language, projectType="", forPreparation=False,
37 parent=None):
38 """
39 Constructor
40
41 @param language language of the APIs object
42 @type str
43 @param projectType type of the project
44 @type str
45 @param forPreparation flag indicating this object is just needed
46 for a preparation process
47 @type bool
48 @param parent reference to the parent object
49 @type QObject
50 """
51 super().__init__(parent)
52 if projectType:
53 self.setObjectName("APIs_{0}_{1}".format(language, projectType))
54 else:
55 self.setObjectName("APIs_{0}".format(language))
56
57 self.__inPreparation = False
58 self.__language = language
59 self.__projectType = projectType
60 self.__forPreparation = forPreparation
61 self.__lexer = Lexers.getLexer(self.__language)
62 self.__apifiles = Preferences.getEditorAPI(self.__language,
63 self.__projectType)
64 self.__apifiles.sort()
65 if self.__lexer is None:
66 self.__apis = None
67 else:
68 self.__apis = QsciAPIs(self.__lexer)
69 self.__apis.apiPreparationFinished.connect(
70 self.__apiPreparationFinished)
71 self.__apis.apiPreparationCancelled.connect(
72 self.__apiPreparationCancelled)
73 self.__apis.apiPreparationStarted.connect(
74 self.__apiPreparationStarted)
75 self.__loadAPIs()
76
77 def __loadAPIs(self):
78 """
79 Private method to load the APIs.
80 """
81 if self.__apis.isPrepared():
82 # load a prepared API file
83 if (
84 not self.__forPreparation and
85 Preferences.getEditor("AutoPrepareAPIs")
86 ):
87 self.prepareAPIs()
88 self.__apis.loadPrepared(self.__preparedName())
89 else:
90 # load the raw files and prepare the API file
91 if (
92 not self.__forPreparation and
93 Preferences.getEditor("AutoPrepareAPIs")
94 ):
95 self.prepareAPIs(ondemand=True)
96
97 def reloadAPIs(self):
98 """
99 Public method to reload the API information.
100 """
101 if (
102 not self.__forPreparation and
103 Preferences.getEditor("AutoPrepareAPIs")
104 ):
105 self.prepareAPIs()
106 self.__loadAPIs()
107
108 def getQsciAPIs(self):
109 """
110 Public method to get a reference to QsciAPIs object.
111
112 @return reference to the QsciAPIs object (QsciAPIs)
113 """
114 if (
115 not self.__forPreparation and
116 Preferences.getEditor("AutoPrepareAPIs")
117 ):
118 self.prepareAPIs()
119 return self.__apis
120
121 def isEmpty(self):
122 """
123 Public method to check, if the object has API files configured.
124
125 @return flag indicating no API files have been configured (boolean)
126 """
127 return len(self.__apifiles) == 0
128
129 def __apiPreparationFinished(self):
130 """
131 Private method called to save an API, after it has been prepared.
132 """
133 self.__apis.savePrepared(self.__preparedName())
134 self.__inPreparation = False
135 self.apiPreparationFinished.emit()
136
137 def __apiPreparationCancelled(self):
138 """
139 Private method called, after the API preparation process has been
140 cancelled.
141 """
142 self.__inPreparation = False
143 self.apiPreparationCancelled.emit()
144
145 def __apiPreparationStarted(self):
146 """
147 Private method called, when the API preparation process started.
148 """
149 self.__inPreparation = True
150 self.apiPreparationStarted.emit()
151
152 def prepareAPIs(self, ondemand=False, rawList=None):
153 """
154 Public method to prepare the APIs if necessary.
155
156 @param ondemand flag indicating a requested preparation (boolean)
157 @param rawList list of raw API files (list of strings)
158 """
159 if self.__apis is None or self.__inPreparation:
160 return
161
162 needsPreparation = False
163 if ondemand:
164 needsPreparation = True
165 else:
166 # check, if a new preparation is necessary
167 preparedAPIs = self.__preparedName()
168 if preparedAPIs:
169 preparedPath = pathlib.Path(preparedAPIs)
170 if not preparedPath.exists():
171 needsPreparation = True
172 else:
173 preparedAPIsModified = preparedPath.stat().st_mtime
174 apifiles = sorted(Preferences.getEditorAPI(
175 self.__language, self.__projectType))
176 if self.__apifiles != apifiles:
177 needsPreparation = True
178 for apifile in apifiles:
179 apifilePath = pathlib.Path(apifile)
180 if (
181 apifilePath.exists() and
182 apifilePath.stat().st_mtime >
183 preparedAPIsModified
184 ):
185 needsPreparation = True
186 break
187
188 if needsPreparation:
189 # do the preparation
190 self.__apis.clear()
191 if rawList:
192 apifiles = rawList
193 else:
194 apifiles = Preferences.getEditorAPI(
195 self.__language, self.__projectType)
196 for apifile in apifiles:
197 self.__apis.load(apifile)
198 self.__apis.prepare()
199 self.__apifiles = apifiles
200
201 def cancelPreparation(self):
202 """
203 Public slot to cancel the APIs preparation.
204 """
205 self.__apis and self.__apis.cancelPreparation()
206
207 def installedAPIFiles(self):
208 """
209 Public method to get a list of installed API files.
210
211 @return list of installed API files (list of strings)
212 """
213 if self.__apis is not None:
214 if Globals.isWindowsPlatform():
215 qsciPath = os.path.join(
216 Globals.getPyQt6ModulesDirectory(), "qsci")
217 if os.path.exists(qsciPath):
218 # it's the installer
219 if self.__lexer.lexerName() is not None:
220 apidir = os.path.join(qsciPath, "api",
221 self.__lexer.lexerName())
222 fnames = []
223 filist = QDir(apidir).entryInfoList(
224 ["*.api"], QDir.Filter.Files,
225 QDir.SortFlag.IgnoreCase)
226 for fi in filist:
227 fnames.append(fi.absoluteFilePath())
228 return fnames
229 else:
230 return []
231
232 return self.__apis.installedAPIFiles()
233 else:
234 return []
235
236 def __preparedName(self):
237 """
238 Private method returning the default name of a prepared API file.
239
240 @return complete filename for the Prepared APIs file (string)
241 """
242 apisDir = os.path.join(Globals.getConfigDir(), "APIs")
243 if self.__apis is not None:
244 if self.__projectType:
245 filename = "{0}_{1}.pap".format(self.__language,
246 self.__projectType)
247 else:
248 filename = "{0}.pap".format(self.__language)
249 return os.path.join(apisDir, filename)
250 else:
251 return ""
252
253
254 class APIsManager(QObject):
255 """
256 Class implementing the APIsManager class, which is the central store for
257 API information used by autocompletion and calltips.
258 """
259 def __init__(self, parent=None):
260 """
261 Constructor
262
263 @param parent reference to the parent object (QObject)
264 """
265 super().__init__(parent)
266 self.setObjectName("APIsManager")
267
268 self.__apis = {}
269
270 def reloadAPIs(self):
271 """
272 Public slot to reload the api information.
273 """
274 for api in list(self.__apis.values()):
275 api and api.reloadAPIs()
276
277 def getAPIs(self, language, projectType="", forPreparation=False):
278 """
279 Public method to get an APIs object for autocompletion/calltips.
280
281 This method creates and loads an APIs object dynamically upon request.
282 This saves memory for languages, that might not be needed at the
283 moment.
284
285 @param language language of the requested APIs object
286 @type str
287 @param projectType type of the project
288 @type str
289 @param forPreparation flag indicating the requested APIs object is just
290 needed for a preparation process
291 @type bool
292 @return reference to the APIs object
293 @rtype APIs
294 """
295 if forPreparation:
296 return APIs(language, projectType=projectType,
297 forPreparation=forPreparation)
298 else:
299 try:
300 return self.__apis[(language, projectType)]
301 except KeyError:
302 if language in Lexers.getSupportedApiLanguages():
303 # create the api object
304 self.__apis[(language, projectType)] = APIs(
305 language, projectType=projectType)
306 return self.__apis[(language, projectType)]
307 else:
308 return None

eric ide

mercurial