3 enum OpenedFileState { unknown, opened, closed };
6 no, summary, yes, full;
10 get { return OnGetString(null, null, null); }
13 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
15 if(this >= no && this <= full)
18 strcpy(tempString, valgrindLeakCheckNames[this]);
19 return valgrindLeakCheckNames[this];
21 if(tempString && tempString[0])
26 static const char * valgrindLeakCheckNames[ValgrindLeakCheck] = { "no", "summary", "yes", "full" };
28 class OpenedFileInfo : struct
34 OpenedFileState state;
43 property bool trackingAllowed
45 get { return !holdTracking && ide && ide.workspace && !ide.workspace.holdTracking; }
48 void CaretMove(int line, int charPos)
50 if(trackingAllowed && (line != lineNumber || position != charPos))
54 ide.workspace.modified = true;
58 void ScrollChange(Point scroll)
62 this.scroll.x = scroll.x;
63 this.scroll.y = scroll.y;
64 ide.workspace.modified = true;
72 List<OpenedFileInfo> files = ide.workspace.openedFiles;
73 Iterator<OpenedFileInfo> it { files };
75 if(it.Find(this) && it.pointer != (last = files.GetLast()))
77 files.Move(it.pointer, last);
78 ide.workspace.modified = true;
80 modified = GetLocalTimeStamp();
84 void SetCodeEditorState(CodeEditor editor)
86 int num = Max(lineNumber - 1, 0);
89 if(editor.editBox.GoToLineNum(num))
91 int pos = Max(Min(editor.editBox.line.count, position - 1), 0);
92 editor.editBox.GoToPosition(editor.editBox.line, num, pos);
94 scrl.x = Max(scroll.x, 0);
95 scrl.y = Max(scroll.y, 0);
96 editor.editBox.scroll = scrl;
106 class WorkspaceFile : struct
110 property const char * format
113 get { return "Ecere IDE Workspace File"; }
114 isset { return true; }
116 property const char * version
119 get { return "0.1"; }
120 isset { return true; }
125 class AddedProjectInfo : struct
129 property const char * path
131 set { delete path; if(value && value[0]) path = CopyString(value); }
132 get { return path && path[0] ? path : null; }
133 isset { return path != null; }
135 property const char * activeConfig
137 set { delete activeConfig; if(value && value[0]) activeConfig = CopyString(value); }
141 if(project && project.config)
142 config = project.config.name;
144 config = activeConfig;
145 return config && config[0] ? config : null;
147 isset { return property::activeConfig != null; }
172 class Workspace : struct
176 property const char * name
178 set { delete name; if(value && value[0]) name = CopyString(value); }
179 get { return name && name[0] ? name : null; }
180 isset { return name != null; }
182 property const char * activeCompiler
184 set { delete activeCompiler; if(value && value[0]) activeCompiler = CopyString(value); }
185 get { return activeCompiler && activeCompiler[0] ? activeCompiler : null; }
186 isset { return activeCompiler != null; }
189 property const char * commandLineArgs
191 set { delete commandLineArgs; if(value && value[0]) commandLineArgs = CopyString(value); }
192 get { return commandLineArgs && commandLineArgs[0] ? commandLineArgs : null; }
193 isset { return commandLineArgs != null; }
195 property const char * debugDir
197 set { delete debugDir; if(value && value[0]) debugDir = CopyString(value); }
198 get { return debugDir && debugDir[0] ? debugDir : null; }
199 isset { return debugDir != null; }
202 List<AddedProjectInfo> addedProjects;
203 List<String> sourceDirs;
204 Array<NamedString> environmentVars;
205 List<Breakpoint> breakpoints;
207 List<OpenedFileInfo> openedFiles;
210 ValgrindLeakCheck vgLeakCheck;
216 char * activeCompiler;
217 char * commandLineArgs;
220 char * workspaceFile;
225 List<Project> projects { };
232 vgLeakCheck = summary;
236 userData = this, delay = 1.0;
239 static bool skip = true;
247 ide.MenuDebugStart(ide.debugStartResumeItem, 0);
248 ide.debugStart = false;
250 else if(ide.debugHideIDE)
252 bool visible = ide.debugger.state != running;
253 if(ideMainFrame.visible != visible)
255 ideMainFrame.visible = visible;
257 ideMainFrame.Activate();
264 void AddProject(Project project, AddedProjectInfo addedProject)
268 ProjectConfig activeConfig = project.GetConfig(addedProject.activeConfig);
270 project.config = activeConfig;
271 addedProject.project = project;
275 char location[MAX_LOCATION];
276 GetRelativePathForProject(location, project);
279 addedProjects.Add(AddedProjectInfo { path = location, project = project });
281 projects.Add(project);
284 property const char * workspaceFile
288 char dir[MAX_DIRECTORY];
289 if(workspaceFile) delete workspaceFile;
290 if(workspaceDir) delete workspaceDir;
291 workspaceFile = CopyString(value);
292 StripLastDirectory(workspaceFile, dir);
293 workspaceDir = CopyUnixPath(dir);
295 get { return workspaceFile; }
298 property const char * projectDir
304 Project prj = projects.firstIterator.data;
305 return prj.topNode ? prj.topNode.path : null;
312 /*property Project project
322 projectDir = CopyString(project.topNode.path);
324 if(!project.config && activeConfig && activeConfig[0])
327 for(cfg = project.configurations.first; cfg; cfg = cfg.next)
328 if(!strcmp(cfg.name, activeConfig))
330 project.config = cfg;
333 project.config = project.configurations.first;
336 get { return project; }
342 if(workspaceFile && workspaceFile[0])
344 File file = FileOpen(workspaceFile, write);
347 WorkspaceFile wf { workspace = this };
348 WriteJSONObject(file, class(WorkspaceFile), wf, 0);
356 char * CopyAbsolutePathFromRelative(const char * relative)
358 char name[MAX_LOCATION];
359 char absolute[MAX_LOCATION];
361 ProjectNode node = null;
363 GetLastDirectory(relative, name);
366 if((node = p.topNode.Find(name, false)))
374 node.GetFullFilePath(absolute);
375 return CopyString(absolute);
381 strcpy(absolute, p.topNode.path);
382 PathCatSlash(absolute, relative);
383 if(FileExists(absolute))
390 return CopyString(absolute);
392 strcpy(absolute, workspaceDir); //projectDir // CHECK?
393 PathCatSlash(absolute, relative);
394 if(FileExists(absolute))
395 return CopyString(absolute);
398 for(dir : sourceDirs)
400 strcpy(absolute, dir);
401 PathCatSlash(absolute, relative);
402 if(FileExists(absolute))
403 return CopyString(absolute);
410 char * CopyUnixPathWorkspaceRelativeOrAbsolute(const char * path)
412 if(IsPathInsideOf(path, workspaceDir))
414 char relativePath[MAX_LOCATION];
415 MakePathRelative(path, workspaceDir, relativePath);
416 return CopyUnixPath(relativePath);
419 return CopyUnixPath(path);
422 char * MakeRelativePath(char * buffer, const char * path)
424 char * result = null;
427 MakePathRelative(path, workspaceDir, buffer);
428 MakeSlashPath(buffer);
434 char * GetRelativePathForProject(char * buffer, Project project)
436 char * result = null;
437 if(buffer && project && project.topNode.path)
439 MakePathRelative(project.topNode.path, workspaceDir, buffer);
440 MakeSlashPath(buffer);
441 PathCatSlash(buffer, project.topNode.name);
447 Array<ProjectNode> GetAllProjectNodes(const char *fullPath, bool skipExcluded)
449 Array<ProjectNode> nodes = null;
450 for(project : projects)
453 if((node = project.topNode.FindByFullPath(fullPath, false)))
455 if(!skipExcluded || !node.GetIsExcluded(project.config))
457 if(!nodes) nodes = { };
465 Project GetFileOwner(const char * absolutePath, const char * objectFileExt)
467 Project owner = null;
470 if(prj.topNode.FindByFullPath(absolutePath, false))
477 GetObjectFileNode(absolutePath, &owner, null, objectFileExt);
481 void GetRelativePath(const char * absolutePath, char * relativePath, Project * owner, const char * objectFileExt)
483 Project prj = GetFileOwner(absolutePath, objectFileExt);
487 prj = projects.firstIterator.data;
490 MakePathRelative(absolutePath, prj.topNode.path, relativePath);
491 MakeSlashPath(relativePath);
494 relativePath[0] = '\0';
497 ProjectNode GetObjectFileNode(const char * filePath, Project * project, char * fullPath, const char * objectFileExt)
499 ProjectNode node = null;
500 char ext[MAX_EXTENSION];
501 GetExtension(filePath, ext);
504 IntermediateFileType type = IntermediateFileType::FromExtension(ext);
507 char fileName[MAX_FILENAME];
508 GetLastDirectory(filePath, fileName);
511 DotMain dotMain = DotMain::FromFileName(fileName);
512 for(prj : ide.workspace.projects)
514 if((node = prj.FindNodeByObjectFileName(fileName, type, dotMain, null, objectFileExt)))
520 const char * cfgName = prj.config ? prj.config.name : "";
521 char name[MAX_FILENAME];
522 CompilerConfig compiler = ideSettings.GetCompilerConfig(prj.lastBuildCompilerName);
523 DirExpression objDir = prj.GetObjDir(compiler, prj.config, bitDepth);
524 strcpy(fullPath, prj.topNode.path);
525 PathCatSlash(fullPath, objDir.dir);
526 node.GetObjectFileName(name, prj.configsNameCollisions[cfgName], type, dotMain, objectFileExt);
527 PathCatSlash(fullPath, name);
540 OpenedFileInfo UpdateOpenedFileInfo(const char * fileName, OpenedFileState state)
542 char absolutePath[MAX_LOCATION];
543 char relativePath[MAX_LOCATION];
545 GetSlashPathBuffer(absolutePath, fileName);
546 MakeRelativePath(relativePath, fileName);
547 ofi = FindOpenedFileInfo(relativePath, absolutePath);
552 ofi = OpenedFileInfo { path = CopyString(relativePath) };
553 openedFiles.Add(ofi);
556 ofi.modified = GetLocalTimeStamp();
562 Iterator<OpenedFileInfo> it { openedFiles };
564 openedFiles.Delete(it.pointer);
571 void LoadOpenedFileInfo(const char * path, OpenedFileState state, int lineNumber, int position, Point scroll, TimeStamp modified, Array<String> openedFilesNotFound)
573 char absolutePath[MAX_LOCATION];
574 char relativePath[MAX_LOCATION];
575 TimeStamp stamp = modified;
577 strcpy(absolutePath, workspaceDir);
578 PathCatSlash(absolutePath, path);
579 MakeRelativePath(relativePath, absolutePath);
580 if(!(exists = FileExists(absolutePath)))
581 stamp -= 60*60*24*20; // Days { 20 };
582 if(stamp > GetLocalTimeStamp() - 60*60*24*384) // Days { 384 });
584 if(state == closed || exists)
586 OpenedFileInfo ofi = FindOpenedFileInfo(relativePath, absolutePath);
588 openedFiles.Add(OpenedFileInfo { CopyString(relativePath), state, lineNumber, position, scroll, stamp });
589 // else silently drop duplicates if they should ever occur;
592 openedFilesNotFound.Add(CopyString(absolutePath));
594 // else silently discarding old or broken OpenedFileInfo entries;
597 void OpenPreviouslyOpenedFiles(bool noParsing)
600 for(ofi : openedFiles)
602 if(ofi.state != closed)
605 char absolutePath[MAX_LOCATION];
606 strcpy(absolutePath, workspaceDir);
607 PathCatSlash(absolutePath, ofi.path);
608 file = ide.OpenFile(absolutePath, false, true, null, no, normal, noParsing);
613 ProjectNode node = prj.topNode.FindByFullPath(absolutePath, true);
615 node.EnsureVisible();
620 holdTracking = false;
623 OpenedFileInfo FindOpenedFileInfo(const char * relativePath, const char * absolutePath)
625 OpenedFileInfo result = null;
628 bool switchToRelative;
629 if((switchToRelative = !fstrcmp(absolutePath, e.path)) || !fstrcmp(relativePath, e.path))
635 result.path = CopyString(relativePath);
643 void RestorePreviouslyOpenedFileState(CodeEditor editor)
645 if((editor.openedFileInfo = UpdateOpenedFileInfo(editor.fileName, opened)))
646 editor.openedFileInfo.SetCodeEditorState(editor);
649 void UpdateSourceDirsArray(Array<String> dirs)
654 sourceDirs.Add(CopyString(s));
656 DropInvalidBreakpoints(null);
661 void RemoveProject(Project project)
663 Iterator<AddedProjectInfo> it { addedProjects };
666 if(it.data.project == project)
668 addedProjects.Remove(it.pointer);
672 projects.TakeOut(project);
674 DropInvalidBreakpoints(project);
676 ide.findInFilesDialog.RemoveProjectItem(project);
677 ide.UpdateToolBarActiveConfigs(false);
683 void SelectActiveConfig(const char * configName)
686 for(prj : ide.workspace.projects)
688 for(cfg : prj.configurations)
690 if(cfg.name && !strcmp(cfg.name, configName))
701 ide.UpdateToolBarActiveConfigs(true);
702 ide.projectView.Update(null);
705 ide.AdjustDebugMenus();
708 bool FindPath(ProjectNode node, const char * path)
710 if(node.type == file)
712 // TODO: Should this code be moved into a ProjectNode::absolutePath property? Taken from NodeProperties.ec
713 char filePath[MAX_LOCATION];
714 GetSlashPathBuffer(filePath, node.project.topNode.path);
715 PathCatSlash(filePath, node.path);
716 PathCatSlash(filePath, node.name);
718 if(!fstrcmp(filePath, path))
725 if(FindPath(n, path))
732 void ChangeBreakpoint(DataRow row, const char * location)
734 Breakpoint bp = (Breakpoint)(intptr)row.tag;
737 char * currentLoc = bp.CopyUserLocationString();
738 if(strcmp(location, currentLoc))
741 bp.location = location;
743 newLoc = bp.CopyUserLocationString();
744 if(strcmp(newLoc, currentLoc))
746 ide.breakpointsView.UpdateBreakpoint(row);
754 // adding a breakpoint by typing it in the breakpoints view
755 // todo, parse location
756 // if good, make add breakpoint, make sure possibly previously entered ignore and level are reflected in breakpoint
759 //bp = Breakpoint { };
760 //row.tag = (int64)bp;
761 //breakpoints.Add(bp);
767 void ChangeBreakpointIgnore(DataRow row, int ignore)
769 Breakpoint bp = (Breakpoint)(intptr)row.tag;
777 void ChangeBreakpointLevel(DataRow row, int level)
779 Breakpoint bp = (Breakpoint)(intptr)row.tag;
787 void ChangeBreakpointCondition(DataRow row, const char * condition)
789 Breakpoint bp = (Breakpoint)(intptr)row.tag;
790 if(bp && !(!bp.condition && !(condition && condition[0])))
794 bp.condition = Watch { };
795 bp.condition.expression = CopyString(condition);
798 else if(!(condition && condition[0]))
804 else if(strcmp(condition, bp.condition.expression))
807 bp.condition = Watch { };
808 bp.condition.expression = CopyString(condition);
814 void RemoveBreakpoint(Breakpoint bp)
817 ide.breakpointsView.RemoveBreakpoint(bp);
818 ide.debugger.UpdateRemovedBreakpoint(bp);
820 Iterator<Breakpoint> it { breakpoints };
822 breakpoints.Remove(it.pointer);
826 for(document = ide.firstChild; document; document = document.next)
828 const char * fileName = document.fileName;
829 if(document.isDocument && fileName && document.created)
831 char winFilePath[MAX_LOCATION];
832 const char * slashPath = GetSlashPathBuffer(winFilePath, fileName);
834 if(!fstrcmp(slashPath, bp.absoluteFilePath))
836 CodeEditor codeEditor = (CodeEditor)document;
837 int boxH = codeEditor.editBox.clientSize.h;
838 Box box { 0, 0, 19, boxH - 1 };
839 document.Update(box);
849 void ParseLoadedBreakpoints()
851 for(bp : breakpoints; bp.location)
854 ide.breakpointsView.UpdateBreakpoint(bp.row);
858 void DropInvalidBreakpoints(Project removedProject) // think about not dropping BPs that are past end of file but simply disable them
859 { // why? when using a scm/vcs you might be alternating between two version of a file
860 if(breakpoints) // and anoyingly keep loosing breakpoints in the version of the file you are working on
863 for(bpLink = breakpoints.first; bpLink; bpLink = next)
865 Breakpoint bp = (Breakpoint)(intptr)bpLink.data;
869 if(bp.project == removedProject)
871 ide.breakpointsView.RemoveBreakpoint(bp);
872 RemoveBreakpoint(bp);
877 Project project = bp.project;
882 if(FindPath(p.topNode, bp.absoluteFilePath))
887 // Handle symbol loader modules:
889 char moduleName[MAX_FILENAME];
891 GetLastDirectory(bp.absoluteFilePath, moduleName);
892 // Tweak for automatically resolving symbol loader modules
893 sl = strstr(moduleName, ".main.ec");
894 if(sl && (*sl = 0, !strcmpi(moduleName, p.name)))
905 for(dir : sourceDirs)
907 if(IsPathInsideOf(bp.absoluteFilePath, dir))
915 ide.breakpointsView.RemoveBreakpoint(bp);
916 RemoveBreakpoint(bp);
921 ide.breakpointsView.Update(null);
927 if(!addedProjects) addedProjects = { };
928 if(!sourceDirs) sourceDirs = { };
929 if(!environmentVars) environmentVars = { };
930 if(!breakpoints) breakpoints = { };
931 if(!watches) watches = { };
932 if(!openedFiles) openedFiles = { };
937 delete workspaceFile;
939 delete commandLineArgs;
941 delete activeCompiler;
945 if(addedProjects) { addedProjects.Free(); delete addedProjects; }
946 if(sourceDirs) { sourceDirs.Free(); delete sourceDirs; }
947 if(environmentVars) { environmentVars.Free(); delete environmentVars; }
948 if(breakpoints) { breakpoints.Free(); delete breakpoints; }
949 if(watches) { watches.Free(); delete watches; }
950 if(openedFiles) { openedFiles.Free(); delete openedFiles; }
957 ide.outputView.buildBox.Clear();
958 ide.outputView.debugBox.Clear();
959 ide.callStackView.Clear();
960 ide.watchesView.Clear();
961 ide.threadsView.Clear();
962 ide.breakpointsView.Clear();
964 property::debugDir = "";
966 SetSourceDirs(sourceDirs);
980 Workspace LoadWorkspace(const char * filePath, const char * fromProjectFile)
983 Workspace workspace = null;
985 f = FileOpen(filePath, read);
988 Array<String> openedFilesNotFound { };
989 WorkspaceFile wf = null;
990 JSONParser parser { f = f };
991 /*JSONResult result = */parser.GetObject(class(WorkspaceFile), &wf);
993 workspace = LoadLegacyWorkspace(filePath, openedFilesNotFound);
996 workspace = wf.workspace;
998 workspace.workspaceFile = filePath;
1000 char absolutePath[MAX_LOCATION];
1003 Iterator<AddedProjectInfo> it { workspace.addedProjects };
1004 while(!done && (ahead || !(done = !it.Next())))
1006 // TODO: implement some type of time based pruning of "dea" added projects instead of just dropping them on the spot
1007 // TimeStamp modified; modified = GetLocalTimeStamp();
1008 // TimeStamp stamp = modified; if(stamp > GetLocalTimeStamp() - 60*60*24*20) // Days { 20 });
1009 AddedProjectInfo addedPrj = it.data;
1010 strcpy(absolutePath, workspace.workspaceDir);
1011 PathCatSlash(absolutePath, addedPrj.path);
1012 if(FileExists(absolutePath))
1014 Project loadedProject = LoadProject(absolutePath, null);
1017 workspace.AddProject(loadedProject, addedPrj);
1018 loadedProject.StartMonitoring();
1020 else if(workspace.projects.count == 0)
1027 // TODO: (#524) show message or something when added project fails to load;
1033 IteratorPointer notFound = it.pointer;
1035 workspace.addedProjects.Delete(notFound);
1041 for(bp : workspace.breakpoints)
1043 char * path = workspace.CopyAbsolutePathFromRelative(bp.relativeFilePath);
1047 bp.absoluteFilePath = path;
1051 bp.absoluteFilePath = "";
1053 if(workspace.openedFiles && workspace.openedFiles.count)
1055 List<OpenedFileInfo> openedFiles = workspace.openedFiles;
1056 workspace.openedFiles = { };
1057 for(of : openedFiles)
1059 workspace.LoadOpenedFileInfo(of.path, of.state, of.lineNumber, of.position, of.scroll, of.modified, openedFilesNotFound);
1071 if(!workspace.projects.first)
1075 project = LoadProject(fromProjectFile /*projectFilePath*/, null);
1078 char projectFilePath[MAX_LOCATION];
1079 strcpy(projectFilePath, workspace.workspaceFile);
1080 ChangeExtension(projectFilePath, ProjectExtension, projectFilePath);
1081 project = LoadProject(projectFilePath, null);
1085 project.StartMonitoring();
1086 workspace.AddProject(project, null);
1087 workspace.name = CopyString(project.name);
1091 MessageBox { type = ok, master = ide, contents = $"Workspace load file failed", text = $"Workspace Load File Error" }.Modal();
1097 if(openedFilesNotFound.count)
1101 String files = new char[MAX_LOCATION * 16];
1103 String msg = new char[MAX_LOCATION * 16 + 2048];
1106 if(openedFilesNotFound.count > 1)
1109 for(item : openedFilesNotFound)
1114 strcat(files, "\n...");
1117 strcat(files, "\n");
1118 strcat(files, item);
1121 sprintf(title, $"File%s not found", s);
1122 sprintf(msg, $"The following file%s could not be re-opened.%s", s, files);
1124 MessageBox { type = ok, master = ide, contents = msg, text = title }.Modal();
1130 openedFilesNotFound.Free();
1131 delete openedFilesNotFound;
1136 else if(fromProjectFile)
1138 //MessageBox { type = Ok, master = ide, contents = "Worspace load file failed", text = "Worspace Load File Error" }.Modal();
1140 //char projectFile[MAX_LOCATION];
1143 //strcpy(projectFile, filePath);
1144 //ChangeExtension(projectFile, ProjectExtension, projectFile);
1145 newProject = LoadProject(fromProjectFile /*projectFile*/, null);
1149 newProject.StartMonitoring();
1150 workspace = Workspace { property::workspaceFile = filePath };
1153 workspace.AddProject(newProject, null);
1160 ide.ChangeFileDialogsDirectory(workspace.workspaceDir, false);
1162 if(!workspace.activeCompiler || !workspace.activeCompiler[0])
1163 workspace.activeCompiler = defaultCompilerName;
1169 Workspace LoadLegacyWorkspace(const char * filePath, Array<String> openedFilesNotFound)
1172 Workspace workspace = null;
1174 file = FileOpen(filePath, read);
1179 char subSection[128];
1181 workspace = Workspace { activeCompiler = ideSettings.defaultCompiler, property::workspaceFile = filePath };
1184 file.Seek(0, start);
1191 Breakpoint bp = null;
1193 file.GetLine(buffer, 65536 - 1);
1194 TrimLSpaces(buffer, buffer);
1195 TrimRSpaces(buffer, buffer);
1198 if(buffer[0] == '~')
1202 TrimLSpaces(equal, equal);
1203 if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Watches"))
1206 if(!workspace.watches) workspace.watches = { };
1207 workspace.watches.Add(wh);
1208 wh.expression = CopyString(equal);
1210 else if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Breakpoints"))
1215 wh.expression = CopyString(equal);
1219 else if(!strcmpi(section, "Execution Data") && !strcmpi(subSection, "Environment Variables"))
1221 String value = strchr(equal, '=');
1226 TrimRSpaces(equal, equal);
1227 TrimLSpaces(value, value);
1228 workspace.environmentVars.Add({ equal, value });
1232 else if(buffer[0] == '*')
1236 TrimLSpaces(equal, equal);
1237 if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Breakpoints"))
1239 char * strEnabled = null;
1240 char * strIgnore = null;
1241 char * strLevel = null;
1242 char * strLine = null;
1243 char * strFile = null;
1246 if(strEnabled && strEnabled[0])
1248 strIgnore = strstr(strEnabled, ",");
1249 strIgnore[0] = '\0';
1252 if(strIgnore && strIgnore[0])
1254 strLevel = strstr(strIgnore, ",");
1258 if(strLevel && strLevel[0])
1260 strLine = strstr(strLevel, ",");
1264 if(strLine && strLine[0])
1266 strFile = strstr(strLine, ",");
1270 if(strEnabled && strEnabled[0] && strIgnore && strIgnore[0] &&
1271 strLevel && strLevel[0] && strLine && strLine[0] && strFile && strFile[0])
1278 TrimLSpaces(strEnabled, strEnabled);
1279 TrimRSpaces(strEnabled, strEnabled);
1280 TrimLSpaces(strIgnore, strIgnore);
1281 TrimRSpaces(strIgnore, strIgnore);
1282 TrimLSpaces(strLevel, strLevel);
1283 TrimRSpaces(strLevel, strLevel);
1284 TrimLSpaces(strLevel, strLevel);
1285 TrimRSpaces(strLevel, strLevel);
1286 TrimLSpaces(strFile, strFile);
1287 TrimRSpaces(strFile, strFile);
1289 enabled = (strEnabled[0] == '1');
1290 ignore = atoi(strIgnore);
1291 level = atoi(strLevel);
1292 line = atoi(strLine);
1294 bp = { type = user, enabled = enabled, ignore = ignore, level = level, line = line };
1295 if(!workspace.breakpoints)
1296 workspace.breakpoints = { };
1297 workspace.breakpoints.Add(bp);
1298 bp.location = strFile;
1302 else if(buffer[0] == '=' || buffer[0] == '-')
1306 TrimLSpaces(equal, equal);
1307 if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Source Directories"))
1308 workspace.sourceDirs.Add(CopyString(equal));
1309 else if(!strcmpi(section, "Opened Files"))
1311 OpenedFileState state = opened;
1317 char * comma = strchr(equal, ',');
1321 lineNumber = atoi(equal);
1325 else if(version >= 0.02)
1327 char * column = strchr(equal, ':');
1331 if(strcmpi(equal, "O"))
1335 column = strchr(equal, ':');
1339 lineNumber = atoi(equal);
1342 column = strchr(equal, ':');
1346 position = atoi(equal);
1349 column = strchr(equal, ':');
1353 scroll.x = atoi(equal);
1356 column = strchr(equal, ':');
1360 scroll.y = atoi(equal);
1369 workspace.LoadOpenedFileInfo(equal, state, lineNumber, position, scroll, GetLocalTimeStamp(), openedFilesNotFound);
1371 else if(!strcmpi(section, "Projects"))
1373 char projectFilePath[MAX_LOCATION];
1375 strcpy(projectFilePath, workspace.workspaceDir);
1376 PathCatSlash(projectFilePath, equal);
1377 newProject = LoadProject(projectFilePath, null);
1380 workspace.AddProject(newProject, null);
1381 newProject.StartMonitoring();
1383 else if(workspace.projects.count == 0)
1390 // TODO: (#524) show message or something when added project fails to load;
1394 else if(!strcmpi(buffer, "ECERE Workspace File"));
1395 else if(!strcmpi(buffer, "Version 0a"))
1397 else if(!strncmp(buffer, "Version ", 8))
1398 version = atof(&buffer[8]);
1399 else if(!strcmpi(buffer, "Workspace"))
1400 strcpy(section, buffer);
1401 else if(!strcmpi(buffer, "Projects"))
1402 strcpy(section, buffer);
1403 else if(!strcmpi(buffer, "Execution Data"))
1404 strcpy(section, buffer);
1405 else if(!strcmpi(buffer, "Debugger Data"))
1406 strcpy(section, buffer);
1407 else if(!strcmpi(buffer, "Source Directories"))
1408 strcpy(subSection, buffer);
1409 else if(!strcmpi(buffer, "Breakpoints"))
1410 strcpy(subSection, buffer);
1411 else if(!strcmpi(buffer, "Watches"))
1412 strcpy(subSection, buffer);
1413 else if(!strcmpi(buffer, "Environment Variables"))
1414 strcpy(subSection, buffer);
1415 else if(!strcmpi(buffer, "Opened Files"))
1417 strcpy(section, buffer);
1418 if(!workspace.openedFiles) workspace.openedFiles = { };
1420 else if(!strcmpi(buffer, "")) // | These two lines were commented out
1421 strcpy(subSection, buffer); // | Do they serve a purpose? They were there for copy paste when adding a new subsection
1424 equal = strstr(buffer, "=");
1427 if(!strcmpi(section, "Workspace"))
1430 TrimRSpaces(buffer, buffer);
1432 TrimLSpaces(equal, equal);
1433 if(!strcmpi(buffer, "Active Compiler"))
1435 CompilerConfig compiler = ideSettings.GetCompilerConfig(equal);
1437 workspace.activeCompiler = defaultCompilerName;
1439 workspace.activeCompiler = equal;
1442 if(!strcmpi(buffer, "Active Bit Depth"))
1444 int bitDepth = atoi(equal);
1445 if(!(bitDepth == 32 || bitDepth == 64))
1447 workspace.bitDepth = bitDepth;
1448 ide.toolBar.activeBitDepth.SelectRow(ide.toolBar.activeBitDepth.FindRow(bitDepth));
1451 else if(!strcmpi(section, "Execution Data"))
1454 TrimRSpaces(buffer, buffer);
1456 TrimLSpaces(equal, equal);
1457 if(!strcmpi(buffer, "Command Line Arguments"))
1458 workspace.commandLineArgs = equal;
1460 if(!strcmpi(buffer, "Environment Variables"))
1462 workspace.environmentVars.Free();
1463 delete workspace.environmentVars;
1464 workspace.environmentVars = { };
1468 else if(!strcmpi(section, "Debugger Data"))
1471 TrimRSpaces(buffer, buffer);
1473 TrimLSpaces(equal, equal);
1474 if(!strcmpi(buffer, "Debug Working Directory"))
1475 workspace.debugDir = equal;
1480 TrimRSpaces(buffer, buffer);
1482 TrimLSpaces(equal, equal);
1483 if(!strcmpi(buffer, "Active Configuration"))
1486 if(workspace.projects.last)
1488 prj = workspace.projects.lastIterator.data;
1489 for(cfg : prj.configurations)
1491 if(!strcmp(cfg.name, equal))
1499 else if(!strcmpi(buffer, "Modified Compiler Config") || !strcmpi(buffer, "Modified Linker Config"))
1502 if(workspace.projects.last)
1504 prj = workspace.projects.lastIterator.data;
1505 for(cfg : prj.configurations)
1507 if(!strcmp(cfg.name, equal))
1509 if(strstr(buffer, "Compiler"))
1510 cfg.compilingModified = true;
1512 cfg.linkingModified = true;
1518 else if(!strcmpi(buffer, "CommandLineArgs"))
1519 workspace.commandLineArgs = equal;
1520 else if(!strcmpi(buffer, "Breakpoint"))
1523 char * lineNum = strstr(equal, ",");
1534 char * absPath = strstr(lineNum, ",");
1541 char * relPath = strstr(absPath, ",");
1548 bp = { type = user, enabled = enabled, level = -1 };
1549 workspace.breakpoints.Add(bp);
1550 bp.line = atoi(lineNum);
1551 bp.location = relPath;
1559 else if(!strcmpi(buffer, "Watch"))
1562 workspace.watches.Add(wh);
1563 wh.expression = CopyString(equal);
1565 else if(!strcmpi(buffer, "SourceDir"))
1567 workspace.sourceDirs.Add(CopyString(equal));
1569 else if(!strcmpi(buffer, "DebugDir"))
1571 workspace.debugDir = equal;
1583 TimeStamp GetLocalTimeStamp()
1587 time.GetLocalTime();