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 data.compilerConfigs.ensureDefaults();
736 data.compilerConfigs.write(this, null);
737 data.compilerConfigs.Free();
739 data.recentFiles.write(this);
740 data.recentFiles.Free();
742 data.recentProjects.write(this);
743 data.recentProjects.Free();
750 SettingsIOResult Save()
752 SettingsIOResult result;
754 useNewConfigurationFiles = true;
755 data = (IDESettings)this.data;
756 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
757 data.ManagePortablePaths(moduleLocation, false);
758 data.ForcePathSeparatorStyle(true);
760 settingsFilePath = null;
761 result = GlobalSettings::Save();
762 if(result != success)
763 PrintLn("Error saving IDE settings");
766 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
767 data.ManagePortablePaths(moduleLocation, true);
770 FileGetSize(settingsFilePath, &settingsFileSize);
776 static Map<String, String> getCompilerConfigFilePathsByName(const char * path)
778 Map<String, String> map { };
779 FileListing fl { path, extensions = "econ" };
782 if(fl.stats.attribs.isFile)
784 char name[MAX_FILENAME];
785 char * path = CopyString(fl.path);
787 GetLastDirectory(path, name);
788 StripExtension(name);
795 static Map<String, CompilerConfig> getCompilerConfigsByName(const char * path)
797 Map<String, CompilerConfig> map { };
798 FileListing fl { path, extensions = "econ" };
801 if(fl.stats.attribs.isFile)
803 char name[MAX_FILENAME];
804 char * path = CopyString(fl.path);
806 GetLastDirectory(path, name);
807 StripExtension(name);
809 CompilerConfig ccfg = CompilerConfig::read(path);
819 static SettingsIOResult writeConfigFile(const char * path, Class dataType, void * data)
821 SettingsIOResult result = error;
822 SafeFile sf = SafeFile::open(path, write);
825 WriteECONObject(sf.file, dataType, data, 0);
831 PrintLn($"error: could not safely open file for writing configuration: ", path);
835 static SettingsIOResult readConfigFile(const char * path, Class dataType, void ** data)
837 SettingsIOResult result = error;
839 if(!FileExists(path))
840 result = fileNotFound;
841 else if((sf = SafeFile::open(path, read)))
843 JSONResult jsonResult;
845 ECONParser parser { f = sf.file };
846 sf.file.Seek(0, start);
847 jsonResult = parser.GetObject(dataType, data);
848 if(jsonResult != success)
852 if(jsonResult == success)
856 result = fileNotCompatibleWithDriver;
857 PrintLn($"error: could not parse configuration file: ", path);
868 char path[MAX_LOCATION];
869 char tmp[MAX_LOCATION];
871 SafeFile ::open(const char * path, FileOpenMode mode)
873 SafeFile result = null;
874 if(mode == write || mode == read)
876 SafeFile sf { mode = mode };
879 FileLock lockType = mode == write ? exclusive : shared;
881 strcpy(sf.path, path);
882 strcpy(sf.tmp, path);
883 strcat(sf.tmp, ".tmp");
884 if(mode == write && FileExists(sf.tmp).isFile)
889 sf.file = FileOpen(sf.tmp, readWrite);
892 sf.file = FileOpen(sf.tmp, writeRead);
896 sf.file = FileOpen(sf.tmp, readWrite);
901 sf.file = FileOpen(path, mode);
904 for(c = 0; c < 10 && !(locked = sf.file.Lock(lockType, 0, 0, false)); c++) Sleep(0.01);
908 sf.file.Seek(0, start);
911 else if(mode == write)
912 PrintLn($"warning: SafeFile::open: unable to obtain exclusive lock on temporary file for writing: ", sf.tmp);
914 PrintLn($"warning: SafeFile::open: unable to obtain shared lock on file for reading: ", path);
916 else if(mode == write)
917 PrintLn($"warning: SafeFile::open: unable to open temporary file for writing: ", sf.tmp);
919 PrintLn($"warning: SafeFile::open: unable to open file for reading: ", path);
925 PrintLn($"warning: SafeFile::open: does not yet support FileOpenMode::", mode);
931 if(file && mode == write)
934 File f = FileOpen(path, readWrite);
937 f = FileOpen(path, writeRead);
941 f = FileOpen(path, readWrite);
947 for(c = 0; c < 10 && !(locked = f.Lock(exclusive, 0,0, false)); c++) Sleep(0.01);
951 f.Unlock(0,0, false);
953 file.Unlock(0,0, false);
956 for(c = 0; c < 10; c++)
958 if(MoveFileEx(tmp, path, { true, true }))
967 PrintLn($"warning: SafeFile::sync: failed to lock file for ", mode);
978 file.Unlock(0,0, false);
984 class RecentFilesData
987 RecentFiles recentFiles;
990 class RecentWorkspacesData
993 RecentWorkspaces recentWorkspaces;
996 class IDESettings : GlobalSettingsData
999 property CompilerConfigs compilerConfigs
1001 set { /*if(settingsContainer.oldConfig)*/ { if(compilerConfigs) compilerConfigs.Free(); delete compilerConfigs; if(value) compilerConfigs = value; } }
1002 get { return compilerConfigs; }
1003 isset { return false; }
1005 property RecentFiles recentFiles
1007 set { if(recentFiles) recentFiles.Free(); delete recentFiles; if(value) recentFiles = value; }
1008 get { return recentFiles; }
1009 isset { return false; }
1011 property RecentWorkspaces recentProjects
1013 set { if(recentProjects) recentProjects.Free(); delete recentProjects; if(value) recentProjects = value; }
1014 get { return recentProjects; }
1015 isset { return false; }
1017 property const char * docDir
1019 set { delete docDir; if(value && value[0]) docDir = CopyString(value); }
1020 get { return docDir ? docDir : ""; }
1021 isset { return docDir && docDir[0]; }
1023 property const char * ideFileDialogLocation
1025 set { delete ideFileDialogLocation; if(value && value[0]) ideFileDialogLocation = CopyString(value); }
1026 get { return ideFileDialogLocation ? ideFileDialogLocation : ""; }
1027 isset { return ideFileDialogLocation && ideFileDialogLocation[0]; }
1029 property const char * ideProjectFileDialogLocation
1031 set { delete ideProjectFileDialogLocation; if(value && value[0]) ideProjectFileDialogLocation = CopyString(value); }
1032 get { return ideProjectFileDialogLocation ? ideProjectFileDialogLocation : ""; }
1033 isset { return ideProjectFileDialogLocation && ideProjectFileDialogLocation[0]; }
1036 bool showLineNumbers;
1037 bool caretFollowsScrolling;
1038 char * displayDriver;
1040 // TODO: Classify settings
1041 //EditorSettings editor { };
1043 property const char * projectDefaultTargetDir
1045 set { delete projectDefaultTargetDir; if(value && value[0]) projectDefaultTargetDir = CopyValidateMakefilePath(value); }
1046 get { return projectDefaultTargetDir ? projectDefaultTargetDir : ""; }
1047 isset { return projectDefaultTargetDir && projectDefaultTargetDir[0]; }
1049 property const char * projectDefaultIntermediateObjDir
1051 set { delete projectDefaultIntermediateObjDir; if(value && value[0]) projectDefaultIntermediateObjDir = CopyValidateMakefilePath(value); }
1052 get { return projectDefaultIntermediateObjDir ? projectDefaultIntermediateObjDir : ""; }
1053 isset { return projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0]; }
1056 property const char * compilerConfigsDir
1058 set { delete compilerConfigsDir; if(value && value[0]) compilerConfigsDir = CopyString(value); }
1059 get { return compilerConfigsDir ? compilerConfigsDir : ""; }
1060 isset { return compilerConfigsDir && compilerConfigsDir[0]; }
1063 property const char * defaultCompiler
1065 set { delete defaultCompiler; if(value && value[0]) defaultCompiler = CopyString(value); }
1066 get { return defaultCompiler && defaultCompiler[0] ? defaultCompiler : defaultCompilerName; }
1067 isset { return defaultCompiler && defaultCompiler[0]; }
1070 property const String language
1075 language = CopyString(value);
1077 get { return language; }
1078 isset { return language != null; }
1081 property const String codeEditorFont
1085 delete codeEditorFont;
1086 codeEditorFont = CopyString(value);
1088 get { return codeEditorFont; }
1091 float codeEditorFontSize;
1092 bool showFixedPitchFontsOnly;
1094 property Array<IDEColorScheme> colorSchemes
1098 if(colorSchemes && colorSchemes._refCount < 2)
1099 colorSchemes.Free();
1100 delete colorSchemes;
1101 colorSchemes = value;
1102 incref colorSchemes;
1104 get { return colorSchemes; }
1107 property const String activeColorScheme
1111 delete activeColorScheme;
1112 activeColorScheme = CopyString(value);
1114 get { return activeColorScheme; }
1118 CompilerConfigs compilerConfigs { };
1120 char * ideFileDialogLocation;
1121 char * ideProjectFileDialogLocation;
1122 char * projectDefaultTargetDir;
1123 char * projectDefaultIntermediateObjDir;
1124 char * compilerConfigsDir;
1125 char * defaultCompiler;
1127 RecentFiles recentFiles { };
1128 RecentWorkspaces recentProjects { };
1130 Array<IDEColorScheme> colorSchemes;
1132 String codeEditorFont;
1134 String activeColorScheme;
1136 showFixedPitchFontsOnly = true;
1137 codeEditorFontSize = 12;
1138 codeEditorFont = CopyString("Courier New");
1142 compilerConfigs.Free();
1143 delete compilerConfigs;
1144 if(recentProjects) { recentFiles.Free(); delete recentFiles; }
1145 if(recentProjects) { recentProjects.Free(); delete recentProjects; }
1148 delete projectDefaultTargetDir;
1149 delete projectDefaultIntermediateObjDir;
1150 delete compilerConfigsDir;
1151 delete defaultCompiler;
1154 delete ideFileDialogLocation;
1155 delete ideProjectFileDialogLocation;
1156 delete displayDriver;
1158 delete codeEditorFont;
1160 colorSchemes.Free();
1161 delete activeColorScheme;
1164 void ForcePathSeparatorStyle(bool unixStyle)
1168 from = '\\', to = '/';
1170 from = '/', to = '\\';
1171 if(compilerConfigs && compilerConfigs.count)
1174 for(config : compilerConfigs)
1176 if(config.includeDirs && config.includeDirs.count)
1178 for(i = 0; i < config.includeDirs.count; i++)
1180 if(config.includeDirs[i] && config.includeDirs[i][0])
1181 ChangeCh(config.includeDirs[i], from, to);
1184 if(config.libraryDirs && config.libraryDirs.count)
1186 for(i = 0; i < config.libraryDirs.count; i++)
1188 if(config.libraryDirs[i] && config.libraryDirs[i][0])
1189 ChangeCh(config.libraryDirs[i], from, to);
1192 if(config.executableDirs && config.executableDirs.count)
1194 for(i = 0; i < config.executableDirs.count; i++)
1196 if(config.executableDirs[i] && config.executableDirs[i][0])
1197 ChangeCh(config.executableDirs[i], from, to);
1202 recentFiles.changeChar(from, to);
1203 recentProjects.changeChar(from, to);
1204 if(docDir && docDir[0])
1205 ChangeCh(docDir, from, to);
1206 if(ideFileDialogLocation && ideFileDialogLocation[0])
1207 ChangeCh(ideFileDialogLocation, from, to);
1208 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
1209 ChangeCh(ideProjectFileDialogLocation, from, to);
1211 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
1212 ChangeCh(projectDefaultTargetDir, from, to);
1213 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
1214 ChangeCh(projectDefaultIntermediateObjDir, from, to);
1216 if(compilerConfigsDir && compilerConfigsDir[0])
1217 ChangeCh(compilerConfigsDir, from, to);
1220 void ManagePortablePaths(char * location, bool makeAbsolute)
1223 if(compilerConfigs && compilerConfigs.count)
1225 for(config : compilerConfigs)
1228 for(t = 0; t < DirTypes::enumSize; t++)
1230 Array<String> dirs = null;
1231 if(t == executables) dirs = config.executableDirs;
1232 else if(t == includes) dirs = config.includeDirs;
1233 else if(t == libraries) dirs = config.libraryDirs;
1234 if(dirs && dirs.count)
1236 for(c = 0; c < dirs.count; c++)
1238 if(dirs[c] && dirs[c][0])
1239 dirs[c] = UpdatePortablePath(dirs[c], location, makeAbsolute);
1245 if(recentFiles && recentFiles.count)
1247 for(c = 0; c < recentFiles.count; c++)
1249 if(recentFiles[c] && recentFiles[c][0])
1250 recentFiles[c] = UpdatePortablePath(recentFiles[c], location, makeAbsolute);
1253 if(recentProjects && recentProjects.count)
1255 for(c = 0; c < recentProjects.count; c++)
1257 if(recentProjects[c] && recentProjects[c][0])
1258 recentProjects[c] = UpdatePortablePath(recentProjects[c], location, makeAbsolute);
1261 if(docDir && docDir[0])
1262 docDir = UpdatePortablePath(docDir, location, makeAbsolute);
1263 if(ideFileDialogLocation && ideFileDialogLocation[0])
1264 ideFileDialogLocation = UpdatePortablePath(ideFileDialogLocation, location, makeAbsolute);
1265 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
1266 ideProjectFileDialogLocation = UpdatePortablePath(ideProjectFileDialogLocation, location, makeAbsolute);
1268 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
1269 projectDefaultTargetDir = UpdatePortablePath(projectDefaultTargetDir, location, makeAbsolute);
1270 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
1271 projectDefaultIntermediateObjDir = UpdatePortablePath(projectDefaultIntermediateObjDir, location, makeAbsolute);
1273 if(compilerConfigsDir && compilerConfigsDir[0])
1274 compilerConfigsDir = UpdatePortablePath(compilerConfigsDir, location, makeAbsolute);
1277 char * UpdatePortablePath(char * path, const char * location, bool makeAbsolute)
1282 char p[MAX_LOCATION];
1283 strcpy(p, location);
1284 PathCatSlash(p, path);
1286 output = CopyString(p);
1290 PathRelationship rel = eString_PathRelated(path, location, null);
1291 if(rel == subPath || rel == identical)
1293 char p[MAX_LOCATION];
1294 MakePathRelative(path, location, p);
1295 if(!*p) strcpy(p, "./");
1296 else ChangeCh(p, '\\', '/');
1298 output = CopyString(p);
1307 class RecentFiles : RecentPaths
1309 void read(IDESettingsContainer settingsContainer)
1311 char path[MAX_LOCATION];
1312 RecentFilesData d = null;
1313 Class _class = class(RecentFilesData);
1314 settingsContainer.getConfigFilePath(path, _class, null, null);
1315 readConfigFile(path, _class, &d);
1316 if(d && d.recentFiles && d.recentFiles.count)
1319 Copy((void *)d.recentFiles);
1320 settingsContainer.recentFiles = this; // Merge IDEConfigHolder / IDESettingsContainer?
1323 settingsContainer.recentFilesMonitor.fileName = path;
1324 settingsContainer.recentFilesMonitor.StartMonitoring();
1325 settingsContainer.onLoadRecentFiles();
1328 void write(IDESettingsContainer settingsContainer)
1330 char path[MAX_LOCATION];
1331 RecentFilesData d { };
1332 Class _class = class(RecentFilesData);
1333 settingsContainer.getConfigFilePath(path, _class, null, null);
1334 d.recentFiles = this;
1335 writeConfigFile(path, _class, d);
1336 d.recentFiles = null;
1341 class RecentWorkspaces : RecentPaths
1343 void read(IDESettingsContainer settingsContainer)
1345 char path[MAX_LOCATION];
1346 RecentWorkspacesData d = null;
1347 Class _class = class(RecentWorkspacesData);
1348 settingsContainer.getConfigFilePath(path, _class, null, null);
1349 readConfigFile(path, _class, &d);
1350 if(d && d.recentWorkspaces && d.recentWorkspaces.count)
1353 Copy((void *)d.recentWorkspaces);
1354 settingsContainer.recentProjects = this; // Merge IDEConfigHolder / IDESettingsContainer?
1357 settingsContainer.recentProjectsMonitor.fileName = path;
1358 settingsContainer.recentProjectsMonitor.StartMonitoring();
1359 settingsContainer.onLoadRecentProjects();
1362 void write(IDESettingsContainer settingsContainer)
1364 char path[MAX_LOCATION];
1365 RecentWorkspacesData d { };
1366 Class _class = class(RecentWorkspacesData);
1367 settingsContainer.getConfigFilePath(path, _class, null, null);
1368 d.recentWorkspaces = this;
1369 writeConfigFile(path, _class, d);
1370 d.recentWorkspaces = null;
1375 class RecentPaths : Array<String>
1377 IteratorPointer Add(T value)
1380 char * filePath = (char *)value;
1381 ChangeCh(filePath, '\\', '/');
1382 for(c = 0; c < count; c++)
1384 if(this[c] && !fstrcmp(this[c], filePath))
1386 Delete((void *)&this[c]);
1390 return Array::Add((T)filePath);
1393 IteratorPointer addRecent(const String value)
1396 char * filePath = CopyString((char *)value);
1398 ChangeCh(filePath, '\\', '/');
1399 for(c = 0; c < count; c++)
1401 if(this[c] && !fstrcmp(this[c], filePath))
1403 Delete((void *)&this[c]);
1407 while(count >= MaxRecent)
1409 ip = Insert(null, filePath);
1413 void changeChar(char from, char to)
1418 for(c = 0; c < count; c++)
1420 if(this[c] && this[c][0])
1421 ChangeCh(this[c], from, to);
1427 static const char * compilerTypeNames[CompilerType] = { "GCC", "TCC", "PCC", "VS8", "VS9", "VS10" };
1428 static const char * compilerTypeVersionString[CompilerType] = { "", "", "", "8.00", "9.00", "10.00" };
1429 static const char * compilerTypeSolutionFileVersionString[CompilerType] = { "", "", "", "9.00", "10.00", "11.00" };
1430 static const char * compilerTypeYearString[CompilerType] = { "", "", "", "2005", "2008", "2010" };
1431 static const char * compilerTypeProjectFileExtension[CompilerType] = { "", "", "", "vcproj", "vcproj", "vcxproj" };
1432 // TODO: i18n with Array
1433 static Array<const String> compilerTypeLongNames
1435 $"GNU Compiler Collection (GCC) / GNU Make",
1436 $"Tiny C Compiler / GNU Make",
1437 $"Portable C Compiler / GNU Make",
1438 $"Microsoft Visual Studio 2005 (8.0) Compiler",
1439 $"Microsoft Visual Studio 2008 (9.0) Compiler",
1440 $"Microsoft Visual Studio 2010 (10.0) Compiler"
1442 const CompilerType firstCompilerType = gcc;
1443 const CompilerType lastCompilerType = vs10;
1444 public enum CompilerType
1446 gcc, tcc, pcc, vs8, vs9, vs10;
1450 get { return this == vs8 || this == vs9 || this == vs10; }
1453 property const char *
1455 get { return OnGetString(null, null, null); }
1461 for(c = firstCompilerType; c <= lastCompilerType; c++)
1462 if(!strcmpi(value, compilerTypeNames[c]))
1469 property const char * longName { get { return OnGetString(null, (void*)1, null); } };
1470 property const char * versionString { get { return OnGetString(null, (void*)2, null); } };
1471 property const char * yearString { get { return OnGetString(null, (void*)3, null); } };
1472 property const char * projectFileExtension { get { return OnGetString(null, (void*)4, null); } };
1473 property const char * solutionFileVersionString { get { return OnGetString(null, (void*)5, null); } };
1475 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
1477 if(this >= firstCompilerType && this <= lastCompilerType)
1480 strcpy(tempString, compilerTypeNames[this]);
1481 if(fieldData == null)
1482 return compilerTypeNames[this];
1483 else if(fieldData == (void*)1)
1484 return compilerTypeLongNames[this];
1485 else if(fieldData == (void*)2)
1486 return compilerTypeVersionString[this];
1487 else if(fieldData == (void*)3)
1488 return compilerTypeYearString[this];
1489 else if(fieldData == (void*)4)
1490 return compilerTypeProjectFileExtension[this];
1491 else if(fieldData == (void*)5)
1492 return compilerTypeSolutionFileVersionString[this];
1498 class CompilerConfig
1504 property const char * name
1506 set { delete name; if(value) name = CopyString(value); }
1507 get { return name; }
1511 Platform targetPlatform;
1513 property const char * makeCommand
1515 set { delete makeCommand; if(value && value[0]) makeCommand = CopyString(value); }
1516 get { return makeCommand; }
1517 isset { return makeCommand && makeCommand[0]; }
1519 property const char * ecpCommand
1521 set { delete ecpCommand; if(value && value[0]) ecpCommand = CopyString(value); }
1522 get { return ecpCommand; }
1523 isset { return ecpCommand && ecpCommand[0]; }
1525 property const char * eccCommand
1527 set { delete eccCommand; if(value && value[0]) eccCommand = CopyString(value); }
1528 get { return eccCommand; }
1529 isset { return eccCommand && eccCommand[0]; }
1531 property const char * ecsCommand
1533 set { delete ecsCommand; if(value && value[0]) ecsCommand = CopyString(value); }
1534 get { return ecsCommand; }
1535 isset { return ecsCommand && ecsCommand[0]; }
1537 property const char * earCommand
1539 set { delete earCommand; if(value && value[0]) earCommand = CopyString(value); }
1540 get { return earCommand; }
1541 isset { return earCommand && earCommand[0]; }
1543 property const char * cppCommand
1545 set { delete cppCommand; if(value && value[0]) cppCommand = CopyString(value); }
1546 get { return cppCommand; }
1547 isset { return cppCommand && cppCommand[0]; }
1549 property const char * ccCommand
1551 set { delete ccCommand; if(value && value[0]) ccCommand = CopyString(value); }
1552 get { return ccCommand; }
1553 isset { return ccCommand && ccCommand[0]; }
1555 property const char * cxxCommand
1557 set { delete cxxCommand; if(value && value[0]) cxxCommand = CopyString(value); }
1558 get { return cxxCommand; }
1559 isset { return cxxCommand && cxxCommand[0]; }
1561 property const char * arCommand
1563 set { delete arCommand; if(value && value[0]) arCommand = CopyString(value); }
1564 get { return arCommand; }
1565 isset { return arCommand && arCommand[0]; }
1567 property const char * ldCommand
1569 set { delete ldCommand; if(value && value[0]) ldCommand = CopyString(value); }
1570 get { return ldCommand; }
1571 isset { return ldCommand && ldCommand[0]; }
1573 property const char * objectFileExt
1575 set { delete objectFileExt; if(value && value[0]) objectFileExt = CopyString(value); }
1576 get { return objectFileExt && objectFileExt[0] ? objectFileExt : objectDefaultFileExt ; }
1577 isset { return objectFileExt && objectFileExt[0] && strcmp(objectFileExt, objectDefaultFileExt); }
1579 property const char * staticLibFileExt
1581 set { delete staticLibFileExt; if(value && value[0]) staticLibFileExt = CopyString(value); }
1582 get { return staticLibFileExt; }
1583 isset { return staticLibFileExt && staticLibFileExt[0]; }
1585 property const char * sharedLibFileExt
1587 set { delete sharedLibFileExt; if(value && value[0]) sharedLibFileExt = CopyString(value); }
1588 get { return sharedLibFileExt; }
1589 isset { return sharedLibFileExt && sharedLibFileExt[0]; }
1591 property const char * executableFileExt
1593 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1594 get { return executableFileExt; }
1595 isset { return executableFileExt && executableFileExt[0]; }
1597 property const char * executableLauncher
1599 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1600 get { return executableLauncher; }
1601 isset { return executableLauncher && executableLauncher[0]; }
1603 // TODO: implement CompilerConfig::windresCommand
1607 property bool supportsBitDepth { set { } get { return true; } isset { return false; } }
1609 property const char * distccHosts
1611 set { delete distccHosts; if(value && value[0]) distccHosts = CopyString(value); }
1612 get { return distccHosts; }
1613 isset { return distccHosts && distccHosts[0]; }
1615 property const char * gnuToolchainPrefix
1617 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1618 get { return gnuToolchainPrefix; }
1619 isset { return gnuToolchainPrefix && gnuToolchainPrefix[0]; }
1621 property const char * sysroot
1623 set { delete sysroot; if(value && value[0]) sysroot = CopyString(value); }
1624 get { return sysroot; }
1625 isset { return sysroot && sysroot[0]; }
1627 bool resourcesDotEar;
1629 property Array<String> includeDirs
1637 includeDirs = value;
1640 get { return includeDirs; }
1641 isset { return includeDirs.count != 0; }
1643 property Array<String> libraryDirs
1651 libraryDirs = value;
1654 get { return libraryDirs; }
1655 isset { return libraryDirs.count != 0; }
1657 property Array<String> executableDirs
1661 executableDirs.Free();
1664 delete executableDirs;
1665 executableDirs = value;
1668 get { return executableDirs; }
1669 isset { return executableDirs.count != 0; }
1671 property Array<NamedString> environmentVars
1675 environmentVars.Free();
1678 delete environmentVars;
1679 environmentVars = value;
1682 get { return environmentVars; }
1683 isset { return environmentVars.count != 0; }
1685 property Array<String> prepDirectives
1689 prepDirectives.Free();
1692 delete prepDirectives;
1693 prepDirectives = value;
1696 get { return prepDirectives; }
1697 isset { return prepDirectives.count != 0; }
1699 property Array<String> excludeLibs
1707 excludeLibs = value;
1710 get { return excludeLibs; }
1711 isset { return excludeLibs.count != 0; }
1713 property Array<String> eCcompilerFlags
1717 eCcompilerFlags.Free();
1720 delete eCcompilerFlags;
1721 eCcompilerFlags = value;
1724 get { return eCcompilerFlags; }
1725 isset { return eCcompilerFlags.count != 0; }
1727 property Array<String> compilerFlags
1731 compilerFlags.Free();
1734 delete compilerFlags;
1735 compilerFlags = value;
1738 get { return compilerFlags; }
1739 isset { return compilerFlags.count != 0; }
1741 property Array<String> cxxFlags
1752 get { return cxxFlags; }
1753 isset { return cxxFlags.count != 0; }
1755 property Array<String> linkerFlags
1763 linkerFlags = value;
1766 get { return linkerFlags; }
1767 isset { return linkerFlags.count != 0; }
1769 // json backward compatibility
1770 property const char * gccPrefix
1772 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1773 get { return gnuToolchainPrefix; }
1774 isset { return false; }
1776 property const char * execPrefixCommand
1778 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1779 get { return executableLauncher; }
1780 isset { return false; }
1782 property const char * outputFileExt
1784 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1785 get { return executableFileExt; }
1786 isset { return false; }
1789 property bool hasDocumentOutput
1793 bool result = executableFileExt && executableFileExt[0] &&
1794 (!strcmpi(executableFileExt, "htm") || !strcmpi(executableFileExt, "html"));
1797 isset { return false; }
1800 Array<String> includeDirs { };
1801 Array<String> libraryDirs { };
1802 Array<String> executableDirs { };
1803 // TODO: Can JSON parse and serialize maps?
1804 //EnvironmentVariables { };
1805 Array<NamedString> environmentVars { };
1806 Array<String> prepDirectives { };
1807 Array<String> excludeLibs { };
1808 Array<String> eCcompilerFlags { };
1809 Array<String> compilerFlags { };
1810 Array<String> cxxFlags { };
1811 Array<String> linkerFlags { };
1823 char * objectFileExt;
1824 char * staticLibFileExt;
1825 char * sharedLibFileExt;
1826 char * executableFileExt;
1827 char * executableLauncher;
1829 char * gnuToolchainPrefix;
1833 struct { Array<String> includes, libraries, executables; };
1834 Array<String> dirs[DirTypes];
1849 delete objectFileExt;
1850 delete staticLibFileExt;
1851 delete sharedLibFileExt;
1852 delete executableFileExt;
1854 delete executableLauncher;
1856 delete gnuToolchainPrefix;
1858 if(environmentVars) environmentVars.Free();
1859 if(includeDirs) { includeDirs.Free(); }
1860 if(libraryDirs) { libraryDirs.Free(); }
1861 if(executableDirs) { executableDirs.Free(); }
1862 if(prepDirectives) { prepDirectives.Free(); }
1863 if(excludeLibs) { excludeLibs.Free(); }
1864 if(compilerFlags) { compilerFlags.Free(); }
1865 if(cxxFlags) { cxxFlags.Free(); }
1866 if(eCcompilerFlags) { eCcompilerFlags.Free(); }
1867 if(linkerFlags) { linkerFlags.Free(); }
1870 int OnCompare(CompilerConfig b)
1874 !(result = type.OnCompare(b.type)) &&
1875 !(result = targetPlatform.OnCompare(b.targetPlatform)) &&
1876 !(result = numJobs.OnCompare(b.numJobs)) &&
1877 !(result = ccacheEnabled.OnCompare(b.ccacheEnabled)) &&
1878 !(result = distccEnabled.OnCompare(b.distccEnabled)) &&
1879 !(result = resourcesDotEar.OnCompare(b.resourcesDotEar)) &&
1880 !(result = noStripTarget.OnCompare(b.noStripTarget))
1884 !(result = name.OnCompare(b.name)) &&
1885 !(result = ecpCommand.OnCompare(b.ecpCommand)) &&
1886 !(result = eccCommand.OnCompare(b.eccCommand)) &&
1887 !(result = ecsCommand.OnCompare(b.ecsCommand)) &&
1888 !(result = earCommand.OnCompare(b.earCommand)) &&
1889 !(result = cppCommand.OnCompare(b.cppCommand)) &&
1890 !(result = ccCommand.OnCompare(b.ccCommand)) &&
1891 !(result = cxxCommand.OnCompare(b.cxxCommand)) &&
1892 !(result = ldCommand.OnCompare(b.ldCommand)) &&
1893 !(result = arCommand.OnCompare(b.arCommand)) &&
1894 !(result = objectFileExt.OnCompare(b.objectFileExt)) &&
1895 !(result = outputFileExt.OnCompare(b.outputFileExt)) &&
1896 !(result = makeCommand.OnCompare(b.makeCommand)) &&
1897 !(result = executableLauncher.OnCompare(b.executableLauncher)) &&
1898 !(result = distccHosts.OnCompare(b.distccHosts)) &&
1899 !(result = gnuToolchainPrefix.OnCompare(b.gnuToolchainPrefix)) &&
1900 !(result = sysroot.OnCompare(b.sysroot)));
1903 !(result = includeDirs.OnCompare(b.includeDirs)) &&
1904 !(result = libraryDirs.OnCompare(b.libraryDirs)) &&
1905 !(result = executableDirs.OnCompare(b.executableDirs)) &&
1906 !(result = environmentVars.OnCompare(b.environmentVars)) &&
1907 !(result = prepDirectives.OnCompare(b.prepDirectives)) &&
1908 !(result = excludeLibs.OnCompare(b.excludeLibs)) &&
1909 !(result = cxxFlags.OnCompare(b.cxxFlags)) &&
1910 !(result = eCcompilerFlags.OnCompare(b.eCcompilerFlags)) &&
1911 !(result = compilerFlags.OnCompare(b.compilerFlags)) &&
1912 !(result = linkerFlags.OnCompare(b.linkerFlags)));
1917 CompilerConfig Copy()
1950 for(s : includeDirs) copy.includeDirs.Add(CopyString(s));
1951 for(s : libraryDirs) copy.libraryDirs.Add(CopyString(s));
1952 for(s : executableDirs) copy.executableDirs.Add(CopyString(s));
1953 for(ns : environmentVars) copy.environmentVars.Add(NamedString { name = ns.name, string = ns.string });
1954 for(s : prepDirectives) copy.prepDirectives.Add(CopyString(s));
1955 for(s : excludeLibs) copy.excludeLibs.Add(CopyString(s));
1956 for(s : compilerFlags) copy.compilerFlags.Add(CopyString(s));
1957 for(s : cxxFlags) copy.cxxFlags.Add(CopyString(s));
1958 for(s : eCcompilerFlags) copy.eCcompilerFlags.Add(CopyString(s));
1959 for(s : linkerFlags) copy.linkerFlags.Add(CopyString(s));
1965 CompilerConfig ::read(const char * path)
1967 CompilerConfig d = null;
1968 readConfigFile(path, class(CompilerConfig), &d);
1972 void write(IDESettingsContainer settingsContainer)
1974 char dir[MAX_LOCATION];
1975 char path[MAX_LOCATION];
1976 const char * settingsFilePath = settingsContainer.settingsFilePath;
1977 settingsContainer.getConfigFilePath(path, _class, dir, name);
1978 if(FileExists(settingsFilePath) && !FileExists(dir))
1981 if(!FileExists(dir))
1982 PrintLn($"Error creating compiler configs directory at ", dir, " location.");
1984 writeConfigFile(path, _class, this);
1988 class CompilerConfigs : List<CompilerConfig>
1990 CompilerConfig GetCompilerConfig(const String compilerName)
1992 const char * name = compilerName && compilerName[0] ? compilerName : defaultCompilerName;
1993 CompilerConfig compilerConfig = null;
1994 for(compiler : this)
1996 if(!strcmp(compiler.name, name))
1998 compilerConfig = compiler;
2002 if(!compilerConfig && count)
2003 compilerConfig = this[0];
2006 incref compilerConfig;
2007 if(compilerConfig._refCount == 1)
2008 incref compilerConfig;
2010 return compilerConfig;
2013 void ensureDefaults()
2015 // Ensure we have a default compiler
2016 CompilerConfig defaultCompiler = GetCompilerConfig(defaultCompilerName);
2017 if(!defaultCompiler)
2019 defaultCompiler = MakeDefaultCompiler(defaultCompilerName, true);
2020 Insert(null, defaultCompiler);
2021 defaultCompiler = null;
2023 delete defaultCompiler;
2027 if(!ccfg.ecpCommand || !ccfg.ecpCommand[0])
2028 ccfg.ecpCommand = ecpDefaultCommand;
2029 if(!ccfg.eccCommand || !ccfg.eccCommand[0])
2030 ccfg.eccCommand = eccDefaultCommand;
2031 if(!ccfg.ecsCommand || !ccfg.ecsCommand[0])
2032 ccfg.ecsCommand = ecsDefaultCommand;
2033 if(!ccfg.earCommand || !ccfg.earCommand[0])
2034 ccfg.earCommand = earDefaultCommand;
2035 if(!ccfg.cppCommand || !ccfg.cppCommand[0])
2036 ccfg.cppCommand = cppDefaultCommand;
2037 if(!ccfg.ccCommand || !ccfg.ccCommand[0])
2038 ccfg.ccCommand = ccDefaultCommand;
2039 if(!ccfg.cxxCommand || !ccfg.cxxCommand[0])
2040 ccfg.cxxCommand = cxxDefaultCommand;
2041 /*if(!ccfg.ldCommand || !ccfg.ldCommand[0])
2042 ccfg.ldCommand = ldDefaultCommand;*/
2043 if(!ccfg.arCommand || !ccfg.arCommand[0])
2044 ccfg.arCommand = arDefaultCommand;
2045 if(!ccfg.objectFileExt || !ccfg.objectFileExt[0])
2046 ccfg.objectFileExt = objectDefaultFileExt;
2047 /*if(!ccfg.staticLibFileExt || !ccfg.staticLibFileExt[0])
2048 ccfg.staticLibFileExt = staticLibDefaultFileExt;*/
2049 /*if(!ccfg.sharedLibFileExt || !ccfg.sharedLibFileExt[0])
2050 ccfg.sharedLibFileExt = sharedLibDefaultFileExt;*/
2051 /*if(!ccfg.executableFileExt || !ccfg.executableFileExt[0])
2052 ccfg.executableFileExt = outputDefaultFileExt;*/
2053 if(!ccfg._refCount) incref ccfg;
2057 AVLTree<String> getWriteRequiredList(CompilerConfigs oldConfigs)
2059 AVLTree<String> list { };
2063 for(occfg : oldConfigs; !strcmp(ccfg.name, occfg.name))
2066 if(ccfg.OnCompare(occfg))
2067 list.Add(CopyString(ccfg.name));
2071 list.Add(CopyString(ccfg.name));
2076 bool read(IDESettingsContainer settingsContainer)
2078 if(settingsContainer.settingsFilePath)
2080 char dir[MAX_LOCATION];
2081 char path[MAX_LOCATION];
2082 Class _class = class(CompilerConfig);
2083 settingsContainer.getConfigFilePath(path, _class, dir, null);
2086 AVLTree<const String> addedConfigs { };
2087 Map<String, CompilerConfig> compilerConfigsByName = getCompilerConfigsByName(dir);
2088 MapIterator<const String, CompilerConfig> it { map = compilerConfigsByName };
2090 settingsContainer.compilerConfigs = this; // Merge IDEConfigHolder / IDESettingsContainer?
2091 if(it.Index("Default", false))
2093 CompilerConfig ccfg = it.data;
2095 addedConfigs.Add(ccfg.name);
2097 for(ccfg : compilerConfigsByName)
2099 if(!addedConfigs.Find(ccfg.name))
2102 addedConfigs.Add(ccfg.name);
2105 delete addedConfigs;
2107 compilerConfigsByName.Free();
2108 delete compilerConfigsByName;
2109 settingsContainer.onLoadCompilerConfigs();
2116 void write(IDESettingsContainer settingsContainer, AVLTree<String> cfgsToWrite)
2118 char dir[MAX_LOCATION];
2119 char path[MAX_LOCATION];
2120 Map<String, String> paths;
2121 settingsContainer.getConfigFilePath(path, class(CompilerConfig), dir, null);
2122 paths = getCompilerConfigFilePathsByName(dir);
2124 MapIterator<String, String> it { map = paths };
2127 CompilerConfig ccfg = c;
2128 if(!cfgsToWrite || cfgsToWrite.Find(ccfg.name))
2129 ccfg.write(settingsContainer);
2130 if(it.Index(ccfg.name, false))
2139 const char * path = p;
2147 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
2148 struct LanguageOption
2151 const String bitmap;
2155 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
2160 void OnDisplay(Surface surface, int x, int y, int width, void * data, Alignment alignment, DataDisplayFlags flags)
2162 Bitmap icon = res ? res.bitmap : null;
2165 surface.Blit(icon, x + (16 - icon.width) / 2,y+2,0,0, icon.width, icon.height);
2166 class::OnDisplay(surface, x + w, y, width - w, null, alignment, flags);
2170 Array<LanguageOption> languages
2172 { "English", ":countryCode/gb.png", "" },
2173 { "汉语", ":countryCode/cn.png", "zh_CN" },
2174 { "Español", ":countryCode/es.png", "es" },
2175 { "Português (Brazil)", ":countryCode/br.png", "pt_BR" },
2176 { "Русский (43%)", ":countryCode/ru.png", "ru" },
2177 { "Nederlandse (13%)", ":countryCode/nl.png", "nl" },
2178 { "Tiếng Việt (12%)", ":countryCode/vn.png", "vi" },
2179 { "मराठी (10%)", ":countryCode/in.png", "mr" },
2180 { "Hebrew (8%)", ":countryCode/il.png", "he" },
2181 { "Magyar (8%)", ":countryCode/hu.png", "hu" }
2184 const String GetLanguageString()
2186 char * dot, * colon;
2187 static char lang[256];
2188 const String language = getenv("ECERE_LANGUAGE");
2189 if(!language) language = getenv("LANGUAGE");
2190 if(!language) language = getenv("LC_ALL");
2191 if(!language) language = getenv("LC_MESSAGES");
2192 if(!language) language = getenv("LANG");
2193 if(!language) language = "";
2194 if(language && (colon = strchr(language, ':')))
2196 if(lang != language)
2197 strncpy(lang, language, sizeof(lang));
2198 lang[sizeof(lang)-1] = 0;
2199 lang[colon - language] = 0;
2202 if(language && (dot = strchr(language, '.')))
2204 if(lang != language)
2205 strncpy(lang, language, sizeof(lang));
2206 lang[sizeof(lang)-1] = 0;
2207 lang[dot - language] = 0;
2213 void setEcereLanguageInWinRegEnvironment(const char * languageCode)
2217 uint16 wLanguage[256];
2221 RegCreateKeyEx(HKEY_CURRENT_USER, "Environment", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
2224 UTF8toUTF16Buffer(languageCode, wLanguage, sizeof(wLanguage) / sizeof(uint16));
2225 RegSetValueExW(key, L"ECERE_LANGUAGE", 0, REG_EXPAND_SZ, (byte *)wLanguage, (uint)(wcslen(wLanguage)+1) * 2);
2231 bool LanguageRestart(const char * code, Application app, IDESettings settings, IDESettingsContainer settingsContainer, Window ide, Window projectView, bool wait)
2233 bool restart = true;
2234 String command = null;
2235 int arg0Len = (int)strlen(app.argv[0]);
2247 for(w = ide.firstChild; w; w = w.next)
2249 if(w.isActiveClient && w.isDocument)
2251 if(!w.CloseConfirmation(true))
2260 if(!projectView.CloseConfirmation(true))
2262 if(projectView.fileName)
2264 const char * name = projectView.fileName;
2267 for(j = 0; (ch = name[j]); j++)
2268 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2272 command = new char[len + 1];
2274 strcpy(command, app.argv[0]);
2276 if(projectView.fileName)
2278 strcat(command, " ");
2280 ReplaceSpaces(command + len, projectView.fileName);
2285 for(w = ide.firstChild; w; w = w.next)
2286 if(w.isActiveClient && w.isDocument)
2287 w.modifiedDocument = false;
2288 projectView.modifiedDocument = false;
2293 for(w = ide.firstChild; w; w = w.next)
2295 if(w.isActiveClient && w.isDocument)
2297 if(!w.CloseConfirmation(true))
2304 const char * name = w.fileName;
2306 for(j = 0; (ch = name[j]); j++)
2307 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2314 command = new char[len + 1];
2315 strcpy(command, app.argv[0]);
2318 for(w = ide.firstChild; w; w = w.next)
2320 if(w.isActiveClient && w.isDocument)
2322 const char * name = w.fileName;
2325 strcat(command, " ");
2327 ReplaceSpaces(command + len, name);
2328 len = (int)strlen(command);
2335 for(w = ide.firstChild; w; w = w.next)
2336 if(w.isActiveClient && w.isDocument)
2337 w.modifiedDocument = false;
2342 settings.language = code;
2343 settingsContainer.Save();
2345 setEcereLanguageInWinRegEnvironment(code);
2347 if(eClass_IsDerived(app._class, class(GuiApplication)))
2349 GuiApplication guiApp = (GuiApplication)app;
2350 guiApp.desktop.Destroy(0);
2357 for(i = 1; i < app.argc; i++)
2359 const char * arg = app.argv[i];
2361 for(j = 0; (ch = arg[j]); j++)
2362 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2365 command = new char[len + 1];
2366 strcpy(command, app.argv[0]);
2368 for(i = 1; i < app.argc; i++)
2370 strcat(command, " ");
2372 ReplaceSpaces(command + len, app.argv[i]);
2373 len = (int)strlen(command);
2379 SetEnvironment("ECERE_LANGUAGE", code);
2381 ExecuteWait(command);