2 public import static "ecere"
7 // *** Color Schemes ***
11 SyntaxColorScheme syntaxColors;
14 property const String name
16 set { delete name; name = CopyString(value); }
22 Color viewsBackground;
24 Color outputBackground;
26 Color projectViewBackground;
27 Color projectViewText;
31 Color selectedMarginColor;
32 Color lineNumbersColor;
33 Color sheetSelectionColor;
34 Color sheetSelectionText;
36 property SyntaxColorScheme syntaxColors
38 set { delete syntaxColors; syntaxColors = value; if(value) incref value; }
39 get { return syntaxColors; }
49 IDEColorScheme colorScheme;
51 // Default Color Schemes
52 IDEColorScheme darkColorScheme
54 name = "Classic Dark";
55 selectionColor = lightYellow;
56 selectionText = Color { 30, 40, 50 };
57 viewsBackground = Color { 30, 40, 50 };
58 viewsText = lightGray;
59 outputBackground = black;
61 sheetSelectionColor = Color { 170, 220, 255 };
62 sheetSelectionText = black;
63 projectViewBackground = Color { 30, 40, 50 };
64 projectViewText = lightGray;
67 marginColor = Color {24, 24, 24};
68 selectedMarginColor = Color {64, 64, 64};
69 lineNumbersColor = Color {160, 160, 160};
72 keywordColors = [ skyBlue, skyBlue ];
73 commentColor = Color { 125, 125, 125 };
74 charLiteralColor = Color { 245, 50, 245 };
75 stringLiteralColor = Color { 245, 50, 245 };
76 preprocessorColor = { 120, 220, 140 };
77 numberColor = Color { 0, 192, 192 };
81 IDEColorScheme lightColorScheme
83 name = "Classic Light";
84 selectionColor = Color { 10, 36, 106 };
85 selectionText = white;
86 viewsBackground = white;
88 outputBackground = white;
90 sheetSelectionColor = Color { 170, 220, 255 };
91 sheetSelectionText = black;
92 projectViewBackground = white;
93 projectViewText = black;
96 marginColor = Color {230, 230, 230};
97 selectedMarginColor = Color {200, 200, 200};
98 lineNumbersColor = Color {60, 60, 60};
101 keywordColors = [ blue, blue ];
102 commentColor = dimGray;
103 charLiteralColor = crimson;
104 stringLiteralColor = crimson;
105 preprocessorColor = green;
110 IDEColorScheme greenColorScheme
113 selectionColor = 0x00FFFFE0,
114 selectionText = 0x001E2832,
115 viewsBackground = 0x001E2832,
116 viewsText = 0x00D3D3D3,
117 outputBackground = 0x00000000,
118 outputText = 0x0000FF00,
119 projectViewBackground = 0x001E2832,
120 projectViewText = 0x00D3D3D3,
121 codeEditorBG = 0x00000000,
122 codeEditorFG = 0x00FFFFF0,
123 marginColor = 0x001100,
124 selectedMarginColor = 0x002200,
125 lineNumbersColor = 0x00FF00,
126 sheetSelectionColor = 0x00AADCFF,
127 sheetSelectionText = 0x00000000,
129 commentColor = 0x008c00,
130 charLiteralColor = 0x89de00,
131 stringLiteralColor = 0x89de00,
132 preprocessorColor = 0x0078DC8C,
133 numberColor = { 8, 237, 141 },
141 IDEColorScheme grayColorScheme
143 name = "Gray & Orange",
144 selectionColor = 0x00FFFFE0,
145 selectionText = 0x001E2832,
146 viewsBackground = 0x001E2832,
147 viewsText = 0x00D3D3D3,
148 outputBackground = 0x00000000,
149 outputText = 0x0000FF00,
150 projectViewBackground = 0x001E2832,
151 projectViewText = 0x00D3D3D3,
152 codeEditorBG = 0x00202020,
153 codeEditorFG = 0x00E2E2E5,
154 marginColor = 0x00303030,
155 selectedMarginColor = 0x00404040,
156 lineNumbersColor = 0x00939395,
157 sheetSelectionColor = 0x00AADCFF,
158 sheetSelectionText = 0x00000000,
160 commentColor = 0x005F5F5F,
161 charLiteralColor = 0x0089DE00,
162 stringLiteralColor = 0x00707070,
163 preprocessorColor = 0x00FAF4C6,
164 numberColor = 0x00FF9800,
172 define ecpDefaultCommand = "ecp";
173 define eccDefaultCommand = "ecc";
174 define ecsDefaultCommand = "ecs";
175 define earDefaultCommand = "ear";
176 define cppDefaultCommand = "gcc"; // As per #624 we decided to default to "gcc"...
177 define ccDefaultCommand = "gcc";
178 define cxxDefaultCommand = "g++";
179 //define ldDefaultCommand = "gcc";
180 define arDefaultCommand = "ar";
181 define objectDefaultFileExt = "o";
182 define outputDefaultFileExt = "";
186 import "OldIDESettings"
189 #define WIN32_LEAN_AND_MEAN
198 define MaxRecent = 9;
200 enum DirTypes { includes, libraries, executables };
202 define defaultCompilerName = "Default";
204 define defaultObjDirExpression = "obj/$(CONFIG).$(PLATFORM)$(COMPILER_SUFFIX)$(DEBUG_SUFFIX)";
206 const char * settingsDirectoryNames[DirTypes] =
213 // This function cannot accept same pointer for source and output
214 // todo: rename ReplaceSpaces to EscapeSpaceAndSpecialChars or something
215 void ReplaceSpaces(char * output, const char * source)
220 for(c = 0, dc = 0; (ch = source[c]); c++, dc++)
222 if(ch == ' ') output[dc++] = '\\';
223 if(ch == '\"') output[dc++] = '\\';
224 if(ch == '&') output[dc++] = '\\';
227 if(ch == '(' || ch == ')') output[dc++] = '\\';
238 enum GlobalSettingsChange { none, editorSettings, projectOptions, compilerSettings };
240 enum PathRelationship { unrelated, identical, siblings, subPath, parentPath, insuficientInput, pathEmpty, toEmpty, pathNull, toNull, bothEmpty, bothNull };
241 PathRelationship eString_PathRelated(const char * path, const char * to, char * pathDiff)
243 PathRelationship result;
244 if(pathDiff) *pathDiff = '\0';
245 if(path && *path && to && *to)
247 char toPart[MAX_FILENAME], toRest[MAX_LOCATION];
248 char pathPart[MAX_FILENAME], pathRest[MAX_LOCATION];
250 strcpy(pathRest, path);
251 for(; toRest[0] && pathRest[0];)
253 SplitDirectory(toRest, toPart, toRest);
254 SplitDirectory(pathRest, pathPart, pathRest);
255 if(!fstrcmp(pathPart, toPart)) result = siblings;
258 if(result == siblings)
260 if(!*toRest && !*pathRest) result = identical;
261 else if(!*pathRest) result = parentPath;
262 else result = subPath;
263 if(pathDiff && result != identical) strcpy(pathDiff, *pathRest == '\0' ? toRest : pathRest);
265 else result = unrelated;
271 if(!*path && !*to) result = bothEmpty;
272 else if(!*path) result = pathEmpty;
273 else result = toEmpty;
275 else if(!path && !to) result = bothNull;
276 else if(!path) result = pathNull;
277 else result = toNull;
282 char * CopyValidateMakefilePath(const char * path)
284 const int map[] = { 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 7 };
285 const char * vars[] = { "$(MODULE)", "$(CONFIG)", "$(PLATFORM)", "$(COMPILER)", "$(TARGET)", "$(COMPILER_SUFFIX)", "$(DEBUG_SUFFIX)", "$(PROJECT)", "$(CONFIGURATION)", "$(TARGET_PLATFORM)",(char *)0 };
291 len = (int)strlen(path);
292 copy = CopyString(path);
298 Array<const char *> parts { };
305 for(v=0; vars[v]; v++)
307 if(SearchString(&tmp[c], 0, vars[v], false, false) == &tmp[c])
311 parts.Add(vars[map[v]]);
312 c += strlen(vars[v]);
326 for(c=0; c<parts.count; c++) len += strlen(parts[c]);
327 copy = new char[++len];
329 for(c=0; c<parts.count; c++) strcat(copy, parts[c]);
340 void ValidPathBufCopy(char *output, const char *input)
343 bool volumePath = false;
345 strcpy(output, input);
346 TrimLSpaces(output, output);
347 TrimRSpaces(output, output);
348 MakeSystemPath(output);
350 if(output[0] && output[1] == ':')
357 const char * chars = "*|:\",<>?";
358 char ch, * s = output, * o = output;
359 while((ch = *s++)) { if(!strchr(chars, ch)) *o++ = ch; }
363 if(volumePath && output[0])
368 void RemoveTrailingPathSeparator(char *path)
371 len = (int)strlen(path);
372 if(len>1 && path[len-1] == DIR_SEP)
376 void BasicValidatePathBoxPath(PathBox pathBox)
378 char path[MAX_LOCATION];
379 ValidPathBufCopy(path, pathBox.path);
380 RemoveTrailingPathSeparator(path);
384 CompilerConfig MakeDefaultCompiler(const char * name, bool readOnly)
386 CompilerConfig defaultCompiler
404 incref defaultCompiler;
405 return defaultCompiler;
408 //#define SETTINGS_TEST
410 define settingsDir = ".ecereIDE-SettingsTest";
411 define ideSettingsName = "ecereIDE-SettingsTest";
413 define settingsDir = ".ecereIDE";
414 define ideSettingsName = "ecereIDE";
417 class IDEConfigHolder
419 CompilerConfigs compilers { };
420 RecentFiles recentFiles { };
421 RecentWorkspaces recentWorkspaces { };
423 property CompilerConfigs compilers
425 set { compilers.Free(); delete compilers; compilers = value; }
426 get { return compilers; }
428 property RecentFiles recentFiles
430 set { recentFiles.Free(); delete recentFiles; recentFiles = value; }
431 get { return recentFiles; }
433 property RecentWorkspaces recentProjects
435 set { recentWorkspaces.Free(); delete recentWorkspaces; recentWorkspaces = value; }
436 get { return recentWorkspaces; }
443 recentWorkspaces.Free();
446 void forcePathSeparatorStyle(bool unixStyle)
450 from = '\\', to = '/';
452 from = '/', to = '\\';
453 recentFiles.changeChar(from, to);
454 recentWorkspaces.changeChar(from, to);
458 class IDESettingsContainer : GlobalSettings
460 virtual void onLoadCompilerConfigs();
461 virtual void onLoadRecentFiles();
462 virtual void onLoadRecentProjects();
463 virtual void onLoad();
465 CompilerConfigs compilerConfigs;
466 RecentFiles recentFiles;
467 RecentWorkspaces recentProjects;
469 property bool useNewConfigurationFiles
476 settingsName = "config";
477 settingsExtension = "econ";
478 settingsDirectory = settingsDir;
483 settingsName = ideSettingsName;
484 settingsExtension = null;
485 settingsDirectory = null;
490 char moduleLocation[MAX_LOCATION];
492 FileMonitor recentFilesMonitor
494 this, fileChange = { modified = true };
496 bool OnFileNotify(FileChange action, const char * param)
499 recentFilesMonitor.StopMonitoring();
500 f = FileOpen(recentFilesMonitor.fileName, read);
505 for(c = 0; c < 10 && !(locked = f.Lock(shared, 0, 0, false)); c++) ecere::sys::Sleep(0.01);
506 recentFiles.read(this);
514 FileMonitor recentProjectsMonitor
516 this, fileChange = { modified = true };
518 bool OnFileNotify(FileChange action, const char * param)
521 recentProjectsMonitor.StopMonitoring();
522 f = FileOpen(recentProjectsMonitor.fileName, read);
527 for(c = 0; c < 10 && !(locked = f.Lock(shared, 0, 0, false)); c++) ecere::sys::Sleep(0.01);
528 recentProjects.read(this);
536 static void getConfigFilePath(char * path, Class _class, char * dir, const char * configName)
539 strcpy(path, settingsFilePath);
540 StripLastDirectory(path, path);
542 PathCatSlash(path, settingsDir);
543 if(_class == class(CompilerConfig))
545 PathCatSlash(path, "compilerConfigs");
550 PathCatSlash(path, configName);
551 strcat(path, ".econ");
554 else if(_class == class(RecentFilesData))
555 PathCatSlash(path, "recentFiles.econ");
556 else if(_class == class(RecentWorkspacesData))
557 PathCatSlash(path, "recentWorkspaces.econ");
562 FileSize settingsFileSize;
564 IDESettingsContainer()
566 char path[MAX_LOCATION];
568 LocateModule(null, moduleLocation);
569 strcpy(path, moduleLocation);
570 StripLastDirectory(moduleLocation, moduleLocation);
571 ChangeCh(moduleLocation, '\\', '/');
572 // PortableApps.com directory structure
573 if((start = strstr(path, "\\App\\EcereSDK\\bin\\ecere-ide.exe")))
575 char configFilePath[MAX_LOCATION];
576 char defaultConfigFilePath[MAX_LOCATION];
580 strcpy(configFilePath, path);
581 PathCat(configFilePath, "Data");
582 PathCat(configFilePath, ideSettingsName);
583 ChangeExtension(configFilePath, "ini", configFilePath);
585 strcpy(defaultConfigFilePath, path);
586 PathCat(defaultConfigFilePath, "App");
587 PathCat(defaultConfigFilePath, "DefaultData");
588 PathCat(defaultConfigFilePath, ideSettingsName);
589 ChangeExtension(defaultConfigFilePath, "ini", defaultConfigFilePath);
591 if(FileExists(defaultConfigFilePath))
593 if(!FileExists(configFilePath))
595 File f = FileOpen(defaultConfigFilePath, read);
596 f.CopyTo(configFilePath);
600 PathCat(path, "Data");
601 // the forced settings location will only be
602 // used if the running ide's path matches
603 // the PortableApps.com directory structure
604 // and the default ini file is found in
605 // the DefaultData directory
606 settingsLocation = path;
612 void OnAskReloadSettings()
614 FileSize newSettingsFileSize;
616 if(OpenAndLock(&newSettingsFileSize))
618 //if((double)settingsFileSize - (double)newSettingsFileSize < 2048)
623 GuiApplication app = ((GuiApplication)__thisModule.application);
625 for(w = app.desktop.firstChild; w && (!w.created || !w.visible); w = w.next);
629 MessageBox { master = w, type = ok, isModal = true,
630 creationActivation = flash,
631 text = "Global Settings Modified Externally",
632 contents = "The global settings were modified by another process and a drastic shrinking of the settings file was detected.\n"
633 "The new settings will not be loaded to prevent loss of your ide settings.\n"
634 "Please check your settings file and make sure to save this IDE's global settings if your settings file has been compromised."
640 SettingsIOResult Load()
643 SettingsIOResult result;
644 useNewConfigurationFiles = true;
645 result = GlobalSettings::Load();
646 data = (IDESettings)this.data;
648 if(result == fileNotFound)
651 useNewConfigurationFiles = false;
652 result = GlobalSettings::Load();
654 data = (IDESettings)this.data;
657 this.data = IDESettings { };
659 *dataOwner = this.data;
661 if(result == fileNotCompatibleWithDriver)
664 OldIDESettings oldSettings { };
666 loaded = oldSettings.Load() == success;
670 data = (IDESettings)this.data;
672 for(c : oldSettings.compilerConfigs)
673 data.compilerConfigs.Add(c.Copy());
675 for(s : oldSettings.recentFiles) data.recentFiles.Add(s);
676 for(s : oldSettings.recentProjects) data.recentProjects.Add(s);
678 data.docDir = oldSettings.docDir;
679 data.ideFileDialogLocation = oldSettings.ideFileDialogLocation;
680 data.ideProjectFileDialogLocation = oldSettings.ideProjectFileDialogLocation;
681 data.useFreeCaret = oldSettings.useFreeCaret;
682 data.showLineNumbers = oldSettings.showLineNumbers;
683 data.caretFollowsScrolling = oldSettings.caretFollowsScrolling;
684 delete data.displayDriver; data.displayDriver = CopyString(oldSettings.displayDriver);
685 data.projectDefaultTargetDir = oldSettings.projectDefaultTargetDir;
686 data.projectDefaultIntermediateObjDir = oldSettings.projectDefaultIntermediateObjDir;
693 if(result == fileNotFound || !data)
695 data = (IDESettings)this.data;
696 data.useFreeCaret = false; //true;
697 data.showLineNumbers = true;
698 data.caretFollowsScrolling = false; //true;
703 FileGetSize(settingsFilePath, &settingsFileSize);
704 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
705 data.ManagePortablePaths(moduleLocation, true);
706 data.ForcePathSeparatorStyle(true);
708 if(!data.colorSchemes || !data.colorSchemes.count)
710 if(!data.colorSchemes) data.colorSchemes = { };
712 data.colorSchemes.Add(darkColorScheme); incref darkColorScheme;
713 data.colorSchemes.Add(lightColorScheme); incref lightColorScheme;
714 data.colorSchemes.Add(greenColorScheme); incref greenColorScheme;
715 data.colorSchemes.Add(grayColorScheme); incref grayColorScheme;
718 if(data.activeColorScheme)
720 for(cs : data.colorSchemes; cs.name && !strcmp(cs.name, data.activeColorScheme))
728 colorScheme = data.colorSchemes[0];
729 data.activeColorScheme = colorScheme.name;
732 // Import from previous ecereIDE settings
735 // Save first so that settingsFilePath get set up
738 data.compilerConfigs.ensureDefaults();
739 data.compilerConfigs.write(this, null);
740 data.compilerConfigs.Free();
742 data.recentFiles.write(this);
743 data.recentFiles.Free();
745 data.recentProjects.write(this);
746 data.recentProjects.Free();
751 SettingsIOResult Save()
753 SettingsIOResult result;
755 useNewConfigurationFiles = true;
756 data = (IDESettings)this.data;
757 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
758 data.ManagePortablePaths(moduleLocation, false);
759 data.ForcePathSeparatorStyle(true);
761 settingsFilePath = null;
762 result = GlobalSettings::Save();
763 if(result != success)
764 PrintLn("Error saving IDE settings");
767 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
768 data.ManagePortablePaths(moduleLocation, true);
771 FileGetSize(settingsFilePath, &settingsFileSize);
777 static Map<String, String> getCompilerConfigFilePathsByName(const char * path)
779 Map<String, String> map { };
780 FileListing fl { path, extensions = "econ" };
783 if(fl.stats.attribs.isFile)
785 char name[MAX_FILENAME];
786 char * path = CopyString(fl.path);
788 GetLastDirectory(path, name);
789 StripExtension(name);
796 static Map<String, CompilerConfig> getCompilerConfigsByName(const char * path)
798 Map<String, CompilerConfig> map { };
799 FileListing fl { path, extensions = "econ" };
802 if(fl.stats.attribs.isFile)
804 char name[MAX_FILENAME];
805 char * path = CopyString(fl.path);
807 GetLastDirectory(path, name);
808 StripExtension(name);
810 CompilerConfig ccfg = CompilerConfig::read(path);
820 static SettingsIOResult writeConfigFile(const char * path, Class dataType, void * data)
822 SettingsIOResult result = error;
823 SafeFile sf = SafeFile::open(path, write);
826 WriteECONObject(sf.file, dataType, data, 0);
832 PrintLn($"error: could not safely open file for writing configuration: ", path);
836 static SettingsIOResult readConfigFile(const char * path, Class dataType, void ** data)
838 SettingsIOResult result = error;
840 if(!FileExists(path))
841 result = fileNotFound;
842 else if((sf = SafeFile::open(path, read)))
844 JSONResult jsonResult;
846 ECONParser parser { f = sf.file };
847 sf.file.Seek(0, start);
848 jsonResult = parser.GetObject(dataType, data);
849 if(jsonResult != success)
853 if(jsonResult == success)
857 result = fileNotCompatibleWithDriver;
858 PrintLn($"error: could not parse configuration file: ", path);
869 char path[MAX_LOCATION];
870 char tmp[MAX_LOCATION];
872 SafeFile ::open(const char * path, FileOpenMode mode)
874 SafeFile result = null;
875 if(mode == write || mode == read)
877 SafeFile sf { mode = mode };
880 FileLock lockType = mode == write ? exclusive : shared;
882 strcpy(sf.path, path);
883 strcpy(sf.tmp, path);
884 strcat(sf.tmp, ".tmp");
885 if(mode == write && FileExists(sf.tmp).isFile)
890 sf.file = FileOpen(sf.tmp, readWrite);
893 sf.file = FileOpen(sf.tmp, writeRead);
897 sf.file = FileOpen(sf.tmp, readWrite);
902 sf.file = FileOpen(path, mode);
905 for(c = 0; c < 10 && !(locked = sf.file.Lock(lockType, 0, 0, false)); c++) Sleep(0.01);
909 sf.file.Seek(0, start);
912 else if(mode == write)
913 PrintLn($"warning: SafeFile::open: unable to obtain exclusive lock on temporary file for writing: ", sf.tmp);
915 PrintLn($"warning: SafeFile::open: unable to obtain shared lock on file for reading: ", path);
917 else if(mode == write)
918 PrintLn($"warning: SafeFile::open: unable to open temporary file for writing: ", sf.tmp);
920 PrintLn($"warning: SafeFile::open: unable to open file for reading: ", path);
926 PrintLn($"warning: SafeFile::open: does not yet support FileOpenMode::", mode);
932 if(file && mode == write)
935 File f = FileOpen(path, readWrite);
938 f = FileOpen(path, writeRead);
942 f = FileOpen(path, readWrite);
948 for(c = 0; c < 10 && !(locked = f.Lock(exclusive, 0,0, false)); c++) Sleep(0.01);
952 f.Unlock(0,0, false);
954 file.Unlock(0,0, false);
957 for(c = 0; c < 10; c++)
959 if(MoveFileEx(tmp, path, { true, true }))
968 PrintLn($"warning: SafeFile::sync: failed to lock file for ", mode);
979 file.Unlock(0,0, false);
985 class RecentFilesData
988 RecentFiles recentFiles;
991 class RecentWorkspacesData
994 RecentWorkspaces recentWorkspaces;
997 class IDESettings : GlobalSettingsData
1000 property CompilerConfigs compilerConfigs
1002 set { /*if(settingsContainer.oldConfig)*/ { if(compilerConfigs) compilerConfigs.Free(); delete compilerConfigs; if(value) compilerConfigs = value; } }
1003 get { return compilerConfigs; }
1004 isset { return false; }
1006 property RecentFiles recentFiles
1008 set { if(recentFiles) recentFiles.Free(); delete recentFiles; if(value) recentFiles = value; }
1009 get { return recentFiles; }
1010 isset { return false; }
1012 property RecentWorkspaces recentProjects
1014 set { if(recentProjects) recentProjects.Free(); delete recentProjects; if(value) recentProjects = value; }
1015 get { return recentProjects; }
1016 isset { return false; }
1018 property const char * docDir
1020 set { delete docDir; if(value && value[0]) docDir = CopyString(value); }
1021 get { return docDir ? docDir : ""; }
1022 isset { return docDir && docDir[0]; }
1024 property const char * ideFileDialogLocation
1026 set { delete ideFileDialogLocation; if(value && value[0]) ideFileDialogLocation = CopyString(value); }
1027 get { return ideFileDialogLocation ? ideFileDialogLocation : ""; }
1028 isset { return ideFileDialogLocation && ideFileDialogLocation[0]; }
1030 property const char * ideProjectFileDialogLocation
1032 set { delete ideProjectFileDialogLocation; if(value && value[0]) ideProjectFileDialogLocation = CopyString(value); }
1033 get { return ideProjectFileDialogLocation ? ideProjectFileDialogLocation : ""; }
1034 isset { return ideProjectFileDialogLocation && ideProjectFileDialogLocation[0]; }
1037 bool showLineNumbers;
1038 bool caretFollowsScrolling;
1039 char * displayDriver;
1041 // TODO: Classify settings
1042 //EditorSettings editor { };
1044 property const char * projectDefaultTargetDir
1046 set { delete projectDefaultTargetDir; if(value && value[0]) projectDefaultTargetDir = CopyValidateMakefilePath(value); }
1047 get { return projectDefaultTargetDir ? projectDefaultTargetDir : ""; }
1048 isset { return projectDefaultTargetDir && projectDefaultTargetDir[0]; }
1050 property const char * projectDefaultIntermediateObjDir
1052 set { delete projectDefaultIntermediateObjDir; if(value && value[0]) projectDefaultIntermediateObjDir = CopyValidateMakefilePath(value); }
1053 get { return projectDefaultIntermediateObjDir ? projectDefaultIntermediateObjDir : ""; }
1054 isset { return projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0]; }
1057 property const char * compilerConfigsDir
1059 set { delete compilerConfigsDir; if(value && value[0]) compilerConfigsDir = CopyString(value); }
1060 get { return compilerConfigsDir ? compilerConfigsDir : ""; }
1061 isset { return compilerConfigsDir && compilerConfigsDir[0]; }
1064 property const char * defaultCompiler
1066 set { delete defaultCompiler; if(value && value[0]) defaultCompiler = CopyString(value); }
1067 get { return defaultCompiler && defaultCompiler[0] ? defaultCompiler : defaultCompilerName; }
1068 isset { return defaultCompiler && defaultCompiler[0]; }
1071 property const String language
1076 language = CopyString(value);
1078 get { return language; }
1079 isset { return language != null; }
1082 property const String codeEditorFont
1086 delete codeEditorFont;
1087 codeEditorFont = CopyString(value);
1089 get { return codeEditorFont; }
1092 float codeEditorFontSize;
1093 bool showFixedPitchFontsOnly;
1095 property Array<IDEColorScheme> colorSchemes
1099 if(colorSchemes && colorSchemes._refCount < 2)
1100 colorSchemes.Free();
1101 delete colorSchemes;
1102 colorSchemes = value;
1104 incref colorSchemes;
1106 get { return colorSchemes; }
1109 property const String activeColorScheme
1113 delete activeColorScheme;
1114 activeColorScheme = CopyString(value);
1116 get { return activeColorScheme; }
1120 CompilerConfigs compilerConfigs { };
1122 char * ideFileDialogLocation;
1123 char * ideProjectFileDialogLocation;
1124 char * projectDefaultTargetDir;
1125 char * projectDefaultIntermediateObjDir;
1126 char * compilerConfigsDir;
1127 char * defaultCompiler;
1129 RecentFiles recentFiles { };
1130 RecentWorkspaces recentProjects { };
1132 Array<IDEColorScheme> colorSchemes;
1134 String codeEditorFont;
1136 String activeColorScheme;
1138 showFixedPitchFontsOnly = true;
1139 codeEditorFontSize = 12;
1140 codeEditorFont = CopyString("Courier New");
1144 compilerConfigs.Free();
1145 delete compilerConfigs;
1146 if(recentProjects) { recentFiles.Free(); delete recentFiles; }
1147 if(recentProjects) { recentProjects.Free(); delete recentProjects; }
1150 delete projectDefaultTargetDir;
1151 delete projectDefaultIntermediateObjDir;
1152 delete compilerConfigsDir;
1153 delete defaultCompiler;
1156 delete ideFileDialogLocation;
1157 delete ideProjectFileDialogLocation;
1158 delete displayDriver;
1160 delete codeEditorFont;
1162 colorSchemes.Free();
1163 delete activeColorScheme;
1166 void ForcePathSeparatorStyle(bool unixStyle)
1170 from = '\\', to = '/';
1172 from = '/', to = '\\';
1173 if(compilerConfigs && compilerConfigs.count)
1176 for(config : compilerConfigs)
1178 if(config.includeDirs && config.includeDirs.count)
1180 for(i = 0; i < config.includeDirs.count; i++)
1182 if(config.includeDirs[i] && config.includeDirs[i][0])
1183 ChangeCh(config.includeDirs[i], from, to);
1186 if(config.libraryDirs && config.libraryDirs.count)
1188 for(i = 0; i < config.libraryDirs.count; i++)
1190 if(config.libraryDirs[i] && config.libraryDirs[i][0])
1191 ChangeCh(config.libraryDirs[i], from, to);
1194 if(config.executableDirs && config.executableDirs.count)
1196 for(i = 0; i < config.executableDirs.count; i++)
1198 if(config.executableDirs[i] && config.executableDirs[i][0])
1199 ChangeCh(config.executableDirs[i], from, to);
1204 recentFiles.changeChar(from, to);
1205 recentProjects.changeChar(from, to);
1206 if(docDir && docDir[0])
1207 ChangeCh(docDir, from, to);
1208 if(ideFileDialogLocation && ideFileDialogLocation[0])
1209 ChangeCh(ideFileDialogLocation, from, to);
1210 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
1211 ChangeCh(ideProjectFileDialogLocation, from, to);
1213 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
1214 ChangeCh(projectDefaultTargetDir, from, to);
1215 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
1216 ChangeCh(projectDefaultIntermediateObjDir, from, to);
1218 if(compilerConfigsDir && compilerConfigsDir[0])
1219 ChangeCh(compilerConfigsDir, from, to);
1222 void ManagePortablePaths(char * location, bool makeAbsolute)
1225 if(compilerConfigs && compilerConfigs.count)
1227 for(config : compilerConfigs)
1230 for(t = 0; t < DirTypes::enumSize; t++)
1232 Array<String> dirs = null;
1233 if(t == executables) dirs = config.executableDirs;
1234 else if(t == includes) dirs = config.includeDirs;
1235 else if(t == libraries) dirs = config.libraryDirs;
1236 if(dirs && dirs.count)
1238 for(c = 0; c < dirs.count; c++)
1240 if(dirs[c] && dirs[c][0])
1241 dirs[c] = UpdatePortablePath(dirs[c], location, makeAbsolute);
1247 if(recentFiles && recentFiles.count)
1249 for(c = 0; c < recentFiles.count; c++)
1251 if(recentFiles[c] && recentFiles[c][0])
1252 recentFiles[c] = UpdatePortablePath(recentFiles[c], location, makeAbsolute);
1255 if(recentProjects && recentProjects.count)
1257 for(c = 0; c < recentProjects.count; c++)
1259 if(recentProjects[c] && recentProjects[c][0])
1260 recentProjects[c] = UpdatePortablePath(recentProjects[c], location, makeAbsolute);
1263 if(docDir && docDir[0])
1264 docDir = UpdatePortablePath(docDir, location, makeAbsolute);
1265 if(ideFileDialogLocation && ideFileDialogLocation[0])
1266 ideFileDialogLocation = UpdatePortablePath(ideFileDialogLocation, location, makeAbsolute);
1267 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
1268 ideProjectFileDialogLocation = UpdatePortablePath(ideProjectFileDialogLocation, location, makeAbsolute);
1270 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
1271 projectDefaultTargetDir = UpdatePortablePath(projectDefaultTargetDir, location, makeAbsolute);
1272 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
1273 projectDefaultIntermediateObjDir = UpdatePortablePath(projectDefaultIntermediateObjDir, location, makeAbsolute);
1275 if(compilerConfigsDir && compilerConfigsDir[0])
1276 compilerConfigsDir = UpdatePortablePath(compilerConfigsDir, location, makeAbsolute);
1279 char * UpdatePortablePath(char * path, const char * location, bool makeAbsolute)
1284 char p[MAX_LOCATION];
1285 strcpy(p, location);
1286 PathCatSlash(p, path);
1288 output = CopyString(p);
1292 PathRelationship rel = eString_PathRelated(path, location, null);
1293 if(rel == subPath || rel == identical)
1295 char p[MAX_LOCATION];
1296 MakePathRelative(path, location, p);
1297 if(!*p) strcpy(p, "./");
1298 else ChangeCh(p, '\\', '/');
1300 output = CopyString(p);
1309 class RecentFiles : RecentPaths
1311 void read(IDESettingsContainer settingsContainer)
1313 char path[MAX_LOCATION];
1314 RecentFilesData d = null;
1315 Class _class = class(RecentFilesData);
1316 settingsContainer.getConfigFilePath(path, _class, null, null);
1317 readConfigFile(path, _class, &d);
1318 if(d && d.recentFiles && d.recentFiles.count)
1321 Copy((void *)d.recentFiles);
1322 settingsContainer.recentFiles = this; // Merge IDEConfigHolder / IDESettingsContainer?
1325 settingsContainer.recentFilesMonitor.fileName = path;
1326 settingsContainer.recentFilesMonitor.StartMonitoring();
1327 settingsContainer.onLoadRecentFiles();
1330 void write(IDESettingsContainer settingsContainer)
1332 char path[MAX_LOCATION];
1333 RecentFilesData d { };
1334 Class _class = class(RecentFilesData);
1335 settingsContainer.getConfigFilePath(path, _class, null, null);
1336 d.recentFiles = this;
1337 writeConfigFile(path, _class, d);
1338 d.recentFiles = null;
1343 class RecentWorkspaces : RecentPaths
1345 void read(IDESettingsContainer settingsContainer)
1347 char path[MAX_LOCATION];
1348 RecentWorkspacesData d = null;
1349 Class _class = class(RecentWorkspacesData);
1350 settingsContainer.getConfigFilePath(path, _class, null, null);
1351 readConfigFile(path, _class, &d);
1352 if(d && d.recentWorkspaces && d.recentWorkspaces.count)
1355 Copy((void *)d.recentWorkspaces);
1356 settingsContainer.recentProjects = this; // Merge IDEConfigHolder / IDESettingsContainer?
1359 settingsContainer.recentProjectsMonitor.fileName = path;
1360 settingsContainer.recentProjectsMonitor.StartMonitoring();
1361 settingsContainer.onLoadRecentProjects();
1364 void write(IDESettingsContainer settingsContainer)
1366 char path[MAX_LOCATION];
1367 RecentWorkspacesData d { };
1368 Class _class = class(RecentWorkspacesData);
1369 settingsContainer.getConfigFilePath(path, _class, null, null);
1370 d.recentWorkspaces = this;
1371 writeConfigFile(path, _class, d);
1372 d.recentWorkspaces = null;
1377 class RecentPaths : Array<String>
1379 IteratorPointer Add(T value)
1382 char * filePath = (char *)value;
1383 ChangeCh(filePath, '\\', '/');
1384 for(c = 0; c < count; c++)
1386 if(this[c] && !fstrcmp(this[c], filePath))
1388 Delete((void *)&this[c]);
1392 return Array::Add((T)filePath);
1395 IteratorPointer addRecent(const String value)
1398 char * filePath = CopyString((char *)value);
1400 ChangeCh(filePath, '\\', '/');
1401 for(c = 0; c < count; c++)
1403 if(this[c] && !fstrcmp(this[c], filePath))
1405 Delete((void *)&this[c]);
1409 while(count >= MaxRecent)
1411 ip = Insert(null, filePath);
1415 void changeChar(char from, char to)
1420 for(c = 0; c < count; c++)
1422 if(this[c] && this[c][0])
1423 ChangeCh(this[c], from, to);
1429 static const char * compilerTypeNames[CompilerType] = { "GCC", "TCC", "PCC", "VS8", "VS9", "VS10" };
1430 static const char * compilerTypeVersionString[CompilerType] = { "", "", "", "8.00", "9.00", "10.00" };
1431 static const char * compilerTypeSolutionFileVersionString[CompilerType] = { "", "", "", "9.00", "10.00", "11.00" };
1432 static const char * compilerTypeYearString[CompilerType] = { "", "", "", "2005", "2008", "2010" };
1433 static const char * compilerTypeProjectFileExtension[CompilerType] = { "", "", "", "vcproj", "vcproj", "vcxproj" };
1434 // TODO: i18n with Array
1435 static Array<const String> compilerTypeLongNames
1437 $"GNU Compiler Collection (GCC) / GNU Make",
1438 $"Tiny C Compiler / GNU Make",
1439 $"Portable C Compiler / GNU Make",
1440 $"Microsoft Visual Studio 2005 (8.0) Compiler",
1441 $"Microsoft Visual Studio 2008 (9.0) Compiler",
1442 $"Microsoft Visual Studio 2010 (10.0) Compiler"
1444 const CompilerType firstCompilerType = gcc;
1445 const CompilerType lastCompilerType = vs10;
1446 public enum CompilerType
1448 gcc, tcc, pcc, vs8, vs9, vs10;
1452 get { return this == vs8 || this == vs9 || this == vs10; }
1455 property const char *
1457 get { return OnGetString(null, null, null); }
1463 for(c = firstCompilerType; c <= lastCompilerType; c++)
1464 if(!strcmpi(value, compilerTypeNames[c]))
1471 property const char * longName { get { return OnGetString(null, (void*)1, null); } };
1472 property const char * versionString { get { return OnGetString(null, (void*)2, null); } };
1473 property const char * yearString { get { return OnGetString(null, (void*)3, null); } };
1474 property const char * projectFileExtension { get { return OnGetString(null, (void*)4, null); } };
1475 property const char * solutionFileVersionString { get { return OnGetString(null, (void*)5, null); } };
1477 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
1479 if(this >= firstCompilerType && this <= lastCompilerType)
1482 strcpy(tempString, compilerTypeNames[this]);
1483 if(fieldData == null)
1484 return compilerTypeNames[this];
1485 else if(fieldData == (void*)1)
1486 return compilerTypeLongNames[this];
1487 else if(fieldData == (void*)2)
1488 return compilerTypeVersionString[this];
1489 else if(fieldData == (void*)3)
1490 return compilerTypeYearString[this];
1491 else if(fieldData == (void*)4)
1492 return compilerTypeProjectFileExtension[this];
1493 else if(fieldData == (void*)5)
1494 return compilerTypeSolutionFileVersionString[this];
1500 class CompilerConfig
1506 property const char * name
1508 set { delete name; if(value) name = CopyString(value); }
1509 get { return name; }
1513 Platform targetPlatform;
1515 property const char * makeCommand
1517 set { delete makeCommand; if(value && value[0]) makeCommand = CopyString(value); }
1518 get { return makeCommand; }
1519 isset { return makeCommand && makeCommand[0]; }
1521 property const char * ecpCommand
1523 set { delete ecpCommand; if(value && value[0]) ecpCommand = CopyString(value); }
1524 get { return ecpCommand; }
1525 isset { return ecpCommand && ecpCommand[0]; }
1527 property const char * eccCommand
1529 set { delete eccCommand; if(value && value[0]) eccCommand = CopyString(value); }
1530 get { return eccCommand; }
1531 isset { return eccCommand && eccCommand[0]; }
1533 property const char * ecsCommand
1535 set { delete ecsCommand; if(value && value[0]) ecsCommand = CopyString(value); }
1536 get { return ecsCommand; }
1537 isset { return ecsCommand && ecsCommand[0]; }
1539 property const char * earCommand
1541 set { delete earCommand; if(value && value[0]) earCommand = CopyString(value); }
1542 get { return earCommand; }
1543 isset { return earCommand && earCommand[0]; }
1545 property const char * cppCommand
1547 set { delete cppCommand; if(value && value[0]) cppCommand = CopyString(value); }
1548 get { return cppCommand; }
1549 isset { return cppCommand && cppCommand[0]; }
1551 property const char * ccCommand
1553 set { delete ccCommand; if(value && value[0]) ccCommand = CopyString(value); }
1554 get { return ccCommand; }
1555 isset { return ccCommand && ccCommand[0]; }
1557 property const char * cxxCommand
1559 set { delete cxxCommand; if(value && value[0]) cxxCommand = CopyString(value); }
1560 get { return cxxCommand; }
1561 isset { return cxxCommand && cxxCommand[0]; }
1563 property const char * arCommand
1565 set { delete arCommand; if(value && value[0]) arCommand = CopyString(value); }
1566 get { return arCommand; }
1567 isset { return arCommand && arCommand[0]; }
1569 property const char * ldCommand
1571 set { delete ldCommand; if(value && value[0]) ldCommand = CopyString(value); }
1572 get { return ldCommand; }
1573 isset { return ldCommand && ldCommand[0]; }
1575 property const char * objectFileExt
1577 set { delete objectFileExt; if(value && value[0]) objectFileExt = CopyString(value); }
1578 get { return objectFileExt && objectFileExt[0] ? objectFileExt : objectDefaultFileExt ; }
1579 isset { return objectFileExt && objectFileExt[0] && strcmp(objectFileExt, objectDefaultFileExt); }
1581 property const char * staticLibFileExt
1583 set { delete staticLibFileExt; if(value && value[0]) staticLibFileExt = CopyString(value); }
1584 get { return staticLibFileExt; }
1585 isset { return staticLibFileExt && staticLibFileExt[0]; }
1587 property const char * sharedLibFileExt
1589 set { delete sharedLibFileExt; if(value && value[0]) sharedLibFileExt = CopyString(value); }
1590 get { return sharedLibFileExt; }
1591 isset { return sharedLibFileExt && sharedLibFileExt[0]; }
1593 property const char * executableFileExt
1595 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1596 get { return executableFileExt; }
1597 isset { return executableFileExt && executableFileExt[0]; }
1599 property const char * executableLauncher
1601 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1602 get { return executableLauncher; }
1603 isset { return executableLauncher && executableLauncher[0]; }
1605 // TODO: implement CompilerConfig::windresCommand
1609 property bool supportsBitDepth { set { } get { return true; } isset { return false; } }
1611 property const char * distccHosts
1613 set { delete distccHosts; if(value && value[0]) distccHosts = CopyString(value); }
1614 get { return distccHosts; }
1615 isset { return distccHosts && distccHosts[0]; }
1617 property const char * gnuToolchainPrefix
1619 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1620 get { return gnuToolchainPrefix; }
1621 isset { return gnuToolchainPrefix && gnuToolchainPrefix[0]; }
1623 property const char * sysroot
1625 set { delete sysroot; if(value && value[0]) sysroot = CopyString(value); }
1626 get { return sysroot; }
1627 isset { return sysroot && sysroot[0]; }
1629 bool resourcesDotEar;
1631 property Array<String> includeDirs
1639 includeDirs = value;
1642 get { return includeDirs; }
1643 isset { return includeDirs.count != 0; }
1645 property Array<String> libraryDirs
1653 libraryDirs = value;
1656 get { return libraryDirs; }
1657 isset { return libraryDirs.count != 0; }
1659 property Array<String> executableDirs
1663 executableDirs.Free();
1666 delete executableDirs;
1667 executableDirs = value;
1670 get { return executableDirs; }
1671 isset { return executableDirs.count != 0; }
1673 property Array<NamedString> environmentVars
1677 environmentVars.Free();
1680 delete environmentVars;
1681 environmentVars = value;
1684 get { return environmentVars; }
1685 isset { return environmentVars.count != 0; }
1687 property Array<String> prepDirectives
1691 prepDirectives.Free();
1694 delete prepDirectives;
1695 prepDirectives = value;
1698 get { return prepDirectives; }
1699 isset { return prepDirectives.count != 0; }
1701 property Array<String> excludeLibs
1709 excludeLibs = value;
1712 get { return excludeLibs; }
1713 isset { return excludeLibs.count != 0; }
1715 property Array<String> eCcompilerFlags
1719 eCcompilerFlags.Free();
1722 delete eCcompilerFlags;
1723 eCcompilerFlags = value;
1726 get { return eCcompilerFlags; }
1727 isset { return eCcompilerFlags.count != 0; }
1729 property Array<String> compilerFlags
1733 compilerFlags.Free();
1736 delete compilerFlags;
1737 compilerFlags = value;
1740 get { return compilerFlags; }
1741 isset { return compilerFlags.count != 0; }
1743 property Array<String> cxxFlags
1754 get { return cxxFlags; }
1755 isset { return cxxFlags.count != 0; }
1757 property Array<String> linkerFlags
1765 linkerFlags = value;
1768 get { return linkerFlags; }
1769 isset { return linkerFlags.count != 0; }
1771 // json backward compatibility
1772 property const char * gccPrefix
1774 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1775 get { return gnuToolchainPrefix; }
1776 isset { return false; }
1778 property const char * execPrefixCommand
1780 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1781 get { return executableLauncher; }
1782 isset { return false; }
1784 property const char * outputFileExt
1786 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1787 get { return executableFileExt; }
1788 isset { return false; }
1791 property bool hasDocumentOutput
1795 bool result = executableFileExt && executableFileExt[0] &&
1796 (!strcmpi(executableFileExt, "htm") || !strcmpi(executableFileExt, "html"));
1799 isset { return false; }
1802 Array<String> includeDirs { };
1803 Array<String> libraryDirs { };
1804 Array<String> executableDirs { };
1805 // TODO: Can JSON parse and serialize maps?
1806 //EnvironmentVariables { };
1807 Array<NamedString> environmentVars { };
1808 Array<String> prepDirectives { };
1809 Array<String> excludeLibs { };
1810 Array<String> eCcompilerFlags { };
1811 Array<String> compilerFlags { };
1812 Array<String> cxxFlags { };
1813 Array<String> linkerFlags { };
1825 char * objectFileExt;
1826 char * staticLibFileExt;
1827 char * sharedLibFileExt;
1828 char * executableFileExt;
1829 char * executableLauncher;
1831 char * gnuToolchainPrefix;
1835 struct { Array<String> includes, libraries, executables; };
1836 Array<String> dirs[DirTypes];
1851 delete objectFileExt;
1852 delete staticLibFileExt;
1853 delete sharedLibFileExt;
1854 delete executableFileExt;
1856 delete executableLauncher;
1858 delete gnuToolchainPrefix;
1860 if(environmentVars) environmentVars.Free();
1861 if(includeDirs) { includeDirs.Free(); }
1862 if(libraryDirs) { libraryDirs.Free(); }
1863 if(executableDirs) { executableDirs.Free(); }
1864 if(prepDirectives) { prepDirectives.Free(); }
1865 if(excludeLibs) { excludeLibs.Free(); }
1866 if(compilerFlags) { compilerFlags.Free(); }
1867 if(cxxFlags) { cxxFlags.Free(); }
1868 if(eCcompilerFlags) { eCcompilerFlags.Free(); }
1869 if(linkerFlags) { linkerFlags.Free(); }
1872 int OnCompare(CompilerConfig b)
1876 !(result = type.OnCompare(b.type)) &&
1877 !(result = targetPlatform.OnCompare(b.targetPlatform)) &&
1878 !(result = numJobs.OnCompare(b.numJobs)) &&
1879 !(result = ccacheEnabled.OnCompare(b.ccacheEnabled)) &&
1880 !(result = distccEnabled.OnCompare(b.distccEnabled)) &&
1881 !(result = resourcesDotEar.OnCompare(b.resourcesDotEar)) &&
1882 !(result = noStripTarget.OnCompare(b.noStripTarget))
1886 !(result = name.OnCompare(b.name)) &&
1887 !(result = ecpCommand.OnCompare(b.ecpCommand)) &&
1888 !(result = eccCommand.OnCompare(b.eccCommand)) &&
1889 !(result = ecsCommand.OnCompare(b.ecsCommand)) &&
1890 !(result = earCommand.OnCompare(b.earCommand)) &&
1891 !(result = cppCommand.OnCompare(b.cppCommand)) &&
1892 !(result = ccCommand.OnCompare(b.ccCommand)) &&
1893 !(result = cxxCommand.OnCompare(b.cxxCommand)) &&
1894 !(result = ldCommand.OnCompare(b.ldCommand)) &&
1895 !(result = arCommand.OnCompare(b.arCommand)) &&
1896 !(result = objectFileExt.OnCompare(b.objectFileExt)) &&
1897 !(result = outputFileExt.OnCompare(b.outputFileExt)) &&
1898 !(result = makeCommand.OnCompare(b.makeCommand)) &&
1899 !(result = executableLauncher.OnCompare(b.executableLauncher)) &&
1900 !(result = distccHosts.OnCompare(b.distccHosts)) &&
1901 !(result = gnuToolchainPrefix.OnCompare(b.gnuToolchainPrefix)) &&
1902 !(result = sysroot.OnCompare(b.sysroot)));
1905 !(result = includeDirs.OnCompare(b.includeDirs)) &&
1906 !(result = libraryDirs.OnCompare(b.libraryDirs)) &&
1907 !(result = executableDirs.OnCompare(b.executableDirs)) &&
1908 !(result = environmentVars.OnCompare(b.environmentVars)) &&
1909 !(result = prepDirectives.OnCompare(b.prepDirectives)) &&
1910 !(result = excludeLibs.OnCompare(b.excludeLibs)) &&
1911 !(result = cxxFlags.OnCompare(b.cxxFlags)) &&
1912 !(result = eCcompilerFlags.OnCompare(b.eCcompilerFlags)) &&
1913 !(result = compilerFlags.OnCompare(b.compilerFlags)) &&
1914 !(result = linkerFlags.OnCompare(b.linkerFlags)));
1919 CompilerConfig Copy()
1952 for(s : includeDirs) copy.includeDirs.Add(CopyString(s));
1953 for(s : libraryDirs) copy.libraryDirs.Add(CopyString(s));
1954 for(s : executableDirs) copy.executableDirs.Add(CopyString(s));
1955 for(ns : environmentVars) copy.environmentVars.Add(NamedString { name = ns.name, string = ns.string });
1956 for(s : prepDirectives) copy.prepDirectives.Add(CopyString(s));
1957 for(s : excludeLibs) copy.excludeLibs.Add(CopyString(s));
1958 for(s : compilerFlags) copy.compilerFlags.Add(CopyString(s));
1959 for(s : cxxFlags) copy.cxxFlags.Add(CopyString(s));
1960 for(s : eCcompilerFlags) copy.eCcompilerFlags.Add(CopyString(s));
1961 for(s : linkerFlags) copy.linkerFlags.Add(CopyString(s));
1967 CompilerConfig ::read(const char * path)
1969 CompilerConfig d = null;
1970 readConfigFile(path, class(CompilerConfig), &d);
1974 void write(IDESettingsContainer settingsContainer)
1976 char dir[MAX_LOCATION];
1977 char path[MAX_LOCATION];
1978 const char * settingsFilePath = settingsContainer.settingsFilePath;
1979 settingsContainer.getConfigFilePath(path, _class, dir, name);
1980 if(FileExists(settingsFilePath) && !FileExists(dir))
1983 if(!FileExists(dir))
1984 PrintLn($"Error creating compiler configs directory at ", dir, " location.");
1986 writeConfigFile(path, _class, this);
1990 class CompilerConfigs : List<CompilerConfig>
1992 CompilerConfig GetCompilerConfig(const String compilerName)
1994 const char * name = compilerName && compilerName[0] ? compilerName : defaultCompilerName;
1995 CompilerConfig compilerConfig = null;
1996 for(compiler : this)
1998 if(!strcmp(compiler.name, name))
2000 compilerConfig = compiler;
2004 if(!compilerConfig && count)
2005 compilerConfig = this[0];
2008 incref compilerConfig;
2009 if(compilerConfig._refCount == 1)
2010 incref compilerConfig;
2012 return compilerConfig;
2015 void ensureDefaults()
2017 // Ensure we have a default compiler
2018 CompilerConfig defaultCompiler = GetCompilerConfig(defaultCompilerName);
2019 if(!defaultCompiler)
2021 defaultCompiler = MakeDefaultCompiler(defaultCompilerName, true);
2022 Insert(null, defaultCompiler);
2023 defaultCompiler = null;
2025 delete defaultCompiler;
2029 if(!ccfg.ecpCommand || !ccfg.ecpCommand[0])
2030 ccfg.ecpCommand = ecpDefaultCommand;
2031 if(!ccfg.eccCommand || !ccfg.eccCommand[0])
2032 ccfg.eccCommand = eccDefaultCommand;
2033 if(!ccfg.ecsCommand || !ccfg.ecsCommand[0])
2034 ccfg.ecsCommand = ecsDefaultCommand;
2035 if(!ccfg.earCommand || !ccfg.earCommand[0])
2036 ccfg.earCommand = earDefaultCommand;
2037 if(!ccfg.cppCommand || !ccfg.cppCommand[0])
2038 ccfg.cppCommand = cppDefaultCommand;
2039 if(!ccfg.ccCommand || !ccfg.ccCommand[0])
2040 ccfg.ccCommand = ccDefaultCommand;
2041 if(!ccfg.cxxCommand || !ccfg.cxxCommand[0])
2042 ccfg.cxxCommand = cxxDefaultCommand;
2043 /*if(!ccfg.ldCommand || !ccfg.ldCommand[0])
2044 ccfg.ldCommand = ldDefaultCommand;*/
2045 if(!ccfg.arCommand || !ccfg.arCommand[0])
2046 ccfg.arCommand = arDefaultCommand;
2047 if(!ccfg.objectFileExt || !ccfg.objectFileExt[0])
2048 ccfg.objectFileExt = objectDefaultFileExt;
2049 /*if(!ccfg.staticLibFileExt || !ccfg.staticLibFileExt[0])
2050 ccfg.staticLibFileExt = staticLibDefaultFileExt;*/
2051 /*if(!ccfg.sharedLibFileExt || !ccfg.sharedLibFileExt[0])
2052 ccfg.sharedLibFileExt = sharedLibDefaultFileExt;*/
2053 /*if(!ccfg.executableFileExt || !ccfg.executableFileExt[0])
2054 ccfg.executableFileExt = outputDefaultFileExt;*/
2055 if(!ccfg._refCount) incref ccfg;
2059 AVLTree<String> getWriteRequiredList(CompilerConfigs oldConfigs)
2061 AVLTree<String> list { };
2065 for(occfg : oldConfigs; !strcmp(ccfg.name, occfg.name))
2068 if(ccfg.OnCompare(occfg))
2069 list.Add(CopyString(ccfg.name));
2073 list.Add(CopyString(ccfg.name));
2078 bool read(IDESettingsContainer settingsContainer)
2080 if(settingsContainer.settingsFilePath)
2082 char dir[MAX_LOCATION];
2083 char path[MAX_LOCATION];
2084 Class _class = class(CompilerConfig);
2085 settingsContainer.getConfigFilePath(path, _class, dir, null);
2088 AVLTree<const String> addedConfigs { };
2089 Map<String, CompilerConfig> compilerConfigsByName = getCompilerConfigsByName(dir);
2090 MapIterator<const String, CompilerConfig> it { map = compilerConfigsByName };
2092 settingsContainer.compilerConfigs = this; // Merge IDEConfigHolder / IDESettingsContainer?
2093 if(it.Index("Default", false))
2095 CompilerConfig ccfg = it.data;
2097 addedConfigs.Add(ccfg.name);
2099 for(ccfg : compilerConfigsByName)
2101 if(!addedConfigs.Find(ccfg.name))
2104 addedConfigs.Add(ccfg.name);
2107 delete addedConfigs;
2109 compilerConfigsByName.Free();
2110 delete compilerConfigsByName;
2111 settingsContainer.onLoadCompilerConfigs();
2118 void write(IDESettingsContainer settingsContainer, AVLTree<String> cfgsToWrite)
2120 char dir[MAX_LOCATION];
2121 char path[MAX_LOCATION];
2122 Map<String, String> paths;
2123 settingsContainer.getConfigFilePath(path, class(CompilerConfig), dir, null);
2124 paths = getCompilerConfigFilePathsByName(dir);
2126 MapIterator<String, String> it { map = paths };
2129 CompilerConfig ccfg = c;
2130 if(!cfgsToWrite || cfgsToWrite.Find(ccfg.name))
2131 ccfg.write(settingsContainer);
2132 if(it.Index(ccfg.name, false))
2141 const char * path = p;
2149 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
2150 struct LanguageOption
2153 const String bitmap;
2157 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
2162 void OnDisplay(Surface surface, int x, int y, int width, void * data, Alignment alignment, DataDisplayFlags flags)
2164 Bitmap icon = res ? res.bitmap : null;
2167 surface.Blit(icon, x + (16 - icon.width) / 2,y+2,0,0, icon.width, icon.height);
2168 class::OnDisplay(surface, x + w, y, width - w, null, alignment, flags);
2172 Array<LanguageOption> languages
2174 { "English", ":countryCode/gb.png", "" },
2175 { "汉语", ":countryCode/cn.png", "zh_CN" },
2176 { "Español", ":countryCode/es.png", "es" },
2177 { "Português (Brazil)", ":countryCode/br.png", "pt_BR" },
2178 { "Русский (43%)", ":countryCode/ru.png", "ru" },
2179 { "Nederlandse (13%)", ":countryCode/nl.png", "nl" },
2180 { "Tiếng Việt (12%)", ":countryCode/vn.png", "vi" },
2181 { "मराठी (10%)", ":countryCode/in.png", "mr" },
2182 { "Hebrew (8%)", ":countryCode/il.png", "he" },
2183 { "Magyar (8%)", ":countryCode/hu.png", "hu" }
2186 const String GetLanguageString()
2188 char * dot, * colon;
2189 static char lang[256];
2190 const String language = getenv("ECERE_LANGUAGE");
2191 if(!language) language = getenv("LANGUAGE");
2192 if(!language) language = getenv("LC_ALL");
2193 if(!language) language = getenv("LC_MESSAGES");
2194 if(!language) language = getenv("LANG");
2195 if(!language) language = "";
2196 if(language && (colon = strchr(language, ':')))
2198 if(lang != language)
2199 strncpy(lang, language, sizeof(lang));
2200 lang[sizeof(lang)-1] = 0;
2201 lang[colon - language] = 0;
2204 if(language && (dot = strchr(language, '.')))
2206 if(lang != language)
2207 strncpy(lang, language, sizeof(lang));
2208 lang[sizeof(lang)-1] = 0;
2209 lang[dot - language] = 0;
2215 void setEcereLanguageInWinRegEnvironment(const char * languageCode)
2219 uint16 wLanguage[256];
2223 RegCreateKeyEx(HKEY_CURRENT_USER, "Environment", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
2226 UTF8toUTF16Buffer(languageCode, wLanguage, sizeof(wLanguage) / sizeof(uint16));
2227 RegSetValueExW(key, L"ECERE_LANGUAGE", 0, REG_EXPAND_SZ, (byte *)wLanguage, (uint)(wcslen(wLanguage)+1) * 2);
2233 bool LanguageRestart(const char * code, Application app, IDESettings settings, IDESettingsContainer settingsContainer, Window ide, Window projectView, bool wait)
2235 bool restart = true;
2236 String command = null;
2237 int arg0Len = (int)strlen(app.argv[0]);
2249 for(w = ide.firstChild; w; w = w.next)
2251 if(w.isActiveClient && w.isDocument)
2253 if(!w.CloseConfirmation(true))
2262 if(!projectView.CloseConfirmation(true))
2264 if(projectView.fileName)
2266 const char * name = projectView.fileName;
2269 for(j = 0; (ch = name[j]); j++)
2270 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2274 command = new char[len + 1];
2276 strcpy(command, app.argv[0]);
2278 if(projectView.fileName)
2280 strcat(command, " ");
2282 ReplaceSpaces(command + len, projectView.fileName);
2287 for(w = ide.firstChild; w; w = w.next)
2288 if(w.isActiveClient && w.isDocument)
2289 w.modifiedDocument = false;
2290 projectView.modifiedDocument = false;
2295 for(w = ide.firstChild; w; w = w.next)
2297 if(w.isActiveClient && w.isDocument)
2299 if(!w.CloseConfirmation(true))
2306 const char * name = w.fileName;
2308 for(j = 0; (ch = name[j]); j++)
2309 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2316 command = new char[len + 1];
2317 strcpy(command, app.argv[0]);
2320 for(w = ide.firstChild; w; w = w.next)
2322 if(w.isActiveClient && w.isDocument)
2324 const char * name = w.fileName;
2327 strcat(command, " ");
2329 ReplaceSpaces(command + len, name);
2330 len = (int)strlen(command);
2337 for(w = ide.firstChild; w; w = w.next)
2338 if(w.isActiveClient && w.isDocument)
2339 w.modifiedDocument = false;
2344 settings.language = code;
2345 settingsContainer.Save();
2347 setEcereLanguageInWinRegEnvironment(code);
2349 if(eClass_IsDerived(app._class, class(GuiApplication)))
2351 GuiApplication guiApp = (GuiApplication)app;
2352 guiApp.desktop.Destroy(0);
2359 for(i = 1; i < app.argc; i++)
2361 const char * arg = app.argv[i];
2363 for(j = 0; (ch = arg[j]); j++)
2364 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2367 command = new char[len + 1];
2368 strcpy(command, app.argv[0]);
2370 for(i = 1; i < app.argc; i++)
2372 strcat(command, " ");
2374 ReplaceSpaces(command + len, app.argv[i]);
2375 len = (int)strlen(command);
2381 SetEnvironment("ECERE_LANGUAGE", code);
2383 ExecuteWait(command);