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";
414 define settingsDir = "EcereIDE";
415 define ideSettingsName = "EcereIDE";
417 define settingsDir = ".ecereIDE";
418 define ideSettingsName = "ecereIDE";
422 class IDEConfigHolder
424 CompilerConfigs compilers { };
425 RecentFiles recentFiles { };
426 RecentWorkspaces recentWorkspaces { };
428 property CompilerConfigs compilers
430 set { compilers.Free(); delete compilers; compilers = value; }
431 get { return compilers; }
433 property RecentFiles recentFiles
435 set { recentFiles.Free(); delete recentFiles; recentFiles = value; }
436 get { return recentFiles; }
438 property RecentWorkspaces recentProjects
440 set { recentWorkspaces.Free(); delete recentWorkspaces; recentWorkspaces = value; }
441 get { return recentWorkspaces; }
448 recentWorkspaces.Free();
451 void forcePathSeparatorStyle(bool unixStyle)
455 from = '\\', to = '/';
457 from = '/', to = '\\';
458 recentFiles.changeChar(from, to);
459 recentWorkspaces.changeChar(from, to);
463 class IDESettingsContainer : GlobalSettings
465 virtual void onLoadCompilerConfigs();
466 virtual void onLoadRecentFiles();
467 virtual void onLoadRecentProjects();
468 virtual void onLoad();
470 CompilerConfigs compilerConfigs;
471 RecentFiles recentFiles;
472 RecentWorkspaces recentProjects;
474 property bool useNewConfigurationFiles
481 settingsName = "config";
482 settingsExtension = "econ";
483 settingsDirectory = settingsDir;
488 settingsName = ideSettingsName;
489 settingsExtension = null;
490 settingsDirectory = null;
495 char moduleLocation[MAX_LOCATION];
497 FileMonitor recentFilesMonitor
499 this, fileChange = { modified = true };
501 bool OnFileNotify(FileChange action, const char * param)
504 recentFilesMonitor.StopMonitoring();
505 f = FileOpen(recentFilesMonitor.fileName, read);
510 for(c = 0; c < 10 && !(locked = f.Lock(shared, 0, 0, false)); c++) ecere::sys::Sleep(0.01);
511 recentFiles.read(this);
519 FileMonitor recentProjectsMonitor
521 this, fileChange = { modified = true };
523 bool OnFileNotify(FileChange action, const char * param)
526 recentProjectsMonitor.StopMonitoring();
527 f = FileOpen(recentProjectsMonitor.fileName, read);
532 for(c = 0; c < 10 && !(locked = f.Lock(shared, 0, 0, false)); c++) ecere::sys::Sleep(0.01);
533 if(!recentProjects) recentProjects = { };
534 recentProjects.read(this);
542 static void getConfigFilePath(char * path, Class _class, char * dir, const char * configName)
545 strcpy(path, settingsFilePath);
546 StripLastDirectory(path, path);
548 PathCatSlash(path, settingsDir);
549 if(_class == class(CompilerConfig))
551 PathCatSlash(path, "compilerConfigs");
556 PathCatSlash(path, configName);
557 strcat(path, ".econ");
560 else if(_class == class(RecentFilesData))
561 PathCatSlash(path, "recentFiles.econ");
562 else if(_class == class(RecentWorkspacesData))
563 PathCatSlash(path, "recentWorkspaces.econ");
568 FileSize settingsFileSize;
570 IDESettingsContainer()
572 char path[MAX_LOCATION];
574 LocateModule(null, moduleLocation);
575 strcpy(path, moduleLocation);
576 StripLastDirectory(moduleLocation, moduleLocation);
577 ChangeCh(moduleLocation, '\\', '/');
578 // PortableApps.com directory structure
579 if((start = strstr(path, "\\App\\EcereSDK\\bin\\ecere-ide.exe")))
581 char configFilePath[MAX_LOCATION];
582 char defaultConfigFilePath[MAX_LOCATION];
586 strcpy(configFilePath, path);
587 PathCat(configFilePath, "Data");
588 PathCat(configFilePath, ideSettingsName);
589 ChangeExtension(configFilePath, "ini", configFilePath);
591 strcpy(defaultConfigFilePath, path);
592 PathCat(defaultConfigFilePath, "App");
593 PathCat(defaultConfigFilePath, "DefaultData");
594 PathCat(defaultConfigFilePath, ideSettingsName);
595 ChangeExtension(defaultConfigFilePath, "ini", defaultConfigFilePath);
597 if(FileExists(defaultConfigFilePath))
599 if(!FileExists(configFilePath))
601 File f = FileOpen(defaultConfigFilePath, read);
602 f.CopyTo(configFilePath);
606 PathCat(path, "Data");
607 // the forced settings location will only be
608 // used if the running ide's path matches
609 // the PortableApps.com directory structure
610 // and the default ini file is found in
611 // the DefaultData directory
612 settingsLocation = path;
618 void OnAskReloadSettings()
620 FileSize newSettingsFileSize;
622 if(OpenAndLock(&newSettingsFileSize))
624 //if((double)settingsFileSize - (double)newSettingsFileSize < 2048)
629 GuiApplication app = ((GuiApplication)__thisModule.application);
631 for(w = app.desktop.firstChild; w && (!w.created || !w.visible); w = w.next);
635 MessageBox { master = w, type = ok, isModal = true,
636 creationActivation = flash,
637 text = "Global Settings Modified Externally",
638 contents = "The global settings were modified by another process and a drastic shrinking of the settings file was detected.\n"
639 "The new settings will not be loaded to prevent loss of your ide settings.\n"
640 "Please check your settings file and make sure to save this IDE's global settings if your settings file has been compromised."
646 SettingsIOResult Load()
649 SettingsIOResult result;
650 useNewConfigurationFiles = true;
651 result = GlobalSettings::Load();
652 data = (IDESettings)this.data;
654 if(result == fileNotFound || (settingsFilePath && isGlobalPath))
656 bool retryNewConfig = settingsFilePath && isGlobalPath;
660 // Need to load the data outside of main config file first
661 data.compilerConfigs.read(this);
662 data.recentFiles.read(this);
663 data.recentProjects.read(this);
665 oldConfig = true; // WARNING: This is being used with two meanings: Old format and loaded from system-wide settings
666 useNewConfigurationFiles = false;
669 settingsFilePath = null;
673 GlobalSettings::Load();
675 if(result == fileNotFound && retryNewConfig)
678 useNewConfigurationFiles = true;
679 result = GlobalSettings::Load();
682 data = (IDESettings)this.data;
685 this.data = IDESettings { };
687 *dataOwner = this.data;
689 if(result == fileNotCompatibleWithDriver)
692 OldIDESettings oldSettings { };
694 loaded = oldSettings.Load() == success;
698 data = (IDESettings)this.data;
700 for(c : oldSettings.compilerConfigs)
701 data.compilerConfigs.Add(c.Copy());
703 for(s : oldSettings.recentFiles) data.recentFiles.Add(s);
704 for(s : oldSettings.recentProjects) data.recentProjects.Add(s);
706 data.docDir = oldSettings.docDir;
707 data.ideFileDialogLocation = oldSettings.ideFileDialogLocation;
708 data.ideProjectFileDialogLocation = oldSettings.ideProjectFileDialogLocation;
709 data.useFreeCaret = oldSettings.useFreeCaret;
710 data.showLineNumbers = oldSettings.showLineNumbers;
711 data.caretFollowsScrolling = oldSettings.caretFollowsScrolling;
712 delete data.displayDriver; data.displayDriver = CopyString(oldSettings.displayDriver);
713 data.projectDefaultTargetDir = oldSettings.projectDefaultTargetDir;
714 data.projectDefaultIntermediateObjDir = oldSettings.projectDefaultIntermediateObjDir;
721 if(result == fileNotFound || !data)
723 data = (IDESettings)this.data;
724 data.useFreeCaret = false; //true;
725 data.showLineNumbers = true;
726 data.caretFollowsScrolling = false; //true;
731 FileGetSize(settingsFilePath, &settingsFileSize);
732 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
733 data.ManagePortablePaths(moduleLocation, true);
734 data.ForcePathSeparatorStyle(true);
736 if(!data.colorSchemes || !data.colorSchemes.count)
738 if(!data.colorSchemes) data.colorSchemes = { };
740 data.colorSchemes.Add(darkColorScheme); incref darkColorScheme;
741 data.colorSchemes.Add(lightColorScheme); incref lightColorScheme;
742 data.colorSchemes.Add(greenColorScheme); incref greenColorScheme;
743 data.colorSchemes.Add(grayColorScheme); incref grayColorScheme;
746 if(data.activeColorScheme)
748 for(cs : data.colorSchemes; cs.name && !strcmp(cs.name, data.activeColorScheme))
756 colorScheme = data.colorSchemes[0];
757 data.activeColorScheme = colorScheme.name;
760 // Import from previous ecereIDE settings
763 // Save first so that settingsFilePath get set up
766 data.compilerConfigs.ensureDefaults();
767 data.compilerConfigs.write(this, null);
768 data.compilerConfigs.Free();
770 data.recentFiles.write(this);
771 data.recentFiles.Free();
773 data.recentProjects.write(this);
774 data.recentProjects.Free();
779 SettingsIOResult Save()
781 SettingsIOResult result;
783 useNewConfigurationFiles = true;
784 data = (IDESettings)this.data;
785 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
786 data.ManagePortablePaths(moduleLocation, false);
787 data.ForcePathSeparatorStyle(true);
789 settingsFilePath = null;
790 result = GlobalSettings::Save();
791 if(result != success)
792 PrintLn("Error saving IDE settings");
795 if(portable && moduleLocation[0] && FileExists(moduleLocation).isDirectory)
796 data.ManagePortablePaths(moduleLocation, true);
799 FileGetSize(settingsFilePath, &settingsFileSize);
805 static Map<String, String> getCompilerConfigFilePathsByName(const char * path)
807 Map<String, String> map { };
808 FileListing fl { path, extensions = "econ" };
811 if(fl.stats.attribs.isFile)
813 char name[MAX_FILENAME];
814 char * path = CopyString(fl.path);
816 GetLastDirectory(path, name);
817 StripExtension(name);
824 static Map<String, CompilerConfig> getCompilerConfigsByName(const char * path)
826 Map<String, CompilerConfig> map { };
827 FileListing fl { path, extensions = "econ" };
830 if(fl.stats.attribs.isFile)
832 char name[MAX_FILENAME];
833 char * path = CopyString(fl.path);
835 GetLastDirectory(path, name);
836 StripExtension(name);
838 CompilerConfig ccfg = CompilerConfig::read(path);
848 static SettingsIOResult writeConfigFile(const char * path, Class dataType, void * data)
850 SettingsIOResult result = error;
851 SafeFile sf = SafeFile::open(path, write);
854 WriteECONObject(sf.file, dataType, data, 0);
860 PrintLn($"error: could not safely open file for writing configuration: ", path);
864 static SettingsIOResult readConfigFile(const char * path, Class dataType, void ** data)
866 SettingsIOResult result = error;
868 if(!FileExists(path))
869 result = fileNotFound;
870 else if((sf = SafeFile::open(path, read)))
872 JSONResult jsonResult;
874 ECONParser parser { f = sf.file };
875 sf.file.Seek(0, start);
876 jsonResult = parser.GetObject(dataType, data);
877 if(jsonResult != success)
881 if(jsonResult == success)
885 result = fileNotCompatibleWithDriver;
886 PrintLn($"error: could not parse configuration file: ", path);
897 char path[MAX_LOCATION];
898 char tmp[MAX_LOCATION];
900 SafeFile ::open(const char * path, FileOpenMode mode)
902 SafeFile result = null;
903 if(mode == write || mode == read)
905 SafeFile sf { mode = mode };
908 FileLock lockType = mode == write ? exclusive : shared;
910 strcpy(sf.path, path);
911 strcpy(sf.tmp, path);
912 strcat(sf.tmp, ".tmp");
913 if(mode == write && FileExists(sf.tmp).isFile)
918 sf.file = FileOpen(sf.tmp, readWrite);
921 sf.file = FileOpen(sf.tmp, writeRead);
925 sf.file = FileOpen(sf.tmp, readWrite);
930 sf.file = FileOpen(path, mode);
933 for(c = 0; c < 10 && !(locked = sf.file.Lock(lockType, 0, 0, false)); c++) Sleep(0.01);
937 sf.file.Seek(0, start);
940 else if(mode == write)
941 PrintLn($"warning: SafeFile::open: unable to obtain exclusive lock on temporary file for writing: ", sf.tmp);
943 PrintLn($"warning: SafeFile::open: unable to obtain shared lock on file for reading: ", path);
945 else if(mode == write)
946 PrintLn($"warning: SafeFile::open: unable to open temporary file for writing: ", sf.tmp);
948 PrintLn($"warning: SafeFile::open: unable to open file for reading: ", path);
954 PrintLn($"warning: SafeFile::open: does not yet support FileOpenMode::", mode);
960 if(file && mode == write)
963 File f = FileOpen(path, readWrite);
966 f = FileOpen(path, writeRead);
970 f = FileOpen(path, readWrite);
976 for(c = 0; c < 10 && !(locked = f.Lock(exclusive, 0,0, false)); c++) Sleep(0.01);
980 f.Unlock(0,0, false);
982 file.Unlock(0,0, false);
985 for(c = 0; c < 10; c++)
987 if(MoveFileEx(tmp, path, { true, true }))
996 PrintLn($"warning: SafeFile::sync: failed to lock file for ", mode);
1007 file.Unlock(0,0, false);
1013 class RecentFilesData
1016 RecentFiles recentFiles;
1020 if(recentFiles) recentFiles.Free();
1025 class RecentWorkspacesData
1028 RecentWorkspaces recentWorkspaces;
1030 ~RecentWorkspacesData()
1032 if(recentWorkspaces) recentWorkspaces.Free();
1033 delete recentWorkspaces;
1037 class IDESettings : GlobalSettingsData
1040 property CompilerConfigs compilerConfigs
1042 set { /*if(settingsContainer.oldConfig)*/ { if(compilerConfigs) compilerConfigs.Free(); delete compilerConfigs; if(value) compilerConfigs = value; } }
1043 get { return compilerConfigs; }
1044 isset { return false; }
1046 property RecentFiles recentFiles
1048 set { if(recentFiles) recentFiles.Free(); delete recentFiles; if(value) recentFiles = value; }
1049 get { return recentFiles; }
1050 isset { return false; }
1052 property RecentWorkspaces recentProjects
1054 set { if(recentProjects) recentProjects.Free(); delete recentProjects; if(value) recentProjects = value; }
1055 get { return recentProjects; }
1056 isset { return false; }
1058 property const char * docDir
1060 set { delete docDir; if(value && value[0]) docDir = CopyString(value); }
1061 get { return docDir ? docDir : ""; }
1062 isset { return docDir && docDir[0]; }
1064 property const char * ideFileDialogLocation
1066 set { delete ideFileDialogLocation; if(value && value[0]) ideFileDialogLocation = CopyString(value); }
1067 get { return ideFileDialogLocation ? ideFileDialogLocation : ""; }
1068 isset { return ideFileDialogLocation && ideFileDialogLocation[0]; }
1070 property const char * ideProjectFileDialogLocation
1072 set { delete ideProjectFileDialogLocation; if(value && value[0]) ideProjectFileDialogLocation = CopyString(value); }
1073 get { return ideProjectFileDialogLocation ? ideProjectFileDialogLocation : ""; }
1074 isset { return ideProjectFileDialogLocation && ideProjectFileDialogLocation[0]; }
1077 bool showLineNumbers;
1078 bool caretFollowsScrolling;
1079 char * displayDriver;
1081 // TODO: Classify settings
1082 //EditorSettings editor { };
1084 property const char * projectDefaultTargetDir
1086 set { delete projectDefaultTargetDir; if(value && value[0]) projectDefaultTargetDir = CopyValidateMakefilePath(value); }
1087 get { return projectDefaultTargetDir ? projectDefaultTargetDir : ""; }
1088 isset { return projectDefaultTargetDir && projectDefaultTargetDir[0]; }
1090 property const char * projectDefaultIntermediateObjDir
1092 set { delete projectDefaultIntermediateObjDir; if(value && value[0]) projectDefaultIntermediateObjDir = CopyValidateMakefilePath(value); }
1093 get { return projectDefaultIntermediateObjDir ? projectDefaultIntermediateObjDir : ""; }
1094 isset { return projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0]; }
1097 property const char * compilerConfigsDir
1099 set { delete compilerConfigsDir; if(value && value[0]) compilerConfigsDir = CopyString(value); }
1100 get { return compilerConfigsDir ? compilerConfigsDir : ""; }
1101 isset { return compilerConfigsDir && compilerConfigsDir[0]; }
1104 property const char * defaultCompiler
1106 set { delete defaultCompiler; if(value && value[0]) defaultCompiler = CopyString(value); }
1107 get { return defaultCompiler && defaultCompiler[0] ? defaultCompiler : defaultCompilerName; }
1108 isset { return defaultCompiler && defaultCompiler[0]; }
1111 property const String language
1116 language = CopyString(value);
1118 get { return language; }
1119 isset { return language != null; }
1122 property const String codeEditorFont
1126 delete codeEditorFont;
1127 codeEditorFont = CopyString(value);
1129 get { return codeEditorFont; }
1132 float codeEditorFontSize;
1133 bool showFixedPitchFontsOnly;
1135 property Array<IDEColorScheme> colorSchemes
1139 if(colorSchemes && colorSchemes._refCount < 2)
1140 colorSchemes.Free();
1141 delete colorSchemes;
1142 colorSchemes = value;
1144 incref colorSchemes;
1146 get { return colorSchemes; }
1149 property const String activeColorScheme
1153 delete activeColorScheme;
1154 activeColorScheme = CopyString(value);
1156 get { return activeColorScheme; }
1160 CompilerConfigs compilerConfigs { };
1162 char * ideFileDialogLocation;
1163 char * ideProjectFileDialogLocation;
1164 char * projectDefaultTargetDir;
1165 char * projectDefaultIntermediateObjDir;
1166 char * compilerConfigsDir;
1167 char * defaultCompiler;
1169 RecentFiles recentFiles { };
1170 RecentWorkspaces recentProjects { };
1172 Array<IDEColorScheme> colorSchemes;
1174 String codeEditorFont;
1176 String activeColorScheme;
1178 showFixedPitchFontsOnly = true;
1179 codeEditorFontSize = 12;
1180 codeEditorFont = CopyString("Courier New");
1184 compilerConfigs.Free();
1185 delete compilerConfigs;
1186 if(recentProjects) { recentFiles.Free(); delete recentFiles; }
1187 if(recentProjects) { recentProjects.Free(); delete recentProjects; }
1190 delete projectDefaultTargetDir;
1191 delete projectDefaultIntermediateObjDir;
1192 delete compilerConfigsDir;
1193 delete defaultCompiler;
1196 delete ideFileDialogLocation;
1197 delete ideProjectFileDialogLocation;
1198 delete displayDriver;
1200 delete codeEditorFont;
1202 colorSchemes.Free();
1203 delete activeColorScheme;
1206 void ForcePathSeparatorStyle(bool unixStyle)
1210 from = '\\', to = '/';
1212 from = '/', to = '\\';
1213 if(compilerConfigs && compilerConfigs.count)
1216 for(config : compilerConfigs)
1218 if(config.includeDirs && config.includeDirs.count)
1220 for(i = 0; i < config.includeDirs.count; i++)
1222 if(config.includeDirs[i] && config.includeDirs[i][0])
1223 ChangeCh(config.includeDirs[i], from, to);
1226 if(config.libraryDirs && config.libraryDirs.count)
1228 for(i = 0; i < config.libraryDirs.count; i++)
1230 if(config.libraryDirs[i] && config.libraryDirs[i][0])
1231 ChangeCh(config.libraryDirs[i], from, to);
1234 if(config.executableDirs && config.executableDirs.count)
1236 for(i = 0; i < config.executableDirs.count; i++)
1238 if(config.executableDirs[i] && config.executableDirs[i][0])
1239 ChangeCh(config.executableDirs[i], from, to);
1244 recentFiles.changeChar(from, to);
1245 recentProjects.changeChar(from, to);
1246 if(docDir && docDir[0])
1247 ChangeCh(docDir, from, to);
1248 if(ideFileDialogLocation && ideFileDialogLocation[0])
1249 ChangeCh(ideFileDialogLocation, from, to);
1250 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
1251 ChangeCh(ideProjectFileDialogLocation, from, to);
1253 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
1254 ChangeCh(projectDefaultTargetDir, from, to);
1255 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
1256 ChangeCh(projectDefaultIntermediateObjDir, from, to);
1258 if(compilerConfigsDir && compilerConfigsDir[0])
1259 ChangeCh(compilerConfigsDir, from, to);
1262 void ManagePortablePaths(char * location, bool makeAbsolute)
1265 if(compilerConfigs && compilerConfigs.count)
1267 for(config : compilerConfigs)
1270 for(t = 0; t < DirTypes::enumSize; t++)
1272 Array<String> dirs = null;
1273 if(t == executables) dirs = config.executableDirs;
1274 else if(t == includes) dirs = config.includeDirs;
1275 else if(t == libraries) dirs = config.libraryDirs;
1276 if(dirs && dirs.count)
1278 for(c = 0; c < dirs.count; c++)
1280 if(dirs[c] && dirs[c][0])
1281 dirs[c] = UpdatePortablePath(dirs[c], location, makeAbsolute);
1287 if(recentFiles && recentFiles.count)
1289 for(c = 0; c < recentFiles.count; c++)
1291 if(recentFiles[c] && recentFiles[c][0])
1292 recentFiles[c] = UpdatePortablePath(recentFiles[c], location, makeAbsolute);
1295 if(recentProjects && recentProjects.count)
1297 for(c = 0; c < recentProjects.count; c++)
1299 if(recentProjects[c] && recentProjects[c][0])
1300 recentProjects[c] = UpdatePortablePath(recentProjects[c], location, makeAbsolute);
1303 if(docDir && docDir[0])
1304 docDir = UpdatePortablePath(docDir, location, makeAbsolute);
1305 if(ideFileDialogLocation && ideFileDialogLocation[0])
1306 ideFileDialogLocation = UpdatePortablePath(ideFileDialogLocation, location, makeAbsolute);
1307 if(ideProjectFileDialogLocation && ideProjectFileDialogLocation[0])
1308 ideProjectFileDialogLocation = UpdatePortablePath(ideProjectFileDialogLocation, location, makeAbsolute);
1310 if(projectDefaultTargetDir && projectDefaultTargetDir[0])
1311 projectDefaultTargetDir = UpdatePortablePath(projectDefaultTargetDir, location, makeAbsolute);
1312 if(projectDefaultIntermediateObjDir && projectDefaultIntermediateObjDir[0])
1313 projectDefaultIntermediateObjDir = UpdatePortablePath(projectDefaultIntermediateObjDir, location, makeAbsolute);
1315 if(compilerConfigsDir && compilerConfigsDir[0])
1316 compilerConfigsDir = UpdatePortablePath(compilerConfigsDir, location, makeAbsolute);
1319 char * UpdatePortablePath(char * path, const char * location, bool makeAbsolute)
1324 char p[MAX_LOCATION];
1325 strcpy(p, location);
1326 PathCatSlash(p, path);
1328 output = CopyString(p);
1332 PathRelationship rel = eString_PathRelated(path, location, null);
1333 if(rel == subPath || rel == identical)
1335 char p[MAX_LOCATION];
1336 MakePathRelative(path, location, p);
1337 if(!*p) strcpy(p, "./");
1338 else ChangeCh(p, '\\', '/');
1340 output = CopyString(p);
1349 class RecentFiles : RecentPaths
1351 void read(IDESettingsContainer settingsContainer)
1353 char path[MAX_LOCATION];
1354 RecentFilesData d = null;
1355 Class _class = class(RecentFilesData);
1356 settingsContainer.getConfigFilePath(path, _class, null, null);
1357 readConfigFile(path, _class, &d);
1358 if(d && d.recentFiles && d.recentFiles.count)
1361 Copy((void *)d.recentFiles);
1362 d.recentFiles.RemoveAll();
1363 settingsContainer.recentFiles = this; // Merge IDEConfigHolder / IDESettingsContainer?
1366 settingsContainer.recentFilesMonitor.fileName = path;
1367 settingsContainer.recentFilesMonitor.StartMonitoring();
1368 settingsContainer.onLoadRecentFiles();
1371 void write(IDESettingsContainer settingsContainer)
1373 char path[MAX_LOCATION];
1374 RecentFilesData d { };
1375 Class _class = class(RecentFilesData);
1376 settingsContainer.getConfigFilePath(path, _class, null, null);
1377 d.recentFiles = this;
1378 writeConfigFile(path, _class, d);
1379 d.recentFiles = null;
1384 class RecentWorkspaces : RecentPaths
1386 void read(IDESettingsContainer settingsContainer)
1388 char path[MAX_LOCATION];
1389 RecentWorkspacesData d = null;
1390 Class _class = class(RecentWorkspacesData);
1391 settingsContainer.getConfigFilePath(path, _class, null, null);
1392 readConfigFile(path, _class, &d);
1393 if(d && d.recentWorkspaces && d.recentWorkspaces.count)
1396 Copy((void *)d.recentWorkspaces);
1397 d.recentWorkspaces.RemoveAll();
1398 settingsContainer.recentProjects = this; // Merge IDEConfigHolder / IDESettingsContainer?
1401 settingsContainer.recentProjectsMonitor.fileName = path;
1402 settingsContainer.recentProjectsMonitor.StartMonitoring();
1403 settingsContainer.onLoadRecentProjects();
1406 void write(IDESettingsContainer settingsContainer)
1408 char path[MAX_LOCATION];
1409 RecentWorkspacesData d { };
1410 Class _class = class(RecentWorkspacesData);
1411 settingsContainer.getConfigFilePath(path, _class, null, null);
1412 d.recentWorkspaces = this;
1413 writeConfigFile(path, _class, d);
1414 d.recentWorkspaces = null;
1419 class RecentPaths : Array<String>
1421 IteratorPointer Add(T value)
1424 char * filePath = (char *)value;
1425 ChangeCh(filePath, '\\', '/');
1426 for(c = 0; c < count; c++)
1428 if(this[c] && !fstrcmp(this[c], filePath))
1430 Delete((void *)&this[c]);
1434 return Array::Add((T)filePath);
1437 IteratorPointer addRecent(const String value)
1440 char * filePath = CopyString((char *)value);
1442 ChangeCh(filePath, '\\', '/');
1443 for(c = 0; c < count; c++)
1445 if(this[c] && !fstrcmp(this[c], filePath))
1447 Delete((void *)&this[c]);
1451 while(count >= MaxRecent)
1453 ip = Insert(null, filePath);
1457 void changeChar(char from, char to)
1462 for(c = 0; c < count; c++)
1464 if(this[c] && this[c][0])
1465 ChangeCh(this[c], from, to);
1471 static const char * compilerTypeNames[CompilerType] = { "GCC", "TCC", "PCC", "VS8", "VS9", "VS10" };
1472 static const char * compilerTypeVersionString[CompilerType] = { "", "", "", "8.00", "9.00", "10.00" };
1473 static const char * compilerTypeSolutionFileVersionString[CompilerType] = { "", "", "", "9.00", "10.00", "11.00" };
1474 static const char * compilerTypeYearString[CompilerType] = { "", "", "", "2005", "2008", "2010" };
1475 static const char * compilerTypeProjectFileExtension[CompilerType] = { "", "", "", "vcproj", "vcproj", "vcxproj" };
1476 // TODO: i18n with Array
1477 static Array<const String> compilerTypeLongNames
1479 $"GNU Compiler Collection (GCC) / GNU Make",
1480 $"Tiny C Compiler / GNU Make",
1481 $"Portable C Compiler / GNU Make",
1482 $"Microsoft Visual Studio 2005 (8.0) Compiler",
1483 $"Microsoft Visual Studio 2008 (9.0) Compiler",
1484 $"Microsoft Visual Studio 2010 (10.0) Compiler"
1486 const CompilerType firstCompilerType = gcc;
1487 const CompilerType lastCompilerType = vs10;
1488 public enum CompilerType
1490 gcc, tcc, pcc, vs8, vs9, vs10;
1494 get { return this == vs8 || this == vs9 || this == vs10; }
1497 property const char *
1499 get { return OnGetString(null, null, null); }
1505 for(c = firstCompilerType; c <= lastCompilerType; c++)
1506 if(!strcmpi(value, compilerTypeNames[c]))
1513 property const char * longName { get { return OnGetString(null, (void*)1, null); } };
1514 property const char * versionString { get { return OnGetString(null, (void*)2, null); } };
1515 property const char * yearString { get { return OnGetString(null, (void*)3, null); } };
1516 property const char * projectFileExtension { get { return OnGetString(null, (void*)4, null); } };
1517 property const char * solutionFileVersionString { get { return OnGetString(null, (void*)5, null); } };
1519 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
1521 if(this >= firstCompilerType && this <= lastCompilerType)
1524 strcpy(tempString, compilerTypeNames[this]);
1525 if(fieldData == null)
1526 return compilerTypeNames[this];
1527 else if(fieldData == (void*)1)
1528 return compilerTypeLongNames[this];
1529 else if(fieldData == (void*)2)
1530 return compilerTypeVersionString[this];
1531 else if(fieldData == (void*)3)
1532 return compilerTypeYearString[this];
1533 else if(fieldData == (void*)4)
1534 return compilerTypeProjectFileExtension[this];
1535 else if(fieldData == (void*)5)
1536 return compilerTypeSolutionFileVersionString[this];
1542 class CompilerConfig
1548 property const char * name
1550 set { delete name; if(value) name = CopyString(value); }
1551 get { return name; }
1555 Platform targetPlatform;
1557 property const char * makeCommand
1559 set { delete makeCommand; if(value && value[0]) makeCommand = CopyString(value); }
1560 get { return makeCommand; }
1561 isset { return makeCommand && makeCommand[0]; }
1563 property const char * ecpCommand
1565 set { delete ecpCommand; if(value && value[0]) ecpCommand = CopyString(value); }
1566 get { return ecpCommand; }
1567 isset { return ecpCommand && ecpCommand[0]; }
1569 property const char * eccCommand
1571 set { delete eccCommand; if(value && value[0]) eccCommand = CopyString(value); }
1572 get { return eccCommand; }
1573 isset { return eccCommand && eccCommand[0]; }
1575 property const char * ecsCommand
1577 set { delete ecsCommand; if(value && value[0]) ecsCommand = CopyString(value); }
1578 get { return ecsCommand; }
1579 isset { return ecsCommand && ecsCommand[0]; }
1581 property const char * earCommand
1583 set { delete earCommand; if(value && value[0]) earCommand = CopyString(value); }
1584 get { return earCommand; }
1585 isset { return earCommand && earCommand[0]; }
1587 property const char * cppCommand
1589 set { delete cppCommand; if(value && value[0]) cppCommand = CopyString(value); }
1590 get { return cppCommand; }
1591 isset { return cppCommand && cppCommand[0]; }
1593 property const char * ccCommand
1595 set { delete ccCommand; if(value && value[0]) ccCommand = CopyString(value); }
1596 get { return ccCommand; }
1597 isset { return ccCommand && ccCommand[0]; }
1599 property const char * cxxCommand
1601 set { delete cxxCommand; if(value && value[0]) cxxCommand = CopyString(value); }
1602 get { return cxxCommand; }
1603 isset { return cxxCommand && cxxCommand[0]; }
1605 property const char * arCommand
1607 set { delete arCommand; if(value && value[0]) arCommand = CopyString(value); }
1608 get { return arCommand; }
1609 isset { return arCommand && arCommand[0]; }
1611 property const char * ldCommand
1613 set { delete ldCommand; if(value && value[0]) ldCommand = CopyString(value); }
1614 get { return ldCommand; }
1615 isset { return ldCommand && ldCommand[0]; }
1617 property const char * objectFileExt
1619 set { delete objectFileExt; if(value && value[0]) objectFileExt = CopyString(value); }
1620 get { return objectFileExt && objectFileExt[0] ? objectFileExt : objectDefaultFileExt ; }
1621 isset { return objectFileExt && objectFileExt[0] && strcmp(objectFileExt, objectDefaultFileExt); }
1623 property const char * staticLibFileExt
1625 set { delete staticLibFileExt; if(value && value[0]) staticLibFileExt = CopyString(value); }
1626 get { return staticLibFileExt; }
1627 isset { return staticLibFileExt && staticLibFileExt[0]; }
1629 property const char * sharedLibFileExt
1631 set { delete sharedLibFileExt; if(value && value[0]) sharedLibFileExt = CopyString(value); }
1632 get { return sharedLibFileExt; }
1633 isset { return sharedLibFileExt && sharedLibFileExt[0]; }
1635 property const char * executableFileExt
1637 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1638 get { return executableFileExt; }
1639 isset { return executableFileExt && executableFileExt[0]; }
1641 property const char * executableLauncher
1643 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1644 get { return executableLauncher; }
1645 isset { return executableLauncher && executableLauncher[0]; }
1647 // TODO: implement CompilerConfig::windresCommand
1651 property bool supportsBitDepth { set { } get { return true; } isset { return false; } }
1653 property const char * distccHosts
1655 set { delete distccHosts; if(value && value[0]) distccHosts = CopyString(value); }
1656 get { return distccHosts; }
1657 isset { return distccHosts && distccHosts[0]; }
1659 property const char * gnuToolchainPrefix
1661 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1662 get { return gnuToolchainPrefix; }
1663 isset { return gnuToolchainPrefix && gnuToolchainPrefix[0]; }
1665 property const char * sysroot
1667 set { delete sysroot; if(value && value[0]) sysroot = CopyString(value); }
1668 get { return sysroot; }
1669 isset { return sysroot && sysroot[0]; }
1671 bool resourcesDotEar;
1673 property Array<String> includeDirs
1681 includeDirs = value;
1684 get { return includeDirs; }
1685 isset { return includeDirs.count != 0; }
1687 property Array<String> libraryDirs
1695 libraryDirs = value;
1698 get { return libraryDirs; }
1699 isset { return libraryDirs.count != 0; }
1701 property Array<String> executableDirs
1705 executableDirs.Free();
1708 delete executableDirs;
1709 executableDirs = value;
1712 get { return executableDirs; }
1713 isset { return executableDirs.count != 0; }
1715 property Array<NamedString> environmentVars
1719 environmentVars.Free();
1722 delete environmentVars;
1723 environmentVars = value;
1726 get { return environmentVars; }
1727 isset { return environmentVars.count != 0; }
1729 property Array<String> prepDirectives
1733 prepDirectives.Free();
1736 delete prepDirectives;
1737 prepDirectives = value;
1740 get { return prepDirectives; }
1741 isset { return prepDirectives.count != 0; }
1743 property Array<String> excludeLibs
1751 excludeLibs = value;
1754 get { return excludeLibs; }
1755 isset { return excludeLibs.count != 0; }
1757 property Array<String> eCcompilerFlags
1761 eCcompilerFlags.Free();
1764 delete eCcompilerFlags;
1765 eCcompilerFlags = value;
1768 get { return eCcompilerFlags; }
1769 isset { return eCcompilerFlags.count != 0; }
1771 property Array<String> compilerFlags
1775 compilerFlags.Free();
1778 delete compilerFlags;
1779 compilerFlags = value;
1782 get { return compilerFlags; }
1783 isset { return compilerFlags.count != 0; }
1785 property Array<String> cxxFlags
1796 get { return cxxFlags; }
1797 isset { return cxxFlags.count != 0; }
1799 property Array<String> linkerFlags
1807 linkerFlags = value;
1810 get { return linkerFlags; }
1811 isset { return linkerFlags.count != 0; }
1813 // json backward compatibility
1814 property const char * gccPrefix
1816 set { delete gnuToolchainPrefix; if(value && value[0]) gnuToolchainPrefix = CopyString(value); }
1817 get { return gnuToolchainPrefix; }
1818 isset { return false; }
1820 property const char * execPrefixCommand
1822 set { delete executableLauncher; if(value && value[0]) executableLauncher = CopyString(value); }
1823 get { return executableLauncher; }
1824 isset { return false; }
1826 property const char * outputFileExt
1828 set { delete executableFileExt; if(value && value[0]) executableFileExt = CopyString(value); }
1829 get { return executableFileExt; }
1830 isset { return false; }
1833 property bool hasDocumentOutput
1837 bool result = executableFileExt && executableFileExt[0] &&
1838 (!strcmpi(executableFileExt, "htm") || !strcmpi(executableFileExt, "html"));
1841 isset { return false; }
1844 Array<String> includeDirs { };
1845 Array<String> libraryDirs { };
1846 Array<String> executableDirs { };
1847 // TODO: Can JSON parse and serialize maps?
1848 //EnvironmentVariables { };
1849 Array<NamedString> environmentVars { };
1850 Array<String> prepDirectives { };
1851 Array<String> excludeLibs { };
1852 Array<String> eCcompilerFlags { };
1853 Array<String> compilerFlags { };
1854 Array<String> cxxFlags { };
1855 Array<String> linkerFlags { };
1867 char * objectFileExt;
1868 char * staticLibFileExt;
1869 char * sharedLibFileExt;
1870 char * executableFileExt;
1871 char * executableLauncher;
1873 char * gnuToolchainPrefix;
1877 struct { Array<String> includes, libraries, executables; };
1878 Array<String> dirs[DirTypes];
1893 delete objectFileExt;
1894 delete staticLibFileExt;
1895 delete sharedLibFileExt;
1896 delete executableFileExt;
1898 delete executableLauncher;
1900 delete gnuToolchainPrefix;
1902 if(environmentVars) environmentVars.Free();
1903 if(includeDirs) { includeDirs.Free(); }
1904 if(libraryDirs) { libraryDirs.Free(); }
1905 if(executableDirs) { executableDirs.Free(); }
1906 if(prepDirectives) { prepDirectives.Free(); }
1907 if(excludeLibs) { excludeLibs.Free(); }
1908 if(compilerFlags) { compilerFlags.Free(); }
1909 if(cxxFlags) { cxxFlags.Free(); }
1910 if(eCcompilerFlags) { eCcompilerFlags.Free(); }
1911 if(linkerFlags) { linkerFlags.Free(); }
1914 int OnCompare(CompilerConfig b)
1918 !(result = type.OnCompare(b.type)) &&
1919 !(result = targetPlatform.OnCompare(b.targetPlatform)) &&
1920 !(result = numJobs.OnCompare(b.numJobs)) &&
1921 !(result = ccacheEnabled.OnCompare(b.ccacheEnabled)) &&
1922 !(result = distccEnabled.OnCompare(b.distccEnabled)) &&
1923 !(result = resourcesDotEar.OnCompare(b.resourcesDotEar)) &&
1924 !(result = noStripTarget.OnCompare(b.noStripTarget))
1928 !(result = name.OnCompare(b.name)) &&
1929 !(result = ecpCommand.OnCompare(b.ecpCommand)) &&
1930 !(result = eccCommand.OnCompare(b.eccCommand)) &&
1931 !(result = ecsCommand.OnCompare(b.ecsCommand)) &&
1932 !(result = earCommand.OnCompare(b.earCommand)) &&
1933 !(result = cppCommand.OnCompare(b.cppCommand)) &&
1934 !(result = ccCommand.OnCompare(b.ccCommand)) &&
1935 !(result = cxxCommand.OnCompare(b.cxxCommand)) &&
1936 !(result = ldCommand.OnCompare(b.ldCommand)) &&
1937 !(result = arCommand.OnCompare(b.arCommand)) &&
1938 !(result = objectFileExt.OnCompare(b.objectFileExt)) &&
1939 !(result = outputFileExt.OnCompare(b.outputFileExt)) &&
1940 !(result = makeCommand.OnCompare(b.makeCommand)) &&
1941 !(result = executableLauncher.OnCompare(b.executableLauncher)) &&
1942 !(result = distccHosts.OnCompare(b.distccHosts)) &&
1943 !(result = gnuToolchainPrefix.OnCompare(b.gnuToolchainPrefix)) &&
1944 !(result = sysroot.OnCompare(b.sysroot)));
1947 !(result = includeDirs.OnCompare(b.includeDirs)) &&
1948 !(result = libraryDirs.OnCompare(b.libraryDirs)) &&
1949 !(result = executableDirs.OnCompare(b.executableDirs)) &&
1950 !(result = environmentVars.OnCompare(b.environmentVars)) &&
1951 !(result = prepDirectives.OnCompare(b.prepDirectives)) &&
1952 !(result = excludeLibs.OnCompare(b.excludeLibs)) &&
1953 !(result = cxxFlags.OnCompare(b.cxxFlags)) &&
1954 !(result = eCcompilerFlags.OnCompare(b.eCcompilerFlags)) &&
1955 !(result = compilerFlags.OnCompare(b.compilerFlags)) &&
1956 !(result = linkerFlags.OnCompare(b.linkerFlags)));
1961 CompilerConfig Copy()
1994 for(s : includeDirs) copy.includeDirs.Add(CopyString(s));
1995 for(s : libraryDirs) copy.libraryDirs.Add(CopyString(s));
1996 for(s : executableDirs) copy.executableDirs.Add(CopyString(s));
1997 for(ns : environmentVars) copy.environmentVars.Add(NamedString { name = ns.name, string = ns.string });
1998 for(s : prepDirectives) copy.prepDirectives.Add(CopyString(s));
1999 for(s : excludeLibs) copy.excludeLibs.Add(CopyString(s));
2000 for(s : compilerFlags) copy.compilerFlags.Add(CopyString(s));
2001 for(s : cxxFlags) copy.cxxFlags.Add(CopyString(s));
2002 for(s : eCcompilerFlags) copy.eCcompilerFlags.Add(CopyString(s));
2003 for(s : linkerFlags) copy.linkerFlags.Add(CopyString(s));
2009 CompilerConfig ::read(const char * path)
2011 CompilerConfig d = null;
2012 readConfigFile(path, class(CompilerConfig), &d);
2016 void write(IDESettingsContainer settingsContainer)
2018 char dir[MAX_LOCATION];
2019 char path[MAX_LOCATION];
2020 const char * settingsFilePath = settingsContainer.settingsFilePath;
2021 settingsContainer.getConfigFilePath(path, _class, dir, name);
2022 if(FileExists(settingsFilePath) && !FileExists(dir))
2025 if(!FileExists(dir))
2026 PrintLn($"Error creating compiler configs directory at ", dir, " location.");
2028 writeConfigFile(path, _class, this);
2032 class CompilerConfigs : List<CompilerConfig>
2034 CompilerConfig GetCompilerConfig(const String compilerName)
2036 const char * name = compilerName && compilerName[0] ? compilerName : defaultCompilerName;
2037 CompilerConfig compilerConfig = null;
2038 for(compiler : this)
2040 if(!strcmp(compiler.name, name))
2042 compilerConfig = compiler;
2046 if(!compilerConfig && count)
2047 compilerConfig = this[0];
2050 incref compilerConfig;
2051 if(compilerConfig._refCount == 1)
2052 incref compilerConfig;
2054 return compilerConfig;
2057 void ensureDefaults()
2059 // Ensure we have a default compiler
2060 CompilerConfig defaultCompiler = GetCompilerConfig(defaultCompilerName);
2061 if(!defaultCompiler)
2063 defaultCompiler = MakeDefaultCompiler(defaultCompilerName, true);
2064 Insert(null, defaultCompiler);
2065 defaultCompiler = null;
2067 delete defaultCompiler;
2071 if(!ccfg.ecpCommand || !ccfg.ecpCommand[0])
2072 ccfg.ecpCommand = ecpDefaultCommand;
2073 if(!ccfg.eccCommand || !ccfg.eccCommand[0])
2074 ccfg.eccCommand = eccDefaultCommand;
2075 if(!ccfg.ecsCommand || !ccfg.ecsCommand[0])
2076 ccfg.ecsCommand = ecsDefaultCommand;
2077 if(!ccfg.earCommand || !ccfg.earCommand[0])
2078 ccfg.earCommand = earDefaultCommand;
2079 if(!ccfg.cppCommand || !ccfg.cppCommand[0])
2080 ccfg.cppCommand = cppDefaultCommand;
2081 if(!ccfg.ccCommand || !ccfg.ccCommand[0])
2082 ccfg.ccCommand = ccDefaultCommand;
2083 if(!ccfg.cxxCommand || !ccfg.cxxCommand[0])
2084 ccfg.cxxCommand = cxxDefaultCommand;
2085 /*if(!ccfg.ldCommand || !ccfg.ldCommand[0])
2086 ccfg.ldCommand = ldDefaultCommand;*/
2087 if(!ccfg.arCommand || !ccfg.arCommand[0])
2088 ccfg.arCommand = arDefaultCommand;
2089 if(!ccfg.objectFileExt || !ccfg.objectFileExt[0])
2090 ccfg.objectFileExt = objectDefaultFileExt;
2091 /*if(!ccfg.staticLibFileExt || !ccfg.staticLibFileExt[0])
2092 ccfg.staticLibFileExt = staticLibDefaultFileExt;*/
2093 /*if(!ccfg.sharedLibFileExt || !ccfg.sharedLibFileExt[0])
2094 ccfg.sharedLibFileExt = sharedLibDefaultFileExt;*/
2095 /*if(!ccfg.executableFileExt || !ccfg.executableFileExt[0])
2096 ccfg.executableFileExt = outputDefaultFileExt;*/
2097 if(!ccfg._refCount) incref ccfg;
2101 AVLTree<String> getWriteRequiredList(CompilerConfigs oldConfigs)
2103 AVLTree<String> list { };
2107 for(occfg : oldConfigs; !strcmp(ccfg.name, occfg.name))
2110 if(ccfg.OnCompare(occfg))
2111 list.Add(CopyString(ccfg.name));
2115 list.Add(CopyString(ccfg.name));
2120 bool read(IDESettingsContainer settingsContainer)
2122 if(settingsContainer.settingsFilePath)
2124 char dir[MAX_LOCATION];
2125 char path[MAX_LOCATION];
2126 Class _class = class(CompilerConfig);
2127 settingsContainer.getConfigFilePath(path, _class, dir, null);
2130 AVLTree<const String> addedConfigs { };
2131 Map<String, CompilerConfig> compilerConfigsByName = getCompilerConfigsByName(dir);
2132 MapIterator<const String, CompilerConfig> it { map = compilerConfigsByName };
2134 settingsContainer.compilerConfigs = this; // Merge IDEConfigHolder / IDESettingsContainer?
2135 if(it.Index("Default", false))
2137 CompilerConfig ccfg = it.data;
2139 addedConfigs.Add(ccfg.name);
2141 for(ccfg : compilerConfigsByName)
2143 if(!addedConfigs.Find(ccfg.name))
2146 addedConfigs.Add(ccfg.name);
2149 delete addedConfigs;
2151 compilerConfigsByName.Free();
2152 delete compilerConfigsByName;
2153 settingsContainer.onLoadCompilerConfigs();
2160 void write(IDESettingsContainer settingsContainer, AVLTree<String> cfgsToWrite)
2162 char dir[MAX_LOCATION];
2163 char path[MAX_LOCATION];
2164 Map<String, String> paths;
2165 settingsContainer.getConfigFilePath(path, class(CompilerConfig), dir, null);
2166 paths = getCompilerConfigFilePathsByName(dir);
2168 MapIterator<String, String> it { map = paths };
2171 CompilerConfig ccfg = c;
2172 if(!cfgsToWrite || cfgsToWrite.Find(ccfg.name))
2173 ccfg.write(settingsContainer);
2174 if(it.Index(ccfg.name, false))
2183 const char * path = p;
2191 #if !defined(ECERE_DOCUMENTOR) && !defined(ECERE_EPJ2MAKE)
2192 struct LanguageOption
2195 const String bitmap;
2199 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
2204 void OnDisplay(Surface surface, int x, int y, int width, void * data, Alignment alignment, DataDisplayFlags flags)
2206 Bitmap icon = res ? res.bitmap : null;
2209 surface.Blit(icon, x + (16 - icon.width) / 2,y+2,0,0, icon.width, icon.height);
2210 class::OnDisplay(surface, x + w, y, width - w, null, alignment, flags);
2214 Array<LanguageOption> languages
2216 { "English", ":countryCode/gb.png", "" },
2217 { "汉语", ":countryCode/cn.png", "zh_CN" },
2218 { "Español", ":countryCode/es.png", "es" },
2219 { "Português (Brazil)", ":countryCode/br.png", "pt_BR" },
2220 { "Русский (43%)", ":countryCode/ru.png", "ru" },
2221 { "Nederlandse (13%)", ":countryCode/nl.png", "nl" },
2222 { "Tiếng Việt (12%)", ":countryCode/vn.png", "vi" },
2223 { "मराठी (10%)", ":countryCode/in.png", "mr" },
2224 { "Hebrew (8%)", ":countryCode/il.png", "he" },
2225 { "Magyar (8%)", ":countryCode/hu.png", "hu" }
2228 const String GetLanguageString()
2230 char * dot, * colon;
2231 static char lang[256];
2232 const String language = getenv("ECERE_LANGUAGE");
2233 if(!language) language = getenv("LANGUAGE");
2234 if(!language) language = getenv("LC_ALL");
2235 if(!language) language = getenv("LC_MESSAGES");
2236 if(!language) language = getenv("LANG");
2237 if(!language) language = "";
2238 if(language && (colon = strchr(language, ':')))
2240 if(lang != language)
2241 strncpy(lang, language, sizeof(lang));
2242 lang[sizeof(lang)-1] = 0;
2243 lang[colon - language] = 0;
2246 if(language && (dot = strchr(language, '.')))
2248 if(lang != language)
2249 strncpy(lang, language, sizeof(lang));
2250 lang[sizeof(lang)-1] = 0;
2251 lang[dot - language] = 0;
2257 void setEcereLanguageInWinRegEnvironment(const char * languageCode)
2261 uint16 wLanguage[256];
2265 RegCreateKeyEx(HKEY_CURRENT_USER, "Environment", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
2268 UTF8toUTF16Buffer(languageCode, wLanguage, sizeof(wLanguage) / sizeof(uint16));
2269 RegSetValueExW(key, L"ECERE_LANGUAGE", 0, REG_EXPAND_SZ, (byte *)wLanguage, (uint)(wcslen(wLanguage)+1) * 2);
2275 bool LanguageRestart(const char * code, Application app, IDESettings settings, IDESettingsContainer settingsContainer, Window ide, Window projectView, bool wait)
2277 bool restart = true;
2278 String command = null;
2279 int arg0Len = (int)strlen(app.argv[0]);
2291 for(w = ide.firstChild; w; w = w.next)
2293 if(w.isActiveClient && w.isDocument)
2295 if(!w.CloseConfirmation(true))
2304 if(!projectView.CloseConfirmation(true))
2306 if(projectView.fileName)
2308 const char * name = projectView.fileName;
2311 for(j = 0; (ch = name[j]); j++)
2312 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2316 command = new char[len + 1];
2318 strcpy(command, app.argv[0]);
2320 if(projectView.fileName)
2322 strcat(command, " ");
2324 ReplaceSpaces(command + len, projectView.fileName);
2329 for(w = ide.firstChild; w; w = w.next)
2330 if(w.isActiveClient && w.isDocument)
2331 w.modifiedDocument = false;
2332 projectView.modifiedDocument = false;
2337 for(w = ide.firstChild; w; w = w.next)
2339 if(w.isActiveClient && w.isDocument)
2341 if(!w.CloseConfirmation(true))
2348 const char * name = w.fileName;
2350 for(j = 0; (ch = name[j]); j++)
2351 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2358 command = new char[len + 1];
2359 strcpy(command, app.argv[0]);
2362 for(w = ide.firstChild; w; w = w.next)
2364 if(w.isActiveClient && w.isDocument)
2366 const char * name = w.fileName;
2369 strcat(command, " ");
2371 ReplaceSpaces(command + len, name);
2372 len = (int)strlen(command);
2379 for(w = ide.firstChild; w; w = w.next)
2380 if(w.isActiveClient && w.isDocument)
2381 w.modifiedDocument = false;
2386 settings.language = code;
2387 settingsContainer.Save();
2389 setEcereLanguageInWinRegEnvironment(code);
2391 if(eClass_IsDerived(app._class, class(GuiApplication)))
2393 GuiApplication guiApp = (GuiApplication)app;
2394 guiApp.desktop.Destroy(0);
2401 for(i = 1; i < app.argc; i++)
2403 const char * arg = app.argv[i];
2405 for(j = 0; (ch = arg[j]); j++)
2406 len += (ch == ' ' || ch == '\"' || ch == '&' || ch == '$' || ch == '(' || ch == ')') ? 2 : 1;
2409 command = new char[len + 1];
2410 strcpy(command, app.argv[0]);
2412 for(i = 1; i < app.argc; i++)
2414 strcat(command, " ");
2416 ReplaceSpaces(command + len, app.argv[i]);
2417 len = (int)strlen(command);
2423 SetEnvironment("ECERE_LANGUAGE", code);
2425 ExecuteWait(command);