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 };
32 OpenedFileState state;
33 int lineNumber, position;
37 property bool trackingAllowed
39 get { return !holdTracking && ide && ide.workspace && !ide.workspace.holdTracking; }
42 void CaretMove(int line, int charPos)
44 if(trackingAllowed && (line != lineNumber || position != charPos))
48 ide.workspace.modified = true;
52 void ScrollChange(Point scroll)
56 this.scroll.x = scroll.x;
57 this.scroll.y = scroll.y;
58 ide.workspace.modified = true;
66 List<OpenedFileInfo> files = ide.workspace.openedFiles;
67 Iterator<OpenedFileInfo> it { files };
68 if(it.Find(this) && it.pointer != files.GetLast())
70 files.Move(it.pointer, files.GetPrev(files.GetLast()));
71 ide.workspace.modified = true;
87 char * commandLineArgs;
88 property char * commandLineArgs { set { delete commandLineArgs; if(value) commandLineArgs = CopyString(value); } }
90 property char * debugDir { set { delete debugDir; if(value) debugDir = CopyString(value); } }
94 property char * compiler
96 set { delete compiler; if(value && value[0]) compiler = CopyString(value); }
97 get { return compiler && compiler[0] ? compiler : null; }
100 List<String> sourceDirs { };
101 Array<NamedString> environmentVars { };
102 List<Breakpoint> breakpoints { };
103 List<Watch> watches { };
104 List<OpenedFileInfo> openedFiles { };
105 List<Project> projects { };
114 userData = this, delay = 2.5;
123 property char * workspaceFile
127 char dir[MAX_DIRECTORY];
128 if(workspaceFile) delete workspaceFile;
129 if(workspaceDir) delete workspaceDir;
130 workspaceFile = CopyString(value);
131 StripLastDirectory(workspaceFile, dir);
132 workspaceDir = CopyUnixPath(dir);
134 get { return workspaceFile; }
137 property char * projectDir
143 Project prj = projects.firstIterator.data;
144 return prj.topNode ? prj.topNode.path : null;
151 /*property Project project
161 projectDir = CopyString(project.topNode.path);
163 if(!project.config && activeConfig && activeConfig[0])
166 for(cfg = project.configurations.first; cfg; cfg = cfg.next)
167 if(!strcmp(cfg.name, activeConfig))
169 project.config = cfg;
172 project.config = project.configurations.first;
175 get { return project; }
187 file = FileOpen(workspaceFile, write);
191 for(bp : breakpoints)
196 file.Printf("Breakpoint=1,%d,%s,%s\n", bp.line, bp.absoluteFilePath, bp.relativeFilePath);
198 file.Printf("Breakpoint=0,%d,%s,%s\n", bp.line, bp.absoluteFilePath, bp.relativeFilePath);
203 file.Printf("Watch=%s\n", wh.expression);
205 for(dir : sourceDirs)
206 file.Printf("SourceDir=%s\n", dir);
208 if(debugDir && debugDir[0])
209 file.Printf("DebugDir=%s\n", debugDir);
211 if(commandLineArgs && commandLineArgs[0])
212 file.Printf("CommandLineArgs=%s\n", commandLineArgs);
216 char indentation[128*3];
217 char path[MAX_LOCATION];
219 file.Printf("\nECERE Workspace File\n");
220 file.Printf("\nVersion 0.02\n");
221 file.Printf("\nWorkspace\n");
222 file.Printf("\n Active Compiler = %s\n", compiler ? compiler : defaultCompilerName);
226 file.Printf("\n Projects\n\n");
229 char location[MAX_LOCATION];
230 MakePathRelative(prj.topNode.path, workspaceDir, location);
231 MakeSlashPath(location);
232 PathCatSlash(location, prj.topNode.name);
233 //strcat(location, ".epj");
235 file.Printf(" %s %s\n", "-", location);
238 file.Printf(" Active Configuration = %s\n", prj.config.name);
239 for(cfg : prj.configurations)
241 if(cfg.compilingModified)
242 file.Printf(" Modified Compiler Config = %s\n", cfg.name);
243 else if(cfg.linkingModified)
244 file.Printf(" Modified Linker Config = %s\n", cfg.name);
249 file.Printf("\n Execution Data\n");
250 if(commandLineArgs && commandLineArgs[0])
252 file.Printf("\n Command Line Arguments = ");
253 file.Puts(commandLineArgs);
257 if(environmentVars.count)
259 file.Printf("\n Environment Variables\n\n");
260 for(v : environmentVars)
270 file.Printf("\n Debugger Data\n");
271 // This really belonged in Execution Data...
272 if(debugDir && debugDir[0])
273 file.Printf("\n Debug Working Directory = %s\n", debugDir);
276 file.Printf("\n Source Directories\n");
277 for(dir : sourceDirs)
278 file.Printf(" = %s\n", dir);
281 for(bp : breakpoints)
288 file.Printf("\n Breakpoints\n\n");
296 file.Printf("\n Watches\n\n");
301 if(openedFiles.count)
303 file.Printf("\n Opened Files\n\n");
304 for(ofi : openedFiles)
308 char relativePath[MAX_LOCATION];
309 if(IsPathInsideOf(ofi.path, workspaceDir))
311 MakePathRelative(ofi.path, workspaceDir, relativePath);
312 MakeSlashPath(relativePath);
313 location = relativePath;
319 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);
328 char * GetAbsolutePathFromRelative(char * relative)
330 char name[MAX_LOCATION];
331 char absolute[MAX_LOCATION];
334 GetLastDirectory(relative, name);
337 if(p.topNode.Find(name, false))
345 strcpy(absolute, prj.topNode.path);
346 PathCatSlash(absolute, relative);
347 return CopyString(absolute);
353 strcpy(absolute, p.topNode.path);
354 PathCatSlash(absolute, relative);
355 if(FileExists(absolute))
362 return CopyString(absolute);
364 strcpy(absolute, workspaceDir); //projectDir // CHECK?
365 PathCatSlash(absolute, relative);
366 if(FileExists(absolute))
367 return CopyString(absolute);
370 for(dir : sourceDirs)
372 strcpy(absolute, dir);
373 PathCatSlash(absolute, relative);
374 if(FileExists(absolute))
375 return CopyString(absolute);
382 char * GetPathWorkspaceRelativeOrAbsolute(char * path)
384 if(IsPathInsideOf(path, workspaceDir))
386 char relativePath[MAX_LOCATION];
387 MakePathRelative(path, workspaceDir, relativePath);
388 return CopyUnixPath(relativePath);
391 return CopyUnixPath(path);
394 OpenedFileInfo UpdateOpenedFileInfo(char * fileName, OpenedFileState state)
396 char filePath[MAX_LOCATION];
397 OpenedFileInfo ofi = null;
398 GetSlashPathBuffer(filePath, fileName);
399 for(item : openedFiles)
401 if(!fstrcmp(item.path, filePath))
411 ofi = OpenedFileInfo { path = CopyString(filePath) };
412 openedFiles.Add(ofi);
420 Iterator<OpenedFileInfo> it { openedFiles };
422 openedFiles.Delete(it.pointer);
429 void UpdateSourceDirsArray(Array<String> dirs)
437 sourceDirs.Add(CopyString(s));
439 DropInvalidBreakpoints();
444 void RemoveProject(Project project)
446 Iterator<Project> it { projects };
450 DropInvalidBreakpoints();
452 ide.findInFilesDialog.RemoveProjectItem(project);
458 bool FindPath(ProjectNode node, char * path)
460 if(node.type == file)
462 // TODO: Should this code be moved into a ProjectNode::absolutePath property? Taken from NodeProperties.ec
463 char filePath[MAX_LOCATION];
464 GetSlashPathBuffer(filePath, node.project.topNode.path);
465 PathCatSlash(filePath, node.path);
466 PathCatSlash(filePath, node.name);
468 if(!fstrcmp(filePath, path))
475 if(FindPath(n, path))
482 void ChangeBreakpoint(DataRow row, char * location)
484 Breakpoint bp = (Breakpoint)row.tag;
487 char * currentLoc = bp.LocationToString();
488 if(strcmp(location, currentLoc))
490 // todo, parse location
491 // if good, make changes to breakpoint, according to execution state delete and place breakpoint
492 ide.breakpointsView.UpdateBreakpoint(row); // this is the else
499 // adding a breakpoint by typing it in the breakpoints view
500 // todo, parse location
501 // if good, make add breakpoint, make sure possibly previously entered ignore and level are reflected in breakpoint
504 //bp = Breakpoint { };
505 //row.tag = (int64)bp;
506 //breakpoints.Add(bp);
512 void ChangeBreakpointIgnore(DataRow row, int ignore)
514 Breakpoint bp = (Breakpoint)row.tag;
522 void ChangeBreakpointLevel(DataRow row, int level)
524 Breakpoint bp = (Breakpoint)row.tag;
532 void ChangeBreakpointCondition(DataRow row, char * condition)
534 Breakpoint bp = (Breakpoint)row.tag;
535 if(bp && !(!bp.condition && !(condition && condition[0])))
539 bp.condition = Watch { };
540 bp.condition.expression = CopyString(condition);
543 else if(!(condition && condition[0]))
549 else if(strcmp(condition, bp.condition.expression))
552 bp.condition = Watch { };
553 bp.condition.expression = CopyString(condition);
559 void RemoveBreakpoint(Breakpoint bp)
562 ide.breakpointsView.RemoveBreakpoint(bp);
563 ide.debugger.UpdateRemovedBreakpoint(bp);
565 Iterator<Breakpoint> it { breakpoints };
567 breakpoints.Remove(it.pointer);
571 for(document = ide.firstChild; document; document = document.next)
573 char * fileName = document.fileName;
574 if(document.isDocument && fileName && document.created)
576 char winFilePath[MAX_LOCATION];
577 char * slashPath = GetSlashPathBuffer(winFilePath, fileName);
579 if(!fstrcmp(slashPath, bp.absoluteFilePath))
581 CodeEditor codeEditor = (CodeEditor)document;
582 int boxH = codeEditor.editBox.clientSize.h;
583 Box box { 0, 0, 19, boxH - 1 };
584 document.Update(box);
594 void DropInvalidBreakpoints()
597 for(bpLink = breakpoints.first; bpLink; bpLink = next)
599 Breakpoint bp = (Breakpoint)bpLink.data;
604 Project project = null;
607 if(FindPath(p.topNode, bp.absoluteFilePath))
612 // Handle symbol loader modules:
614 char moduleName[MAX_FILENAME];
616 GetLastDirectory(bp.absoluteFilePath, moduleName);
617 // Tweak for automatically resolving symbol loader modules
618 sl = strstr(moduleName, ".main.ec");
619 if(sl && (*sl = 0, !strcmpi(moduleName, p.name)))
629 for(dir : sourceDirs)
631 if(IsPathInsideOf(bp.absoluteFilePath, dir))
639 ide.breakpointsView.RemoveBreakpoint(bp);
640 RemoveBreakpoint(bp);
645 ide.breakpointsView.Update(null);
650 delete workspaceFile;
652 delete commandLineArgs;
664 ide.outputView.buildBox.Clear();
665 ide.outputView.debugBox.Clear();
666 ide.callStackView.Clear();
667 ide.watchesView.Clear();
668 ide.threadsView.Clear();
669 ide.breakpointsView.Clear();
671 property::debugDir = "";
673 SetSourceDirs(sourceDirs);
682 environmentVars.Free();
691 Workspace LoadWorkspace(char * filePath, char * fromProjectFile)
694 Workspace workspace = null;
696 file = FileOpen(filePath, read);
699 OldList openedFilesNotFound { };
701 workspace = Workspace { compiler = ideSettings.defaultCompiler, workspaceFile = filePath };
708 char subSection[128];
717 file.GetLine(buffer, 65536 - 1);
718 TrimLSpaces(buffer, buffer);
719 TrimRSpaces(buffer, buffer);
726 TrimLSpaces(equal, equal);
727 if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Watches"))
730 workspace.watches.Add(wh);
731 wh.expression = CopyString(equal);
733 else if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Breakpoints"))
738 wh.expression = CopyString(equal);
742 else if(!strcmpi(section, "Execution Data") && !strcmpi(subSection, "Environment Variables"))
744 String value = strchr(equal, '=');
749 TrimRSpaces(equal, equal);
750 TrimLSpaces(value, value);
751 workspace.environmentVars.Add({ equal, value });
755 else if(buffer[0] == '*')
759 TrimLSpaces(equal, equal);
760 if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Breakpoints"))
762 char * strEnabled = null;
763 char * strIgnore = null;
764 char * strLevel = null;
765 char * strLine = null;
766 char * strFile = null;
769 if(strEnabled && strEnabled[0])
771 strIgnore = strstr(strEnabled, ",");
775 if(strIgnore && strIgnore[0])
777 strLevel = strstr(strIgnore, ",");
781 if(strLevel && strLevel[0])
783 strLine = strstr(strLevel, ",");
787 if(strLine && strLine[0])
789 strFile = strstr(strLine, ",");
793 if(strEnabled && strEnabled[0] && strIgnore && strIgnore[0] &&
794 strLevel && strLevel[0] && strLine && strLine[0] && strFile && strFile[0])
801 TrimLSpaces(strEnabled, strEnabled);
802 TrimRSpaces(strEnabled, strEnabled);
803 TrimLSpaces(strIgnore, strIgnore);
804 TrimRSpaces(strIgnore, strIgnore);
805 TrimLSpaces(strLevel, strLevel);
806 TrimRSpaces(strLevel, strLevel);
807 TrimLSpaces(strLevel, strLevel);
808 TrimRSpaces(strLevel, strLevel);
809 TrimLSpaces(strFile, strFile);
810 TrimRSpaces(strFile, strFile);
812 enabled = (strEnabled[0] == '1');
813 ignore = atoi(strIgnore);
814 level = atoi(strLevel);
815 line = atoi(strLine);
817 bp = { type = user, enabled = enabled, ignore = ignore, level = level, line = line };
818 workspace.breakpoints.Add(bp);
819 bp.relativeFilePath = CopyString(strFile);
820 bp.absoluteFilePath = workspace.GetAbsolutePathFromRelative(strFile);
821 if(!bp.absoluteFilePath)
822 bp.absoluteFilePath = CopyString("");
826 else if(buffer[0] == '=' || buffer[0] == '-')
830 TrimLSpaces(equal, equal);
831 if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Source Directories"))
832 workspace.sourceDirs.Add(CopyString(equal));
833 else if(!strcmpi(section, "Opened Files"))
835 OpenedFileState state = opened;
839 char absolutePath[MAX_LOCATION];
840 strcpy(absolutePath, workspace.workspaceDir);
843 char * comma = strchr(equal, ',');
847 lineNumber = atoi(equal);
851 else if(version >= 0.02f)
853 char * column = strchr(equal, ':');
857 if(strcmpi(equal, "O"))
861 column = strchr(equal, ':');
865 lineNumber = atoi(equal);
868 column = strchr(equal, ':');
872 position = atoi(equal);
875 column = strchr(equal, ':');
879 scroll.x = atoi(equal);
882 column = strchr(equal, ':');
886 scroll.y = atoi(equal);
895 PathCatSlash(absolutePath, equal);
897 if(state == closed || FileExists(absolutePath))
898 workspace.openedFiles.Add(OpenedFileInfo { path = CopyString(absolutePath), state = state, lineNumber = lineNumber, position = position, scroll = scroll });
900 openedFilesNotFound.Add(NamedItem { name = CopyString(equal) });
902 else if(!strcmpi(section, "Projects"))
904 char projectFilePath[MAX_LOCATION];
906 strcpy(projectFilePath, workspace.workspaceDir);
907 PathCatSlash(projectFilePath, equal);
908 newProject = LoadProject(projectFilePath, null);
911 workspace.projects.Add(newProject);
912 newProject.StartMonitoring();
914 else if(workspace.projects.count == 0)
921 // TODO: show message or something when added project fails to load
922 // http://ecere.com/mantis/view.php?id=524
926 else if(!strcmpi(buffer, "ECERE Workspace File"));
927 else if(!strcmpi(buffer, "Version 0a"))
929 else if(!strncmp(buffer, "Version ", 8))
930 version = atof(&buffer[8]);
931 else if(!strcmpi(buffer, "Workspace"))
932 strcpy(section, buffer);
933 else if(!strcmpi(buffer, "Projects"))
934 strcpy(section, buffer);
935 else if(!strcmpi(buffer, "Execution Data"))
936 strcpy(section, buffer);
937 else if(!strcmpi(buffer, "Debugger Data"))
938 strcpy(section, buffer);
939 else if(!strcmpi(buffer, "Source Directories"))
940 strcpy(subSection, buffer);
941 else if(!strcmpi(buffer, "Breakpoints"))
942 strcpy(subSection, buffer);
943 else if(!strcmpi(buffer, "Watches"))
944 strcpy(subSection, buffer);
945 else if(!strcmpi(buffer, "Environment Variables"))
946 strcpy(subSection, buffer);
947 else if(!strcmpi(buffer, "Opened Files"))
948 strcpy(section, buffer);
949 else if(!strcmpi(buffer, "")) // | These two lines were commented out
950 strcpy(subSection, buffer); // | Do they serve a purpose? They were there for copy paste when adding a new subsection
953 equal = strstr(buffer, "=");
956 if(!strcmpi(section, "Workspace"))
959 TrimRSpaces(buffer, buffer);
961 TrimLSpaces(equal, equal);
962 if(!strcmpi(buffer, "Active Compiler"))
964 CompilerConfig compiler = ideSettings.GetCompilerConfig(equal);
966 workspace.compiler = defaultCompilerName;
968 workspace.compiler = equal;
972 else if(!strcmpi(section, "Execution Data"))
975 TrimRSpaces(buffer, buffer);
977 TrimLSpaces(equal, equal);
978 if(!strcmpi(buffer, "Command Line Arguments"))
979 workspace.commandLineArgs = equal;
981 if(!strcmpi(buffer, "Environment Variables"))
983 delete workspace.environmentVars;
984 workspace.environmentVars = { };
988 else if(!strcmpi(section, "Debugger Data"))
991 TrimRSpaces(buffer, buffer);
993 TrimLSpaces(equal, equal);
994 if(!strcmpi(buffer, "Debug Working Directory"))
995 workspace.debugDir = equal;
1000 TrimRSpaces(buffer, buffer);
1002 TrimLSpaces(equal, equal);
1003 if(!strcmpi(buffer, "Active Configuration"))
1006 if(workspace.projects.last)
1008 prj = workspace.projects.lastIterator.data;
1009 for(cfg : prj.configurations)
1011 if(!strcmp(cfg.name, equal))
1019 else if(!strcmpi(buffer, "Modified Compiler Config") || !strcmpi(buffer, "Modified Linker Config"))
1022 if(workspace.projects.last)
1024 prj = workspace.projects.lastIterator.data;
1025 for(cfg : prj.configurations)
1027 if(!strcmp(cfg.name, equal))
1029 if(strstr(buffer, "Compiler"))
1030 cfg.compilingModified = true;
1032 cfg.linkingModified = true;
1038 else if(!strcmpi(buffer, "CommandLineArgs"))
1039 workspace.commandLineArgs = equal;
1040 else if(!strcmpi(buffer, "Breakpoint"))
1043 char * lineNum = strstr(equal, ",");
1054 char * absPath = strstr(lineNum, ",");
1061 char * relPath = strstr(absPath, ",");
1068 bp = { type = user, enabled = enabled, level = -1 };
1069 workspace.breakpoints.Add(bp);
1070 bp.line = atoi(lineNum);
1071 bp.relativeFilePath = CopyString(relPath);
1072 bp.absoluteFilePath = workspace.GetAbsolutePathFromRelative(relPath);
1073 if(!bp.absoluteFilePath)
1074 bp.absoluteFilePath = CopyString("");
1082 else if(!strcmpi(buffer, "Watch"))
1085 workspace.watches.Add(wh);
1086 wh.expression = CopyString(equal);
1088 else if(!strcmpi(buffer, "SourceDir"))
1090 workspace.sourceDirs.Add(CopyString(equal));
1092 else if(!strcmpi(buffer, "DebugDir"))
1094 workspace.debugDir = equal;
1106 if(!workspace.projects.first)
1110 project = LoadProject(fromProjectFile /*projectFilePath*/, null);
1113 char projectFilePath[MAX_LOCATION];
1114 strcpy(projectFilePath, workspace.workspaceFile);
1115 ChangeExtension(projectFilePath, ProjectExtension, projectFilePath);
1116 project = LoadProject(projectFilePath, null);
1120 project.StartMonitoring();
1121 workspace.projects.Add(project);
1122 workspace.name = CopyString(project.name);
1126 MessageBox { type = ok, master = ide, contents = $"Workspace load file failed", text = $"Workspace Load File Error" }.Modal();
1132 if(openedFilesNotFound.first)
1136 String files = new char[MAX_LOCATION * 16];
1138 String msg = new char[MAX_LOCATION * 16 + 2048];
1142 item = openedFilesNotFound.first;
1146 for(item = openedFilesNotFound.first; item; item = item.next)
1151 strcat(files, "\n...");
1154 strcat(files, "\n");
1155 strcat(files, item.name);
1158 sprintf(title, $"File%s not found", s);
1159 sprintf(msg, $"The following file%s could not be re-opened.%s", s, files);
1161 MessageBox { type = ok, master = ide, contents = msg, text = title }.Modal();
1166 openedFilesNotFound.Free(OldLink::Free);
1169 openedFilesNotFound.Free(OldLink::Free);
1171 else if(fromProjectFile)
1173 //MessageBox { type = Ok, master = ide, contents = "Worspace load file failed", text = "Worspace Load File Error" }.Modal();
1175 char projectFile[MAX_LOCATION];
1178 //strcpy(projectFile, filePath);
1179 //ChangeExtension(projectFile, ProjectExtension, projectFile);
1180 newProject = LoadProject(fromProjectFile /*projectFile*/, null);
1184 newProject.StartMonitoring();
1185 workspace = Workspace { workspaceFile = filePath };
1187 workspace.projects.Add(newProject);
1194 ide.ChangeFileDialogsDirectory(workspace.workspaceDir, false);
1196 if(!workspace.compiler || !workspace.compiler[0])
1197 workspace.compiler = defaultCompilerName;