src/eric7/Sessions/SessionFile.py

branch
eric7
changeset 9209
b99e7fd55fd3
parent 8881
54e42bc2437a
child 9221
bf71ee032bb4
equal deleted inserted replaced
9208:3fc8dfeb6ebe 9209:b99e7fd55fd3
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2021 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a class representing the session JSON file.
8 """
9
10 import contextlib
11 import json
12 import time
13
14 from PyQt6.QtCore import Qt, QObject
15
16 from EricWidgets import EricMessageBox
17 from EricGui.EricOverrideCursor import EricOverridenCursor
18 from EricWidgets.EricApplication import ericApp
19
20 import Preferences
21
22
23 class SessionFile(QObject):
24 """
25 Class representing the session JSON file.
26 """
27 def __init__(self, isGlobal: bool, parent: QObject = None):
28 """
29 Constructor
30
31 @param isGlobal flag indicating a file for a global session
32 @type bool
33 @param parent reference to the parent object (defaults to None)
34 @type QObject (optional)
35 """
36 super().__init__(parent)
37
38 self.__isGlobal = isGlobal
39
40 def writeFile(self, filename: str) -> bool:
41 """
42 Public method to write the session data to a session JSON file.
43
44 @param filename name of the session file
45 @type str
46 @return flag indicating a successful write
47 @rtype bool
48 """
49 # get references to objects we need
50 project = ericApp().getObject("Project")
51 projectBrowser = ericApp().getObject("ProjectBrowser")
52 multiProject = ericApp().getObject("MultiProject")
53 vm = ericApp().getObject("ViewManager")
54 dbg = ericApp().getObject("DebugUI")
55 dbs = ericApp().getObject("DebugServer")
56
57 # prepare the session data dictionary
58 # step 0: header
59 sessionDict = {}
60 sessionDict["header"] = {}
61 if not self.__isGlobal:
62 sessionDict["header"]["comment"] = (
63 "eric session file for project {0}"
64 .format(project.getProjectName())
65 )
66 sessionDict["header"]["warning"] = (
67 "This file was generated automatically, do not edit."
68 )
69
70 if Preferences.getProject("TimestampFile") or self.__isGlobal:
71 sessionDict["header"]["saved"] = (
72 time.strftime('%Y-%m-%d, %H:%M:%S')
73 )
74
75 # step 1: open multi project and project for global session
76 sessionDict["MultiProject"] = ""
77 sessionDict["Project"] = ""
78 if self.__isGlobal:
79 if multiProject.isOpen():
80 sessionDict["MultiProject"] = (
81 multiProject.getMultiProjectFile()
82 )
83 if project.isOpen():
84 sessionDict["Project"] = project.getProjectFile()
85
86 # step 2: all open (project) filenames and the active editor
87 if vm.canSplit():
88 sessionDict["ViewManagerSplits"] = {
89 "Count": vm.splitCount(),
90 "Orientation": vm.getSplitOrientation().value,
91 }
92 else:
93 sessionDict["ViewManagerSplits"] = {
94 "Count": 0,
95 "Orientation": 1,
96 }
97
98 editorsDict = {} # remember editors by file name to detect clones
99 sessionDict["Editors"] = []
100 allOpenEditorLists = vm.getOpenEditorsForSession()
101 for splitIndex, openEditorList in enumerate(allOpenEditorLists):
102 for editorIndex, editor in enumerate(openEditorList):
103 fileName = editor.getFileName()
104 if self.__isGlobal or project.isProjectFile(fileName):
105 if fileName in editorsDict:
106 isClone = editorsDict[fileName].isClone(editor)
107 else:
108 isClone = False
109 editorsDict[fileName] = editor
110 editorDict = {
111 "Filename": fileName,
112 "Cursor": editor.getCursorPosition(),
113 "Folds": editor.contractedFolds(),
114 "Zoom": editor.getZoom(),
115 "Clone": isClone,
116 "Splitindex": splitIndex,
117 "Editorindex": editorIndex,
118 }
119 sessionDict["Editors"].append(editorDict)
120
121 aw = vm.getActiveName()
122 sessionDict["ActiveWindow"] = {}
123 if aw and (self.__isGlobal or project.isProjectFile(aw)):
124 ed = vm.getOpenEditor(aw)
125 sessionDict["ActiveWindow"] = {
126 "Filename": aw,
127 "Cursor": ed.getCursorPosition(),
128 }
129
130 # step 3: breakpoints
131 allBreaks = Preferences.getProject("SessionAllBreakpoints")
132 projectFiles = project.getSources(True)
133 bpModel = dbs.getBreakPointModel()
134 if self.__isGlobal or allBreaks:
135 sessionDict["Breakpoints"] = bpModel.getAllBreakpoints()
136 else:
137 sessionDict["Breakpoints"] = [
138 bp
139 for bp in bpModel.getAllBreakpoints()
140 if bp[0] in projectFiles
141 ]
142
143 # step 4: watch expressions
144 wpModel = dbs.getWatchPointModel()
145 sessionDict["Watchpoints"] = wpModel.getAllWatchpoints()
146
147 # step 5: debug info
148 if self.__isGlobal:
149 if len(dbg.scriptsHistory):
150 dbgScriptName = dbg.scriptsHistory[0]
151 else:
152 dbgScriptName = ""
153 if len(dbg.argvHistory):
154 dbgCmdline = dbg.argvHistory[0]
155 else:
156 dbgCmdline = ""
157 if len(dbg.wdHistory):
158 dbgWd = dbg.wdHistory[0]
159 else:
160 dbgWd = ""
161 if len(dbg.envHistory):
162 dbgEnv = dbg.envHistory[0]
163 else:
164 dbgEnv = ""
165 if len(dbg.multiprocessNoDebugHistory):
166 dbgMultiprocessNoDebug = (
167 dbg.multiprocessNoDebugHistory[0]
168 )
169 else:
170 dbgMultiprocessNoDebug = ""
171 sessionDict["DebugInfo"] = {
172 "VirtualEnv": dbg.lastUsedVenvName,
173 "ScriptName": dbgScriptName,
174 "CommandLine": dbgCmdline,
175 "WorkingDirectory": dbgWd,
176 "Environment": dbgEnv,
177 "ReportExceptions": dbg.exceptions,
178 "Exceptions": dbg.excList,
179 "IgnoredExceptions": dbg.excIgnoreList,
180 "AutoClearShell": dbg.autoClearShell,
181 "TracePython": dbg.tracePython,
182 "AutoContinue": dbg.autoContinue,
183 "EnableMultiprocess": dbg.enableMultiprocess,
184 "MultiprocessNoDebug": dbgMultiprocessNoDebug,
185 "GlobalConfigOverride": dbg.overrideGlobalConfig,
186 }
187 else:
188 sessionDict["DebugInfo"] = {
189 "VirtualEnv": project.dbgVirtualEnv,
190 "ScriptName": "",
191 "CommandLine": project.dbgCmdline,
192 "WorkingDirectory": project.dbgWd,
193 "Environment": project.dbgEnv,
194 "ReportExceptions": project.dbgReportExceptions,
195 "Exceptions": project.dbgExcList,
196 "IgnoredExceptions": project.dbgExcIgnoreList,
197 "AutoClearShell": project.dbgAutoClearShell,
198 "TracePython": project.dbgTracePython,
199 "AutoContinue": project.dbgAutoContinue,
200 "EnableMultiprocess": project.dbgEnableMultiprocess,
201 "MultiprocessNoDebug": project.dbgMultiprocessNoDebug,
202 "GlobalConfigOverride": project.dbgGlobalConfigOverride,
203 }
204
205 # step 6: bookmarks
206 bookmarksList = []
207 for fileName in editorsDict:
208 if self.__isGlobal or project.isProjectFile(fileName):
209 editor = editorsDict[fileName]
210 bookmarks = editor.getBookmarks()
211 if bookmarks:
212 bookmarksList.append({
213 "Filename": fileName,
214 "Lines": bookmarks,
215 })
216 sessionDict["Bookmarks"] = bookmarksList
217
218 # step 7: state of the various project browsers
219 browsersList = []
220 for browserName in projectBrowser.getProjectBrowserNames():
221 expandedItems = (
222 projectBrowser.getProjectBrowser(browserName)
223 .getExpandedItemNames()
224 )
225 if expandedItems:
226 browsersList.append({
227 "Name": browserName,
228 "ExpandedItems": expandedItems,
229 })
230 sessionDict["ProjectBrowserStates"] = browsersList
231
232 try:
233 jsonString = json.dumps(sessionDict, indent=2)
234 with open(filename, "w") as f:
235 f.write(jsonString)
236 except (TypeError, OSError) as err:
237 with EricOverridenCursor():
238 EricMessageBox.critical(
239 None,
240 self.tr("Save Session"),
241 self.tr(
242 "<p>The session file <b>{0}</b> could not be"
243 " written.</p><p>Reason: {1}</p>"
244 ).format(filename, str(err))
245 )
246 return False
247
248 return True
249
250 def readFile(self, filename: str) -> bool:
251 """
252 Public method to read the session data from a session JSON file.
253
254 @param filename name of the project file
255 @type str
256 @return flag indicating a successful read
257 @rtype bool
258 """
259 try:
260 with open(filename, "r") as f:
261 jsonString = f.read()
262 sessionDict = json.loads(jsonString)
263 except (OSError, json.JSONDecodeError) as err:
264 EricMessageBox.critical(
265 None,
266 self.tr("Read Session"),
267 self.tr(
268 "<p>The session file <b>{0}</b> could not be read.</p>"
269 "<p>Reason: {1}</p>"
270 ).format(filename, str(err))
271 )
272 return False
273
274 # get references to objects we need
275 project = ericApp().getObject("Project")
276 projectBrowser = ericApp().getObject("ProjectBrowser")
277 multiProject = ericApp().getObject("MultiProject")
278 vm = ericApp().getObject("ViewManager")
279 dbg = ericApp().getObject("DebugUI")
280 dbs = ericApp().getObject("DebugServer")
281
282 # step 1: multi project and project
283 # =================================
284 if sessionDict["MultiProject"]:
285 multiProject.openMultiProject(sessionDict["MultiProject"], False)
286 if sessionDict["Project"]:
287 project.openProject(sessionDict["Project"], False)
288
289 # step 2: (project) filenames and the active editor
290 # =================================================
291 vm.setSplitOrientation(
292 Qt.Orientation(sessionDict["ViewManagerSplits"]["Orientation"])
293 )
294 vm.setSplitCount(sessionDict["ViewManagerSplits"]["Count"])
295
296 editorsDict = {}
297 for editorDict in sessionDict["Editors"]:
298 if editorDict["Clone"] and editorDict["Filename"] in editorsDict:
299 editor = editorsDict[editorDict["Filename"]]
300 ed = vm.newEditorView(
301 editorDict["Filename"], editor, editor.getFileType(),
302 indexes=(editorDict["Splitindex"],
303 editorDict["Editorindex"])
304 )
305 else:
306 ed = vm.openSourceFile(
307 editorDict["Filename"],
308 indexes=(editorDict["Splitindex"],
309 editorDict["Editorindex"])
310 )
311 editorsDict[editorDict["Filename"]] = ed
312 if ed is not None:
313 ed.zoomTo(editorDict["Zoom"])
314 if editorDict["Folds"]:
315 ed.recolor()
316 ed.setContractedFolds(editorDict["Folds"])
317 ed.setCursorPosition(*editorDict["Cursor"])
318
319 # step 3: breakpoints
320 # ===================
321 bpModel = dbs.getBreakPointModel()
322 bpModel.addBreakPoints(sessionDict["Breakpoints"])
323
324 # step 4: watch expressions
325 # =========================
326 wpModel = dbs.getWatchPointModel()
327 wpModel.addWatchPoints(sessionDict["Watchpoints"])
328
329 # step 5: debug info
330 # ==================
331 debugInfoDict = sessionDict["DebugInfo"]
332
333 # adjust for newer session types
334 if "GlobalConfigOverride" not in debugInfoDict:
335 debugInfoDict["GlobalConfigOverride"] = {
336 "enable": False,
337 "redirect": True,
338 }
339
340 dbg.lastUsedVenvName = debugInfoDict["VirtualEnv"]
341 with contextlib.suppress(KeyError):
342 dbg.setScriptsHistory(debugInfoDict["ScriptName"])
343 dbg.setArgvHistory(debugInfoDict["CommandLine"])
344 dbg.setWdHistory(debugInfoDict["WorkingDirectory"])
345 dbg.setEnvHistory(debugInfoDict["Environment"])
346 dbg.setExceptionReporting(debugInfoDict["ReportExceptions"])
347 dbg.setExcList(debugInfoDict["Exceptions"])
348 dbg.setExcIgnoreList(debugInfoDict["IgnoredExceptions"])
349 dbg.setAutoClearShell(debugInfoDict["AutoClearShell"])
350 dbg.setTracePython(debugInfoDict["TracePython"])
351 dbg.setAutoContinue(debugInfoDict["AutoContinue"])
352 dbg.setEnableMultiprocess(debugInfoDict["EnableMultiprocess"])
353 dbg.setMultiprocessNoDebugHistory(debugInfoDict["MultiprocessNoDebug"])
354 dbg.setEnableGlobalConfigOverride(
355 debugInfoDict["GlobalConfigOverride"])
356 if not self.__isGlobal:
357 project.setDbgInfo(
358 debugInfoDict["VirtualEnv"],
359 debugInfoDict["CommandLine"],
360 debugInfoDict["WorkingDirectory"],
361 debugInfoDict["Environment"],
362 debugInfoDict["ReportExceptions"],
363 debugInfoDict["Exceptions"],
364 debugInfoDict["IgnoredExceptions"],
365 debugInfoDict["AutoClearShell"],
366 debugInfoDict["TracePython"],
367 debugInfoDict["AutoContinue"],
368 debugInfoDict["EnableMultiprocess"],
369 debugInfoDict["MultiprocessNoDebug"],
370 debugInfoDict["GlobalConfigOverride"],
371 )
372
373 # step 6: bookmarks
374 # =================
375 for bookmark in sessionDict["Bookmarks"]:
376 editor = vm.getOpenEditor(bookmark["Filename"])
377 if editor is not None:
378 for lineno in bookmark["Lines"]:
379 editor.toggleBookmark(lineno)
380
381 # step 7: state of the various project browsers
382 # =============================================
383 for browserState in sessionDict["ProjectBrowserStates"]:
384 browser = projectBrowser.getProjectBrowser(browserState["Name"])
385 if browser is not None:
386 browser.expandItemsByName(browserState["ExpandedItems"])
387
388 # step 8: active window
389 # =====================
390 if sessionDict["ActiveWindow"]:
391 vm.openFiles(sessionDict["ActiveWindow"]["Filename"])
392 ed = vm.getOpenEditor(sessionDict["ActiveWindow"]["Filename"])
393 if ed is not None:
394 ed.setCursorPosition(*sessionDict["ActiveWindow"]["Cursor"])
395 ed.ensureCursorVisible()
396
397 return True

eric ide

mercurial