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 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 char * commandLineArgs { set { delete commandLineArgs; if(value) commandLineArgs = CopyString(value); } }
113 property char * debugDir { set { delete debugDir; if(value) debugDir = CopyString(value); } }
117 property 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 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 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;
216 file = FileOpen(workspaceFile, write);
220 for(bp : breakpoints)
225 file.Printf("Breakpoint=1,%d,%s,%s\n", bp.line, bp.absoluteFilePath, bp.relativeFilePath);
227 file.Printf("Breakpoint=0,%d,%s,%s\n", bp.line, bp.absoluteFilePath, bp.relativeFilePath);
232 file.Printf("Watch=%s\n", wh.expression);
234 for(dir : sourceDirs)
235 file.Printf("SourceDir=%s\n", dir);
237 if(debugDir && debugDir[0])
238 file.Printf("DebugDir=%s\n", debugDir);
240 if(commandLineArgs && commandLineArgs[0])
241 file.Printf("CommandLineArgs=%s\n", commandLineArgs);
245 char indentation[128*3];
246 char path[MAX_LOCATION];
248 file.Printf("\nECERE Workspace File\n");
249 file.Printf("\nVersion 0.02\n");
250 file.Printf("\nWorkspace\n");
251 file.Printf("\n Active Compiler = %s\n", compiler ? compiler : defaultCompilerName);
252 file.Printf("\n Active Bit Depth = %d\n", bitDepth);
256 file.Printf("\n Projects\n\n");
259 char location[MAX_LOCATION];
260 MakePathRelative(prj.topNode.path, workspaceDir, location);
261 MakeSlashPath(location);
262 PathCatSlash(location, prj.topNode.name);
263 //strcat(location, ".epj");
265 file.Printf(" %s %s\n", "-", location);
268 file.Printf(" Active Configuration = %s\n", prj.config.name);
269 for(cfg : prj.configurations)
271 if(cfg.compilingModified)
272 file.Printf(" Modified Compiler Config = %s\n", cfg.name);
273 else if(cfg.linkingModified)
274 file.Printf(" Modified Linker Config = %s\n", cfg.name);
279 file.Printf("\n Execution Data\n");
280 if(commandLineArgs && commandLineArgs[0])
282 file.Printf("\n Command Line Arguments = ");
283 file.Puts(commandLineArgs);
287 if(environmentVars.count)
289 file.Printf("\n Environment Variables\n\n");
290 for(v : environmentVars)
300 file.Printf("\n Debugger Data\n");
301 // This really belonged in Execution Data...
302 if(debugDir && debugDir[0])
303 file.Printf("\n Debug Working Directory = %s\n", debugDir);
306 file.Printf("\n Source Directories\n");
307 for(dir : sourceDirs)
308 file.Printf(" = %s\n", dir);
311 for(bp : breakpoints)
318 file.Printf("\n Breakpoints\n\n");
326 file.Printf("\n Watches\n\n");
331 if(openedFiles.count)
333 file.Printf("\n Opened Files\n\n");
334 for(ofi : openedFiles)
338 char relativePath[MAX_LOCATION];
339 if(IsPathInsideOf(ofi.path, workspaceDir))
341 MakePathRelative(ofi.path, workspaceDir, relativePath);
342 MakeSlashPath(relativePath);
343 location = relativePath;
349 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);
358 char * GetAbsolutePathFromRelative(char * relative)
360 char name[MAX_LOCATION];
361 char absolute[MAX_LOCATION];
363 ProjectNode node = null;
365 GetLastDirectory(relative, name);
368 if(node = p.topNode.Find(name, false))
376 node.GetFullFilePath(absolute);
377 return CopyString(absolute);
383 strcpy(absolute, p.topNode.path);
384 PathCatSlash(absolute, relative);
385 if(FileExists(absolute))
392 return CopyString(absolute);
394 strcpy(absolute, workspaceDir); //projectDir // CHECK?
395 PathCatSlash(absolute, relative);
396 if(FileExists(absolute))
397 return CopyString(absolute);
400 for(dir : sourceDirs)
402 strcpy(absolute, dir);
403 PathCatSlash(absolute, relative);
404 if(FileExists(absolute))
405 return CopyString(absolute);
412 char * GetPathWorkspaceRelativeOrAbsolute(char * path)
414 if(IsPathInsideOf(path, workspaceDir))
416 char relativePath[MAX_LOCATION];
417 MakePathRelative(path, workspaceDir, relativePath);
418 return CopyUnixPath(relativePath);
421 return CopyUnixPath(path);
424 OpenedFileInfo UpdateOpenedFileInfo(char * fileName, OpenedFileState state)
426 char filePath[MAX_LOCATION];
427 OpenedFileInfo ofi = null;
428 GetSlashPathBuffer(filePath, fileName);
429 for(item : openedFiles)
431 if(!fstrcmp(item.path, filePath))
441 ofi = OpenedFileInfo { path = CopyString(filePath) };
442 openedFiles.Add(ofi);
450 Iterator<OpenedFileInfo> it { openedFiles };
452 openedFiles.Delete(it.pointer);
459 void UpdateSourceDirsArray(Array<String> dirs)
467 sourceDirs.Add(CopyString(s));
469 DropInvalidBreakpoints();
474 void RemoveProject(Project project)
476 Iterator<Project> it { projects };
480 DropInvalidBreakpoints();
482 ide.findInFilesDialog.RemoveProjectItem(project);
483 ide.UpdateToolBarActiveConfigs(false);
489 void SelectActiveConfig(char * configName)
492 for(prj : ide.workspace.projects)
494 for(cfg : prj.configurations)
496 if(cfg.name && !strcmp(cfg.name, configName))
507 ide.UpdateToolBarActiveConfigs(true);
508 ide.projectView.Update(null);
513 bool FindPath(ProjectNode node, char * path)
515 if(node.type == file)
517 // TODO: Should this code be moved into a ProjectNode::absolutePath property? Taken from NodeProperties.ec
518 char filePath[MAX_LOCATION];
519 GetSlashPathBuffer(filePath, node.project.topNode.path);
520 PathCatSlash(filePath, node.path);
521 PathCatSlash(filePath, node.name);
523 if(!fstrcmp(filePath, path))
530 if(FindPath(n, path))
537 void ChangeBreakpoint(DataRow row, char * location)
539 Breakpoint bp = (Breakpoint)row.tag;
542 char * currentLoc = bp.CopyUserLocationString();
543 if(strcmp(location, currentLoc))
545 // todo, parse location
546 // if good, make changes to breakpoint, according to execution state delete and place breakpoint
547 ide.breakpointsView.UpdateBreakpoint(row); // this is the else
554 // adding a breakpoint by typing it in the breakpoints view
555 // todo, parse location
556 // if good, make add breakpoint, make sure possibly previously entered ignore and level are reflected in breakpoint
559 //bp = Breakpoint { };
560 //row.tag = (int64)bp;
561 //breakpoints.Add(bp);
567 void ChangeBreakpointIgnore(DataRow row, int ignore)
569 Breakpoint bp = (Breakpoint)row.tag;
577 void ChangeBreakpointLevel(DataRow row, int level)
579 Breakpoint bp = (Breakpoint)row.tag;
587 void ChangeBreakpointCondition(DataRow row, char * condition)
589 Breakpoint bp = (Breakpoint)row.tag;
590 if(bp && !(!bp.condition && !(condition && condition[0])))
594 bp.condition = Watch { };
595 bp.condition.expression = CopyString(condition);
598 else if(!(condition && condition[0]))
604 else if(strcmp(condition, bp.condition.expression))
607 bp.condition = Watch { };
608 bp.condition.expression = CopyString(condition);
614 void RemoveBreakpoint(Breakpoint bp)
617 ide.breakpointsView.RemoveBreakpoint(bp);
618 ide.debugger.UpdateRemovedBreakpoint(bp);
620 Iterator<Breakpoint> it { breakpoints };
622 breakpoints.Remove(it.pointer);
626 for(document = ide.firstChild; document; document = document.next)
628 char * fileName = document.fileName;
629 if(document.isDocument && fileName && document.created)
631 char winFilePath[MAX_LOCATION];
632 char * slashPath = GetSlashPathBuffer(winFilePath, fileName);
634 if(!fstrcmp(slashPath, bp.absoluteFilePath))
636 CodeEditor codeEditor = (CodeEditor)document;
637 int boxH = codeEditor.editBox.clientSize.h;
638 Box box { 0, 0, 19, boxH - 1 };
639 document.Update(box);
649 void DropInvalidBreakpoints()
652 for(bpLink = breakpoints.first; bpLink; bpLink = next)
654 Breakpoint bp = (Breakpoint)bpLink.data;
659 Project project = null;
662 if(FindPath(p.topNode, bp.absoluteFilePath))
667 // Handle symbol loader modules:
669 char moduleName[MAX_FILENAME];
671 GetLastDirectory(bp.absoluteFilePath, moduleName);
672 // Tweak for automatically resolving symbol loader modules
673 sl = strstr(moduleName, ".main.ec");
674 if(sl && (*sl = 0, !strcmpi(moduleName, p.name)))
684 for(dir : sourceDirs)
686 if(IsPathInsideOf(bp.absoluteFilePath, dir))
694 ide.breakpointsView.RemoveBreakpoint(bp);
695 RemoveBreakpoint(bp);
700 ide.breakpointsView.Update(null);
705 delete workspaceFile;
707 delete commandLineArgs;
719 ide.outputView.buildBox.Clear();
720 ide.outputView.debugBox.Clear();
721 ide.callStackView.Clear();
722 ide.watchesView.Clear();
723 ide.threadsView.Clear();
724 ide.breakpointsView.Clear();
726 property::debugDir = "";
728 SetSourceDirs(sourceDirs);
737 environmentVars.Free();
746 Workspace LoadWorkspace(char * filePath, char * fromProjectFile)
749 Workspace workspace = null;
751 file = FileOpen(filePath, read);
754 OldList openedFilesNotFound { };
757 char subSection[128];
759 workspace = Workspace { compiler = ideSettings.defaultCompiler, workspaceFile = filePath };
771 file.GetLine(buffer, 65536 - 1);
772 TrimLSpaces(buffer, buffer);
773 TrimRSpaces(buffer, buffer);
780 TrimLSpaces(equal, equal);
781 if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Watches"))
784 workspace.watches.Add(wh);
785 wh.expression = CopyString(equal);
787 else if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Breakpoints"))
792 wh.expression = CopyString(equal);
796 else if(!strcmpi(section, "Execution Data") && !strcmpi(subSection, "Environment Variables"))
798 String value = strchr(equal, '=');
803 TrimRSpaces(equal, equal);
804 TrimLSpaces(value, value);
805 workspace.environmentVars.Add({ equal, value });
809 else if(buffer[0] == '*')
813 TrimLSpaces(equal, equal);
814 if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Breakpoints"))
816 char * strEnabled = null;
817 char * strIgnore = null;
818 char * strLevel = null;
819 char * strLine = null;
820 char * strFile = null;
823 if(strEnabled && strEnabled[0])
825 strIgnore = strstr(strEnabled, ",");
829 if(strIgnore && strIgnore[0])
831 strLevel = strstr(strIgnore, ",");
835 if(strLevel && strLevel[0])
837 strLine = strstr(strLevel, ",");
841 if(strLine && strLine[0])
843 strFile = strstr(strLine, ",");
847 if(strEnabled && strEnabled[0] && strIgnore && strIgnore[0] &&
848 strLevel && strLevel[0] && strLine && strLine[0] && strFile && strFile[0])
855 TrimLSpaces(strEnabled, strEnabled);
856 TrimRSpaces(strEnabled, strEnabled);
857 TrimLSpaces(strIgnore, strIgnore);
858 TrimRSpaces(strIgnore, strIgnore);
859 TrimLSpaces(strLevel, strLevel);
860 TrimRSpaces(strLevel, strLevel);
861 TrimLSpaces(strLevel, strLevel);
862 TrimRSpaces(strLevel, strLevel);
863 TrimLSpaces(strFile, strFile);
864 TrimRSpaces(strFile, strFile);
866 enabled = (strEnabled[0] == '1');
867 ignore = atoi(strIgnore);
868 level = atoi(strLevel);
869 line = atoi(strLine);
871 bp = { type = user, enabled = enabled, ignore = ignore, level = level, line = line };
872 workspace.breakpoints.Add(bp);
873 bp.relativeFilePath = strFile;
874 bp.absoluteFilePath = workspace.GetAbsolutePathFromRelative(strFile);
875 if(!bp.absoluteFilePath)
876 bp.absoluteFilePath = CopyString("");
880 else if(buffer[0] == '=' || buffer[0] == '-')
884 TrimLSpaces(equal, equal);
885 if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Source Directories"))
886 workspace.sourceDirs.Add(CopyString(equal));
887 else if(!strcmpi(section, "Opened Files"))
889 OpenedFileState state = opened;
893 char absolutePath[MAX_LOCATION];
894 strcpy(absolutePath, workspace.workspaceDir);
897 char * comma = strchr(equal, ',');
901 lineNumber = atoi(equal);
905 else if(version >= 0.02)
907 char * column = strchr(equal, ':');
911 if(strcmpi(equal, "O"))
915 column = strchr(equal, ':');
919 lineNumber = atoi(equal);
922 column = strchr(equal, ':');
926 position = atoi(equal);
929 column = strchr(equal, ':');
933 scroll.x = atoi(equal);
936 column = strchr(equal, ':');
940 scroll.y = atoi(equal);
949 PathCatSlash(absolutePath, equal);
951 if(state == closed || FileExists(absolutePath))
952 workspace.openedFiles.Add(OpenedFileInfo { path = CopyString(absolutePath), state = state, lineNumber = lineNumber, position = position, scroll = scroll });
954 openedFilesNotFound.Add(NamedItem { name = CopyString(equal) });
956 else if(!strcmpi(section, "Projects"))
958 char projectFilePath[MAX_LOCATION];
960 strcpy(projectFilePath, workspace.workspaceDir);
961 PathCatSlash(projectFilePath, equal);
962 newProject = LoadProject(projectFilePath, null);
965 workspace.projects.Add(newProject);
966 newProject.StartMonitoring();
968 else if(workspace.projects.count == 0)
975 // TODO: show message or something when added project fails to load
976 // http://ecere.com/mantis/view.php?id=524
980 else if(!strcmpi(buffer, "ECERE Workspace File"));
981 else if(!strcmpi(buffer, "Version 0a"))
983 else if(!strncmp(buffer, "Version ", 8))
984 version = atof(&buffer[8]);
985 else if(!strcmpi(buffer, "Workspace"))
986 strcpy(section, buffer);
987 else if(!strcmpi(buffer, "Projects"))
988 strcpy(section, buffer);
989 else if(!strcmpi(buffer, "Execution Data"))
990 strcpy(section, buffer);
991 else if(!strcmpi(buffer, "Debugger Data"))
992 strcpy(section, buffer);
993 else if(!strcmpi(buffer, "Source Directories"))
994 strcpy(subSection, buffer);
995 else if(!strcmpi(buffer, "Breakpoints"))
996 strcpy(subSection, buffer);
997 else if(!strcmpi(buffer, "Watches"))
998 strcpy(subSection, buffer);
999 else if(!strcmpi(buffer, "Environment Variables"))
1000 strcpy(subSection, buffer);
1001 else if(!strcmpi(buffer, "Opened Files"))
1002 strcpy(section, buffer);
1003 else if(!strcmpi(buffer, "")) // | These two lines were commented out
1004 strcpy(subSection, buffer); // | Do they serve a purpose? They were there for copy paste when adding a new subsection
1007 equal = strstr(buffer, "=");
1010 if(!strcmpi(section, "Workspace"))
1013 TrimRSpaces(buffer, buffer);
1015 TrimLSpaces(equal, equal);
1016 if(!strcmpi(buffer, "Active Compiler"))
1018 CompilerConfig compiler = ideSettings.GetCompilerConfig(equal);
1020 workspace.compiler = defaultCompilerName;
1022 workspace.compiler = equal;
1025 if(!strcmpi(buffer, "Active Bit Depth"))
1027 int bitDepth = atoi(equal);
1028 if(!(bitDepth == 32 || bitDepth == 64))
1030 workspace.bitDepth = bitDepth;
1031 ide.toolBar.activeBitDepth.SelectRow(ide.toolBar.activeBitDepth.FindRow(bitDepth));
1034 else if(!strcmpi(section, "Execution Data"))
1037 TrimRSpaces(buffer, buffer);
1039 TrimLSpaces(equal, equal);
1040 if(!strcmpi(buffer, "Command Line Arguments"))
1041 workspace.commandLineArgs = equal;
1043 if(!strcmpi(buffer, "Environment Variables"))
1045 workspace.environmentVars.Free();
1046 delete workspace.environmentVars;
1047 workspace.environmentVars = { };
1051 else if(!strcmpi(section, "Debugger Data"))
1054 TrimRSpaces(buffer, buffer);
1056 TrimLSpaces(equal, equal);
1057 if(!strcmpi(buffer, "Debug Working Directory"))
1058 workspace.debugDir = equal;
1063 TrimRSpaces(buffer, buffer);
1065 TrimLSpaces(equal, equal);
1066 if(!strcmpi(buffer, "Active Configuration"))
1069 if(workspace.projects.last)
1071 prj = workspace.projects.lastIterator.data;
1072 for(cfg : prj.configurations)
1074 if(!strcmp(cfg.name, equal))
1082 else if(!strcmpi(buffer, "Modified Compiler Config") || !strcmpi(buffer, "Modified Linker Config"))
1085 if(workspace.projects.last)
1087 prj = workspace.projects.lastIterator.data;
1088 for(cfg : prj.configurations)
1090 if(!strcmp(cfg.name, equal))
1092 if(strstr(buffer, "Compiler"))
1093 cfg.compilingModified = true;
1095 cfg.linkingModified = true;
1101 else if(!strcmpi(buffer, "CommandLineArgs"))
1102 workspace.commandLineArgs = equal;
1103 else if(!strcmpi(buffer, "Breakpoint"))
1106 char * lineNum = strstr(equal, ",");
1117 char * absPath = strstr(lineNum, ",");
1124 char * relPath = strstr(absPath, ",");
1131 bp = { type = user, enabled = enabled, level = -1 };
1132 workspace.breakpoints.Add(bp);
1133 bp.line = atoi(lineNum);
1134 bp.relativeFilePath = relPath;
1135 bp.absoluteFilePath = workspace.GetAbsolutePathFromRelative(relPath);
1136 if(!bp.absoluteFilePath)
1137 bp.absoluteFilePath = "";
1145 else if(!strcmpi(buffer, "Watch"))
1148 workspace.watches.Add(wh);
1149 wh.expression = CopyString(equal);
1151 else if(!strcmpi(buffer, "SourceDir"))
1153 workspace.sourceDirs.Add(CopyString(equal));
1155 else if(!strcmpi(buffer, "DebugDir"))
1157 workspace.debugDir = equal;
1169 if(!workspace.projects.first)
1173 project = LoadProject(fromProjectFile /*projectFilePath*/, null);
1176 char projectFilePath[MAX_LOCATION];
1177 strcpy(projectFilePath, workspace.workspaceFile);
1178 ChangeExtension(projectFilePath, ProjectExtension, projectFilePath);
1179 project = LoadProject(projectFilePath, null);
1183 project.StartMonitoring();
1184 workspace.projects.Add(project);
1185 workspace.name = CopyString(project.name);
1189 MessageBox { type = ok, master = ide, contents = $"Workspace load file failed", text = $"Workspace Load File Error" }.Modal();
1195 if(openedFilesNotFound.first)
1199 String files = new char[MAX_LOCATION * 16];
1201 String msg = new char[MAX_LOCATION * 16 + 2048];
1205 item = openedFilesNotFound.first;
1209 for(item = openedFilesNotFound.first; item; item = item.next)
1214 strcat(files, "\n...");
1217 strcat(files, "\n");
1218 strcat(files, item.name);
1221 sprintf(title, $"File%s not found", s);
1222 sprintf(msg, $"The following file%s could not be re-opened.%s", s, files);
1224 MessageBox { type = ok, master = ide, contents = msg, text = title }.Modal();
1229 openedFilesNotFound.Free(OldLink::Free);
1232 openedFilesNotFound.Free(OldLink::Free);
1234 else if(fromProjectFile)
1236 //MessageBox { type = Ok, master = ide, contents = "Worspace load file failed", text = "Worspace Load File Error" }.Modal();
1238 char projectFile[MAX_LOCATION];
1241 //strcpy(projectFile, filePath);
1242 //ChangeExtension(projectFile, ProjectExtension, projectFile);
1243 newProject = LoadProject(fromProjectFile /*projectFile*/, null);
1247 newProject.StartMonitoring();
1248 workspace = Workspace { workspaceFile = filePath };
1250 workspace.projects.Add(newProject);
1257 ide.ChangeFileDialogsDirectory(workspace.workspaceDir, false);
1259 if(!workspace.compiler || !workspace.compiler[0])
1260 workspace.compiler = defaultCompilerName;