[
  {
    "path": ".gitignore",
    "content": "UE4Editor-CLionSourceCodeAccess.dylib.ready\nIntermediate\nBinaries\n"
  },
  {
    "path": "CLionSourceCodeAccess.uplugin",
    "content": "{\n\t\"FileVersion\" : 3,\n\t\"EngineVersion\" : \"4.18.0\",\n\t\"Version\" : 107,\n\t\"VersionName\" : \"1.07\",\n\t\"FriendlyName\" : \"CLion Integration\",\n\t\"Description\" : \"Allows access to source code in CLion.\",\n\t\"Category\" : \"Programming\",\n\t\"CreatedBy\" : \"dotBunny, Inc.\",\n\t\"CreatedByURL\" : \"http://dotbunny.com\",\n\t\"DocsURL\" : \"https://github.com/dotBunny/CLionSourceCodeAccess/wiki\",\n\t\"MarketplaceURL\" : \"com.epicgames.launcher://ue/marketplace/content/7a2e6de4c71a48c7b9df5f49b73e1a09\",\n\t\"SupportURL\" : \"https://github.com/dotBunny/CLionSourceCodeAccess/issues\",\n\t\"EnabledByDefault\" : true,\n\t\"CanContainContent\" : false,\n\t\"IsBetaVersion\" : false,\n\t\"Installed\" : false,\n\t\"Modules\" :\n\t[\n\t\t{\n\t\t\t\"Name\" : \"CLionSourceCodeAccess\",\n\t\t\t\"Type\" : \"Editor\",\n\t\t\t\"LoadingPhase\" : \"PostEngineInit\",\n\t\t\t\"WhitelistPlatforms\" :\n\t\t\t[\n\t\t\t\t\"Mac\",\n\t\t\t\t\"Linux\",\n\t\t\t\t\"Win64\"\n\t\t\t]\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "README.md",
    "content": "# CLionSourceCodeAccess (UE4 <= 4.18)\nA CLion Plugin for Unreal Engine\n\nThe plugin creates a fully flushed out CMakeList file for use with CLion, adding intellisense, compiler definitions, etc.\nPlease visit https://github.com/dotBunny/CLionSourceCodeAccess/wiki for information on how to install and use the plugin.\n  \nThis will be the last release of the plugin seperate from Unreal Engine. To all those in the community that helped and contributed: **Thank You!** It is because of contributions like yours that projects like this thrive and grow.\n\n# CLionSourceCodeAccess (UE4 >= 4.19)\nAs of Unreal Engine 4.19 the plugin has been merged into the UE4 source code and will be distributed with Unreal Engine. You can check it out the [repository](https://github.com/EpicGames/UnrealEngine/tree/master/Engine/Plugins/Developer/CLionSourceCodeAccess), and see some of the [changes](https://github.com/EpicGames/UnrealEngine/blob/master/Engine/Source/Programs/UnrealBuildTool/ProjectFiles/CMake/CMakefileGenerator.cs) done to UBT that made it possible.\n  \n## Mentions\n[CLion Blog](https://blog.jetbrains.com/clion/2016/10/clion-and-ue4/)  \n[UE Marketplace](https://www.unrealengine.com/marketplace/clion-integration)\n"
  },
  {
    "path": "Resources/CLion-Unreal-CodeStyle.xml",
    "content": "<code_scheme name=\"Unreal\">\n  <Objective-C>\n    <option name=\"NAMESPACE_BRACE_PLACEMENT\" value=\"2\" />\n    <option name=\"FUNCTION_BRACE_PLACEMENT\" value=\"2\" />\n    <option name=\"BLOCK_BRACE_PLACEMENT\" value=\"2\" />\n    <option name=\"SPACE_BEFORE_POINTER_IN_DECLARATION\" value=\"false\" />\n    <option name=\"SPACE_AFTER_POINTER_IN_DECLARATION\" value=\"true\" />\n    <option name=\"SPACE_BEFORE_REFERENCE_IN_DECLARATION\" value=\"false\" />\n    <option name=\"SPACE_AFTER_REFERENCE_IN_DECLARATION\" value=\"true\" />\n    <option name=\"DISCHARGED_SHORT_TERNARY_OPERATOR\" value=\"true\" />\n  </Objective-C>\n  <Objective-C-extensions>\n    <option name=\"GENERATE_INSTANCE_VARIABLES_FOR_PROPERTIES\" value=\"ASK\" />\n    <option name=\"RELEASE_STYLE\" value=\"IVAR\" />\n    <option name=\"TAG_PREFIX_OF_BLOCK_COMMENT\" value=\"AT\" />\n    <option name=\"TAG_PREFIX_OF_LINE_COMMENT\" value=\"BACK_SLASH\" />\n    <option name=\"TYPE_QUALIFIERS_PLACEMENT\" value=\"BEFORE\" />\n    <file>\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Import\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Macro\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Typedef\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Enum\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Constant\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Global\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Struct\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"FunctionPredecl\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Function\" />\n    </file>\n    <class>\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Property\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Synthesize\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"InitMethod\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"StaticMethod\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"InstanceMethod\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"DeallocMethod\" />\n    </class>\n    <extensions>\n      <pair source=\"cpp\" header=\"h\" />\n      <pair source=\"c\" header=\"h\" />\n    </extensions>\n  </Objective-C-extensions>\n  <Objective-C-extensions>\n    <option name=\"GENERATE_INSTANCE_VARIABLES_FOR_PROPERTIES\" value=\"ASK\" />\n    <option name=\"RELEASE_STYLE\" value=\"IVAR\" />\n    <option name=\"TAG_PREFIX_OF_BLOCK_COMMENT\" value=\"AT\" />\n    <option name=\"TAG_PREFIX_OF_LINE_COMMENT\" value=\"BACK_SLASH\" />\n    <option name=\"TYPE_QUALIFIERS_PLACEMENT\" value=\"BEFORE\" />\n    <file>\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Import\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Macro\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Typedef\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Enum\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Constant\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Global\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Struct\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"FunctionPredecl\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Function\" />\n    </file>\n    <class>\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Property\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Synthesize\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"InitMethod\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"StaticMethod\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"InstanceMethod\" />\n      <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"DeallocMethod\" />\n    </class>\n    <extensions>\n      <pair source=\"cpp\" header=\"h\" />\n      <pair source=\"c\" header=\"h\" />\n    </extensions>\n  </Objective-C-extensions>\n  <codeStyleSettings language=\"ObjectiveC\">\n    <option name=\"KEEP_FIRST_COLUMN_COMMENT\" value=\"false\" />\n    <option name=\"KEEP_CONTROL_STATEMENT_IN_ONE_LINE\" value=\"false\" />\n    <option name=\"BRACE_STYLE\" value=\"2\" />\n    <option name=\"CLASS_BRACE_STYLE\" value=\"2\" />\n    <option name=\"ELSE_ON_NEW_LINE\" value=\"true\" />\n    <option name=\"ALIGN_MULTILINE_CHAINED_METHODS\" value=\"true\" />\n    <option name=\"KEEP_SIMPLE_BLOCKS_IN_ONE_LINE\" value=\"false\" />\n    <option name=\"KEEP_SIMPLE_METHODS_IN_ONE_LINE\" value=\"false\" />\n    <option name=\"IF_BRACE_FORCE\" value=\"3\" />\n    <option name=\"DOWHILE_BRACE_FORCE\" value=\"3\" />\n    <option name=\"WHILE_BRACE_FORCE\" value=\"3\" />\n    <option name=\"FOR_BRACE_FORCE\" value=\"3\" />\n    <indentOptions>\n      <option name=\"USE_TAB_CHARACTER\" value=\"true\" />\n      <option name=\"SMART_TABS\" value=\"true\" />\n    </indentOptions>\n  </codeStyleSettings>\n</code_scheme>"
  },
  {
    "path": "Source/CLionSourceCodeAccess/CLionSourceCodeAccess.Build.cs",
    "content": "// Copyright 2017 dotBunny Inc. All Rights Reserved.\n\nnamespace UnrealBuildTool.Rules\n{\n\tpublic class CLionSourceCodeAccess : ModuleRules\n\t{\n        public CLionSourceCodeAccess(ReadOnlyTargetRules Target) : base(Target)\n\t\t{\n\t\t\tPrivateDependencyModuleNames.AddRange(\n\t\t\t\tnew string[]\n\t\t\t\t{\n\t\t\t\t\t\"Core\",\n\t\t\t\t\t\"SourceCodeAccess\",\n\t\t\t\t\t\"DesktopPlatform\",\n                    \"LevelEditor\",\n                    \"XmlParser\",\n                    \"HotReload\",\n\t\t\t\t}\n\t\t\t);\n\n            PublicDependencyModuleNames.AddRange(\n                new string[]\n                {\n                    \"Core\",\n                    \"Engine\",\n                    \"InputCore\",\n                    \"UnrealEd\",\n                    \"CoreUObject\",\n                    \"Slate\",\n                    \"SlateCore\",\n                    \"WorkspaceMenuStructure\",\n                    \"Projects\",\n                    \"PropertyEditor\",\n                    \"HotReload\",\n                    \"Json\",\n                }\n            );\n\n            PCHUsage = PCHUsageMode.NoSharedPCHs;\n\t\t}\n\t}\n}"
  },
  {
    "path": "Source/CLionSourceCodeAccess/Private/CLionSettings.cpp",
    "content": "// Copyright 2017 dotBunny Inc. All Rights Reserved.\n\n#include \"CLionSourceCodeAccessPrivatePCH.h\"\n#include \"CLionSettings.h\"\n\n#if PLATFORM_WINDOWS\n#include \"AllowWindowsPlatformTypes.h\"\n#endif\n\n#define LOCTEXT_NAMESPACE \"CLionSourceCodeAccessor\"\n\nUCLionSettings::UCLionSettings(const FObjectInitializer& ObjectInitializer)\n\t\t: Super(ObjectInitializer)\n{\n\n}\n\nbool UCLionSettings::CheckSettings()\n{\n#if PLATFORM_WINDOWS\n\tif (this->CLion.FilePath.IsEmpty())\n\t{\n\t\t// search from JetBrainsToolbox folder\n\t\tFString ToolboxBinPath;\n\n\t\tif (FWindowsPlatformMisc::QueryRegKey(HKEY_CURRENT_USER, TEXT(\"Software\\\\JetBrains s.r.o.\\\\JetBrainsToolbox\\\\\"), TEXT(\"\"), ToolboxBinPath)) {\n\t\t\tFPaths::NormalizeDirectoryName(ToolboxBinPath);\n\t\t\tFString PatternString(TEXT(\"(.*)/bin\"));\n\t\t\tFRegexPattern Pattern(PatternString);\n\t\t\tFRegexMatcher Matcher(Pattern, ToolboxBinPath);\n\t\t\tif (Matcher.FindNext())\n\t\t\t{\n\t\t\t\tFString ToolboxPath = Matcher.GetCaptureGroup(1);\n\n\t\t\t\tFString SettingJsonPath = FPaths::Combine(ToolboxPath, FString(\".settings.json\"));\n\t\t\t\tif (FPaths::FileExists(SettingJsonPath))\n\t\t\t\t{\n\t\t\t\t\tFString JsonStr;\n\t\t\t\t\tFFileHelper::LoadFileToString(JsonStr, *SettingJsonPath);\n\t\t\t\t\tTSharedRef<TJsonReader<TCHAR>> JsonReader = TJsonReaderFactory<TCHAR>::Create(JsonStr);\n\t\t\t\t\tTSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject());\n\t\t\t\t\tif (FJsonSerializer::Deserialize(JsonReader, JsonObject) && JsonObject.IsValid())\n\t\t\t\t\t{\n\t\t\t\t\t\tFString InstallLocation;\n\t\t\t\t\t\tif (JsonObject->TryGetStringField(TEXT(\"install_location\"), InstallLocation))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!InstallLocation.IsEmpty())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tToolboxPath = InstallLocation;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tFString CLionHome = FPaths::Combine(ToolboxPath, FString(\"apps\"), FString(\"CLion\"));\n\t\t\t\tif (FPaths::DirectoryExists(CLionHome))\n\t\t\t\t{\n\t\t\t\t\tTArray<FString> IDEPaths;\n\t\t\t\t\tIFileManager::Get().FindFilesRecursive(IDEPaths, *CLionHome, TEXT(\"clion64.exe\"), true, false);\n\t\t\t\t\tif (IDEPaths.Num() > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis->CLion.FilePath = IDEPaths[0];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (this->CLion.FilePath.IsEmpty())\n\t{\n\t\t// search from ProgID\n\t\tFString OpenCommand;\n\n\t\tif (!FWindowsPlatformMisc::QueryRegKey(HKEY_CURRENT_USER, TEXT(\"SOFTWARE\\\\Classes\\\\Applications\\\\clion64.exe\\\\shell\\\\open\\\\command\\\\\"), TEXT(\"\"), OpenCommand)) {\n\t\t\tFWindowsPlatformMisc::QueryRegKey(HKEY_LOCAL_MACHINE, TEXT(\"SOFTWARE\\\\Classes\\\\Applications\\\\clion64.exe\\\\shell\\\\open\\\\command\\\\\"), TEXT(\"\"), OpenCommand);\n\t\t}\n\n\t\tFString PatternString(TEXT(\"\\\"(.*)\\\" \\\".*\\\"\"));\n\t\tFRegexPattern Pattern(PatternString);\n\t\tFRegexMatcher Matcher(Pattern, OpenCommand);\n\t\tif (Matcher.FindNext())\n\t\t{\n\t\t\tFString IDEPath = Matcher.GetCaptureGroup(1);\n\t\t\tif (FPaths::FileExists(IDEPath))\n\t\t\t{\n\t\t\t\tthis->CLion.FilePath = IDEPath;\n\t\t\t}\n\t\t}\n\t}\n#elif PLATFORM_MAC\n\tif (this->CLion.FilePath.IsEmpty())\n\t{\n\t\tNSURL* AppURL = [[NSWorkspace sharedWorkspace] URLForApplicationWithBundleIdentifier:@\"com.jetbrains.CLion-EAP\"];\n\t\tif (AppURL != nullptr)\n\t\t{\n\t\t\tthis->CLion.FilePath = FString([AppURL path]);\n\t\t}\n\t}\n\tif (this->CLion.FilePath.IsEmpty())\n\t{\n\t\tNSURL* AppURL = [[NSWorkspace sharedWorkspace] URLForApplicationWithBundleIdentifier:@\"com.jetbrains.CLion\"];\n\t\tif (AppURL != nullptr)\n\t\t{\n\t\t\tthis->CLion.FilePath = FString([AppURL path]);\n\t\t}\n\t}\n\tif (this->Mono.FilePath.IsEmpty())\n\t{\n\t\tFString MonoPath = FPaths::Combine(*FPaths::RootDir(), TEXT(\"Engine\"), TEXT(\"Binaries\"), TEXT(\"ThirdParty\"), TEXT(\"Mono\"), TEXT(\"Mac\"), TEXT(\"bin\"), TEXT(\"mono\"));\n\t\tif (FPaths::FileExists(MonoPath))\n\t\t{\n\t\t\tthis->Mono.FilePath = MonoPath;\n\t\t}\n\t}\n\tif (this->CCompiler.FilePath.IsEmpty())\n\t{\n\t\tif (FPaths::FileExists(TEXT(\"/usr/bin/clang\")))\n\t\t{\n\t\t\tthis->CCompiler.FilePath = TEXT(\"/usr/bin/clang\");\n\t\t}\n\t}\n\tif (this->CXXCompiler.FilePath.IsEmpty())\n\t{\n\t\tif (FPaths::FileExists(TEXT(\"/usr/bin/clang++\")))\n\t\t{\n\t\t\tthis->CXXCompiler.FilePath = TEXT(\"/usr/bin/clang++\");\n\t\t}\n\t}\n#else\n\tif ( this->CLion.FilePath.IsEmpty())\n\t{\n\t\tif(FPaths::FileExists(TEXT(\"/opt/clion/bin/clion.sh\")))\n\t\t{\n\t\t\tthis->CLion.FilePath = TEXT(\"/opt/clion/bin/clion.sh\");\n\t\t}\n\t}\n\tif (this->Mono.FilePath.IsEmpty() )\n\t{\n\t\tif (FPaths::FileExists(TEXT(\"/usr/bin/mono\")))\n\t\t{\n\t\t\tthis->Mono.FilePath = TEXT(\"/usr/bin/mono\");\n\t\t}\n\t\telse if (FPaths::FileExists(TEXT(\"/opt/mono/bin/mono\")))\n\t\t{\n\t\t\tthis->Mono.FilePath = TEXT(\"/opt/mono/bin/mono\");\n\t\t}\n\t}\n\tif (this->CCompiler.FilePath.IsEmpty())\n\t{\n\t\tif(FPaths::FileExists(TEXT(\"/usr/bin/clang\")))\n\t\t{\n\t\t\tthis->CCompiler.FilePath = TEXT(\"/usr/bin/clang\");\n\t\t}\n\t}\n\tif (this->CXXCompiler.FilePath.IsEmpty())\n\t{\n\t\tif(FPaths::FileExists(TEXT(\"/usr/bin/clang++\")))\n\t\t{\n\t\t\tthis->CXXCompiler.FilePath = TEXT(\"/usr/bin/clang++\");\n\t\t}\n\t}\n\n#endif\n\n\t// Reset the setup complete before we check things\n\tthis->bSetupComplete = true;\n\n\tif (this->CLion.FilePath.IsEmpty())\n\t{\n\t\tthis->bSetupComplete = false;\n\t}\n\n#if !PLATFORM_WINDOWS\n\tif (this->Mono.FilePath.IsEmpty())\n\t{\n\t\tthis->bSetupComplete = false;\n\t}\n#endif\n\n\n\t// Update CMakeList path\n\tthis->CachedCMakeListPath = FPaths::Combine(*FPaths::ConvertRelativePathToFull(*FPaths::ProjectDir()),\n\t                                            TEXT(\"CMakeLists.txt\"));\n\n\treturn this->bSetupComplete;\n}\n\nFString UCLionSettings::GetCMakeListPath()\n{\n\treturn this->CachedCMakeListPath;\n}\n\nbool UCLionSettings::IsSetup()\n{\n\treturn this->bSetupComplete;\n}\n\n\n#if WITH_EDITOR\n\nvoid UCLionSettings::PreEditChange(UProperty* PropertyAboutToChange)\n{\n\n\tSuper::PreEditChange(PropertyAboutToChange);\n\n\t// Cache our previous values\n\tthis->PreviousCCompiler = this->CCompiler.FilePath;\n\tthis->PreviousCLion = this->CLion.FilePath;\n\tthis->PreviousCXXCompiler = this->CXXCompiler.FilePath;\n#if !PLATFORM_WINDOWS\n\tthis->PreviousMono = this->Mono.FilePath;\n#endif\n\n}\n\nvoid UCLionSettings::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)\n{\n\tconst FName MemberPropertyName = (PropertyChangedEvent.Property != nullptr)\n\t                                 ? PropertyChangedEvent.MemberProperty->GetFName() : NAME_None;\n\n\t// CLion Executable Path Check\n\tif (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UCLionSettings, CLion))\n\t{\n\t\tif (this->CLion.FilePath.IsEmpty())\n\t\t{\n\t\t\tthis->bSetupComplete = false;\n\t\t\treturn;\n\t\t}\n\n\t\tthis->CLion.FilePath = FPaths::ConvertRelativePathToFull(this->CLion.FilePath);\n\n\t\tFText FailReason;\n\n#if PLATFORM_MAC\n\t\tNSString *AppPath = [NSString stringWithUTF8String: TCHAR_TO_UTF8(*this->CLion.FilePath)];\n\t\tNSBundle *Bundle = [NSBundle bundleWithPath: AppPath];\n\t\tFString BundleId = FString([Bundle bundleIdentifier]);\n\n\t\tif (!BundleId.StartsWith(TEXT(\"com.jetbrains.CLion\"), ESearchCase::CaseSensitive))\n\t\t{\n\t\t\tFailReason = LOCTEXT(\"CLionSelectMacApp\", \"Please select the CLion app\");\n\t\t\tFMessageDialog::Open(EAppMsgType::Ok, FailReason);\n\t\t\tthis->CLion.FilePath = this->PreviousCLion;\n\t\t\treturn;\n\t\t}\n\t\tthis->CLion.FilePath = FString([Bundle executablePath]);\n#endif\n\n\t\tif (this->CLion.FilePath == this->PreviousCLion)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tif (!FPaths::ValidatePath(this->CLion.FilePath, &FailReason))\n\t\t{\n\t\t\tFMessageDialog::Open(EAppMsgType::Ok, FailReason);\n\t\t\tthis->CLion.FilePath = this->PreviousCLion;\n\t\t\tif (this->CLion.FilePath.IsEmpty())\n\t\t\t{\n\t\t\t\tthis->bSetupComplete = false;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t}\n\n#if !PLATFORM_WINDOWS\n\t// Mono Path\n\tif (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UCLionSettings, Mono))\n\t{\n\t\tif (this->Mono.FilePath.IsEmpty())\n\t\t{\n\t\t\tthis->bSetupComplete = false;\n\t\t\treturn;\n\t\t}\n\n\t\tthis->Mono.FilePath = FPaths::ConvertRelativePathToFull(this->Mono.FilePath);\n\n\t\tFText FailReason;\n\n\t\tif (this->Mono.FilePath == this->PreviousMono)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tif (!FPaths::ValidatePath(this->Mono.FilePath, &FailReason))\n\t\t{\n\t\t\tFMessageDialog::Open(EAppMsgType::Ok, FailReason);\n\t\t\tthis->Mono.FilePath = this->PreviousMono;\n\t\t\treturn;\n\t\t}\n\t}\n#endif\n\n\n\t// Check C Compiler Path\n\tif (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UCLionSettings, CCompiler))\n\t{\n\t\t// Bail out if you've wiped it out\n\t\tif (this->CCompiler.FilePath.IsEmpty())\n\t\t{\n\t\t\tthis->bRequireRefresh = true;\n\t\t\treturn;\n\t\t}\n\n\t\tthis->CCompiler.FilePath = FPaths::ConvertRelativePathToFull(this->CCompiler.FilePath);\n\n\t\tif (this->CCompiler.FilePath == this->PreviousCCompiler)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tif (!FPaths::FileExists(this->CCompiler.FilePath))\n\t\t{\n\t\t\tthis->CCompiler.FilePath = this->PreviousCCompiler;\n\t\t\treturn;\n\t\t}\n\t\tthis->bRequireRefresh = true;\n\t}\n\n\t// Check C++ Compiler Path\n\tif (MemberPropertyName == GET_MEMBER_NAME_CHECKED(UCLionSettings, CXXCompiler))\n\t{\n\t\tif (this->CXXCompiler.FilePath.IsEmpty())\n\t\t{\n\t\t\tthis->bRequireRefresh = true;\n\t\t\treturn;\n\t\t}\n\n\t\tthis->CXXCompiler.FilePath = FPaths::ConvertRelativePathToFull(this->CXXCompiler.FilePath);\n\n\t\tif (this->CXXCompiler.FilePath == this->PreviousCXXCompiler)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tif (!FPaths::FileExists(CXXCompiler.FilePath))\n\t\t{\n\t\t\tthis->CXXCompiler.FilePath = this->PreviousCXXCompiler;\n\t\t\treturn;\n\t\t}\n\t\tthis->bRequireRefresh = true;\n\t}\n\n\tthis->CheckSettings();\n}\n\n#endif\n\n\n"
  },
  {
    "path": "Source/CLionSourceCodeAccess/Private/CLionSettings.h",
    "content": "// Copyright 2017 dotBunny Inc. All Rights Reserved.\n\n#pragma once\n\n#include \"CLionSourceCodeAccessPrivatePCH.h\"\n#include \"CLionSettings.generated.h\"\n\nUCLASS(config = EditorUserSettings, defaultconfig)\n\nclass UCLionSettings : public UObject\n{\n\tGENERATED_UCLASS_BODY()\n\npublic:\n\n\t/**\n\t * Does the project files require a refresh based on changes made to the settings?\n\t */\n\tbool bRequireRefresh = false;\n\n\t/**\n\t * Check our settings, cache results and return\n\t * @return Can the plugin be used?\n\t */\n\tbool CheckSettings();\n\n\t/**\n \t* Get the cached CMakeList path.\n \t* @return CMakeList Path\n \t*/\n\tFString GetCMakeListPath();\n\n\t/**\n\t* Are the settings for the plugin complete and usable?\n\t*/\n\tbool IsSetup();\n\n\t/**\n\t * [optional] Path to a C compiler to be used in the CMakeList file.\n\t */\n\tUPROPERTY(Config, EditAnywhere, Category = \"CMake Compiler\", Meta = (DisplayName = \"C Compiler (Optional)\"))\n\tFFilePath CCompiler;\n\n\t/**\n\t * Path to CLion executable, used when needing to launch CLion.\n\t */\n\tUPROPERTY(Config, EditAnywhere, Category = \"CLion\", Meta = (DisplayName = \"CLion Executable\"))\n\tFFilePath CLion;\n\n\t/**\n\t * [optional] Path to a C++ compiler to be used in the CMakeList file.\"\n\t */\n\tUPROPERTY(Config, EditAnywhere, Category = \"CMake Compiler\", Meta = (DisplayName = \"C++ Compiler (Optional)\"))\n\tFFilePath CXXCompiler;\n\n\t/**\n\t* Target Configuration Debug\n\t*/\n\tUPROPERTY(Config, EditAnywhere, Category = \"CMake Target Configurations\", Meta = (DisplayName = \"Debug\"))\n\tbool bConfigureDebug = false;\n\n\t/**\n\t * Target Configuration DebugGame\n\t */\n\tUPROPERTY(Config, EditAnywhere, Category = \"CMake Target Configurations\", Meta = (DisplayName = \"DebugGame\"))\n\tbool bConfigureDebugGame = false;\n\n\t/**\n\t* Target Configuration Development\n\t*/\n\tUPROPERTY(Config, EditAnywhere, Category = \"CMake Target Configurations\", Meta = (DisplayName = \"Development\"))\n\tbool bConfigureDevelopment = true;\n\n\t/**\n\t * Target Configuration Shipping\n\t */\n\tUPROPERTY(Config, EditAnywhere, Category = \"CMake Target Configurations\", Meta = (DisplayName = \"Shipping\"))\n\tbool bConfigureShipping = false;\n\n\t/**\n\t * Target Configuration Test\n\t */\n\tUPROPERTY(Config, EditAnywhere, Category = \"CMake Target Configurations\", Meta = (DisplayName = \"Test\"))\n\tbool bConfigureTest = false;\n\n\t/**\n\t* General Visual Studio Code Project Files\n\t*/\n\tUPROPERTY(Config, EditAnywhere, Category = \"Visual Studio Code\", Meta = (DisplayName = \"Generate c_cpp_properties.json File\"))\n\tbool bGenerateVisualStudioCodeProject = false;\n\t\n\t/**\n\t * Include Config In Makefile\n\t */\n\tUPROPERTY(Config, EditAnywhere, Category = \"Additional Folders\", Meta = (DisplayName = \"Include Configs\"))\n\tbool bIncludeConfigs = false;\n\n\t/**\n\t * Include Plugins In Makefile\n\t */\n\tUPROPERTY(Config, EditAnywhere, Category = \"Additional Folders\", Meta = (DisplayName = \"Include Plugins\"))\n\tbool bIncludePlugins = false;\n\n\t/**\n\t * Include Shaders In Makefile\n\t */\n\tUPROPERTY(Config, EditAnywhere, Category = \"Additional Folders\", Meta = (DisplayName = \"Include Shaders\"))\n\tbool bIncludeShaders = false;\n\n\t/**\n\t * Target Project Game Editor\n\t */\n\tUPROPERTY(Config, EditAnywhere, Category = \"CMake Target Projects\", Meta = (DisplayName = \"Project Game\"))\n\tbool bProjectSpecificGame = false;\n\t/**\n\t * Target Project Specific Editor\n\t */\n\tUPROPERTY(Config, EditAnywhere, Category = \"CMake Target Projects\", Meta = (DisplayName = \"Project Editor\"))\n\tbool bProjectSpecificEditor = true;\n\n\t/**\n\t * Target Project UE4 Editor\n\t */\n\tUPROPERTY(Config, EditAnywhere, Category = \"CMake Target Projects\", Meta = (DisplayName = \"UE4 Editor\"))\n\tbool bProjectUE4Editor = false;\n\t/**\n\t * Target Project UE4 Game\n\t */\n\tUPROPERTY(Config, EditAnywhere, Category = \"CMake Target Projects\", Meta = (DisplayName = \"UE4 Game\"))\n\tbool bProjectUE4Game = false;\n\n\t// TODO: We can't !PLATFORM_WINDOWS this as UBT/UHT barfs\n\t/**\n\t * Path to the Mono executable (Required on non-Windows platforms).\n\t */\n\tUPROPERTY(Config, EditAnywhere, Category = \"Unreal Engine\", Meta = (DisplayName = \"Mono Executable (Ignore On Windows)\"))\n\tFFilePath Mono;\n\nprotected:\n#if WITH_EDITOR\n\n\tvirtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override;\n\n\tvirtual void PreEditChange(UProperty* PropertyAboutToChange) override;\n\n#endif\n\nprivate:\n\n\t/**\n\t * Cached flag to tell if all settings are present needed to use the plugin.\n\t */\n\tbool bSetupComplete = false;\n\n\t/**\n \t* A cached reference of the path to the CMakeList.txt file\n \t*/\n\tFString CachedCMakeListPath;\n\n\t/**\n     * Cached version of C Compiler location.\n     */\n\tFString PreviousCCompiler;\n\n\t/**\n     * Cached version of CLion location.\n     */\n\tFString PreviousCLion;\n\n\t/**\n     * Cached version of C++ Compiler location.\n     */\n\tFString PreviousCXXCompiler;\n\n\t/**\n\t * Cached version of Mono location.\n\t */\n\tFString PreviousMono;\n};"
  },
  {
    "path": "Source/CLionSourceCodeAccess/Private/CLionSourceCodeAccessModule.cpp",
    "content": "// Copyright 2017 dotBunny Inc. All Rights Reserved.\n\n#include \"CLionSourceCodeAccessPrivatePCH.h\"\n#include \"Runtime/Core/Public/Features/IModularFeatures.h\"\n#include \"Editor/LevelEditor/Public/LevelEditor.h\"\n#include \"ISettingsModule.h\"\n#include \"ISettingsSection.h\"\n#include \"CLionSourceCodeAccessModule.h\"\n#include \"CLionSettings.h\"\n\n#define LOCTEXT_NAMESPACE \"CLionSourceCodeAccessor\"\n\nIMPLEMENT_MODULE(FCLionSourceCodeAccessModule, CLionSourceCodeAccess);\n\nvoid FCLionSourceCodeAccessModule::AddMenuOptions(FMenuBuilder& MenuBuilder)\n{\n\tMenuBuilder.BeginSection(\"CLionMenu\", LOCTEXT(\"CLionMenuLabel\", \"CLion\"));\n\n\tMenuBuilder.AddMenuEntry(\n\t\t\tLOCTEXT(\"CLionMenuGenerateCMakeListLabel\", \"Generate CMakeList\"),\n\t\t\tLOCTEXT(\"CLionMenuGenerateCMakeListTooltip\", \"Generates the CMakeList file for the opened project.\"),\n\t\t\tFSlateIcon(),\n\t\t\tFUIAction(FExecuteAction::CreateRaw(this, &FCLionSourceCodeAccessModule::HandleGenerateProjectFiles)));\n\n\tMenuBuilder.AddMenuEntry(\n\t\t\tLOCTEXT(\"CLionMenuOpenCLionLabel\", \"Open CLion\"),\n\t\t\tLOCTEXT(\"CLionMenuOpenCLionTooltip\", \"Generates the CMakeList file, and opens CLion.\"),\n\t\t\tFSlateIcon(),\n\t\t\tFUIAction(FExecuteAction::CreateRaw(this, &FCLionSourceCodeAccessModule::HandleOpenCLion)));\n\n\tMenuBuilder.EndSection();\n}\n\nvoid FCLionSourceCodeAccessModule::HandleGenerateProjectFiles()\n{\n\tCLionSourceCodeAccessor.GenerateProjectFile();\n}\n\nvoid FCLionSourceCodeAccessModule::HandleOpenCLion()\n{\n\tCLionSourceCodeAccessor.OpenSolution();\n}\n\nvoid FCLionSourceCodeAccessModule::RegisterMenu()\n{\n\tif (FModuleManager::Get().IsModuleLoaded(\"LevelEditor\"))\n\t{\n\t\tFLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>(\n\t\t\t\tTEXT(\"LevelEditor\"));\n\n\t\tMainMenuExtender = MakeShareable(new FExtender);\n\t\tMainMenuExtender->AddMenuExtension(\"FileProject\", EExtensionHook::After, NULL,\n\t\t                                   FMenuExtensionDelegate::CreateRaw(this,\n\t\t                                                                     &FCLionSourceCodeAccessModule::AddMenuOptions));\n\n\t\tLevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MainMenuExtender);\n\t}\n\n}\n\nvoid FCLionSourceCodeAccessModule::RegisterSettings()\n{\n\tif (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>(\"Settings\"))\n\t{\n\t\tSettingsModule->RegisterSettings(\"Project\", \"Plugins\", \"CLion\", LOCTEXT(\"RuntimeSettingsName\", \"CLion\"),\n\t\t                                 LOCTEXT(\"RuntimeSettingsDescription\", \"Configure the CLion Integration\"),\n\t\t                                 GetMutableDefault<UCLionSettings>());\n\t}\n}\n\nvoid FCLionSourceCodeAccessModule::ShutdownModule()\n{\n\tCLionSourceCodeAccessor.Shutdown();\n\n\tif (UObjectInitialized())\n\t{\n\t\tthis->UnregisterSettings();\n\t}\n\n\n\t// unbind provider from editor\n\tIModularFeatures::Get().UnregisterModularFeature(TEXT(\"SourceCodeAccessor\"), &CLionSourceCodeAccessor);\n}\n\nvoid FCLionSourceCodeAccessModule::StartupModule()\n{\n\n\t// Register our custom settings\n\tthis->RegisterSettings();\n\n\t// Register our custom menu additions\n\tthis->RegisterMenu();\n\n\t// Start her up\n\tCLionSourceCodeAccessor.Startup();\n\n\t// Bind our source control provider to the editor\n\tIModularFeatures::Get().RegisterModularFeature(TEXT(\"SourceCodeAccessor\"), &CLionSourceCodeAccessor);\n}\n\nbool FCLionSourceCodeAccessModule::SupportsDynamicReloading()\n{\n\t// TODO: Until we have this all fixed up\n\treturn false;\n}\n\nvoid FCLionSourceCodeAccessModule::UnregisterSettings()\n{\n\t// Ensure to unregister all of your registered settings here, hot-reload would\n\t// otherwise yield unexpected results.\n\tif (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>(\"Settings\"))\n\t{\n\t\tSettingsModule->UnregisterSettings(\"Project\", \"CLionSettings\", \"General\");\n\t}\n}\n\n#undef LOCTEXT_NAMESPACE"
  },
  {
    "path": "Source/CLionSourceCodeAccess/Private/CLionSourceCodeAccessModule.h",
    "content": "// Copyright 2017 dotBunny Inc. All Rights Reserved.\n\n#pragma once\n\n#include \"CLionSourceCodeAccessPrivatePCH.h\"\n#include \"CLionSourceCodeAccessor.h\"\n\nclass FCLionSourceCodeAccessModule : public IModuleInterface\n{\npublic:\n\t/** IModuleInterface implementation */\n\tvirtual void StartupModule() override;\n\n\tvirtual void ShutdownModule() override;\n\n\tvirtual bool SupportsDynamicReloading() override;\n\n\tvoid AddMenuOptions(FMenuBuilder& MenuBuilder);\n\n\nprivate:\n\tTSharedPtr<FExtender> MainMenuExtender;\n\tFCLionSourceCodeAccessor CLionSourceCodeAccessor;\n\n\tvoid RegisterSettings();\n\n\tvoid RegisterMenu();\n\n\tvoid UnregisterSettings();\n\n\tvoid HandleGenerateProjectFiles();\n\n\tvoid HandleOpenCLion();\n};"
  },
  {
    "path": "Source/CLionSourceCodeAccess/Private/CLionSourceCodeAccessPrivatePCH.h",
    "content": "// Copyright 2017 dotBunny Inc. All Rights Reserved.\n\n#pragma once\n\n#include \"Core.h\"\n#include \"UnrealEd.h\"\n#include \"ModuleManager.h\"\n#include \"ISourceCodeAccessModule.h\""
  },
  {
    "path": "Source/CLionSourceCodeAccess/Private/CLionSourceCodeAccessor.cpp",
    "content": "// Copyright 2017 dotBunny, Inc. All Rights Reserved.\n\n#include \"CLionSourceCodeAccessPrivatePCH.h\"\n#include \"CLionSourceCodeAccessor.h\"\n\n#define LOCTEXT_NAMESPACE \"CLionSourceCodeAccessor\"\n\nDEFINE_LOG_CATEGORY_STATIC(LogCLionAccessor, Log, All);\n\nbool FCLionSourceCodeAccessor::AddSourceFiles(const TArray<FString>& AbsoluteSourcePaths,\n                                              const TArray<FString>& AvailableModules)\n{\n\t// There is no need to add the files to the make file because it already has wildcard searches of the necessary project folders\n\treturn true;\n}\n\nbool FCLionSourceCodeAccessor::CanAccessSourceCode() const\n{\n\treturn this->Settings->IsSetup();\n}\n\nvoid FCLionSourceCodeAccessor::GenerateProjectFile()\n{\n\n\tif (!this->Settings->IsSetup())\n\t{\n\t\tFMessageDialog::Open(EAppMsgType::Ok,\n\t\t                     LOCTEXT(\"SetupNotComplete\", \"The CLion plugin settings have not been completed.\"));\n\t\treturn;\n\t}\n\n\n\tif (!FPaths::IsProjectFilePathSet())\n\t{\n\t\tFMessageDialog::Open(EAppMsgType::Ok, LOCTEXT(\"ProjectFileNotFound\", \"A project file was not found.\"));\n\t\treturn;\n\t}\n\n\t// Due to the currently broken production of CMakeFiles in UBT, we create a CodeLite project and convert it when\n\t// a viable CMakeList generation is available this will change.\n\tif (!this->GenerateFromCodeLiteProject())\n\t{\n\t\tFMessageDialog::Open(EAppMsgType::Ok, LOCTEXT(\"ProjectGenerationFailed\", \"Unable to produce project files\"));\n\t\tthis->Settings->bRequireRefresh = true;\n\t}\n\telse\n\t{\n\t\tthis->Settings->bRequireRefresh = false;\n\t}\n}\n\nbool FCLionSourceCodeAccessor::GenerateFromCodeLiteProject()\n{\n\t// Create our progress bar dialog.\n\tFScopedSlowTask ProjectGenerationTask(21, LOCTEXT(\"StartCMakeListGeneration\", \"Starting CMakeList Generation\"));\n\tProjectGenerationTask.MakeDialog();\n\tProjectGenerationTask.EnterProgressFrame(1, LOCTEXT(\"StartCMakeListGeneration\", \"Starting CMakeList Generation\"));\n\n\t// Cache our path information\n\tFString UnrealBuildToolPath = *FPaths::ConvertRelativePathToFull(\n\t\t\t*FPaths::Combine(*FPaths::EngineDir(), TEXT(\"Binaries\"), TEXT(\"DotNET\"), TEXT(\"UnrealBuildTool.exe\")));\n\tFPaths::NormalizeFilename(UnrealBuildToolPath);\n\tFString ProjectFilePath = *FPaths::ConvertRelativePathToFull(*FPaths::GetProjectFilePath());\n\tFPaths::NormalizeFilename(ProjectFilePath);\n\tFString ProjectPath = *FPaths::ConvertRelativePathToFull(*FPaths::ProjectDir());\n\tFPaths::NormalizeFilename(ProjectPath);\n\n\t// Assign and filter our project name\n\tthis->WorkingProjectName = FPaths::GetBaseFilename(ProjectFilePath, true);\n\tFPaths::NormalizeFilename(this->WorkingProjectName);\n\n\t// Reset our working folder, just incase\n\tthis->WorkingMonoPath = \"\";\n\n\t// Start our master CMakeList file\n\tFString OutputTemplate = TEXT(\"cmake_minimum_required (VERSION 2.6)\\nproject (UE4)\\n\");\n\tOutputTemplate.Append(TEXT(\"set(CMAKE_CXX_STANDARD 11)\\n\"));\n\n  //Set Response files output\n  OutputTemplate.Append(FString::Printf(TEXT(\"\\nSET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1 CACHE BOOL \\\"\\\" FORCE)\")));\n  OutputTemplate.Append(FString::Printf(TEXT(\"\\nSET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1 CACHE BOOL \\\"\\\" FORCE)\\n\")));\n\n\t// Handle CLang++ / CLang (If Defined)\n\tif (!this->Settings->CXXCompiler.FilePath.IsEmpty())\n\t{\n\t\tOutputTemplate.Append(\n\t\t\t\tFString::Printf(TEXT(\"set(CMAKE_CXX_COMPILER \\\"%s\\\")\\n\"), *this->Settings->CXXCompiler.FilePath));\n\t}\n\tif (!this->Settings->CCompiler.FilePath.IsEmpty())\n\t{\n\t\tOutputTemplate.Append(\n\t\t\t\tFString::Printf(TEXT(\"set(CMAKE_C_COMPILER \\\"%s\\\")\\n\"), *this->Settings->CCompiler.FilePath));\n\t}\n\n\tif (this->Settings->bGenerateVisualStudioCodeProject)\n\t{\n\t\tOutputTemplate.Append(TEXT(\"set(CMAKE_EXPORT_COMPILE_COMMANDS ON)\\n\"));\n\t}\n\n\t// Add an empty line in the file, because we like organization.\n\tOutputTemplate.Append(TEXT(\"\\n\"));\n\n\t// Increase our progress\n\tProjectGenerationTask.EnterProgressFrame(10, LOCTEXT(\"GeneratingCodLiteProject\", \"Generating CodeLite Project\"));\n\n#if PLATFORM_WINDOWS\n\tconst FString BuildProjectCommand = *UnrealBuildToolPath;\n\tconst FString BuildProjectParameters = FString::Printf(TEXT(\"\\\"%s\\\" -Game \\\"%s\\\" -OnlyPublic -CodeLiteFiles -CurrentPlatform -NoShippingConfigs\"),\n\t\t\t\t\t\t\t\t\t\t\t   *ProjectFilePath,\n\t\t\t\t\t\t\t\t\t\t\t   *this->WorkingProjectName);\n#else\n\tconst FString BuildProjectCommand = *this->Settings->Mono.FilePath;\n\tconst FString BuildProjectParameters = FString::Printf(\n\t\t\tTEXT(\"\\\"%s\\\" \\\"%s\\\" -Game \\\"%s\\\" -OnlyPublic -CodeLiteFiles -CurrentPlatform -NoShippingConfigs\"),\n\t\t\t*UnrealBuildToolPath,\n\t\t\t*ProjectFilePath,\n\t\t\t*this->WorkingProjectName);\n#endif\n\n\tFProcHandle BuildProjectProcess = FPlatformProcess::CreateProc(*BuildProjectCommand, *BuildProjectParameters, true,\n\t                                                               true, false, nullptr, 0, nullptr, nullptr);\n\tif (!BuildProjectProcess.IsValid())\n\t{\n\t\tUE_LOG(LogCLionAccessor, Error, TEXT(\"Failure to run UBT [%s %s].\"), *BuildProjectCommand,\n\t\t       *BuildProjectParameters);\n\t\tFPlatformProcess::CloseProc(BuildProjectProcess);\n\t\treturn false;\n\t}\n\n\t// Wait for the process to finish before moving on\n\tFPlatformProcess::WaitForProc(BuildProjectProcess);\n\n\t// Enter next phase of generation\n\tProjectGenerationTask.EnterProgressFrame(1, LOCTEXT(\"CheckingFiles\", \"Checking Files\"));\n\n\t// Setup path for Includes files\n\tFString IncludeDirectoriesPath = FPaths::Combine(*ProjectPath, *FString::Printf(TEXT(\"%sCodeCompletionFolders.txt\"),\n\t                                                                                *this->WorkingProjectName));\n\tFPaths::NormalizeFilename(IncludeDirectoriesPath);\n\tif (!FPaths::FileExists(IncludeDirectoriesPath))\n\t{\n\t\tUE_LOG(LogCLionAccessor, Error, TEXT(\"Unable to find %s\"), *IncludeDirectoriesPath);\n\t\tProjectGenerationTask.EnterProgressFrame(9);\n\t\treturn false;\n\t}\n\n\t// Setup path for Definitions file\n\tFString DefinitionsPath = FPaths::Combine(*ProjectPath, *FString::Printf(TEXT(\"%sCodeLitePreProcessor.txt\"),\n\t                                                                         *this->WorkingProjectName));\n\tFPaths::NormalizeFilename(DefinitionsPath);\n\tif (!FPaths::FileExists(DefinitionsPath))\n\t{\n\t\tUE_LOG(LogCLionAccessor, Error, TEXT(\"Unable to find %s\"), *DefinitionsPath);\n\t\tProjectGenerationTask.EnterProgressFrame(9);\n\t\treturn false;\n\t}\n\n\t// Setup path for our master project file\n\tFString GeneratedProjectFilePath = FPaths::Combine(*ProjectPath, *FString::Printf(TEXT(\"%s.workspace\"),\n\t                                                                                  *this->WorkingProjectName));\n\tFPaths::NormalizeFilename(GeneratedProjectFilePath);\n\tif (!FPaths::FileExists(GeneratedProjectFilePath))\n\t{\n\t\tUE_LOG(LogCLionAccessor, Error, TEXT(\"Unable to find %s\"), *GeneratedProjectFilePath);\n\t\tProjectGenerationTask.EnterProgressFrame(9);\n\t\treturn false;\n\t}\n\n\t// Setup path for where we will output the sub CMake files\n\tFString ProjectFileOutputFolder = FPaths::Combine(*ProjectPath, TEXT(\"Intermediate\"), TEXT(\"ProjectFiles\"));\n\tFPaths::NormalizeFilename(ProjectFileOutputFolder);\n\tif (!FPaths::DirectoryExists(ProjectFileOutputFolder))\n\t{\n\t\tFPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*ProjectFileOutputFolder);\n\t}\n\n\tProjectGenerationTask.EnterProgressFrame(3, LOCTEXT(\"CreatingHelperCMakeFiles\", \"Creating Helper CMake Files\"));\n\n\n\t// Gather our information on include directories\n\tFString IncludeDirectoriesData;\n\tFFileHelper::LoadFileToString(IncludeDirectoriesData, *IncludeDirectoriesPath);\n\tTArray<FString> IncludeDirectoriesLines;\n\tIncludeDirectoriesData.ParseIntoArrayLines(IncludeDirectoriesLines, true);\n\n\tFString IncludeDirectoriesContent = TEXT(\"set(INCLUDE_DIRECTORIES \\n\");\n\n\t// Friendly requested helper for VS Code folks (this is not the main stay of the plugin, but it works)\n\tFString IncludeDirectoriesJSON = TEXT(\"\");\n\n\tfor (FString Line : IncludeDirectoriesLines)\n\t{\n\t\tFPaths::NormalizeFilename(Line);\n\t\tIncludeDirectoriesContent.Append(FString::Printf(TEXT(\"\\t\\\"%s\\\"\\n\"), *Line));\n\n\t\tif ( this->Settings->bGenerateVisualStudioCodeProject ) {\n\t\t\tIncludeDirectoriesJSON.Append(FString::Printf(TEXT(\"\\n\\t\\t\\t\\\"%s\\\",\"), *Line));\n\t\t}\n\t}\n\tIncludeDirectoriesContent.Append(TEXT(\")\\ninclude_directories(${INCLUDE_DIRECTORIES})\\n\"));\n\n\t// Output our Include Directories content and add an entry to the CMakeList\n\tFString IncludeDirectoriesOutputPath = FPaths::Combine(*ProjectFileOutputFolder, TEXT(\"IncludeDirectories.cmake\"));\n\tFPaths::NormalizeFilename(IncludeDirectoriesOutputPath);\n\tif (!FFileHelper::SaveStringToFile(IncludeDirectoriesContent, *IncludeDirectoriesOutputPath,\n\t                                   FFileHelper::EEncodingOptions::ForceAnsi))\n\t{\n\t\tUE_LOG(LogCLionAccessor, Error, TEXT(\"Error writing %s\"), *IncludeDirectoriesOutputPath);\n\t\treturn false;\n\t}\n\tOutputTemplate.Append(FString::Printf(TEXT(\"include(\\\"%s\\\")\\n\"), *IncludeDirectoriesOutputPath));\n\n\n\t// Output our VSCode project json file\n\tif ( this->Settings->bGenerateVisualStudioCodeProject )\n\t{\n\n\t\t// Output Path\n\t\tFString IncludeJSONOutputPath = FPaths::Combine(*ProjectPath, TEXT(\".vscode\"), TEXT(\"c_cpp_properties.json\"));\n\n\t\t// Build Content\n\t\tFString JSONOutput = TEXT(\"\");\n#if PLATFORM_MAC\n\t\tJSONOutput.Append(TEXT(\"{\\n\\t\\\"configurations\\\": [\\n\\t{\\n\\t\\t\\\"name\\\": \\\"Mac\\\",\\n\\t\\t\\\"includePath\\\": [\"));\n#elif PLATFORM_LINUX\n\t\tJSONOutput.Append(TEXT(\"{\\n\\t\\\"configurations\\\": [\\n\\t{\\n\\t\\t\\\"name\\\": \\\"Linux\\\",\\n\\t\\t\\\"includePath\\\": [\"));\n#else\n\t\tJSONOutput.Append(TEXT(\"{\\n\\t\\\"configurations\\\": [\\n\\t{\\n\\t\\t\\\"name\\\": \\\"Windows\\\",\\n\\t\\t\\\"includePath\\\": [\"));\n#endif\n\t\tIncludeDirectoriesJSON.RemoveFromEnd(TEXT(\",\"), ESearchCase::Type::IgnoreCase);\n\n\t\tJSONOutput.Append(IncludeDirectoriesJSON);\n\t\tJSONOutput.Append(TEXT(\"\\n\\t\\t\\t],\\n\\t\\t\\t\\\"browse\\\" : {\\n\\t\\t\\t\\t\\\"limitSymbolsToIncludedHeaders\\\" : true, \\n\\t\\t\\t\\t\\\"path\\\": [\"));\n\t\tJSONOutput.Append(IncludeDirectoriesJSON);\n\t\tJSONOutput.Append(TEXT(\"\\n\\t\\t\\t\\t]\\n\\t\\t\\t}\\n\\t\\t}\\n\\t]\\n}\"));\n\n\n\t\tif (!FFileHelper::SaveStringToFile(JSONOutput, *IncludeJSONOutputPath,\n\t\t                                   FFileHelper::EEncodingOptions::ForceAnsi))\n\t\t{\n\t\t\tUE_LOG(LogCLionAccessor, Error, TEXT(\"Error writing %s\"), *IncludeJSONOutputPath);\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n\t// Gather our information on definitions\n\tFString DefinitionsData;\n\tFFileHelper::LoadFileToString(DefinitionsData, *DefinitionsPath);\n\tTArray<FString> DefinitionsLines;\n\tDefinitionsData.ParseIntoArrayLines(DefinitionsLines, true);\n\n\tFString DefinitionsProcessed = TEXT(\"add_definitions(\\n\");\n\tfor (FString Line : DefinitionsLines)\n\t{\n\t\tDefinitionsProcessed.Append(FString::Printf(TEXT(\"\\t-D%s\\n\"), *Line));\n\t}\n\tDefinitionsProcessed.Append(TEXT(\")\\n\"));\n\n\t// Output our Definitions content and add an entry to the CMakeList\n\tFString DefinitionsOutputPath = FPaths::Combine(*ProjectFileOutputFolder, TEXT(\"Definitions.cmake\"));\n\tif (!FFileHelper::SaveStringToFile(DefinitionsProcessed, *DefinitionsOutputPath,\n\t                                   FFileHelper::EEncodingOptions::ForceAnsi))\n\t{\n\t\tUE_LOG(LogCLionAccessor, Error, TEXT(\"Error writing %s\"), *DefinitionsOutputPath);\n\t\treturn false;\n\t}\n\tOutputTemplate.Append(FString::Printf(TEXT(\"include(\\\"%s\\\")\\n\"), *DefinitionsOutputPath));\n\n\n\tProjectGenerationTask.EnterProgressFrame(5, LOCTEXT(\"CreatingProjectCMakeFiles\", \"Creating Project CMake Files\"));\n\n\t// Handle finding the project file (we'll use this to determine the subprojects)\n\tFXmlFile* RootGeneratedProjectFile = new FXmlFile();\n\tRootGeneratedProjectFile->LoadFile(*GeneratedProjectFilePath);\n\tconst FXmlNode* RootProjectNode = RootGeneratedProjectFile->GetRootNode();\n\tconst TArray<FXmlNode*> RootProjectNodes = RootProjectNode->GetChildrenNodes();\n\tTArray<FXmlNode*> ProjectNodes;\n\n\t// Iterate over nodes to come up with our project nodes\n\tfor (FXmlNode* Node : RootProjectNodes)\n\t{\n\t\tif (Node->GetTag() == TEXT(\"Project\"))\n\t\t{\n\t\t\tProjectNodes.Add(Node);\n\t\t}\n\t}\n\n\t//WorkspaceConfiguration (DebugGame/Development/Shipping)\n\n\t// Iterate and create projects\n\tFXmlFile* WorkingGeneratedProjectFile = new FXmlFile();\n\n\tFScopedSlowTask SubProjectGenerationTask(ProjectNodes.Num(),\n\t                                         LOCTEXT(\"StartSubProjects\", \"Generating Sub Project File\"));\n\tSubProjectGenerationTask.MakeDialog();\n\n\n\t// This is gonna function as a storage block of what we think the mono path (inside of HandleConfiguration)\n\tfor (FXmlNode* Node : ProjectNodes)\n\t{\n\t\t// Increment Progress Bar\n\t\tFString OutputProjectTemplate = \"\";\n\t\tFString SubProjectName = Node->GetAttribute(\"Name\");\n\n\t\t// Determine if we want this subproject\n\t\tif ((!this->Settings->bProjectSpecificEditor &&\n\t\t    (SubProjectName.Contains(this->WorkingProjectName) && SubProjectName.EndsWith(\"Editor\"))) ||\n\t\t    (!this->Settings->bProjectSpecificGame && SubProjectName.Equals(this->WorkingProjectName)) ||\n\t\t    (!this->Settings->bProjectUE4Editor && SubProjectName.Equals(\"UE4Editor\")) ||\n\t\t    (!this->Settings->bProjectUE4Game && SubProjectName.Equals(\"UE4Game\")))\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\n\n\t\tFString SubProjectFile = FPaths::Combine(*ProjectPath, *Node->GetAttribute(\"Path\"));\n\n\t\tSubProjectGenerationTask.EnterProgressFrame(1);\n\n\t\t// Check the project file does exist\n\t\tif (!FPaths::FileExists(SubProjectFile))\n\t\t{\n\t\t\tUE_LOG(LogCLionAccessor, Warning, TEXT(\"Cannot find %s\"), *SubProjectFile);\n\t\t\tcontinue;\n\t\t}\n\n\t\tFString ProjectFilesProcessed;\n\n\t\tWorkingGeneratedProjectFile->LoadFile(*SubProjectFile);\n\n\t\t// This is painful as we're going to have to iterate through each node/child till we have none\n\t\tFXmlNode* CurrentNode = WorkingGeneratedProjectFile->GetRootNode();\n\n\t\t// Call our recursive function to delve deep and get the data we need\n\t\tFString WorkingProjectFiles = this->GetAttributeByTagWithRestrictions(CurrentNode, TEXT(\"File\"), TEXT(\"Name\"));\n\t\tTArray<FString> WorkingProjectFilesLines;\n\t\tWorkingProjectFiles.ParseIntoArrayLines(WorkingProjectFilesLines, true);\n\n\t\tFString WorkingProjectFilesContent = TEXT(\"\");\n\t\tfor (FString Line : WorkingProjectFilesLines)\n\t\t{\n\t\t\tFPaths::NormalizeFilename(Line);\n\t\t\tWorkingProjectFilesContent.Append(FString::Printf(TEXT(\"%s\\n\"), *Line));\n\t\t}\n\n\t\t// Add file set to the project cmake file (this is so we split things up, so CLion does't have\n\t\t// any issues with the file size of one individual file.\n\t\tOutputProjectTemplate.Append(\n\t\t\t\tFString::Printf(TEXT(\"set(%s_FILES \\n%s)\\n\"), *SubProjectName, *WorkingProjectFilesContent));\n\n\t\t// Time to output this, determine the output path\n\t\tFString ProjectOutputPath = FPaths::Combine(*ProjectFileOutputFolder,\n\t\t                                            *FString::Printf(TEXT(\"%s.cmake\"), *SubProjectName));\n\t\tif (!FFileHelper::SaveStringToFile(OutputProjectTemplate, *ProjectOutputPath,\n\t\t                                   FFileHelper::EEncodingOptions::ForceAnsi))\n\t\t{\n\t\t\tUE_LOG(LogCLionAccessor, Error, TEXT(\"Error writing %s\"), *ProjectOutputPath);\n\t\t\treturn false;\n\t\t}\n\n\t\t// Add Include Of Project Files\n\t\tOutputTemplate.Append(FString::Printf(TEXT(\"include(\\\"%s\\\")\\n\"), *ProjectOutputPath));\n\n\n\t\t//Get working directory and build command\n\t\tFString CustomTargets = this->GetBuildCommands(CurrentNode, SubProjectName);\n\t\tOutputTemplate.Append(CustomTargets);\n\n\t}\n\n\tProjectGenerationTask.EnterProgressFrame(1, LOCTEXT(\"CreatingCMakeListsFile\", \"Creating CMakeLists.txt File\"));\n\n\t// Add Executable Definition To Main Template\n\tOutputTemplate.Append(\n\t\t\tFString::Printf(TEXT(\"add_executable(PleaseIgnoreMe ${%sEditor_FILES})\"), *this->WorkingProjectName));\n\n\t// Write out the file\n\tif (!FFileHelper::SaveStringToFile(OutputTemplate, *this->Settings->GetCMakeListPath(),\n\t                                   FFileHelper::EEncodingOptions::ForceAnsi))\n\t{\n\t\tUE_LOG(LogCLionAccessor, Error, TEXT(\"Error writing %s\"), *this->Settings->GetCMakeListPath());\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nFString FCLionSourceCodeAccessor::GetAttributeByTagWithRestrictions(FXmlNode* CurrentNode, const FString& Tag,\n                                                                    const FString& Attribute)\n{\n\tFString ReturnContent = \"\";\n\n\tif (CurrentNode->GetTag() == Tag)\n\t{\n\t\tReturnContent.Append(FString::Printf(TEXT(\"\\t\\\"%s\\\"\\n\"), *CurrentNode->GetAttribute(Attribute)));\n\t}\n\n\tconst TArray<FXmlNode*> childrenNodes = CurrentNode->GetChildrenNodes();\n\tfor (FXmlNode* Node : childrenNodes)\n\t{\n\t\t//Don't get files from \"Config\", \"Plugins\", \"Shaders\"\n\t\tif (Node->GetTag() == TEXT(\"VirtualDirectory\"))\n\t\t{\n\t\t\tconst FString& name = Node->GetAttribute(TEXT(\"Name\"));\n\n\t\t\tif (!this->Settings->bIncludeConfigs && name == TEXT(\"Config\"))\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!this->Settings->bIncludePlugins && name == TEXT(\"Plugins\"))\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!this->Settings->bIncludeShaders && name == TEXT(\"Shaders\"))\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tReturnContent += FCLionSourceCodeAccessor::GetAttributeByTagWithRestrictions(Node, Tag, Attribute);\n\t}\n\n\treturn ReturnContent;\n}\n\nFString FCLionSourceCodeAccessor::GetBuildCommands(FXmlNode* CurrentNode, const FString& SubprojectName)\n{\n\tFString ReturnContent = \"\";\n\n\tif (CurrentNode->GetTag() != TEXT(\"Settings\"))\n\t{\n\t\tconst TArray<FXmlNode*> childrenNodes = CurrentNode->GetChildrenNodes();\n\t\tfor (FXmlNode* Node : childrenNodes)\n\t\t{\n\t\t\tReturnContent += FCLionSourceCodeAccessor::GetBuildCommands(Node, SubprojectName);\n\t\t}\n\t}\n\telse\n\t{\n\t\tconst TArray<FXmlNode*> childrenNodes = CurrentNode->GetChildrenNodes();\n\t\tfor (FXmlNode* Node : childrenNodes)\n\t\t{\n\t\t\tif (Node->GetTag() == TEXT(\"Configuration\"))\n\t\t\t{\n\t\t\t\tReturnContent += FCLionSourceCodeAccessor::HandleConfiguration(Node, SubprojectName);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn ReturnContent;\n}\n\nFString FCLionSourceCodeAccessor::HandleConfiguration(FXmlNode* CurrentNode, const FString& SubprojectName)\n{\n\tFString ReturnContent = \"\";\n\n\tconst FString& ConfigurationName = CurrentNode->GetAttribute(TEXT(\"Name\"));\n\n\tFString WorkingDirectory = \"\";\n\tFString BuildCommand = \"\";\n\tFString CleanCommand = \"\";\n\n\tconst TArray<FXmlNode*> childrenNodes = CurrentNode->GetChildrenNodes();\n\tfor (FXmlNode* Node : childrenNodes)\n\t{\n\n\t\tif ((Node->GetTag() == TEXT(\"CustomBuild\")) && (Node->GetAttribute(TEXT(\"Enabled\")) == TEXT(\"yes\")))\n\t\t{\n\n\t\t\tconst TArray<FXmlNode*> subchildrenNodes = Node->GetChildrenNodes();\n\n\t\t\tfor (FXmlNode* subNode : subchildrenNodes)\n\t\t\t{\n\t\t\t\tif (subNode->GetTag() == TEXT(\"WorkingDirectory\"))\n\t\t\t\t{\n\t\t\t\t\tWorkingDirectory = subNode->GetContent();\n\t\t\t\t\tFPaths::NormalizeFilename(WorkingDirectory);\n\t\t\t\t}\n\n\t\t\t\tif (subNode->GetTag() == TEXT(\"BuildCommand\"))\n\t\t\t\t{\n\t\t\t\t\tBuildCommand = subNode->GetContent();\n\t\t\t\t\tFPaths::NormalizeFilename(BuildCommand);\n\t\t\t\t}\n\n\t\t\t\tif (subNode->GetTag() == TEXT(\"CleanCommand\"))\n\t\t\t\t{\n\t\t\t\t\tCleanCommand = subNode->GetContent();\n\t\t\t\t\tFPaths::NormalizeFilename(CleanCommand);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!this->WorkingMonoPath.Equals(WorkingDirectory))\n\t\t\t{ // Do this to avoid duplication in CMakeLists.txt\n\t\t\t\tReturnContent += FString::Printf(TEXT(\"\\nset(MONO_ROOT_PATH \\\"%s\\\")\\n\"), *WorkingDirectory);\n#if PLATFORM_WINDOWS\n\t\t\t\tReturnContent += FString::Printf(TEXT(\"set(BUILD cd /d \\\"${MONO_ROOT_PATH}\\\")\\n\"));\n#else\n\t\t\t\tReturnContent += FString::Printf(TEXT(\"set(BUILD cd \\\"${MONO_ROOT_PATH}\\\")\\n\"));\n#endif\n\n\t\t\t\tthis->WorkingMonoPath = WorkingDirectory;\n\t\t\t}\n\n\t\t\tif ((ConfigurationName == TEXT(\"Debug\") && !this->Settings->bConfigureDebug) ||\n\t\t\t    (ConfigurationName == TEXT(\"DebugGame\") && !this->Settings->bConfigureDebugGame) ||\n\t\t\t    (ConfigurationName == TEXT(\"Development\") && !this->Settings->bConfigureDevelopment) ||\n\t\t\t    (ConfigurationName == TEXT(\"Shipping\") && !this->Settings->bConfigureShipping) ||\n\t\t\t    (ConfigurationName == TEXT(\"Test\") && !this->Settings->bConfigureTest))\n\t\t\t{\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tReturnContent += FString::Printf(TEXT(\"\\n# Custom target for %s project, %s configuration\\n\"),\n\t\t\t\t                                 *SubprojectName, *ConfigurationName);\n\t\t\t\tReturnContent += FString::Printf(TEXT(\"add_custom_target(%s-%s ${BUILD} && %s -game -progress)\\n\"),\n\t\t\t\t                                 *SubprojectName, *ConfigurationName, *BuildCommand);\n\t\t\t\tReturnContent += FString::Printf(TEXT(\"add_custom_target(%s-%s-CLEAN ${BUILD} && %s)\\n\\n\"),\n\t\t\t\t                                 *SubprojectName, *ConfigurationName, *CleanCommand);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn ReturnContent;\n}\n\nFText FCLionSourceCodeAccessor::GetDescriptionText() const\n{\n\treturn LOCTEXT(\"CLionDisplayDesc\", \"Open source code files in CLion\");\n}\n\nFName FCLionSourceCodeAccessor::GetFName() const\n{\n\treturn FName(\"CLionSourceCodeAccessor\");\n}\n\n\nFText FCLionSourceCodeAccessor::GetNameText() const\n{\n\treturn LOCTEXT(\"CLionDisplayName\", \"CLion\");\n}\n\nbool FCLionSourceCodeAccessor::OpenFileAtLine(const FString& FullPath, int32 LineNumber, int32 ColumnNumber)\n{\n\tif (!this->Settings->IsSetup())\n\t{\n\t\tUE_LOG(LogCLionAccessor, Warning, TEXT(\"Please configure the CLion integration in your project settings.\"));\n\t\treturn false;\n\t}\n\n\tif (this->Settings->bRequireRefresh || !FPaths::FileExists(*this->Settings->GetCMakeListPath()))\n\t{\n\t\tthis->GenerateProjectFile();\n\t}\n\n\n\tconst FString Path = FString::Printf(TEXT(\"\\\"%s\\\" --line %d \\\"%s\\\"\"),\n\t                                     *FPaths::ConvertRelativePathToFull(*FPaths::ProjectDir()), LineNumber, *FullPath);\n\n\n\n\tFProcHandle Proc = FPlatformProcess::CreateProc(*this->Settings->CLion.FilePath, *Path, true, true, false, nullptr,\n\t                                                0, nullptr, nullptr);\n\tif (!Proc.IsValid())\n\t{\n\t\tUE_LOG(LogCLionAccessor, Warning, TEXT(\"Opening file (%s) at a specific line failed.\"), *Path);\n\t\tFPlatformProcess::CloseProc(Proc);\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nbool FCLionSourceCodeAccessor::OpenSolution()\n{\n\tif (!this->Settings->IsSetup())\n\t{\n\t\tUE_LOG(LogCLionAccessor, Warning, TEXT(\"Please configure the CLion integration in your project settings.\"));\n\t\treturn false;\n\t}\n\n\t// TODO: Add check for CMakeProject file, if not there generate\n\n\tif (this->Settings->bRequireRefresh)\n\t{\n\t\tthis->GenerateProjectFile();\n\t}\n\n\tif (this->Settings->bRequireRefresh || !FPaths::FileExists(*this->Settings->GetCMakeListPath()))\n\t{\n\t\tthis->GenerateProjectFile();\n\t}\n\n\tconst FString Path = FString::Printf(TEXT(\"\\\"%s\\\"\"), *FPaths::ConvertRelativePathToFull(*FPaths::ProjectDir()));\n\tif (FPlatformProcess::CreateProc(*this->Settings->CLion.FilePath, *Path, true, true, false, nullptr, 0, nullptr,\n\t                                 nullptr).IsValid())\n\t{\n\t\t// This seems to always fail no matter what we do - could be the process type? Get rid of the warning for now\n\t\t//UE_LOG(LogCLionAccessor, Warning, TEXT(\"Opening the solution failed.\"));\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool FCLionSourceCodeAccessor::OpenSolutionAtPath(const FString& InSolutionPath) {\n\t// TODO: Add check for CMakeProject file, if not there generate\n\n\tif (this->Settings->bRequireRefresh)\n\t{\n\t\tthis->GenerateProjectFile();\n\t}\n\n\tif (this->Settings->bRequireRefresh || !FPaths::FileExists(*this->Settings->GetCMakeListPath()))\n\t{\n\t\tthis->GenerateProjectFile();\n\t}\n\n\tif (FPlatformProcess::CreateProc(*this->Settings->CLion.FilePath, *InSolutionPath, true, true, false, nullptr, 0, nullptr,\n\t                                 nullptr).IsValid())\n\t{\n\t\t// This seems to always fail no matter what we do - could be the process type? Get rid of the warning for now\n\t\t//UE_LOG(LogCLionAccessor, Warning, TEXT(\"Opening the solution failed.\"));\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool FCLionSourceCodeAccessor::OpenSourceFiles(const TArray<FString>& AbsoluteSourcePaths)\n{\n\tif (!this->Settings->IsSetup())\n\t{\n\t\tUE_LOG(LogCLionAccessor, Warning, TEXT(\"Please configure the CLion integration in your project settings.\"));\n\t\treturn false;\n\t}\n\n\tif (this->Settings->bRequireRefresh || !FPaths::FileExists(*this->Settings->GetCMakeListPath()))\n\t{\n\t\tthis->GenerateProjectFile();\n\t}\n\n\n\tFString sourceFilesList = \"\";\n\n\t// Build our paths based on what unreal sends to be opened\n\tfor (const auto& SourcePath : AbsoluteSourcePaths)\n\t{\n\t\tsourceFilesList = FString::Printf(TEXT(\"%s \\\"%s\\\"\"), *sourceFilesList, *SourcePath);\n\t}\n\n\t// Trim any whitespace on our source file list\n\tsourceFilesList.TrimStartInline();\n\tsourceFilesList.TrimEndInline();\n\n\tFProcHandle Proc = FPlatformProcess::CreateProc(*this->Settings->CLion.FilePath, *sourceFilesList, true, false,\n\t                                                false, nullptr, 0, nullptr, nullptr);\n\n\tif (!Proc.IsValid())\n\t{\n\t\tUE_LOG(LogCLionAccessor, Warning, TEXT(\"Opening the source file (%s) failed.\"), *sourceFilesList);\n\t\tFPlatformProcess::CloseProc(Proc);\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nbool FCLionSourceCodeAccessor::SaveAllOpenDocuments() const\n{\n\t// TODO: Implement saving remotely?\n\treturn true;\n}\n\nbool FCLionSourceCodeAccessor::DoesSolutionExist() const\n{\n\t// TODO: check if the solution really exists\n\treturn true;\n}\n\nvoid FCLionSourceCodeAccessor::Shutdown()\n{\n\tthis->Settings = nullptr;\n}\n\nvoid FCLionSourceCodeAccessor::Startup()\n{\n\t// Get reference to our settings object\n\tthis->Settings = GetMutableDefault<UCLionSettings>();\n\n\tthis->Settings->CheckSettings();\n}\n\n#undef LOCTEXT_NAMESPACE\n"
  },
  {
    "path": "Source/CLionSourceCodeAccess/Private/CLionSourceCodeAccessor.h",
    "content": "// Copyright 2017 dotBunny Inc. All Rights Reserved.\n\n#pragma once\n\n#include \"CLionSourceCodeAccessPrivatePCH.h\"\n#include \"ISourceCodeAccessor.h\"\n#include \"XmlParser.h\"\n#include \"CLionSettings.h\"\n\nclass FCLionSourceCodeAccessor : public ISourceCodeAccessor\n{\npublic:\n\t/** ISourceCodeAccessor implementation */\n\tvirtual void RefreshAvailability() override\n\t{\n\t}\n\n\tvirtual bool CanAccessSourceCode() const override;\n\n\tvirtual FName GetFName() const override;\n\n\tvirtual FText GetNameText() const override;\n\n\tvirtual FText GetDescriptionText() const override;\n\n\tvirtual bool OpenSolution() override;\n\n\tvirtual bool OpenSolutionAtPath(const FString& InSolutionPath) override;\n\n\tvirtual bool OpenFileAtLine(const FString& FullPath, int32 LineNumber, int32 ColumnNumber = 0) override;\n\n\tvirtual bool OpenSourceFiles(const TArray<FString>& AbsoluteSourcePaths) override;\n\n\tvirtual bool\n\tAddSourceFiles(const TArray<FString>& AbsoluteSourcePaths, const TArray<FString>& AvailableModules) override;\n\n\tvirtual bool SaveAllOpenDocuments() const override;\n\n\tvirtual bool DoesSolutionExist() const override;\n\n\t/**\n\t * Frame Tick (Not Used)\n\t * @param DeltaTime of frame\n\t */\n\tvirtual void Tick(const float DeltaTime) override\n\t{\n\t}\n\n\t/**\n \t* Create the CMakeLists.txt file and all the sub *.cmake addins.\n \t*/\n\tvoid GenerateProjectFile();\n\n\t/**\n \t* Deinitialize the accessor.\n \t*/\n\tvoid Shutdown();\n\n\t/**\n\t * Initialize the accessor.\n\t */\n\tvoid Startup();\n\nprivate:\n\n\t/**\n\t * A local storage of the working Project name as we parse files\n\t */\n\tFString WorkingProjectName;\n\n\t/**\n     * A local reference to the Settings object.\n     */\n\tUCLionSettings* Settings;\n\n\t/**\n\t * A local storage of the working Mono path found while parsing files\n\t */\n\tFString WorkingMonoPath;\n\n\n\n\t/**\n\t * Instruct UnrealBuildTool to generate a CodeLite project, then convert it to CMakeList\n\t * @return Was the project generation successful?\n\t */\n\tbool GenerateFromCodeLiteProject();\n\n\t/**\n\t * Recursively search XmlNode for children namd Tag, and grab their Attribute.\n\t * @param The root XmlNode to search from.\n\t * @param The tag of the elements to uses.\n\t * @param The attribute that we want to collect.\n\t * @return A CMakeList compatible string set of the attributes.\n\t */\n\tFString GetAttributeByTagWithRestrictions(FXmlNode* CurrentNode, const FString& Tag, const FString& Attribute);\n\n\tFString GetBuildCommands(FXmlNode* CurrentNode, const FString& SubprojectName);\n\n\tFString HandleConfiguration(FXmlNode* CurrentNode, const FString& SubprojectName);\n};"
  }
]