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;
717 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;
1103 incref colorSchemes;
1105 get { return colorSchemes; }
1108 property const String activeColorScheme
1112 delete activeColorScheme;
1113 activeColorScheme = CopyString(value);
1115 get { return activeColorScheme; }
1119 CompilerConfigs compilerConfigs { };
1121 char * ideFileDialogLocation;
1122 char * ideProjectFileDialogLocation;
1123 char * projectDefaultTargetDir;
1124 char * projectDefaultIntermediateObjDir;
1125 char * compilerConfigsDir;
1126 char * defaultCompiler;
1128 RecentFiles recentFiles { };
1129 RecentWorkspaces recentProjects { };
1131 Array<IDEColorScheme> colorSchemes;
1133 String codeEditorFont;
1135 String activeColorScheme;
1137 showFixedPitchFontsOnly = true;
1138 codeEditorFontSize = 12;
1139 codeEditorFont = CopyString("Courier New");
1143 compilerConfigs.Free();
1144 delete compilerConfigs;
1145 if(recentProjects) { recentFiles.Free(); delete recentFiles; }
1146 if(recentProjects) { recentProjects.Free(); delete recentProjects; }
1149 delete projectDefaultTargetDir;
1150 delete projectDefaultIntermediateObjDir;
1151 delete compilerConfigsDir;
1152 delete defaultCompiler;
1155 delete ideFileDialogLocation;
1156 delete ideProjectFileDialogLocation;
1157 delete displayDriver;
1159 delete codeEditorFont;
1161 colorSchemes.Free();
1162 delete activeColorScheme;
1165 void ForcePathSeparatorStyle(bool unixStyle)
1169 from = '\\', to = '/';
1171 from = '/', to = '\\';
1172 if(compilerConfigs && compilerConfigs.count)
1175 for(config : compilerConfigs)
1177 if(config.includeDirs && config.includeDirs.count)
1179 for(i = 0; i < config.includeDirs.count; i++)
1181 if(config.includeDirs[i] && config.includeDirs[i][0])
1182 ChangeCh(config.includeDirs[i], from, to);
1185 if(config.libraryDirs && config.libraryDirs.count)
1187 for(i = 0; i < config.libraryDirs.count; i++)
1189 if(config.libraryDirs[i] && config.libraryDirs[i][0])
1190 ChangeCh(config.libraryDirs[i], from, to);
1193 if(config.executableDirs && config.executableDirs.count)
1195 for(i = 0; i < config.executableDirs.count; i++)
1197 if(config.executableDirs[i] && config.executableDirs[i][0])
1198 ChangeCh(config.executableDirs[i], from, to);
1203 recentFiles.changeChar(from, to);
1204 recentProjects.changeChar(from, to);
1205 if(docDir && docDir[0])
1206 ChangeCh(docDir, from, to);
1207 if(ideFileDialogLocation && ideFileDialogLocation[0])
1208 ChangeCh(ideFileDialogLocation, from, to);
1209 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
1210 ChangeCh(ideProjectFileDialogLocation, from, to);
1212 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
1213 ChangeCh(projectDefaultTargetDir, from, to);
1214 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
1215 ChangeCh(projectDefaultIntermediateObjDir, from, to);
1217 if(compilerConfigsDir && compilerConfigsDir[0])
1218 ChangeCh(compilerConfigsDir, from, to);
1221 void ManagePortablePaths(char * location, bool makeAbsolute)
1224 if(compilerConfigs && compilerConfigs.count)
1226 for(config : compilerConfigs)
1229 for(t = 0; t < DirTypes::enumSize; t++)
1231 Array<String> dirs = null;
1232 if(t == executables) dirs = config.executableDirs;
1233 else if(t == includes) dirs = config.includeDirs;
1234 else if(t == libraries) dirs = config.libraryDirs;
1235 if(dirs && dirs.count)
1237 for(c = 0; c < dirs.count; c++)
1239 if(dirs[c] && dirs[c][0])
1240 dirs[c] = UpdatePortablePath(dirs[c], location, makeAbsolute);
1246 if(recentFiles && recentFiles.count)
1248 for(c = 0; c < recentFiles.count; c++)
1250 if(recentFiles[c] && recentFiles[c][0])
1251 recentFiles[c] = UpdatePortablePath(recentFiles[c], location, makeAbsolute);
1254 if(recentProjects && recentProjects.count)
1256 for(c = 0; c < recentProjects.count; c++)
1258 if(recentProjects[c] && recentProjects[c][0])
1259 recentProjects[c] = UpdatePortablePath(recentProjects[c], location, makeAbsolute);
1262 if(docDir && docDir[0])
1263 docDir = UpdatePortablePath(docDir, location, makeAbsolute);
1264 if(ideFileDialogLocation && ideFileDialogLocation[0])
1265 ideFileDialogLocation = UpdatePortablePath(ideFileDialogLocation, location, makeAbsolute);
1266 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
1267 ideProjectFileDialogLocation = UpdatePortablePath(ideProjectFileDialogLocation, location, makeAbsolute);
1269 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
1270 projectDefaultTargetDir = UpdatePortablePath(projectDefaultTargetDir, location, makeAbsolute);
1271 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
1272 projectDefaultIntermediateObjDir = UpdatePortablePath(projectDefaultIntermediateObjDir, location, makeAbsolute);
1274 if(compilerConfigsDir && compilerConfigsDir[0])
1275 compilerConfigsDir = UpdatePortablePath(compilerConfigsDir, location, makeAbsolute);
1278 char * UpdatePortablePath(char * path, const char * location, bool makeAbsolute)
1283 char p[MAX_LOCATION];
1284 strcpy(p, location);
1285 PathCatSlash(p, path);
1287 output = CopyString(p);
1291 PathRelationship rel = eString_PathRelated(path, location, null);
1292 if(rel == subPath || rel == identical)
1294 char p[MAX_LOCATION];
1295 MakePathRelative(path, location, p);
1296 if(!*p) strcpy(p, "./");
1297 else ChangeCh(p, '\\', '/');
1299 output = CopyString(p);
1308 class RecentFiles : RecentPaths
1310 void read(IDESettingsContainer settingsContainer)
1312 char path[MAX_LOCATION];
1313 RecentFilesData d = null;
1314 Class _class = class(RecentFilesData);
1315 settingsContainer.getConfigFilePath(path, _class, null, null);
1316 readConfigFile(path, _class, &d);
1317 if(d && d.recentFiles && d.recentFiles.count)
1320 Copy((void *)d.recentFiles);
1321 settingsContainer.recentFiles = this; // Merge IDEConfigHolder / IDESettingsContainer?
1324 settingsContainer.recentFilesMonitor.fileName = path;
1325 settingsContainer.recentFilesMonitor.StartMonitoring();
1326 settingsContainer.onLoadRecentFiles();
1329 void write(IDESettingsContainer settingsContainer)
1331 char path[MAX_LOCATION];
1332 RecentFilesData d { };
1333 Class _class = class(RecentFilesData);
1334 settingsContainer.getConfigFilePath(path, _class, null, null);
1335 d.recentFiles = this;
1336 writeConfigFile(path, _class, d);
1337 d.recentFiles = null;
1342 class RecentWorkspaces : RecentPaths
1344 void read(IDESettingsContainer settingsContainer)
1346 char path[MAX_LOCATION];
1347 RecentWorkspacesData d = null;
1348 Class _class = class(RecentWorkspacesData);
1349 settingsContainer.getConfigFilePath(path, _class, null, null);
1350 readConfigFile(path, _class, &d);
1351 if(d && d.recentWorkspaces && d.recentWorkspaces.count)
1354 Copy((void *)d.recentWorkspaces);
1355 settingsContainer.recentProjects = this; // Merge IDEConfigHolder / IDESettingsContainer?
1358 settingsContainer.recentProjectsMonitor.fileName = path;
1359 settingsContainer.recentProjectsMonitor.StartMonitoring();
1360 settingsContainer.onLoadRecentProjects();
1363 void write(IDESettingsContainer settingsContainer)
1365 char path[MAX_LOCATION];
1366 RecentWorkspacesData d { };
1367 Class _class = class(RecentWorkspacesData);
1368 settingsContainer.getConfigFilePath(path, _class, null, null);
1369 d.recentWorkspaces = this;
1370 writeConfigFile(path, _class, d);
1371 d.recentWorkspaces = null;
1376 class RecentPaths : Array<String>
1378 IteratorPointer Add(T value)
1381 char * filePath = (char *)value;
1382 ChangeCh(filePath, '\\', '/');
1383 for(c = 0; c < count; c++)
1385 if(this[c] && !fstrcmp(this[c], filePath))
1387 Delete((void *)&this[c]);
1391 return Array::Add((T)filePath);
1394 IteratorPointer addRecent(const String value)
1397 char * filePath = CopyString((char *)value);
1399 ChangeCh(filePath, '\\', '/');
1400 for(c = 0; c < count; c++)
1402 if(this[c] && !fstrcmp(this[c], filePath))
1404 Delete((void *)&this[c]);
1408 while(count >= MaxRecent)
1410 ip = Insert(null, filePath);
1414 void changeChar(char from, char to)
1419 for(c = 0; c < count; c++)
1421 if(this[c] && this[c][0])
1422 ChangeCh(this[c], from, to);
1428 static const char * compilerTypeNames[CompilerType] = { "GCC", "TCC", "PCC", "VS8", "VS9", "VS10" };
1429 static const char * compilerTypeVersionString[CompilerType] = { "", "", "", "8.00", "9.00", "10.00" };
1430 static const char * compilerTypeSolutionFileVersionString[CompilerType] = { "", "", "", "9.00", "10.00", "11.00" };
1431 static const char * compilerTypeYearString[CompilerType] = { "", "", "", "2005", "2008", "2010" };
1432 static const char * compilerTypeProjectFileExtension[CompilerType] = { "", "", "", "vcproj", "vcproj", "vcxproj" };
1433 // TODO: i18n with Array
1434 static Array<const String> compilerTypeLongNames
1436 $"GNU Compiler Collection (GCC) / GNU Make",
1437 $"Tiny C Compiler / GNU Make",
1438 $"Portable C Compiler / GNU Make",
1439 $"Microsoft Visual Studio 2005 (8.0) Compiler",
1440 $"Microsoft Visual Studio 2008 (9.0) Compiler",
1441 $"Microsoft Visual Studio 2010 (10.0) Compiler"
1443 const CompilerType firstCompilerType = gcc;
1444 const CompilerType lastCompilerType = vs10;
1445 public enum CompilerType
1447 gcc, tcc, pcc, vs8, vs9, vs10;
1451 get { return this == vs8 || this == vs9 || this == vs10; }
1454 property const char *
1456 get { return OnGetString(null, null, null); }
1462 for(c = firstCompilerType; c <= lastCompilerType; c++)
1463 if(!strcmpi(value, compilerTypeNames[c]))
1470 property const char * longName { get { return OnGetString(null, (void*)1, null); } };
1471 property const char * versionString { get { return OnGetString(null, (void*)2, null); } };
1472 property const char * yearString { get { return OnGetString(null, (void*)3, null); } };
1473 property const char * projectFileExtension { get { return OnGetString(null, (void*)4, null); } };
1474 property const char * solutionFileVersionString { get { return OnGetString(null, (void*)5, null); } };
1476 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
1478 if(this >= firstCompilerType && this <= lastCompilerType)
1481 strcpy(tempString, compilerTypeNames[this]);
1482 if(fieldData == null)
1483 return compilerTypeNames[this];
1484 else if(fieldData == (void*)1)
1485 return compilerTypeLongNames[this];
1486 else if(fieldData == (void*)2)
1487 return compilerTypeVersionString[this];
1488 else if(fieldData == (void*)3)
1489 return compilerTypeYearString[this];
1490 else if(fieldData == (void*)4)
1491 return compilerTypeProjectFileExtension[this];
1492 else if(fieldData == (void*)5)
1493 return compilerTypeSolutionFileVersionString[this];
1499 class CompilerConfig
1505 property const char * name
1507 set { delete name; if(value) name = CopyString(value); }
1508 get { return name; }
1512 Platform targetPlatform;
1514 property const char * makeCommand
1516 set { delete makeCommand; if(value && value[0]) makeCommand = CopyString(value); }
1517 get { return makeCommand; }
1518 isset { return makeCommand && makeCommand[0]; }
1520 property const char * ecpCommand
1522 set { delete ecpCommand; if(value && value[0]) ecpCommand = CopyString(value); }
1523 get { return ecpCommand; }
1524 isset { return ecpCommand && ecpCommand[0]; }
1526 property const char * eccCommand
1528 set { delete eccCommand; if(value && value[0]) eccCommand = CopyString(value); }
1529 get { return eccCommand; }
1530 isset { return eccCommand && eccCommand[0]; }
1532 property const char * ecsCommand
1534 set { delete ecsCommand; if(value && value[0]) ecsCommand = CopyString(value); }
1535 get { return ecsCommand; }
1536 isset { return ecsCommand && ecsCommand[0]; }
1538 property const char * earCommand
1540 set { delete earCommand; if(value && value[0]) earCommand = CopyString(value); }
1541 get { return earCommand; }
1542 isset { return earCommand && earCommand[0]; }
1544 property const char * cppCommand
1546 set { delete cppCommand; if(value && value[0]) cppCommand = CopyString(value); }
1547 get { return cppCommand; }
1548 isset { return cppCommand && cppCommand[0]; }
1550 property const char * ccCommand
1552 set { delete ccCommand; if(value && value[0]) ccCommand = CopyString(value); }
1553 get { return ccCommand; }
1554 isset { return ccCommand && ccCommand[0]; }
1556 property const char * cxxCommand
1558 set { delete cxxCommand; if(value && value[0]) cxxCommand = CopyString(value); }
1559 get { return cxxCommand; }
1560 isset { return cxxCommand && cxxCommand[0]; }
1562 property const char * arCommand
1564 set { delete arCommand; if(value && value[0]) arCommand = CopyString(value); }
1565 get { return arCommand; }
1566 isset { return arCommand && arCommand[0]; }
1568 property const char * ldCommand
1570 set { delete ldCommand; if(value && value[0]) ldCommand = CopyString(value); }
1571 get { return ldCommand; }
1572 isset { return ldCommand && ldCommand[0]; }
1574 property const char * objectFileExt
1576 set { delete objectFileExt; if(value && value[0]) objectFileExt = CopyString(value); }
1577 get { return objectFileExt && objectFileExt[0] ? objectFileExt : objectDefaultFileExt ; }
1578 isset { return objectFileExt && objectFileExt[0] && strcmp(objectFileExt, objectDefaultFileExt); }
1580 property const char * staticLibFileExt
1582 set { delete staticLibFileExt; if(value && value[0]) staticLibFileExt = CopyString(value); }
1583 get { return staticLibFileExt; }
1584 isset { return staticLibFileExt && staticLibFileExt[0]; }
1586 property const char * sharedLibFileExt
1588 set { delete sharedLibFileExt; if(value && value[0]) sharedLibFileExt = CopyString(value); }
1589 get { return sharedLibFileExt; }
1590 isset { return sharedLibFileExt && sharedLibFileExt[0]; }
1592 property const char * executableFileExt
1594 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1595 get { return executableFileExt; }
1596 isset { return executableFileExt && executableFileExt[0]; }
1598 property const char * executableLauncher
1600 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1601 get { return executableLauncher; }
1602 isset { return executableLauncher && executableLauncher[0]; }
1604 // TODO: implement CompilerConfig::windresCommand
1608 property bool supportsBitDepth { set { } get { return true; } isset { return false; } }
1610 property const char * distccHosts
1612 set { delete distccHosts; if(value && value[0]) distccHosts = CopyString(value); }
1613 get { return distccHosts; }
1614 isset { return distccHosts && distccHosts[0]; }
1616 property const char * gnuToolchainPrefix
1618 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1619 get { return gnuToolchainPrefix; }
1620 isset { return gnuToolchainPrefix && gnuToolchainPrefix[0]; }
1622 property const char * sysroot
1624 set { delete sysroot; if(value && value[0]) sysroot = CopyString(value); }
1625 get { return sysroot; }
1626 isset { return sysroot && sysroot[0]; }
1628 bool resourcesDotEar;
1630 property Array<String> includeDirs
1638 includeDirs = value;
1641 get { return includeDirs; }
1642 isset { return includeDirs.count != 0; }
1644 property Array<String> libraryDirs
1652 libraryDirs = value;
1655 get { return libraryDirs; }
1656 isset { return libraryDirs.count != 0; }
1658 property Array<String> executableDirs
1662 executableDirs.Free();
1665 delete executableDirs;
1666 executableDirs = value;
1669 get { return executableDirs; }
1670 isset { return executableDirs.count != 0; }
1672 property Array<NamedString> environmentVars
1676 environmentVars.Free();
1679 delete environmentVars;
1680 environmentVars = value;
1683 get { return environmentVars; }
1684 isset { return environmentVars.count != 0; }
1686 property Array<String> prepDirectives
1690 prepDirectives.Free();
1693 delete prepDirectives;
1694 prepDirectives = value;
1697 get { return prepDirectives; }
1698 isset { return prepDirectives.count != 0; }
1700 property Array<String> excludeLibs
1708 excludeLibs = value;
1711 get { return excludeLibs; }
1712 isset { return excludeLibs.count != 0; }
1714 property Array<String> eCcompilerFlags
1718 eCcompilerFlags.Free();
1721 delete eCcompilerFlags;
1722 eCcompilerFlags = value;
1725 get { return eCcompilerFlags; }
1726 isset { return eCcompilerFlags.count != 0; }
1728 property Array<String> compilerFlags
1732 compilerFlags.Free();
1735 delete compilerFlags;
1736 compilerFlags = value;
1739 get { return compilerFlags; }
1740 isset { return compilerFlags.count != 0; }
1742 property Array<String> cxxFlags
1753 get { return cxxFlags; }
1754 isset { return cxxFlags.count != 0; }
1756 property Array<String> linkerFlags
1764 linkerFlags = value;
1767 get { return linkerFlags; }
1768 isset { return linkerFlags.count != 0; }
1770 // json backward compatibility
1771 property const char * gccPrefix
1773 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1774 get { return gnuToolchainPrefix; }
1775 isset { return false; }
1777 property const char * execPrefixCommand
1779 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1780 get { return executableLauncher; }
1781 isset { return false; }
1783 property const char * outputFileExt
1785 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1786 get { return executableFileExt; }
1787 isset { return false; }
1790 property bool hasDocumentOutput
1794 bool result = executableFileExt && executableFileExt[0] &&
1795 (!strcmpi(executableFileExt, "htm") || !strcmpi(executableFileExt, "html"));
1798 isset { return false; }
1801 Array<String> includeDirs { };
1802 Array<String> libraryDirs { };
1803 Array<String> executableDirs { };
1804 // TODO: Can JSON parse and serialize maps?
1805 //EnvironmentVariables { };
1806 Array<NamedString> environmentVars { };
1807 Array<String> prepDirectives { };
1808 Array<String> excludeLibs { };
1809 Array<String> eCcompilerFlags { };
1810 Array<String> compilerFlags { };
1811 Array<String> cxxFlags { };
1812 Array<String> linkerFlags { };
1824 char * objectFileExt;
1825 char * staticLibFileExt;
1826 char * sharedLibFileExt;
1827 char * executableFileExt;
1828 char * executableLauncher;
1830 char * gnuToolchainPrefix;
1834 struct { Array<String> includes, libraries, executables; };
1835 Array<String> dirs[DirTypes];
1850 delete objectFileExt;
1851 delete staticLibFileExt;
1852 delete sharedLibFileExt;
1853 delete executableFileExt;
1855 delete executableLauncher;
1857 delete gnuToolchainPrefix;
1859 if(environmentVars) environmentVars.Free();
1860 if(includeDirs) { includeDirs.Free(); }
1861 if(libraryDirs) { libraryDirs.Free(); }
1862 if(executableDirs) { executableDirs.Free(); }
1863 if(prepDirectives) { prepDirectives.Free(); }
1864 if(excludeLibs) { excludeLibs.Free(); }
1865 if(compilerFlags) { compilerFlags.Free(); }
1866 if(cxxFlags) { cxxFlags.Free(); }
1867 if(eCcompilerFlags) { eCcompilerFlags.Free(); }
1868 if(linkerFlags) { linkerFlags.Free(); }
1871 int OnCompare(CompilerConfig b)
1875 !(result = type.OnCompare(b.type)) &&
1876 !(result = targetPlatform.OnCompare(b.targetPlatform)) &&
1877 !(result = numJobs.OnCompare(b.numJobs)) &&
1878 !(result = ccacheEnabled.OnCompare(b.ccacheEnabled)) &&
1879 !(result = distccEnabled.OnCompare(b.distccEnabled)) &&
1880 !(result = resourcesDotEar.OnCompare(b.resourcesDotEar)) &&
1881 !(result = noStripTarget.OnCompare(b.noStripTarget))
1885 !(result = name.OnCompare(b.name)) &&
1886 !(result = ecpCommand.OnCompare(b.ecpCommand)) &&
1887 !(result = eccCommand.OnCompare(b.eccCommand)) &&
1888 !(result = ecsCommand.OnCompare(b.ecsCommand)) &&
1889 !(result = earCommand.OnCompare(b.earCommand)) &&
1890 !(result = cppCommand.OnCompare(b.cppCommand)) &&
1891 !(result = ccCommand.OnCompare(b.ccCommand)) &&
1892 !(result = cxxCommand.OnCompare(b.cxxCommand)) &&
1893 !(result = ldCommand.OnCompare(b.ldCommand)) &&
1894 !(result = arCommand.OnCompare(b.arCommand)) &&
1895 !(result = objectFileExt.OnCompare(b.objectFileExt)) &&
1896 !(result = outputFileExt.OnCompare(b.outputFileExt)) &&
1897 !(result = makeCommand.OnCompare(b.makeCommand)) &&
1898 !(result = executableLauncher.OnCompare(b.executableLauncher)) &&
1899 !(result = distccHosts.OnCompare(b.distccHosts)) &&
1900 !(result = gnuToolchainPrefix.OnCompare(b.gnuToolchainPrefix)) &&
1901 !(result = sysroot.OnCompare(b.sysroot)));
1904 !(result = includeDirs.OnCompare(b.includeDirs)) &&
1905 !(result = libraryDirs.OnCompare(b.libraryDirs)) &&
1906 !(result = executableDirs.OnCompare(b.executableDirs)) &&
1907 !(result = environmentVars.OnCompare(b.environmentVars)) &&
1908 !(result = prepDirectives.OnCompare(b.prepDirectives)) &&
1909 !(result = excludeLibs.OnCompare(b.excludeLibs)) &&
1910 !(result = cxxFlags.OnCompare(b.cxxFlags)) &&
1911 !(result = eCcompilerFlags.OnCompare(b.eCcompilerFlags)) &&
1912 !(result = compilerFlags.OnCompare(b.compilerFlags)) &&
1913 !(result = linkerFlags.OnCompare(b.linkerFlags)));
1918 CompilerConfig Copy()
1951 for(s : includeDirs) copy.includeDirs.Add(CopyString(s));
1952 for(s : libraryDirs) copy.libraryDirs.Add(CopyString(s));
1953 for(s : executableDirs) copy.executableDirs.Add(CopyString(s));
1954 for(ns : environmentVars) copy.environmentVars.Add(NamedString { name = ns.name, string = ns.string });
1955 for(s : prepDirectives) copy.prepDirectives.Add(CopyString(s));
1956 for(s : excludeLibs) copy.excludeLibs.Add(CopyString(s));
1957 for(s : compilerFlags) copy.compilerFlags.Add(CopyString(s));
1958 for(s : cxxFlags) copy.cxxFlags.Add(CopyString(s));
1959 for(s : eCcompilerFlags) copy.eCcompilerFlags.Add(CopyString(s));
1960 for(s : linkerFlags) copy.linkerFlags.Add(CopyString(s));
1966 CompilerConfig ::read(const char * path)
1968 CompilerConfig d = null;
1969 readConfigFile(path, class(CompilerConfig), &d);
1973 void write(IDESettingsContainer settingsContainer)
1975 char dir[MAX_LOCATION];
1976 char path[MAX_LOCATION];
1977 const char * settingsFilePath = settingsContainer.settingsFilePath;
1978 settingsContainer.getConfigFilePath(path, _class, dir, name);
1979 if(FileExists(settingsFilePath) && !FileExists(dir))
1982 if(!FileExists(dir))
1983 PrintLn($"Error creating compiler configs directory at ", dir, " location.");
1985 writeConfigFile(path, _class, this);
1989 class CompilerConfigs : List<CompilerConfig>
1991 CompilerConfig GetCompilerConfig(const String compilerName)
1993 const char * name = compilerName && compilerName[0] ? compilerName : defaultCompilerName;
1994 CompilerConfig compilerConfig = null;
1995 for(compiler : this)
1997 if(!strcmp(compiler.name, name))
1999 compilerConfig = compiler;
2003 if(!compilerConfig && count)
2004 compilerConfig = this[0];
2007 incref compilerConfig;
2008 if(compilerConfig._refCount == 1)
2009 incref compilerConfig;
2011 return compilerConfig;
2014 void ensureDefaults()
2016 // Ensure we have a default compiler
2017 CompilerConfig defaultCompiler = GetCompilerConfig(defaultCompilerName);
2018 if(!defaultCompiler)
2020 defaultCompiler = MakeDefaultCompiler(defaultCompilerName, true);
2021 Insert(null, defaultCompiler);
2022 defaultCompiler = null;
2024 delete defaultCompiler;
2028 if(!ccfg.ecpCommand || !ccfg.ecpCommand[0])
2029 ccfg.ecpCommand = ecpDefaultCommand;
2030 if(!ccfg.eccCommand || !ccfg.eccCommand[0])
2031 ccfg.eccCommand = eccDefaultCommand;
2032 if(!ccfg.ecsCommand || !ccfg.ecsCommand[0])
2033 ccfg.ecsCommand = ecsDefaultCommand;
2034 if(!ccfg.earCommand || !ccfg.earCommand[0])
2035 ccfg.earCommand = earDefaultCommand;
2036 if(!ccfg.cppCommand || !ccfg.cppCommand[0])
2037 ccfg.cppCommand = cppDefaultCommand;
2038 if(!ccfg.ccCommand || !ccfg.ccCommand[0])
2039 ccfg.ccCommand = ccDefaultCommand;
2040 if(!ccfg.cxxCommand || !ccfg.cxxCommand[0])
2041 ccfg.cxxCommand = cxxDefaultCommand;
2042 /*if(!ccfg.ldCommand || !ccfg.ldCommand[0])
2043 ccfg.ldCommand = ldDefaultCommand;*/
2044 if(!ccfg.arCommand || !ccfg.arCommand[0])
2045 ccfg.arCommand = arDefaultCommand;
2046 if(!ccfg.objectFileExt || !ccfg.objectFileExt[0])
2047 ccfg.objectFileExt = objectDefaultFileExt;
2048 /*if(!ccfg.staticLibFileExt || !ccfg.staticLibFileExt[0])
2049 ccfg.staticLibFileExt = staticLibDefaultFileExt;*/
2050 /*if(!ccfg.sharedLibFileExt || !ccfg.sharedLibFileExt[0])
2051 ccfg.sharedLibFileExt = sharedLibDefaultFileExt;*/
2052 /*if(!ccfg.executableFileExt || !ccfg.executableFileExt[0])
2053 ccfg.executableFileExt = outputDefaultFileExt;*/
2054 if(!ccfg._refCount) incref ccfg;
2058 AVLTree<String> getWriteRequiredList(CompilerConfigs oldConfigs)
2060 AVLTree<String> list { };
2064 for(occfg : oldConfigs; !strcmp(ccfg.name, occfg.name))
2067 if(ccfg.OnCompare(occfg))
2068 list.Add(CopyString(ccfg.name));
2072 list.Add(CopyString(ccfg.name));
2077 bool read(IDESettingsContainer settingsContainer)
2079 if(settingsContainer.settingsFilePath)
2081 char dir[MAX_LOCATION];
2082 char path[MAX_LOCATION];
2083 Class _class = class(CompilerConfig);
2084 settingsContainer.getConfigFilePath(path, _class, dir, null);
2087 AVLTree<const String> addedConfigs { };
2088 Map<String, CompilerConfig> compilerConfigsByName = getCompilerConfigsByName(dir);
2089 MapIterator<const String, CompilerConfig> it { map = compilerConfigsByName };
2091 settingsContainer.compilerConfigs = this; // Merge IDEConfigHolder / IDESettingsContainer?
2092 if(it.Index("Default", false))
2094 CompilerConfig ccfg = it.data;
2096 addedConfigs.Add(ccfg.name);
2098 for(ccfg : compilerConfigsByName)
2100 if(!addedConfigs.Find(ccfg.name))
2103 addedConfigs.Add(ccfg.name);
2106 delete addedConfigs;
2108 compilerConfigsByName.Free();
2109 delete compilerConfigsByName;
2110 settingsContainer.onLoadCompilerConfigs();
2117 void write(IDESettingsContainer settingsContainer, AVLTree<String> cfgsToWrite)
2119 char dir[MAX_LOCATION];
2120 char path[MAX_LOCATION];
2121 Map<String, String> paths;
2122 settingsContainer.getConfigFilePath(path, class(CompilerConfig), dir, null);
2123 paths = getCompilerConfigFilePathsByName(dir);
2125 MapIterator<String, String> it { map = paths };
2128 CompilerConfig ccfg = c;
2129 if(!cfgsToWrite || cfgsToWrite.Find(ccfg.name))
2130 ccfg.write(settingsContainer);
2131 if(it.Index(ccfg.name, false))
2140 const char * path = p;
2148 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
2149 struct LanguageOption
2152 const String bitmap;
2156 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
2161 void OnDisplay(Surface surface, int x, int y, int width, void * data, Alignment alignment, DataDisplayFlags flags)
2163 Bitmap icon = res ? res.bitmap : null;
2166 surface.Blit(icon, x + (16 - icon.width) / 2,y+2,0,0, icon.width, icon.height);
2167 class::OnDisplay(surface, x + w, y, width - w, null, alignment, flags);
2171 Array<LanguageOption> languages
2173 { "English", ":countryCode/gb.png", "" },
2174 { "汉语", ":countryCode/cn.png", "zh_CN" },
2175 { "Español", ":countryCode/es.png", "es" },
2176 { "Português (Brazil)", ":countryCode/br.png", "pt_BR" },
2177 { "Русский (43%)", ":countryCode/ru.png", "ru" },
2178 { "Nederlandse (13%)", ":countryCode/nl.png", "nl" },
2179 { "Tiếng Việt (12%)", ":countryCode/vn.png", "vi" },
2180 { "मराठी (10%)", ":countryCode/in.png", "mr" },
2181 { "Hebrew (8%)", ":countryCode/il.png", "he" },
2182 { "Magyar (8%)", ":countryCode/hu.png", "hu" }
2185 const String GetLanguageString()
2187 char * dot, * colon;
2188 static char lang[256];
2189 const String language = getenv("ECERE_LANGUAGE");
2190 if(!language) language = getenv("LANGUAGE");
2191 if(!language) language = getenv("LC_ALL");
2192 if(!language) language = getenv("LC_MESSAGES");
2193 if(!language) language = getenv("LANG");
2194 if(!language) language = "";
2195 if(language && (colon = strchr(language, ':')))
2197 if(lang != language)
2198 strncpy(lang, language, sizeof(lang));
2199 lang[sizeof(lang)-1] = 0;
2200 lang[colon - language] = 0;
2203 if(language && (dot = strchr(language, '.')))
2205 if(lang != language)
2206 strncpy(lang, language, sizeof(lang));
2207 lang[sizeof(lang)-1] = 0;
2208 lang[dot - language] = 0;
2214 void setEcereLanguageInWinRegEnvironment(const char * languageCode)
2218 uint16 wLanguage[256];
2222 RegCreateKeyEx(HKEY_CURRENT_USER, "Environment", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
2225 UTF8toUTF16Buffer(languageCode, wLanguage, sizeof(wLanguage) / sizeof(uint16));
2226 RegSetValueExW(key, L"ECERE_LANGUAGE", 0, REG_EXPAND_SZ, (byte *)wLanguage, (uint)(wcslen(wLanguage)+1) * 2);
2232 bool LanguageRestart(const char * code, Application app, IDESettings settings, IDESettingsContainer settingsContainer, Window ide, Window projectView, bool wait)
2234 bool restart = true;
2235 String command = null;
2236 int arg0Len = (int)strlen(app.argv[0]);
2248 for(w = ide.firstChild; w; w = w.next)
2250 if(w.isActiveClient && w.isDocument)
2252 if(!w.CloseConfirmation(true))
2261 if(!projectView.CloseConfirmation(true))
2263 if(projectView.fileName)
2265 const char * name = projectView.fileName;
2268 for(j = 0; (ch = name[j]); j++)
2269 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2273 command = new char[len + 1];
2275 strcpy(command, app.argv[0]);
2277 if(projectView.fileName)
2279 strcat(command, " ");
2281 ReplaceSpaces(command + len, projectView.fileName);
2286 for(w = ide.firstChild; w; w = w.next)
2287 if(w.isActiveClient && w.isDocument)
2288 w.modifiedDocument = false;
2289 projectView.modifiedDocument = false;
2294 for(w = ide.firstChild; w; w = w.next)
2296 if(w.isActiveClient && w.isDocument)
2298 if(!w.CloseConfirmation(true))
2305 const char * name = w.fileName;
2307 for(j = 0; (ch = name[j]); j++)
2308 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2315 command = new char[len + 1];
2316 strcpy(command, app.argv[0]);
2319 for(w = ide.firstChild; w; w = w.next)
2321 if(w.isActiveClient && w.isDocument)
2323 const char * name = w.fileName;
2326 strcat(command, " ");
2328 ReplaceSpaces(command + len, name);
2329 len = (int)strlen(command);
2336 for(w = ide.firstChild; w; w = w.next)
2337 if(w.isActiveClient && w.isDocument)
2338 w.modifiedDocument = false;
2343 settings.language = code;
2344 settingsContainer.Save();
2346 setEcereLanguageInWinRegEnvironment(code);
2348 if(eClass_IsDerived(app._class, class(GuiApplication)))
2350 GuiApplication guiApp = (GuiApplication)app;
2351 guiApp.desktop.Destroy(0);
2358 for(i = 1; i < app.argc; i++)
2360 const char * arg = app.argv[i];
2362 for(j = 0; (ch = arg[j]); j++)
2363 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2366 command = new char[len + 1];
2367 strcpy(command, app.argv[0]);
2369 for(i = 1; i < app.argc; i++)
2371 strcat(command, " ");
2373 ReplaceSpaces(command + len, app.argv[i]);
2374 len = (int)strlen(command);
2380 SetEnvironment("ECERE_LANGUAGE", code);
2382 ExecuteWait(command);