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; }
188 file = FileOpen(workspaceFile, write);
192 for(bp : breakpoints)
197 file.Printf("Breakpoint=1,%d,%s,%s\n", bp.line, bp.absoluteFilePath, bp.relativeFilePath);
199 file.Printf("Breakpoint=0,%d,%s,%s\n", bp.line, bp.absoluteFilePath, bp.relativeFilePath);
204 file.Printf("Watch=%s\n", wh.expression);
206 for(dir : sourceDirs)
207 file.Printf("SourceDir=%s\n", dir);
209 if(debugDir && debugDir[0])
210 file.Printf("DebugDir=%s\n", debugDir);
212 if(commandLineArgs && commandLineArgs[0])
213 file.Printf("CommandLineArgs=%s\n", commandLineArgs);
217 char indentation[128*3];
218 char path[MAX_LOCATION];
220 file.Printf("\nECERE Workspace File\n");
221 file.Printf("\nVersion 0.02\n");
222 file.Printf("\nWorkspace\n");
223 file.Printf("\n Active Compiler = %s\n", compiler ? compiler : defaultCompilerName);
224 file.Printf("\n Active Bit Depth = %d\n", bitDepth);
228 file.Printf("\n Projects\n\n");
231 char location[MAX_LOCATION];
232 MakePathRelative(prj.topNode.path, workspaceDir, location);
233 MakeSlashPath(location);
234 PathCatSlash(location, prj.topNode.name);
235 //strcat(location, ".epj");
237 file.Printf(" %s %s\n", "-", location);
240 file.Printf(" Active Configuration = %s\n", prj.config.name);
241 for(cfg : prj.configurations)
243 if(cfg.compilingModified)
244 file.Printf(" Modified Compiler Config = %s\n", cfg.name);
245 else if(cfg.linkingModified)
246 file.Printf(" Modified Linker Config = %s\n", cfg.name);
251 file.Printf("\n Execution Data\n");
252 if(commandLineArgs && commandLineArgs[0])
254 file.Printf("\n Command Line Arguments = ");
255 file.Puts(commandLineArgs);
259 if(environmentVars.count)
261 file.Printf("\n Environment Variables\n\n");
262 for(v : environmentVars)
272 file.Printf("\n Debugger Data\n");
273 // This really belonged in Execution Data...
274 if(debugDir && debugDir[0])
275 file.Printf("\n Debug Working Directory = %s\n", debugDir);
278 file.Printf("\n Source Directories\n");
279 for(dir : sourceDirs)
280 file.Printf(" = %s\n", dir);
283 for(bp : breakpoints)
290 file.Printf("\n Breakpoints\n\n");
298 file.Printf("\n Watches\n\n");
303 if(openedFiles.count)
305 file.Printf("\n Opened Files\n\n");
306 for(ofi : openedFiles)
310 char relativePath[MAX_LOCATION];
311 if(IsPathInsideOf(ofi.path, workspaceDir))
313 MakePathRelative(ofi.path, workspaceDir, relativePath);
314 MakeSlashPath(relativePath);
315 location = relativePath;
321 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);
330 char * GetAbsolutePathFromRelative(char * relative)
332 char name[MAX_LOCATION];
333 char absolute[MAX_LOCATION];
335 ProjectNode node = null;
337 GetLastDirectory(relative, name);
340 if(node = p.topNode.Find(name, false))
348 node.GetFullFilePath(absolute);
349 return CopyString(absolute);
355 strcpy(absolute, p.topNode.path);
356 PathCatSlash(absolute, relative);
357 if(FileExists(absolute))
364 return CopyString(absolute);
366 strcpy(absolute, workspaceDir); //projectDir // CHECK?
367 PathCatSlash(absolute, relative);
368 if(FileExists(absolute))
369 return CopyString(absolute);
372 for(dir : sourceDirs)
374 strcpy(absolute, dir);
375 PathCatSlash(absolute, relative);
376 if(FileExists(absolute))
377 return CopyString(absolute);
384 char * GetPathWorkspaceRelativeOrAbsolute(char * path)
386 if(IsPathInsideOf(path, workspaceDir))
388 char relativePath[MAX_LOCATION];
389 MakePathRelative(path, workspaceDir, relativePath);
390 return CopyUnixPath(relativePath);
393 return CopyUnixPath(path);
396 OpenedFileInfo UpdateOpenedFileInfo(char * fileName, OpenedFileState state)
398 char filePath[MAX_LOCATION];
399 OpenedFileInfo ofi = null;
400 GetSlashPathBuffer(filePath, fileName);
401 for(item : openedFiles)
403 if(!fstrcmp(item.path, filePath))
413 ofi = OpenedFileInfo { path = CopyString(filePath) };
414 openedFiles.Add(ofi);
422 Iterator<OpenedFileInfo> it { openedFiles };
424 openedFiles.Delete(it.pointer);
431 void UpdateSourceDirsArray(Array<String> dirs)
439 sourceDirs.Add(CopyString(s));
441 DropInvalidBreakpoints();
446 void RemoveProject(Project project)
448 Iterator<Project> it { projects };
452 DropInvalidBreakpoints();
454 ide.findInFilesDialog.RemoveProjectItem(project);
455 ide.UpdateToolBarActiveConfigs(false);
461 bool FindPath(ProjectNode node, char * path)
463 if(node.type == file)
465 // TODO: Should this code be moved into a ProjectNode::absolutePath property? Taken from NodeProperties.ec
466 char filePath[MAX_LOCATION];
467 GetSlashPathBuffer(filePath, node.project.topNode.path);
468 PathCatSlash(filePath, node.path);
469 PathCatSlash(filePath, node.name);
471 if(!fstrcmp(filePath, path))
478 if(FindPath(n, path))
485 void ChangeBreakpoint(DataRow row, char * location)
487 Breakpoint bp = (Breakpoint)row.tag;
490 char * currentLoc = bp.LocationToString();
491 if(strcmp(location, currentLoc))
493 // todo, parse location
494 // if good, make changes to breakpoint, according to execution state delete and place breakpoint
495 ide.breakpointsView.UpdateBreakpoint(row); // this is the else
502 // adding a breakpoint by typing it in the breakpoints view
503 // todo, parse location
504 // if good, make add breakpoint, make sure possibly previously entered ignore and level are reflected in breakpoint
507 //bp = Breakpoint { };
508 //row.tag = (int64)bp;
509 //breakpoints.Add(bp);
515 void ChangeBreakpointIgnore(DataRow row, int ignore)
517 Breakpoint bp = (Breakpoint)row.tag;
525 void ChangeBreakpointLevel(DataRow row, int level)
527 Breakpoint bp = (Breakpoint)row.tag;
535 void ChangeBreakpointCondition(DataRow row, char * condition)
537 Breakpoint bp = (Breakpoint)row.tag;
538 if(bp && !(!bp.condition && !(condition && condition[0])))
542 bp.condition = Watch { };
543 bp.condition.expression = CopyString(condition);
546 else if(!(condition && condition[0]))
552 else if(strcmp(condition, bp.condition.expression))
555 bp.condition = Watch { };
556 bp.condition.expression = CopyString(condition);
562 void RemoveBreakpoint(Breakpoint bp)
565 ide.breakpointsView.RemoveBreakpoint(bp);
566 ide.debugger.UpdateRemovedBreakpoint(bp);
568 Iterator<Breakpoint> it { breakpoints };
570 breakpoints.Remove(it.pointer);
574 for(document = ide.firstChild; document; document = document.next)
576 char * fileName = document.fileName;
577 if(document.isDocument && fileName && document.created)
579 char winFilePath[MAX_LOCATION];
580 char * slashPath = GetSlashPathBuffer(winFilePath, fileName);
582 if(!fstrcmp(slashPath, bp.absoluteFilePath))
584 CodeEditor codeEditor = (CodeEditor)document;
585 int boxH = codeEditor.editBox.clientSize.h;
586 Box box { 0, 0, 19, boxH - 1 };
587 document.Update(box);
597 void DropInvalidBreakpoints()
600 for(bpLink = breakpoints.first; bpLink; bpLink = next)
602 Breakpoint bp = (Breakpoint)bpLink.data;
607 Project project = null;
610 if(FindPath(p.topNode, bp.absoluteFilePath))
615 // Handle symbol loader modules:
617 char moduleName[MAX_FILENAME];
619 GetLastDirectory(bp.absoluteFilePath, moduleName);
620 // Tweak for automatically resolving symbol loader modules
621 sl = strstr(moduleName, ".main.ec");
622 if(sl && (*sl = 0, !strcmpi(moduleName, p.name)))
632 for(dir : sourceDirs)
634 if(IsPathInsideOf(bp.absoluteFilePath, dir))
642 ide.breakpointsView.RemoveBreakpoint(bp);
643 RemoveBreakpoint(bp);
648 ide.breakpointsView.Update(null);
653 delete workspaceFile;
655 delete commandLineArgs;
667 ide.outputView.buildBox.Clear();
668 ide.outputView.debugBox.Clear();
669 ide.callStackView.Clear();
670 ide.watchesView.Clear();
671 ide.threadsView.Clear();
672 ide.breakpointsView.Clear();
674 property::debugDir = "";
676 SetSourceDirs(sourceDirs);
685 environmentVars.Free();
694 Workspace LoadWorkspace(char * filePath, char * fromProjectFile)
697 Workspace workspace = null;
699 file = FileOpen(filePath, read);
702 OldList openedFilesNotFound { };
705 char subSection[128];
707 workspace = Workspace { compiler = ideSettings.defaultCompiler, workspaceFile = filePath };
719 file.GetLine(buffer, 65536 - 1);
720 TrimLSpaces(buffer, buffer);
721 TrimRSpaces(buffer, buffer);
728 TrimLSpaces(equal, equal);
729 if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Watches"))
732 workspace.watches.Add(wh);
733 wh.expression = CopyString(equal);
735 else if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Breakpoints"))
740 wh.expression = CopyString(equal);
744 else if(!strcmpi(section, "Execution Data") && !strcmpi(subSection, "Environment Variables"))
746 String value = strchr(equal, '=');
751 TrimRSpaces(equal, equal);
752 TrimLSpaces(value, value);
753 workspace.environmentVars.Add({ equal, value });
757 else if(buffer[0] == '*')
761 TrimLSpaces(equal, equal);
762 if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Breakpoints"))
764 char * strEnabled = null;
765 char * strIgnore = null;
766 char * strLevel = null;
767 char * strLine = null;
768 char * strFile = null;
771 if(strEnabled && strEnabled[0])
773 strIgnore = strstr(strEnabled, ",");
777 if(strIgnore && strIgnore[0])
779 strLevel = strstr(strIgnore, ",");
783 if(strLevel && strLevel[0])
785 strLine = strstr(strLevel, ",");
789 if(strLine && strLine[0])
791 strFile = strstr(strLine, ",");
795 if(strEnabled && strEnabled[0] && strIgnore && strIgnore[0] &&
796 strLevel && strLevel[0] && strLine && strLine[0] && strFile && strFile[0])
803 TrimLSpaces(strEnabled, strEnabled);
804 TrimRSpaces(strEnabled, strEnabled);
805 TrimLSpaces(strIgnore, strIgnore);
806 TrimRSpaces(strIgnore, strIgnore);
807 TrimLSpaces(strLevel, strLevel);
808 TrimRSpaces(strLevel, strLevel);
809 TrimLSpaces(strLevel, strLevel);
810 TrimRSpaces(strLevel, strLevel);
811 TrimLSpaces(strFile, strFile);
812 TrimRSpaces(strFile, strFile);
814 enabled = (strEnabled[0] == '1');
815 ignore = atoi(strIgnore);
816 level = atoi(strLevel);
817 line = atoi(strLine);
819 bp = { type = user, enabled = enabled, ignore = ignore, level = level, line = line };
820 workspace.breakpoints.Add(bp);
821 bp.relativeFilePath = CopyString(strFile);
822 bp.absoluteFilePath = workspace.GetAbsolutePathFromRelative(strFile);
823 if(!bp.absoluteFilePath)
824 bp.absoluteFilePath = CopyString("");
828 else if(buffer[0] == '=' || buffer[0] == '-')
832 TrimLSpaces(equal, equal);
833 if(!strcmpi(section, "Debugger Data") && !strcmpi(subSection, "Source Directories"))
834 workspace.sourceDirs.Add(CopyString(equal));
835 else if(!strcmpi(section, "Opened Files"))
837 OpenedFileState state = opened;
841 char absolutePath[MAX_LOCATION];
842 strcpy(absolutePath, workspace.workspaceDir);
845 char * comma = strchr(equal, ',');
849 lineNumber = atoi(equal);
853 else if(version >= 0.02)
855 char * column = strchr(equal, ':');
859 if(strcmpi(equal, "O"))
863 column = strchr(equal, ':');
867 lineNumber = atoi(equal);
870 column = strchr(equal, ':');
874 position = atoi(equal);
877 column = strchr(equal, ':');
881 scroll.x = atoi(equal);
884 column = strchr(equal, ':');
888 scroll.y = atoi(equal);
897 PathCatSlash(absolutePath, equal);
899 if(state == closed || FileExists(absolutePath))
900 workspace.openedFiles.Add(OpenedFileInfo { path = CopyString(absolutePath), state = state, lineNumber = lineNumber, position = position, scroll = scroll });
902 openedFilesNotFound.Add(NamedItem { name = CopyString(equal) });
904 else if(!strcmpi(section, "Projects"))
906 char projectFilePath[MAX_LOCATION];
908 strcpy(projectFilePath, workspace.workspaceDir);
909 PathCatSlash(projectFilePath, equal);
910 newProject = LoadProject(projectFilePath, null);
913 workspace.projects.Add(newProject);
914 newProject.StartMonitoring();
916 else if(workspace.projects.count == 0)
923 // TODO: show message or something when added project fails to load
924 // http://ecere.com/mantis/view.php?id=524
928 else if(!strcmpi(buffer, "ECERE Workspace File"));
929 else if(!strcmpi(buffer, "Version 0a"))
931 else if(!strncmp(buffer, "Version ", 8))
932 version = atof(&buffer[8]);
933 else if(!strcmpi(buffer, "Workspace"))
934 strcpy(section, buffer);
935 else if(!strcmpi(buffer, "Projects"))
936 strcpy(section, buffer);
937 else if(!strcmpi(buffer, "Execution Data"))
938 strcpy(section, buffer);
939 else if(!strcmpi(buffer, "Debugger Data"))
940 strcpy(section, buffer);
941 else if(!strcmpi(buffer, "Source Directories"))
942 strcpy(subSection, buffer);
943 else if(!strcmpi(buffer, "Breakpoints"))
944 strcpy(subSection, buffer);
945 else if(!strcmpi(buffer, "Watches"))
946 strcpy(subSection, buffer);
947 else if(!strcmpi(buffer, "Environment Variables"))
948 strcpy(subSection, buffer);
949 else if(!strcmpi(buffer, "Opened Files"))
950 strcpy(section, buffer);
951 else if(!strcmpi(buffer, "")) // | These two lines were commented out
952 strcpy(subSection, buffer); // | Do they serve a purpose? They were there for copy paste when adding a new subsection
955 equal = strstr(buffer, "=");
958 if(!strcmpi(section, "Workspace"))
961 TrimRSpaces(buffer, buffer);
963 TrimLSpaces(equal, equal);
964 if(!strcmpi(buffer, "Active Compiler"))
966 CompilerConfig compiler = ideSettings.GetCompilerConfig(equal);
968 workspace.compiler = defaultCompilerName;
970 workspace.compiler = equal;
973 if(!strcmpi(buffer, "Active Bit Depth"))
975 int bitDepth = atoi(equal);
976 if(!(bitDepth == 32 || bitDepth == 64))
978 workspace.bitDepth = bitDepth;
979 ide.toolBar.activeBitDepth.SelectRow(ide.toolBar.activeBitDepth.FindRow(bitDepth));
982 else if(!strcmpi(section, "Execution Data"))
985 TrimRSpaces(buffer, buffer);
987 TrimLSpaces(equal, equal);
988 if(!strcmpi(buffer, "Command Line Arguments"))
989 workspace.commandLineArgs = equal;
991 if(!strcmpi(buffer, "Environment Variables"))
993 workspace.environmentVars.Free();
994 delete workspace.environmentVars;
995 workspace.environmentVars = { };
999 else if(!strcmpi(section, "Debugger Data"))
1002 TrimRSpaces(buffer, buffer);
1004 TrimLSpaces(equal, equal);
1005 if(!strcmpi(buffer, "Debug Working Directory"))
1006 workspace.debugDir = equal;
1011 TrimRSpaces(buffer, buffer);
1013 TrimLSpaces(equal, equal);
1014 if(!strcmpi(buffer, "Active Configuration"))
1017 if(workspace.projects.last)
1019 prj = workspace.projects.lastIterator.data;
1020 for(cfg : prj.configurations)
1022 if(!strcmp(cfg.name, equal))
1030 else if(!strcmpi(buffer, "Modified Compiler Config") || !strcmpi(buffer, "Modified Linker Config"))
1033 if(workspace.projects.last)
1035 prj = workspace.projects.lastIterator.data;
1036 for(cfg : prj.configurations)
1038 if(!strcmp(cfg.name, equal))
1040 if(strstr(buffer, "Compiler"))
1041 cfg.compilingModified = true;
1043 cfg.linkingModified = true;
1049 else if(!strcmpi(buffer, "CommandLineArgs"))
1050 workspace.commandLineArgs = equal;
1051 else if(!strcmpi(buffer, "Breakpoint"))
1054 char * lineNum = strstr(equal, ",");
1065 char * absPath = strstr(lineNum, ",");
1072 char * relPath = strstr(absPath, ",");
1079 bp = { type = user, enabled = enabled, level = -1 };
1080 workspace.breakpoints.Add(bp);
1081 bp.line = atoi(lineNum);
1082 bp.relativeFilePath = CopyString(relPath);
1083 bp.absoluteFilePath = workspace.GetAbsolutePathFromRelative(relPath);
1084 if(!bp.absoluteFilePath)
1085 bp.absoluteFilePath = CopyString("");
1093 else if(!strcmpi(buffer, "Watch"))
1096 workspace.watches.Add(wh);
1097 wh.expression = CopyString(equal);
1099 else if(!strcmpi(buffer, "SourceDir"))
1101 workspace.sourceDirs.Add(CopyString(equal));
1103 else if(!strcmpi(buffer, "DebugDir"))
1105 workspace.debugDir = equal;
1117 if(!workspace.projects.first)
1121 project = LoadProject(fromProjectFile /*projectFilePath*/, null);
1124 char projectFilePath[MAX_LOCATION];
1125 strcpy(projectFilePath, workspace.workspaceFile);
1126 ChangeExtension(projectFilePath, ProjectExtension, projectFilePath);
1127 project = LoadProject(projectFilePath, null);
1131 project.StartMonitoring();
1132 workspace.projects.Add(project);
1133 workspace.name = CopyString(project.name);
1137 MessageBox { type = ok, master = ide, contents = $"Workspace load file failed", text = $"Workspace Load File Error" }.Modal();
1143 if(openedFilesNotFound.first)
1147 String files = new char[MAX_LOCATION * 16];
1149 String msg = new char[MAX_LOCATION * 16 + 2048];
1153 item = openedFilesNotFound.first;
1157 for(item = openedFilesNotFound.first; item; item = item.next)
1162 strcat(files, "\n...");
1165 strcat(files, "\n");
1166 strcat(files, item.name);
1169 sprintf(title, $"File%s not found", s);
1170 sprintf(msg, $"The following file%s could not be re-opened.%s", s, files);
1172 MessageBox { type = ok, master = ide, contents = msg, text = title }.Modal();
1177 openedFilesNotFound.Free(OldLink::Free);
1180 openedFilesNotFound.Free(OldLink::Free);
1182 else if(fromProjectFile)
1184 //MessageBox { type = Ok, master = ide, contents = "Worspace load file failed", text = "Worspace Load File Error" }.Modal();
1186 char projectFile[MAX_LOCATION];
1189 //strcpy(projectFile, filePath);
1190 //ChangeExtension(projectFile, ProjectExtension, projectFile);
1191 newProject = LoadProject(fromProjectFile /*projectFile*/, null);
1195 newProject.StartMonitoring();
1196 workspace = Workspace { workspaceFile = filePath };
1198 workspace.projects.Add(newProject);
1205 ide.ChangeFileDialogsDirectory(workspace.workspaceDir, false);
1207 if(!workspace.compiler || !workspace.compiler[0])
1208 workspace.compiler = defaultCompilerName;