3 /*static void ParseListValue(List<String> list, char * equal)
7 string = CopyString(equal);
11 comma = strstr(start, ",");
14 list.Add(CopyString(start));
24 enum OpenedFileState { unknown, opened, closed };
25 enum ValgrindLeakCheck
27 no, summary, yes, full;
31 get { return OnGetString(null, null, null); }
34 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
36 if(this >= no && this <= full)
39 strcpy(tempString, valgrindLeakCheckNames[this]);
40 return valgrindLeakCheckNames[this];
42 if(tempString && tempString[0])
47 static const char * valgrindLeakCheckNames[ValgrindLeakCheck] = { "no", "summary", "yes", "full" };
55 OpenedFileState state;
56 int lineNumber, position;
60 property bool trackingAllowed
62 get { return !holdTracking && ide && ide.workspace && !ide.workspace.holdTracking; }
65 void CaretMove(int line, int charPos)
67 if(trackingAllowed && (line != lineNumber || position != charPos))
71 ide.workspace.modified = true;
75 void ScrollChange(Point scroll)
79 this.scroll.x = scroll.x;
80 this.scroll.y = scroll.y;
81 ide.workspace.modified = true;
89 List<OpenedFileInfo> files = ide.workspace.openedFiles;
90 Iterator<OpenedFileInfo> it { files };
91 if(it.Find(this) && it.pointer != files.GetLast())
93 files.Move(it.pointer, files.GetPrev(files.GetLast()));
94 ide.workspace.modified = true;
108 char * workspaceFile;
110 char * commandLineArgs;
111 property const char * commandLineArgs { set { delete commandLineArgs; if(value) commandLineArgs = CopyString(value); } }
113 property const char * debugDir { set { delete debugDir; if(value) debugDir = CopyString(value); } }
117 property const char * compiler
119 set { delete compiler; if(value && value[0]) compiler = CopyString(value); }
120 get { return compiler && compiler[0] ? compiler : null; }
123 List<String> sourceDirs { };
124 Array<NamedString> environmentVars { };
125 List<Breakpoint> breakpoints { };
126 List<Watch> watches { };
127 List<OpenedFileInfo> openedFiles { };
128 List<Project> projects { };
137 userData = this, delay = 2.5;
146 property const char * workspaceFile
150 char dir[MAX_DIRECTORY];
151 if(workspaceFile) delete workspaceFile;
152 if(workspaceDir) delete workspaceDir;
153 workspaceFile = CopyString(value);
154 StripLastDirectory(workspaceFile, dir);
155 workspaceDir = CopyUnixPath(dir);
157 get { return workspaceFile; }
160 property const char * projectDir
166 Project prj = projects.firstIterator.data;
167 return prj.topNode ? prj.topNode.path : null;
174 /*property Project project
184 projectDir = CopyString(project.topNode.path);
186 if(!project.config && activeConfig && activeConfig[0])
189 for(cfg = project.configurations.first; cfg; cfg = cfg.next)
190 if(!strcmp(cfg.name, activeConfig))
192 project.config = cfg;
195 project.config = project.configurations.first;
198 get { return project; }
204 // TODO: save these new settings when json format is ready
206 ValgrindLeakCheck vgLeakCheck;
211 vgLeakCheck = summary;
219 file = FileOpen(workspaceFile, write);
223 for(bp : breakpoints)
228 file.Printf("Breakpoint=1,%d,%s,%s\n", bp.line, bp.absoluteFilePath, bp.relativeFilePath);
230 file.Printf("Breakpoint=0,%d,%s,%s\n", bp.line, bp.absoluteFilePath, bp.relativeFilePath);
235 file.Printf("Watch=%s\n", wh.expression);
237 for(dir : sourceDirs)
238 file.Printf("SourceDir=%s\n", dir);
240 if(debugDir && debugDir[0])
241 file.Printf("DebugDir=%s\n", debugDir);
243 if(commandLineArgs && commandLineArgs[0])
244 file.Printf("CommandLineArgs=%s\n", commandLineArgs);
248 char indentation[128*3];
249 char path[MAX_LOCATION];
251 file.Printf("\nECERE Workspace File\n");
252 file.Printf("\nVersion 0.02\n");
253 file.Printf("\nWorkspace\n");
254 file.Printf("\n Active Compiler = %s\n", compiler ? compiler : defaultCompilerName);
255 file.Printf("\n Active Bit Depth = %d\n", bitDepth);
259 file.Printf("\n Projects\n\n");
262 char location[MAX_LOCATION];
263 MakePathRelative(prj.topNode.path, workspaceDir, location);
264 MakeSlashPath(location);
265 PathCatSlash(location, prj.topNode.name);
266 //strcat(location, ".epj");
268 file.Printf(" %s %s\n", "-", location);
271 file.Printf(" Active Configuration = %s\n", prj.config.name);
272 for(cfg : prj.configurations)
274 if(cfg.compilingModified)
275 file.Printf(" Modified Compiler Config = %s\n", cfg.name);
276 else if(cfg.linkingModified)
277 file.Printf(" Modified Linker Config = %s\n", cfg.name);
282 file.Printf("\n Execution Data\n");
283 if(commandLineArgs && commandLineArgs[0])
285 file.Printf("\n Command Line Arguments = ");
286 file.Puts(commandLineArgs);
290 if(environmentVars.count)
292 file.Printf("\n Environment Variables\n\n");
293 for(v : environmentVars)
303 file.Printf("\n Debugger Data\n");
304 // This really belonged in Execution Data...
305 if(debugDir && debugDir[0])
306 file.Printf("\n Debug Working Directory = %s\n", debugDir);
309 file.Printf("\n Source Directories\n");
310 for(dir : sourceDirs)
311 file.Printf(" = %s\n", dir);
314 for(bp : breakpoints)
321 file.Printf("\n Breakpoints\n\n");
329 file.Printf("\n Watches\n\n");
334 if(openedFiles.count)
336 file.Printf("\n Opened Files\n\n");
337 for(ofi : openedFiles)
341 char relativePath[MAX_LOCATION];
342 if(IsPathInsideOf(ofi.path, workspaceDir))
344 MakePathRelative(ofi.path, workspaceDir, relativePath);
345 MakeSlashPath(relativePath);
346 location = relativePath;
352 file.Printf(" %s %s:%d:%d:%d:%d:%s\n", chr, ofi.state == closed ? "C" : "O", ofi.lineNumber, ofi.position, ofi.scroll.x, ofi.scroll.y, location);
361 char * GetAbsolutePathFromRelative(const char * relative)
363 char name[MAX_LOCATION];
364 char absolute[MAX_LOCATION];
366 ProjectNode node = null;
368 GetLastDirectory(relative, name);
371 if((node = p.topNode.Find(name, false)))
379 node.GetFullFilePath(absolute);
380 return CopyString(absolute);
386 strcpy(absolute, p.topNode.path);
387 PathCatSlash(absolute, relative);
388 if(FileExists(absolute))
395 return CopyString(absolute);
397 strcpy(absolute, workspaceDir); //projectDir // CHECK?
398 PathCatSlash(absolute, relative);
399 if(FileExists(absolute))
400 return CopyString(absolute);
403 for(dir : sourceDirs)
405 strcpy(absolute, dir);
406 PathCatSlash(absolute, relative);
407 if(FileExists(absolute))
408 return CopyString(absolute);
415 char * GetPathWorkspaceRelativeOrAbsolute(const char * path)
417 if(IsPathInsideOf(path, workspaceDir))
419 char relativePath[MAX_LOCATION];
420 MakePathRelative(path, workspaceDir, relativePath);
421 return CopyUnixPath(relativePath);
424 return CopyUnixPath(path);
427 Array<ProjectNode> GetAllProjectNodes(const char *fullPath, bool skipExcluded)
429 Array<ProjectNode> nodes = null;
430 for(project : projects)
433 if((node = project.topNode.FindByFullPath(fullPath, false)))
435 if(!skipExcluded || !node.GetIsExcluded(project.config))
437 if(!nodes) nodes = { };
445 OpenedFileInfo UpdateOpenedFileInfo(const char * fileName, OpenedFileState state)
447 char filePath[MAX_LOCATION];
448 OpenedFileInfo ofi = null;
449 GetSlashPathBuffer(filePath, fileName);
450 for(item : openedFiles)
452 if(!fstrcmp(item.path, filePath))
462 ofi = OpenedFileInfo { path = CopyString(filePath) };
463 openedFiles.Add(ofi);
471 Iterator<OpenedFileInfo> it { openedFiles };
473 openedFiles.Delete(it.pointer);
480 void UpdateSourceDirsArray(Array<String> dirs)
485 sourceDirs.Add(CopyString(s));
487 DropInvalidBreakpoints(null);
492 void RemoveProject(Project project)
494 Iterator<Project> it { projects };
498 for(bp : breakpoints)
499 DropInvalidBreakpoints(project);
501 ide.findInFilesDialog.RemoveProjectItem(project);
502 ide.UpdateToolBarActiveConfigs(false);
508 void SelectActiveConfig(const char * configName)
511 for(prj : ide.workspace.projects)
513 for(cfg : prj.configurations)
515 if(cfg.name && !strcmp(cfg.name, configName))
526 ide.UpdateToolBarActiveConfigs(true);
527 ide.projectView.Update(null);
532 bool FindPath(ProjectNode node, const char * path)
534 if(node.type == file)
536 // TODO: Should this code be moved into a ProjectNode::absolutePath property? Taken from NodeProperties.ec
537 char filePath[MAX_LOCATION];
538 GetSlashPathBuffer(filePath, node.project.topNode.path);
539 PathCatSlash(filePath, node.path);
540 PathCatSlash(filePath, node.name);
542 if(!fstrcmp(filePath, path))
549 if(FindPath(n, path))
556 void ChangeBreakpoint(DataRow row, const char * location)
558 Breakpoint bp = (Breakpoint)row.tag;
561 char * currentLoc = bp.CopyUserLocationString();
562 if(strcmp(location, currentLoc))
565 bp.location = location;
567 newLoc = bp.CopyUserLocationString();
568 if(strcmp(newLoc, currentLoc))
570 ide.breakpointsView.UpdateBreakpoint(row);
578 // adding a breakpoint by typing it in the breakpoints view
579 // todo, parse location
580 // if good, make add breakpoint, make sure possibly previously entered ignore and level are reflected in breakpoint
583 //bp = Breakpoint { };
584 //row.tag = (int64)bp;
585 //breakpoints.Add(bp);
591 void ChangeBreakpointIgnore(DataRow row, int ignore)
593 Breakpoint bp = (Breakpoint)row.tag;
601 void ChangeBreakpointLevel(DataRow row, int level)
603 Breakpoint bp = (Breakpoint)row.tag;
611 void ChangeBreakpointCondition(DataRow row, const char * condition)
613 Breakpoint bp = (Breakpoint)row.tag;
614 if(bp && !(!bp.condition && !(condition && condition[0])))
618 bp.condition = Watch { };
619 bp.condition.expression = CopyString(condition);
622 else if(!(condition && condition[0]))
628 else if(strcmp(condition, bp.condition.expression))
631 bp.condition = Watch { };
632 bp.condition.expression = CopyString(condition);
638 void RemoveBreakpoint(Breakpoint bp)
641 ide.breakpointsView.RemoveBreakpoint(bp);
642 ide.debugger.UpdateRemovedBreakpoint(bp);
644 Iterator<Breakpoint> it { breakpoints };
646 breakpoints.Remove(it.pointer);
650 for(document = ide.firstChild; document; document = document.next)
652 const char * fileName = document.fileName;
653 if(document.isDocument && fileName && document.created)
655 char winFilePath[MAX_LOCATION];
656 const char * slashPath = GetSlashPathBuffer(winFilePath, fileName);
658 if(!fstrcmp(slashPath, bp.absoluteFilePath))
660 CodeEditor codeEditor = (CodeEditor)document;
661 int boxH = codeEditor.editBox.clientSize.h;
662 Box box { 0, 0, 19, boxH - 1 };
663 document.Update(box);
673 void ParseLoadedBreakpoints()
675 for(bp : breakpoints; bp.location)
678 ide.breakpointsView.UpdateBreakpoint(bp.row);
682 void DropInvalidBreakpoints(Project removedProject)
685 for(bpLink = breakpoints.first; bpLink; bpLink = next)
687 Breakpoint bp = (Breakpoint)bpLink.data;
694 if(bp.project == removedProject)
696 ide.breakpointsView.RemoveBreakpoint(bp);
697 RemoveBreakpoint(bp);
702 Project project = bp.project;
707 if(FindPath(p.topNode, bp.absoluteFilePath))
712 // Handle symbol loader modules:
714 char moduleName[MAX_FILENAME];
716 GetLastDirectory(bp.absoluteFilePath, moduleName);
717 // Tweak for automatically resolving symbol loader modules
718 sl = strstr(moduleName, ".main.ec");
719 if(sl && (*sl = 0, !strcmpi(moduleName, p.name)))
730 for(dir : sourceDirs)
732 if(IsPathInsideOf(bp.absoluteFilePath, dir))
740 ide.breakpointsView.RemoveBreakpoint(bp);
741 RemoveBreakpoint(bp);
747 ide.breakpointsView.Update(null);
752 delete workspaceFile;
754 delete commandLineArgs;
766 ide.outputView.buildBox.Clear();
767 ide.outputView.debugBox.Clear();
768 ide.callStackView.Clear();
769 ide.watchesView.Clear();
770 ide.threadsView.Clear();
771 ide.breakpointsView.Clear();
773 property::debugDir = "";
775 SetSourceDirs(sourceDirs);
784 environmentVars.Free();
793 Workspace LoadWorkspace(const char * filePath, const char * fromProjectFile)
796 Workspace workspace = null;
798 file = FileOpen(filePath, read);
801 OldList openedFilesNotFound { };
804 char subSection[128];
806 workspace = Workspace { compiler = ideSettings.defaultCompiler, workspaceFile = filePath };
817 file.GetLine(buffer, 65536 - 1);
818 TrimLSpaces(buffer, buffer);
819 TrimRSpaces(buffer, buffer);
826 TrimLSpaces(equal, equal);
827 if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Watches"))
830 workspace.watches.Add(wh);
831 wh.expression = CopyString(equal);
833 else if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Breakpoints"))
838 wh.expression = CopyString(equal);
842 else if(!strcmpi(section, "Execution Data") && !strcmpi(subSection, "Environment Variables"))
844 String value = strchr(equal, '=');
849 TrimRSpaces(equal, equal);
850 TrimLSpaces(value, value);
851 workspace.environmentVars.Add({ equal, value });
855 else if(buffer[0] == '*')
859 TrimLSpaces(equal, equal);
860 if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Breakpoints"))
862 char * strEnabled = null;
863 char * strIgnore = null;
864 char * strLevel = null;
865 char * strLine = null;
866 char * strFile = null;
869 if(strEnabled && strEnabled[0])
871 strIgnore = strstr(strEnabled, ",");
875 if(strIgnore && strIgnore[0])
877 strLevel = strstr(strIgnore, ",");
881 if(strLevel && strLevel[0])
883 strLine = strstr(strLevel, ",");
887 if(strLine && strLine[0])
889 strFile = strstr(strLine, ",");
893 if(strEnabled && strEnabled[0] && strIgnore && strIgnore[0] &&
894 strLevel && strLevel[0] && strLine && strLine[0] && strFile && strFile[0])
901 TrimLSpaces(strEnabled, strEnabled);
902 TrimRSpaces(strEnabled, strEnabled);
903 TrimLSpaces(strIgnore, strIgnore);
904 TrimRSpaces(strIgnore, strIgnore);
905 TrimLSpaces(strLevel, strLevel);
906 TrimRSpaces(strLevel, strLevel);
907 TrimLSpaces(strLevel, strLevel);
908 TrimRSpaces(strLevel, strLevel);
909 TrimLSpaces(strFile, strFile);
910 TrimRSpaces(strFile, strFile);
912 enabled = (strEnabled[0] == '1');
913 ignore = atoi(strIgnore);
914 level = atoi(strLevel);
915 line = atoi(strLine);
917 bp = { type = user, enabled = enabled, ignore = ignore, level = level, line = line };
918 workspace.breakpoints.Add(bp);
919 bp.location = strFile;
923 else if(buffer[0] == '=' || buffer[0] == '-')
927 TrimLSpaces(equal, equal);
928 if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Source Directories"))
929 workspace.sourceDirs.Add(CopyString(equal));
930 else if(!strcmpi(section, "Opened Files"))
932 OpenedFileState state = opened;
936 char absolutePath[MAX_LOCATION];
937 strcpy(absolutePath, workspace.workspaceDir);
940 char * comma = strchr(equal, ',');
944 lineNumber = atoi(equal);
948 else if(version >= 0.02)
950 char * column = strchr(equal, ':');
954 if(strcmpi(equal, "O"))
958 column = strchr(equal, ':');
962 lineNumber = atoi(equal);
965 column = strchr(equal, ':');
969 position = atoi(equal);
972 column = strchr(equal, ':');
976 scroll.x = atoi(equal);
979 column = strchr(equal, ':');
983 scroll.y = atoi(equal);
992 PathCatSlash(absolutePath, equal);
994 if(state == closed || FileExists(absolutePath))
995 workspace.openedFiles.Add(OpenedFileInfo { path = CopyString(absolutePath), state = state, lineNumber = lineNumber, position = position, scroll = scroll });
997 openedFilesNotFound.Add(NamedItem { name = CopyString(equal) });
999 else if(!strcmpi(section, "Projects"))
1001 char projectFilePath[MAX_LOCATION];
1003 strcpy(projectFilePath, workspace.workspaceDir);
1004 PathCatSlash(projectFilePath, equal);
1005 newProject = LoadProject(projectFilePath, null);
1008 workspace.projects.Add(newProject);
1009 newProject.StartMonitoring();
1011 else if(workspace.projects.count == 0)
1018 // TODO: show message or something when added project fails to load
1019 // http://ecere.com/mantis/view.php?id=524
1023 else if(!strcmpi(buffer, "ECERE Workspace File"));
1024 else if(!strcmpi(buffer, "Version 0a"))
1026 else if(!strncmp(buffer, "Version ", 8))
1027 version = atof(&buffer[8]);
1028 else if(!strcmpi(buffer, "Workspace"))
1029 strcpy(section, buffer);
1030 else if(!strcmpi(buffer, "Projects"))
1031 strcpy(section, buffer);
1032 else if(!strcmpi(buffer, "Execution Data"))
1033 strcpy(section, buffer);
1034 else if(!strcmpi(buffer, "Debugger Data"))
1035 strcpy(section, buffer);
1036 else if(!strcmpi(buffer, "Source Directories"))
1037 strcpy(subSection, buffer);
1038 else if(!strcmpi(buffer, "Breakpoints"))
1039 strcpy(subSection, buffer);
1040 else if(!strcmpi(buffer, "Watches"))
1041 strcpy(subSection, buffer);
1042 else if(!strcmpi(buffer, "Environment Variables"))
1043 strcpy(subSection, buffer);
1044 else if(!strcmpi(buffer, "Opened Files"))
1045 strcpy(section, buffer);
1046 else if(!strcmpi(buffer, "")) // | These two lines were commented out
1047 strcpy(subSection, buffer); // | Do they serve a purpose? They were there for copy paste when adding a new subsection
1050 equal = strstr(buffer, "=");
1053 if(!strcmpi(section, "Workspace"))
1056 TrimRSpaces(buffer, buffer);
1058 TrimLSpaces(equal, equal);
1059 if(!strcmpi(buffer, "Active Compiler"))
1061 CompilerConfig compiler = ideSettings.GetCompilerConfig(equal);
1063 workspace.compiler = defaultCompilerName;
1065 workspace.compiler = equal;
1068 if(!strcmpi(buffer, "Active Bit Depth"))
1070 int bitDepth = atoi(equal);
1071 if(!(bitDepth == 32 || bitDepth == 64))
1073 workspace.bitDepth = bitDepth;
1074 ide.toolBar.activeBitDepth.SelectRow(ide.toolBar.activeBitDepth.FindRow(bitDepth));
1077 else if(!strcmpi(section, "Execution Data"))
1080 TrimRSpaces(buffer, buffer);
1082 TrimLSpaces(equal, equal);
1083 if(!strcmpi(buffer, "Command Line Arguments"))
1084 workspace.commandLineArgs = equal;
1086 if(!strcmpi(buffer, "Environment Variables"))
1088 workspace.environmentVars.Free();
1089 delete workspace.environmentVars;
1090 workspace.environmentVars = { };
1094 else if(!strcmpi(section, "Debugger Data"))
1097 TrimRSpaces(buffer, buffer);
1099 TrimLSpaces(equal, equal);
1100 if(!strcmpi(buffer, "Debug Working Directory"))
1101 workspace.debugDir = equal;
1106 TrimRSpaces(buffer, buffer);
1108 TrimLSpaces(equal, equal);
1109 if(!strcmpi(buffer, "Active Configuration"))
1112 if(workspace.projects.last)
1114 prj = workspace.projects.lastIterator.data;
1115 for(cfg : prj.configurations)
1117 if(!strcmp(cfg.name, equal))
1125 else if(!strcmpi(buffer, "Modified Compiler Config") || !strcmpi(buffer, "Modified Linker Config"))
1128 if(workspace.projects.last)
1130 prj = workspace.projects.lastIterator.data;
1131 for(cfg : prj.configurations)
1133 if(!strcmp(cfg.name, equal))
1135 if(strstr(buffer, "Compiler"))
1136 cfg.compilingModified = true;
1138 cfg.linkingModified = true;
1144 else if(!strcmpi(buffer, "CommandLineArgs"))
1145 workspace.commandLineArgs = equal;
1146 else if(!strcmpi(buffer, "Breakpoint"))
1149 char * lineNum = strstr(equal, ",");
1160 char * absPath = strstr(lineNum, ",");
1167 char * relPath = strstr(absPath, ",");
1174 bp = { type = user, enabled = enabled, level = -1 };
1175 workspace.breakpoints.Add(bp);
1176 bp.line = atoi(lineNum);
1177 bp.location = relPath;
1185 else if(!strcmpi(buffer, "Watch"))
1188 workspace.watches.Add(wh);
1189 wh.expression = CopyString(equal);
1191 else if(!strcmpi(buffer, "SourceDir"))
1193 workspace.sourceDirs.Add(CopyString(equal));
1195 else if(!strcmpi(buffer, "DebugDir"))
1197 workspace.debugDir = equal;
1209 if(!workspace.projects.first)
1213 project = LoadProject(fromProjectFile /*projectFilePath*/, null);
1216 char projectFilePath[MAX_LOCATION];
1217 strcpy(projectFilePath, workspace.workspaceFile);
1218 ChangeExtension(projectFilePath, ProjectExtension, projectFilePath);
1219 project = LoadProject(projectFilePath, null);
1223 project.StartMonitoring();
1224 workspace.projects.Add(project);
1225 workspace.name = CopyString(project.name);
1229 MessageBox { type = ok, master = ide, contents = $"Workspace load file failed", text = $"Workspace Load File Error" }.Modal();
1235 if(openedFilesNotFound.first)
1239 String files = new char[MAX_LOCATION * 16];
1241 String msg = new char[MAX_LOCATION * 16 + 2048];
1245 item = openedFilesNotFound.first;
1249 for(item = openedFilesNotFound.first; item; item = item.next)
1254 strcat(files, "\n...");
1257 strcat(files, "\n");
1258 strcat(files, item.name);
1261 sprintf(title, $"File%s not found", s);
1262 sprintf(msg, $"The following file%s could not be re-opened.%s", s, files);
1264 MessageBox { type = ok, master = ide, contents = msg, text = title }.Modal();
1269 openedFilesNotFound.Free(OldLink::Free);
1272 openedFilesNotFound.Free(OldLink::Free);
1274 else if(fromProjectFile)
1276 //MessageBox { type = Ok, master = ide, contents = "Worspace load file failed", text = "Worspace Load File Error" }.Modal();
1277 //char projectFile[MAX_LOCATION];
1280 //strcpy(projectFile, filePath);
1281 //ChangeExtension(projectFile, ProjectExtension, projectFile);
1282 newProject = LoadProject(fromProjectFile /*projectFile*/, null);
1286 newProject.StartMonitoring();
1287 workspace = Workspace { workspaceFile = filePath };
1289 workspace.projects.Add(newProject);
1296 ide.ChangeFileDialogsDirectory(workspace.workspaceDir, false);
1298 if(!workspace.compiler || !workspace.compiler[0])
1299 workspace.compiler = defaultCompilerName;