1 module creator.core.path; 2 import std.path; 3 import std.process; 4 import std.file : getcwd, mkdirRecurse, exists; 5 6 private { 7 string cachedConfigDir; 8 string cachedImguiFileDir; 9 string cachedFontDir; 10 string cachedLocaleDir; 11 string inForcedConfigDir; 12 } 13 14 /** 15 The name of the folder inochi creator config gets thrown in to. 16 */ 17 enum APP_FOLDER_NAME = "inochi-creator"; 18 19 /** 20 Name of environment variable to force a configuration path 21 */ 22 enum ENV_CONFIG_PATH = "INOCHI_CONFIG_PATH"; 23 24 /** 25 Returns the app configuration directory for the platform 26 */ 27 string incGetAppConfigPath() { 28 if (cachedConfigDir) return cachedConfigDir; 29 if (inForcedConfigDir) return inForcedConfigDir; 30 string appDataDir; 31 32 // Once this function has completed cache the result. 33 scope(success) { 34 35 if (inForcedConfigDir) { 36 37 // Also make sure the folder exists 38 if (!exists(inForcedConfigDir)) { 39 mkdirRecurse(inForcedConfigDir); 40 } 41 } else { 42 cachedConfigDir = appDataDir; 43 44 // Also make sure the folder exists 45 if (!exists(cachedConfigDir)) { 46 mkdirRecurse(cachedConfigDir); 47 } 48 } 49 } 50 51 // On Windows %AppData% is used. 52 // Example: C:/Users/USERNAME/AppData/Roaming/.inochi-creatorS 53 version(Windows) { 54 appDataDir = environment.get("AppData"); 55 } 56 57 // On Linux the app data dir is in $XDG_CONFIG_DIR, $HOME/.config or $HOME 58 // Example: /home/USERNAME/.inochi-creator 59 else version(linux) { 60 appDataDir = environment.get("XDG_CONFIG_HOME"); 61 if (!appDataDir) appDataDir = buildPath(environment.get("HOME"), ".config"); 62 } 63 64 // On macOS things are thrown in to $HOME/Library/Application Support 65 // Example: /home/USERNAME/Library/Application Support/.inochi-creator 66 else version(OSX) { 67 appDataDir = environment.get("HOME"); 68 if (appDataDir) appDataDir = buildPath(appDataDir, "Library", "Application Support"); 69 } 70 71 // On other POSIX platforms just assume $HOME exists. 72 // Example: /home/USERNAME/.inochi-creator 73 else version(posix) { 74 appDataDir = environment.get("HOME"); 75 } 76 77 // Allow packagers, etc. to specify a forced config directory. 78 inForcedConfigDir = environment.get(ENV_CONFIG_PATH); 79 if (inForcedConfigDir) return inForcedConfigDir; 80 81 82 if (!appDataDir) appDataDir = getcwd(); 83 84 version(linux) { 85 86 // On linux we're using standard XDG dirs, prior we 87 // used .inochi-creator there, but that's not correct 88 // This code will ensure we still use old config if it's there. 89 // Otherwise we create config for the *correct* path 90 string fdir = buildPath(appDataDir, "."~APP_FOLDER_NAME); 91 if (!exists(fdir)) fdir = buildPath(appDataDir, APP_FOLDER_NAME); 92 appDataDir = fdir; 93 return appDataDir; 94 } else { 95 96 // On other platforms we go for .(app name) 97 appDataDir = buildPath(appDataDir, "."~APP_FOLDER_NAME); 98 return appDataDir; 99 } 100 } 101 102 /** 103 Gets the directory for an imgui config file. 104 */ 105 string incGetAppImguiConfigFile() { 106 if (cachedImguiFileDir) return cachedImguiFileDir; 107 cachedImguiFileDir = buildPath(incGetAppConfigPath(), "imgui.ini"); 108 return cachedImguiFileDir; 109 } 110 111 /** 112 Gets directory for custom fonts 113 */ 114 string incGetAppFontsPath() { 115 if (cachedFontDir) return cachedFontDir; 116 cachedFontDir = buildPath(incGetAppConfigPath(), "fonts"); 117 if (!exists(cachedFontDir)) { 118 119 // Create our font directory 120 mkdirRecurse(cachedFontDir); 121 122 // Create our font dir and install our fonts 123 import std.file : write; 124 125 write(buildPath(cachedFontDir, "OpenDyslexic.otf"), import("OpenDyslexic.otf")); 126 // TODO: Write a license file for OpenDyslexic? 127 } 128 return cachedFontDir; 129 } 130 131 /** 132 Gets directory for custom fonts 133 */ 134 string incGetAppLocalePath() { 135 if (cachedLocaleDir) return cachedLocaleDir; 136 cachedLocaleDir = buildPath(incGetAppConfigPath(), "i18n"); 137 if (!exists(cachedLocaleDir)) { 138 139 // Create our font directory 140 mkdirRecurse(cachedLocaleDir); 141 } 142 return cachedLocaleDir; 143 }