From 98116801dccb018a1001201afc621a0442128c6a Mon Sep 17 00:00:00 2001 From: xuyanghuang Date: Tue, 15 Mar 2022 01:38:26 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=EF=BC=9AIntelliSense?= =?UTF-8?q?=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BlueprintIntelliSenseGenerator.cpp | 506 +++--------------- .../UnLuaEditor/Private/UnLuaIntelliSense.cpp | 351 ++++++++++++ .../Public/BlueprintIntelliSenseGenerator.h | 27 +- .../UnLuaEditor/Public/UnLuaIntelliSense.h | 39 ++ .../Private/UnLuaIntelliSense.cpp | 43 +- .../UnLuaIntelliSense.Build.cs | 5 +- TPSProject.sln.DotSettings | 1 + 7 files changed, 488 insertions(+), 484 deletions(-) create mode 100644 Plugins/UnLua/Source/UnLuaEditor/Private/UnLuaIntelliSense.cpp create mode 100644 Plugins/UnLua/Source/UnLuaEditor/Public/UnLuaIntelliSense.h diff --git a/Plugins/UnLua/Source/UnLuaEditor/Private/BlueprintIntelliSenseGenerator.cpp b/Plugins/UnLua/Source/UnLuaEditor/Private/BlueprintIntelliSenseGenerator.cpp index 2fb3b86e..b9665db3 100644 --- a/Plugins/UnLua/Source/UnLuaEditor/Private/BlueprintIntelliSenseGenerator.cpp +++ b/Plugins/UnLua/Source/UnLuaEditor/Private/BlueprintIntelliSenseGenerator.cpp @@ -15,486 +15,148 @@ #include "BlueprintIntelliSenseGenerator.h" #include "AssetRegistryModule.h" #include "CoreUObject.h" -#include "ObjectEditorUtils.h" #include "ToolMenus.h" +#include "UnLua.h" +#include "UnLuaIntelliSense.h" #include "WidgetBlueprint.h" #include "Blueprint/WidgetTree.h" -#include "Components/Widget.h" #include "Engine/Blueprint.h" #include "Interfaces/IPluginManager.h" -#include "Kismet2/BlueprintEditorUtils.h" #define LOCTEXT_NAMESPACE "BlueprintIntelliSenseGenerator" -static const FName NAME_ToolTip(TEXT("ToolTip")); // key of ToolTip meta data -static const FName NAME_LatentInfo = TEXT("LatentInfo"); // tag of latent function - TSharedPtr FBlueprintIntelliSenseGenerator::Singleton; TSharedRef FBlueprintIntelliSenseGenerator::Get() { - if (!Singleton.IsValid()) - Singleton = MakeShareable(new FBlueprintIntelliSenseGenerator); - return Singleton.ToSharedRef(); + if (!Singleton.IsValid()) + Singleton = MakeShareable(new FBlueprintIntelliSenseGenerator); + return Singleton.ToSharedRef(); } void FBlueprintIntelliSenseGenerator::Initialize() { - if (bInitialized) - return; - - OutputDir = IPluginManager::Get().FindPlugin("UnLua")->GetBaseDir() + "/Intermediate/"; - - FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); - AssetRegistryModule.Get().OnAssetAdded().AddRaw(this, &FBlueprintIntelliSenseGenerator::OnAssetAdded); - AssetRegistryModule.Get().OnAssetRemoved().AddRaw(this, &FBlueprintIntelliSenseGenerator::OnAssetRemoved); - AssetRegistryModule.Get().OnAssetRenamed().AddRaw(this, &FBlueprintIntelliSenseGenerator::OnAssetRenamed); - AssetRegistryModule.Get().OnAssetUpdated().AddRaw(this, &FBlueprintIntelliSenseGenerator::OnAssetUpdated); - - bInitialized = true; -} - -void FBlueprintIntelliSenseGenerator::UpdateAll() -{ - FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); - - FARFilter Filter; - Filter.ClassNames.Add(UBlueprint::StaticClass()->GetFName()); - Filter.ClassNames.Add(UWidgetBlueprint::StaticClass()->GetFName()); + if (bInitialized) + return; - TArray BlueprintList; + OutputDir = IPluginManager::Get().FindPlugin("UnLua")->GetBaseDir() + "/Intermediate/"; - if (AssetRegistryModule.Get().GetAssets(Filter, BlueprintList)) - { - FScopedSlowTask SlowTask(BlueprintList.Num(), LOCTEXT("GeneratingBlueprintsIntelliSense", "Generating Blueprints InstelliSense")); - SlowTask.MakeDialog(); + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); + AssetRegistryModule.Get().OnAssetAdded().AddRaw(this, &FBlueprintIntelliSenseGenerator::OnAssetAdded); + AssetRegistryModule.Get().OnAssetRemoved().AddRaw(this, &FBlueprintIntelliSenseGenerator::OnAssetRemoved); + AssetRegistryModule.Get().OnAssetRenamed().AddRaw(this, &FBlueprintIntelliSenseGenerator::OnAssetRenamed); + AssetRegistryModule.Get().OnAssetUpdated().AddRaw(this, &FBlueprintIntelliSenseGenerator::OnAssetUpdated); - for (int32 i = 0; i < BlueprintList.Num(); i++) - { - if (SlowTask.ShouldCancel()) - break; - OnAssetUpdated(BlueprintList[i]); - SlowTask.EnterProgressFrame(); - } - } - - //Register BP add/remove/update callbacks - BPVariablesMap.Reset(); - BPFunctionMap.Reset(); + bInitialized = true; } -void FBlueprintIntelliSenseGenerator::ExportBPFunctions(const UBlueprint* Blueprint) +void FBlueprintIntelliSenseGenerator::UpdateAll() { - FString BPName = Blueprint->GetName(); - TArray& FunctionArr = BPFunctionMap.FindOrAdd(BPName); - - // Cache potentially overridable functions - UClass* ParentClass = *Blueprint->ParentClass; - for (TFieldIterator FunctionIt(ParentClass, EFieldIteratorFlags::IncludeSuper); FunctionIt; ++FunctionIt) - { - const UFunction* Function = *FunctionIt; - if (UEdGraphSchema_K2::CanKismetOverrideFunction(Function) - && !FObjectEditorUtils::IsFunctionHiddenFromClass(Function, ParentClass) - && !FBlueprintEditorUtils::FindOverrideForFunction(Blueprint, CastChecked(Function->GetOuter()), Function->GetFName())) - { - FunctionArr.Add(GetFunctionStr(Function, BPName)); - } - } + FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); - // Also functions implemented from interfaces - for (int32 i = 0; i < Blueprint->ImplementedInterfaces.Num(); i++) - { - const FBPInterfaceDescription& InterfaceDesc = Blueprint->ImplementedInterfaces[i]; - const UClass* InterfaceClass = InterfaceDesc.Interface.Get(); - if (InterfaceClass) - { - for (TFieldIterator FunctionIt(InterfaceClass, EFieldIteratorFlags::IncludeSuper); FunctionIt; ++FunctionIt) - { - const UFunction* Function = *FunctionIt; - FunctionArr.Add(GetFunctionStr(Function, BPName)); - } - } - } + FARFilter Filter; + Filter.ClassNames.Add(UBlueprint::StaticClass()->GetFName()); + Filter.ClassNames.Add(UWidgetBlueprint::StaticClass()->GetFName()); - // Grab functions implemented by the blueprint - for (UEdGraph* Graph : Blueprint->FunctionGraphs) - { - check(Graph); - if (Blueprint->SkeletonGeneratedClass != nullptr) - { - const UFunction* Function = Blueprint->SkeletonGeneratedClass->FindFunctionByName(Graph->GetFName()); - if (Function != nullptr) - { - FunctionArr.Add(GetFunctionStr(Function, BPName)); - } - } - } -} - -void FBlueprintIntelliSenseGenerator::ExportBPSyntax(const UBlueprint* Blueprint) -{ - FString BPName = Blueprint->GetName(); - TArray& VarArr = BPVariablesMap.FindOrAdd(BPName); - VarArr.Reset(); + TArray BlueprintList; - ExportBPFunctions(Blueprint); + if (AssetRegistryModule.Get().GetAssets(Filter, BlueprintList)) + { + FScopedSlowTask SlowTask(BlueprintList.Num(), LOCTEXT("GeneratingBlueprintsIntelliSense", "Generating Blueprints InstelliSense")); + SlowTask.MakeDialog(); - //export variables - for (const FBPVariableDescription& VarDesc : Blueprint->NewVariables) - { - //UE_LOG(LogTemp, Warning, TEXT("variable name is %s"), *VarDesc.VarName.ToString()); - VarArr.Add(VarDesc.VarName.ToString() + FString(" ") + VarDesc.VarType.PinCategory.ToString()); - } - - //export extra widget variables for UWidgetBlueprint - const UWidgetBlueprint* WidgetBlueprint = Cast(Blueprint); - if (WidgetBlueprint) - { - ExportWidgetBPSyntax(WidgetBlueprint); - } - ExportSyntaxToFile(BPName); + for (int32 i = 0; i < BlueprintList.Num(); i++) + { + if (SlowTask.ShouldCancel()) + break; + OnAssetUpdated(BlueprintList[i]); + SlowTask.EnterProgressFrame(); + } + } } -void FBlueprintIntelliSenseGenerator::ExportWidgetBPSyntax(const UWidgetBlueprint* WidgetBlueprint) +bool FBlueprintIntelliSenseGenerator::IsBlueprint(const FAssetData& AssetData) { - //export widget variables - FString BPName = WidgetBlueprint->GetName(); - TArray& VarArr = BPVariablesMap.FindOrAdd(BPName); - WidgetBlueprint->WidgetTree->ForEachWidget([this, &VarArr](const UWidget* Widget) - { - if (Widget->bIsVariable) - { - //UE_LOG(LogTemp, Warning, TEXT("Widget name is %s %s"), *Widget->GetClass()->GetName(), *Widget->GetName()); - VarArr.Add(*Widget->GetName() + FString(" U") + Widget->GetClass()->GetName()); - } - }); + const FName AssetClass = AssetData.AssetClass; + return AssetClass == UBlueprint::StaticClass()->GetFName() || AssetClass == UWidgetBlueprint::StaticClass()->GetFName(); } -void FBlueprintIntelliSenseGenerator::ExportSyntaxToFile(const FString& BPName) +void FBlueprintIntelliSenseGenerator::Export(const UBlueprint* Blueprint) { - FString content = ""; - content += "---@class " + BPName + "\r\n"; - TArray& VarArr = BPVariablesMap.FindOrAdd(BPName); - TArray& FuncArr = BPFunctionMap.FindOrAdd(BPName); - - for (FString Var : VarArr) - { - content += "---@field public " + Var + "\r\n"; - } - content += "local M = {}\r\n\r\n"; - - for (FString Func : FuncArr) - { - content += Func + "\r\n"; - } - - content += "return M"; - - SaveFile(FString("Blueprints"), BPName, content); + FString BPName = Blueprint->GetName(); + FString Content = UnLua::IntelliSense::Get(Blueprint); + SaveFile(FString("Blueprints"), BPName, Content); } void FBlueprintIntelliSenseGenerator::SaveFile(const FString& ModuleName, const FString& FileName, const FString& GeneratedFileContent) { - IFileManager& FileManager = IFileManager::Get(); - FString Directory = FString::Printf(TEXT("%sIntelliSense/%s"), *OutputDir, *ModuleName); - if (!FileManager.DirectoryExists(*Directory)) - { - FileManager.MakeDirectory(*Directory); - } + IFileManager& FileManager = IFileManager::Get(); + FString Directory = FString::Printf(TEXT("%sIntelliSense/%s"), *OutputDir, *ModuleName); + if (!FileManager.DirectoryExists(*Directory)) + { + FileManager.MakeDirectory(*Directory); + } - const FString FilePath = FString::Printf(TEXT("%s/%s.lua"), *Directory, *FileName); - FString FileContent; - FFileHelper::LoadFileToString(FileContent, *FilePath); - if (FileContent != GeneratedFileContent) - { - bool bResult = FFileHelper::SaveStringToFile(GeneratedFileContent, *FilePath); - //check(bResult); - } + const FString FilePath = FString::Printf(TEXT("%s/%s.lua"), *Directory, *FileName); + FString FileContent; + FFileHelper::LoadFileToString(FileContent, *FilePath); + if (FileContent != GeneratedFileContent) + { + bool bResult = FFileHelper::SaveStringToFile(GeneratedFileContent, *FilePath); + //check(bResult); + } } void FBlueprintIntelliSenseGenerator::DeleteFile(const FString& ModuleName, const FString& FileName) { - IFileManager& FileManager = IFileManager::Get(); - FString Directory = FString::Printf(TEXT("%sIntelliSense/%s"), *OutputDir, *ModuleName); - if (!FileManager.DirectoryExists(*Directory)) - { - FileManager.MakeDirectory(*Directory); - } - const FString FilePath = FString::Printf(TEXT("%s/%s.lua"), *Directory, *FileName); - if (FileManager.FileExists(*FilePath)) - { - FileManager.Delete(*FilePath); - } + IFileManager& FileManager = IFileManager::Get(); + FString Directory = FString::Printf(TEXT("%sIntelliSense/%s"), *OutputDir, *ModuleName); + if (!FileManager.DirectoryExists(*Directory)) + { + FileManager.MakeDirectory(*Directory); + } + const FString FilePath = FString::Printf(TEXT("%s/%s.lua"), *Directory, *FileName); + if (FileManager.FileExists(*FilePath)) + { + FileManager.Delete(*FilePath); + } } void FBlueprintIntelliSenseGenerator::OnAssetAdded(const FAssetData& AssetData) { - OnAssetUpdated(AssetData); + OnAssetUpdated(AssetData); } void FBlueprintIntelliSenseGenerator::OnAssetRemoved(const FAssetData& AssetData) { - //filter all UBlueprint - if (AssetData.AssetClass == UBlueprint::StaticClass()->GetFName() || - AssetData.AssetClass == UWidgetBlueprint::StaticClass()->GetFName()) - { - BPVariablesMap.Remove(AssetData.AssetName.ToString()); - DeleteFile(FString("Blueprints"), AssetData.AssetName.ToString()); - } -} - -void FBlueprintIntelliSenseGenerator::OnAssetRenamed(const FAssetData& AssetData, const FString& OldPath) -{ - //filter all UBlueprint - if (AssetData.AssetClass == UBlueprint::StaticClass()->GetFName() || - AssetData.AssetClass == UWidgetBlueprint::StaticClass()->GetFName()) - { - //remove old Blueprint name - const FString OldPackageName = FPackageName::GetShortName(OldPath); - BPVariablesMap.Remove(OldPackageName); - DeleteFile(FString("Blueprints"), OldPackageName); - - //update new name - OnAssetUpdated(AssetData); - } -} - -void FBlueprintIntelliSenseGenerator::OnAssetUpdated(const FAssetData& AssetData) -{ - //filter all UBlueprint - if (AssetData.AssetClass == UBlueprint::StaticClass()->GetFName() || - AssetData.AssetClass == UWidgetBlueprint::StaticClass()->GetFName()) - { - //UE_LOG(LogTemp, Warning, TEXT("updated bp name is %s"), *AssetData.GetFullName()); - UBlueprint* Blueprint = LoadObject(nullptr, *AssetData.ObjectPath.ToString()); - if (Blueprint) - { - ExportBPSyntax(Blueprint); - } - } -} - -FString FBlueprintIntelliSenseGenerator::GetFunctionStr(const UFunction* Function, FString ClassName) const -{ - FString Ret; - - // properties - FString Properties; - Ret += GetFunctionProperties(Function, Properties); + if (!IsBlueprint(AssetData)) + return; - // function definition - Ret += FString::Printf(TEXT("function M%s%s(%s) end\r\n\r\n"), Function->HasAnyFunctionFlags(FUNC_Static) ? TEXT(".") : TEXT(":"), *Function->GetName(), *Properties); - - return Ret; + DeleteFile(FString("Blueprints"), AssetData.AssetName.ToString()); } -FString FBlueprintIntelliSenseGenerator::GetFunctionProperties(const UFunction* Function, FString& Properties) const +void FBlueprintIntelliSenseGenerator::OnAssetRenamed(const FAssetData& AssetData, const FString& OldPath) { - FString Ret; - TMap* MetaMap = UMetaData::GetMapForObject(Function); - - // black list of Lua key words - static FString LuaKeyWords[] = { TEXT("local"), TEXT("function"), TEXT("end") }; - static const int32 NumLuaKeyWords = sizeof(LuaKeyWords) / sizeof(FString); - - for (TFieldIterator It(Function); It && (It->PropertyFlags & CPF_Parm); ++It) - { - FProperty* Property = *It; - if (Property->GetFName() == NAME_LatentInfo) - { - continue; // filter out 'LatentInfo' parameter - } - - FString TypeName = GetTypeName(Property); - const FString& PropertyComment = Property->GetMetaData(NAME_ToolTip); - FString ExtraDesc; + if (!IsBlueprint(AssetData)) + return; - if (Property->HasAnyPropertyFlags(CPF_ReturnParm)) - { - Ret += FString::Printf(TEXT("---@return %s"), *TypeName); // return parameter - } - else - { - FString PropertyName = Property->GetName(); - for (int32 KeyWordIdx = 0; KeyWordIdx < NumLuaKeyWords; ++KeyWordIdx) - { - if (PropertyName == LuaKeyWords[KeyWordIdx]) - { - PropertyName += TEXT("__"); // add suffix for Lua key words - break; - } - } + //remove old Blueprint name + const FString OldPackageName = FPackageName::GetShortName(OldPath); + DeleteFile(FString("Blueprints"), OldPackageName); - if (Properties.Len() < 1) - { - Properties = PropertyName; - } - else - { - Properties += FString::Printf(TEXT(", %s"), *PropertyName); - } - - if (MetaMap) - { - FName KeyName = FName(*FString::Printf(TEXT("CPP_Default_%s"), *Property->GetName())); - FString* ValuePtr = MetaMap->Find(KeyName); // find default parameter value - if (ValuePtr) - { - ExtraDesc = TEXT("[opt]"); // default parameter - } - else if (Property->HasAnyPropertyFlags(CPF_OutParm) && !Property->HasAnyPropertyFlags(CPF_ConstParm)) - { - ExtraDesc = TEXT("[out]"); // non-const reference - } - } - Ret += FString::Printf(TEXT("---@param %s %s"), *PropertyName, *TypeName); - } - - if (ExtraDesc.Len() > 0 || PropertyComment.Len() > 0) - { - Ret += TEXT(" @"); - if (ExtraDesc.Len() > 0) - { - Ret += FString::Printf(TEXT("%s "), *ExtraDesc); - } - } - - Ret += TEXT("\r\n"); - } - - return Ret; + //update new name + OnAssetUpdated(AssetData); } -FString FBlueprintIntelliSenseGenerator::GetTypeName(const FProperty* Property) const +void FBlueprintIntelliSenseGenerator::OnAssetUpdated(const FAssetData& AssetData) { - check(Property); + if (!IsBlueprint(AssetData)) + return; - if (Property) - { - if (const FByteProperty* TempByteProperty = CastField(Property)) - { - return TEXT("integer"); - } - else if (const FInt8Property* TempI8Property = CastField(Property)) - { - return TEXT("integer"); - } - else if (const FInt16Property* TempI16Property = CastField(Property)) - { - return TEXT("integer"); - } - else if (const FIntProperty* TempI32Property = CastField(Property)) - { - return TEXT("integer"); - } - else if (const FInt64Property* TempI64Property = CastField(Property)) - { - return TEXT("integer"); - } - else if (const FUInt16Property* TempU16Property = CastField(Property)) - { - return TEXT("integer"); - } - else if (const FUInt32Property* TempU32Property = CastField(Property)) - { - return TEXT("integer"); - } - else if (const FUInt64Property* TempU64Property = CastField(Property)) - { - return TEXT("integer"); - } - else if (const FFloatProperty* TempFloatProperty = CastField(Property)) - { - return TEXT("number"); - } - else if (const FDoubleProperty* TempDoubleProperty = CastField(Property)) - { - return TEXT("number"); - } - else if (const FEnumProperty* TempEnumProperty = CastField(Property)) - { - return ((FEnumProperty*)Property)->GetEnum()->GetName(); - } - else if (const FBoolProperty* TempBoolProperty = CastField(Property)) - { - return TEXT("boolean"); - } - else if (const FClassProperty* TempClassProperty = CastField(Property)) - { - UClass* Class = ((FClassProperty*)Property)->MetaClass; - return FString::Printf(TEXT("TSubclassOf<%s%s>"), Class->GetPrefixCPP(), *Class->GetName()); - } - else if (const FSoftObjectProperty* TempSoftObjectProperty = CastField(Property)) - { - if (((FSoftObjectProperty*)Property)->PropertyClass->IsChildOf(UClass::StaticClass())) - { - UClass* Class = ((FSoftClassProperty*)Property)->MetaClass; - return FString::Printf(TEXT("TSoftClassPtr<%s%s>"), Class->GetPrefixCPP(), *Class->GetName()); - } - UClass* Class = ((FSoftObjectProperty*)Property)->PropertyClass; - return FString::Printf(TEXT("TSoftObjectPtr<%s%s>"), Class->GetPrefixCPP(), *Class->GetName()); - } - else if (const FObjectProperty* TempObjectProperty = CastField(Property)) - { - UClass* Class = ((FObjectProperty*)Property)->PropertyClass; - return FString::Printf(TEXT("%s%s"), Class->GetPrefixCPP(), *Class->GetName()); - } - else if (const FWeakObjectProperty* TempWeakObjectProperty = CastField(Property)) - { - UClass* Class = ((FWeakObjectProperty*)Property)->PropertyClass; - return FString::Printf(TEXT("TWeakObjectPtr<%s%s>"), Class->GetPrefixCPP(), *Class->GetName()); - } - else if (const FLazyObjectProperty* TempLazyObjectProperty = CastField(Property)) - { - UClass* Class = ((FLazyObjectProperty*)Property)->PropertyClass; - return FString::Printf(TEXT("TLazyObjectPtr<%s%s>"), Class->GetPrefixCPP(), *Class->GetName()); - } - else if (const FInterfaceProperty* TempInterfaceProperty = CastField(Property)) - { - UClass* Class = ((FInterfaceProperty*)Property)->InterfaceClass; - return FString::Printf(TEXT("TScriptInterface<%s%s>"), Class->GetPrefixCPP(), *Class->GetName()); - } - else if (const FNameProperty* TempNameProperty = CastField(Property)) - { - return TEXT("string"); - } - else if (const FStrProperty* TempStringProperty = CastField(Property)) - { - return TEXT("string"); - } - else if (const FTextProperty* TempTextProperty = CastField(Property)) - { - return TEXT("string"); - } - else if (const FArrayProperty* TempArrayProperty = CastField(Property)) - { - FProperty* Inner = ((FArrayProperty*)Property)->Inner; - return FString::Printf(TEXT("TArray<%s>"), *GetTypeName(Inner)); - } - else if (const FMapProperty* TempMapProperty = CastField(Property)) - { - FProperty* KeyProp = ((FMapProperty*)Property)->KeyProp; - FProperty* ValueProp = ((FMapProperty*)Property)->ValueProp; - return FString::Printf(TEXT("TMap<%s, %s>"), *GetTypeName(KeyProp), *GetTypeName(ValueProp)); - } - else if (const FSetProperty* TempSetProperty = CastField(Property)) - { - FProperty* ElementProp = ((FSetProperty*)Property)->ElementProp; - return FString::Printf(TEXT("TSet<%s>"), *GetTypeName(ElementProp)); - } - else if (const FStructProperty* TempStructProperty = CastField(Property)) - { - return ((FStructProperty*)Property)->Struct->GetStructCPPName(); - } - else if (const FDelegateProperty* TempDelegateProperty = CastField(Property)) - { - return TEXT("Delegate"); - } - else if (const FMulticastDelegateProperty* TempMulticastDelegateProperty = CastField(Property)) - { - return TEXT("MulticastDelegate"); - } - } + //UE_LOG(LogTemp, Warning, TEXT("updated bp name is %s"), *AssetData.GetFullName()); + UBlueprint* Blueprint = LoadObject(nullptr, *AssetData.ObjectPath.ToString()); + if (!Blueprint) + return; - return TEXT("Unknown"); + Export(Blueprint); } diff --git a/Plugins/UnLua/Source/UnLuaEditor/Private/UnLuaIntelliSense.cpp b/Plugins/UnLua/Source/UnLuaEditor/Private/UnLuaIntelliSense.cpp new file mode 100644 index 00000000..73921ddc --- /dev/null +++ b/Plugins/UnLua/Source/UnLuaEditor/Private/UnLuaIntelliSense.cpp @@ -0,0 +1,351 @@ +// Tencent is pleased to support the open source community by making UnLua available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and limitations under the License. + +#include "UnLuaIntelliSense.h" + +#include "ObjectEditorUtils.h" +#include "UnLuaInterface.h" +#include "UObject/MetaData.h" + +static const FName NAME_ToolTip(TEXT("ToolTip")); // key of ToolTip meta data +static const FName NAME_LatentInfo = TEXT("LatentInfo"); // tag of latent function + +FString UnLua::IntelliSense::Get(const UBlueprint* Blueprint) +{ + FString BPName = Blueprint->GetName(); + FString Ret = Get(Blueprint->GeneratedClass); + Ret += "local M = {}\r\n\r\n"; + + const UClass* GeneratedClass = *Blueprint->GeneratedClass; + + // functions + for (TFieldIterator FunctionIt(GeneratedClass, EFieldIteratorFlags::ExcludeSuper, EFieldIteratorFlags::ExcludeDeprecated, EFieldIteratorFlags::ExcludeInterfaces); FunctionIt; ++FunctionIt) + { + const UFunction* Function = *FunctionIt; + if (!IsValid(Function)) + continue; + if (FObjectEditorUtils::IsFunctionHiddenFromClass(Function, GeneratedClass)) + continue; + Ret += Get(Function) + "\r\n"; + } + + // interfaces + for (int32 i = 0; i < Blueprint->ImplementedInterfaces.Num(); i++) + { + const FBPInterfaceDescription& InterfaceDesc = Blueprint->ImplementedInterfaces[i]; + const UClass* InterfaceClass = InterfaceDesc.Interface.Get(); + if (!InterfaceClass || InterfaceClass == UUnLuaInterface::StaticClass()) + continue; + + for (TFieldIterator FunctionIt(InterfaceClass, EFieldIteratorFlags::IncludeSuper); FunctionIt; ++FunctionIt) + { + const UFunction* Function = *FunctionIt; + if (!IsValid(Function)) + continue; + Ret += Get(Function) + "\r\n"; + } + } + + Ret += "return M"; + return Ret; +} + +FString UnLua::IntelliSense::Get(const UStruct* Struct) +{ + if (!Struct) + return ""; + + FString Ret = "---@class " + GetTypeName(Struct); + UStruct* SuperStruct = Struct->GetSuperStruct(); + if (SuperStruct) + Ret += " : " + GetTypeName(SuperStruct); + Ret += "\r\n"; + + for (TFieldIterator It(Struct, EFieldIteratorFlags::ExcludeSuper, EFieldIteratorFlags::ExcludeDeprecated); It; ++It) + { + const FProperty* Property = *It; + Ret += Get(Property) += "\r\n"; + } + + return Ret; +} + +FString UnLua::IntelliSense::Get(const UFunction* Function) +{ + FString Ret; + FString Properties; + TMap* MetaMap = UMetaData::GetMapForObject(Function); + + if (MetaMap) + { + const FString* ToolTip = MetaMap->Find(NAME_ToolTip); + if (ToolTip && !ToolTip->IsEmpty()) + { + Ret += "---" + ToolTip->Replace(TEXT("\n"), TEXT("\r\n---")); + Ret += "\r\n"; + } + } + + // black list of Lua key words + static FString LuaKeyWords[] = {TEXT("local"), TEXT("function"), TEXT("end")}; + static constexpr int32 NumLuaKeyWords = sizeof(LuaKeyWords) / sizeof(FString); + + for (TFieldIterator It(Function); It && (It->PropertyFlags & CPF_Parm); ++It) + { + const FProperty* Property = *It; + if (Property->GetFName() == NAME_LatentInfo) + continue; + + FString TypeName = GetTypeName(Property); + const FString& PropertyComment = Property->GetMetaData(NAME_ToolTip); + FString ExtraDesc; + + if (Property->HasAnyPropertyFlags(CPF_ReturnParm)) + { + Ret += FString::Printf(TEXT("---@return %s"), *TypeName); // return parameter + } + else + { + FString PropertyName = Property->GetName(); + for (int32 KeyWordIdx = 0; KeyWordIdx < NumLuaKeyWords; ++KeyWordIdx) + { + if (PropertyName == LuaKeyWords[KeyWordIdx]) + { + PropertyName += TEXT("__"); // add suffix for Lua key words + break; + } + } + + if (Properties.IsEmpty()) + Properties = PropertyName; + else + Properties += FString::Printf(TEXT(", %s"), *PropertyName); + + if (MetaMap) + { + FName KeyName = FName(*FString::Printf(TEXT("CPP_Default_%s"), *Property->GetName())); + FString* ValuePtr = MetaMap->Find(KeyName); // find default parameter value + if (ValuePtr) + { + ExtraDesc = TEXT("[opt]"); // default parameter + } + else if (Property->HasAnyPropertyFlags(CPF_OutParm) && !Property->HasAnyPropertyFlags(CPF_ConstParm)) + { + ExtraDesc = TEXT("[out]"); // non-const reference + } + } + Ret += FString::Printf(TEXT("---@param %s %s"), *PropertyName, *TypeName); + } + + if (ExtraDesc.Len() > 0 || PropertyComment.Len() > 0) + { + Ret += TEXT(" @"); + if (ExtraDesc.Len() > 0) + Ret += FString::Printf(TEXT("%s "), *ExtraDesc); + } + + Ret += TEXT("\r\n"); + } + + Ret += FString::Printf(TEXT("function M%s%s(%s) end\r\n\r\n"), Function->HasAnyFunctionFlags(FUNC_Static) ? TEXT(".") : TEXT(":"), *Function->GetName(), *Properties); + return Ret; +} + +FString UnLua::IntelliSense::Get(const FProperty* Property) +{ + FString Ret; + + const UStruct* Struct = Property->GetOwnerStruct(); + + // access level + FString AccessLevel; + if (Property->HasAnyPropertyFlags(CPF_NativeAccessSpecifierPublic)) + AccessLevel = TEXT("public"); + else if (Property->HasAllPropertyFlags(CPF_NativeAccessSpecifierProtected)) + AccessLevel = TEXT("protected"); + else if (Property->HasAllPropertyFlags(CPF_NativeAccessSpecifierPrivate)) + AccessLevel = TEXT("private"); + else + AccessLevel = Struct->IsNative() ? "private" : "public"; + + FString TypeName = IntelliSense::GetTypeName(Property); + Ret += FString::Printf(TEXT("---@field %s %s %s"), *AccessLevel, *Property->GetName(), *TypeName); + + // comment + const FString& ToolTip = Property->GetMetaData(NAME_ToolTip); + if (!ToolTip.IsEmpty()) + Ret += " @" + EscapeComments(ToolTip); + + return Ret; +} + +FString UnLua::IntelliSense::GetTypeName(const UObject* Field) +{ + if (!Field) + return ""; + if (!Field->IsNative()) + return Field->GetName().LeftChop(2); + const UStruct* Struct = Cast(Field); + if (Struct) + return Struct->GetPrefixCPP() + Struct->GetName(); + return Field->GetName(); +} + +FString UnLua::IntelliSense::GetTypeName(const FProperty* Property) +{ + if (!Property) + return "Unknown"; + + if (CastField(Property)) + return "integer"; + + if (CastField(Property)) + return "integer"; + + if (CastField(Property)) + return "integer"; + + if (CastField(Property)) + return "integer"; + + if (CastField(Property)) + return "integer"; + + if (CastField(Property)) + return "integer"; + + if (CastField(Property)) + return "integer"; + + if (CastField(Property)) + return "integer"; + + if (CastField(Property)) + return "number"; + + if (CastField(Property)) + return "number"; + + if (CastField(Property)) + return ((FEnumProperty*)Property)->GetEnum()->GetName(); + + if (CastField(Property)) + return TEXT("boolean"); + + if (CastField(Property)) + { + UClass* Class = ((FClassProperty*)Property)->MetaClass; + return FString::Printf(TEXT("TSubclassOf<%s%s>"), Class->GetPrefixCPP(), *Class->GetName()); + } + + if (CastField(Property)) + { + if (((FSoftObjectProperty*)Property)->PropertyClass->IsChildOf(UClass::StaticClass())) + { + UClass* Class = ((FSoftClassProperty*)Property)->MetaClass; + return FString::Printf(TEXT("TSoftClassPtr<%s%s>"), Class->GetPrefixCPP(), *Class->GetName()); + } + UClass* Class = ((FSoftObjectProperty*)Property)->PropertyClass; + return FString::Printf(TEXT("TSoftObjectPtr<%s%s>"), Class->GetPrefixCPP(), *Class->GetName()); + } + + if (CastField(Property)) + { + UClass* Class = ((FObjectProperty*)Property)->PropertyClass; + return FString::Printf(TEXT("%s%s"), Class->GetPrefixCPP(), *Class->GetName()); + } + + if (CastField(Property)) + { + UClass* Class = ((FWeakObjectProperty*)Property)->PropertyClass; + return FString::Printf(TEXT("TWeakObjectPtr<%s%s>"), Class->GetPrefixCPP(), *Class->GetName()); + } + + if (CastField(Property)) + { + UClass* Class = ((FLazyObjectProperty*)Property)->PropertyClass; + return FString::Printf(TEXT("TLazyObjectPtr<%s%s>"), Class->GetPrefixCPP(), *Class->GetName()); + } + + if (CastField(Property)) + { + UClass* Class = ((FInterfaceProperty*)Property)->InterfaceClass; + return FString::Printf(TEXT("TScriptInterface<%s%s>"), Class->GetPrefixCPP(), *Class->GetName()); + } + + if (CastField(Property)) + return "string"; + + if (CastField(Property)) + return "string"; + + if (CastField(Property)) + return "string"; + + if (CastField(Property)) + { + FProperty* Inner = ((FArrayProperty*)Property)->Inner; + return FString::Printf(TEXT("TArray<%s>"), *GetTypeName(Inner)); + } + + if (CastField(Property)) + { + FProperty* KeyProp = ((FMapProperty*)Property)->KeyProp; + FProperty* ValueProp = ((FMapProperty*)Property)->ValueProp; + return FString::Printf(TEXT("TMap<%s, %s>"), *GetTypeName(KeyProp), *GetTypeName(ValueProp)); + } + + if (CastField(Property)) + { + FProperty* ElementProp = ((FSetProperty*)Property)->ElementProp; + return FString::Printf(TEXT("TSet<%s>"), *GetTypeName(ElementProp)); + } + + if (CastField(Property)) + return ((FStructProperty*)Property)->Struct->GetStructCPPName(); + + if (CastField(Property)) + return "Delegate"; + + if (CastField(Property)) + return "MulticastDelegate"; + + return "Unknown"; +} + +FString UnLua::IntelliSense::EscapeComments(const FString Comments) +{ + return Comments; +} + +bool UnLua::IntelliSense::IsValid(const UFunction* Function) +{ + if (!Function) + return false; + + if (Function->HasAnyFunctionFlags(FUNC_UbergraphFunction)) + return false; + + if (!UEdGraphSchema_K2::CanUserKismetCallFunction(Function)) + return false; + + const FString Name = Function->GetName(); + if (Name.Len() == 0) + return false; + + if (Name.Contains(" ")) + return false; + + return true; +} diff --git a/Plugins/UnLua/Source/UnLuaEditor/Public/BlueprintIntelliSenseGenerator.h b/Plugins/UnLua/Source/UnLuaEditor/Public/BlueprintIntelliSenseGenerator.h index 24159add..e7306227 100644 --- a/Plugins/UnLua/Source/UnLuaEditor/Public/BlueprintIntelliSenseGenerator.h +++ b/Plugins/UnLua/Source/UnLuaEditor/Public/BlueprintIntelliSenseGenerator.h @@ -28,8 +28,8 @@ class FBlueprintIntelliSenseGenerator } static TSharedRef Get(); - - //Update all Blueprints from command + + // Update all Blueprints from command void UpdateAll(); void Initialize(); @@ -37,33 +37,20 @@ class FBlueprintIntelliSenseGenerator private: static TSharedPtr Singleton; - //Export bp variables - void ExportBPFunctions(const UBlueprint* Blueprint); - void ExportBPSyntax(const UBlueprint* Blueprint); - void ExportWidgetBPSyntax(const UWidgetBlueprint* WidgetBlueprint); - void ExportSyntaxToFile(const FString& BPName); + static bool IsBlueprint(const FAssetData& AssetData); + + void Export(const UBlueprint* Blueprint); - //File helper + // File helper void SaveFile(const FString& ModuleName, const FString& FileName, const FString& GeneratedFileContent); void DeleteFile(const FString& ModuleName, const FString& FileName); - //Handle asset event + // Handle asset event void OnAssetAdded(const FAssetData& AssetData); void OnAssetRemoved(const FAssetData& AssetData); void OnAssetRenamed(const FAssetData& AssetData, const FString& OldPath); void OnAssetUpdated(const FAssetData& AssetData); - // Get function IntelliSense - FString GetFunctionStr(const UFunction* Function, FString ClassName) const; - - // Get function properties string - FString GetFunctionProperties(const UFunction* Function, FString& Properties) const; - - // Get readable type name for a UPROPERTY - FString GetTypeName(const FProperty* Property) const; - - TMap> BPVariablesMap; - TMap> BPFunctionMap; FString OutputDir; bool bInitialized; }; diff --git a/Plugins/UnLua/Source/UnLuaEditor/Public/UnLuaIntelliSense.h b/Plugins/UnLua/Source/UnLuaEditor/Public/UnLuaIntelliSense.h new file mode 100644 index 00000000..8f385041 --- /dev/null +++ b/Plugins/UnLua/Source/UnLuaEditor/Public/UnLuaIntelliSense.h @@ -0,0 +1,39 @@ +// Tencent is pleased to support the open source community by making UnLua available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and limitations under the License. + +#pragma once + +#include "CoreMinimal.h" + +namespace UnLua +{ + namespace IntelliSense + { + FString Get(const UBlueprint* Blueprint); + + FString Get(const UStruct* Struct); + + FString Get(const UFunction* Function); + + FString Get(const FProperty* Property); + + FString GetTypeName(const UObject* Field); + + FString GetTypeName(const FProperty* Property); + + FString EscapeComments(const FString Comments); + + bool IsValid(const UFunction* Function); + } +} diff --git a/Plugins/UnLua/Source/UnLuaIntelliSense/Private/UnLuaIntelliSense.cpp b/Plugins/UnLua/Source/UnLuaIntelliSense/Private/UnLuaIntelliSense.cpp index 65d6b057..fbd4b92c 100644 --- a/Plugins/UnLua/Source/UnLuaIntelliSense/Private/UnLuaIntelliSense.cpp +++ b/Plugins/UnLua/Source/UnLuaIntelliSense/Private/UnLuaIntelliSense.cpp @@ -12,6 +12,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and limitations under the License. +#include "BlueprintIntelliSenseGenerator.h" #include "CoreUObject.h" #include "Features/IModularFeatures.h" #include "IScriptGeneratorPluginInterface.h" @@ -42,7 +43,6 @@ class FUnLuaIntelliSenseModule : public IScriptGeneratorPluginInterface virtual void Initialize(const FString& RootLocalPath, const FString& RootBuildPath, const FString& OutputDirectory, const FString& IncludeBase) override { OutputDir = IncludeBase + TEXT("../Intermediate/"); // export symbol (IntelliSense) files to plugin's 'Intermediate' dir - UENamespace = TEXT("_G.UE = {\r\n\r\n"); } virtual void ExportClass(UClass* Class, const FString& SourceHeaderFilename, const FString& GeneratedHeaderFilename, bool bHasChanged) override @@ -171,6 +171,7 @@ class FUnLuaIntelliSenseModule : public IScriptGeneratorPluginInterface } // save 'UENamespace' to lua file + UENamespace = TEXT("_G.UE = {\r\n\r\n"); UENames.Sort(); for (const FString &Name : UENames) { @@ -194,45 +195,7 @@ class FUnLuaIntelliSenseModule : public IScriptGeneratorPluginInterface // comment ExportMultiLineComments(Struct->GetMetaData(NAME_ToolTip), GeneratedFileContent); - // struct name - GeneratedFileContent += FString::Printf(TEXT("---@class %s"), *StructName); - UStruct *ParentStruct = Struct->GetSuperStruct(); - if (ParentStruct) - { - GeneratedFileContent += FString::Printf(TEXT(" : %s%s"), ParentStruct->GetPrefixCPP(), *ParentStruct->GetName()); - } - - // fields - for (TFieldIterator PropertyIt(Struct, EFieldIteratorFlags::ExcludeSuper, EFieldIteratorFlags::ExcludeDeprecated); PropertyIt; ++PropertyIt) - { - FProperty *Property = *PropertyIt; - - // access level - FString AccessLevel; - if (Property->HasAnyPropertyFlags(CPF_NativeAccessSpecifierPublic)) - { - AccessLevel = TEXT("public"); - } - else if (Property->HasAllPropertyFlags(CPF_NativeAccessSpecifierProtected)) - { - AccessLevel = TEXT("protected"); - } - else - { - AccessLevel = TEXT("private"); - } - - FString TypeName = GetTypeName(Property); - GeneratedFileContent += FString::Printf(TEXT("\r\n---@field %s %s %s"), *AccessLevel, *Property->GetName(), *TypeName); - - // comment - const FString &PropertyComment = Property->GetMetaData(NAME_ToolTip); - if (PropertyComment.Len() > 0) - { - ExportPropertyComment(PropertyComment, GeneratedFileContent); - //GeneratedFileContent += FString::Printf(TEXT(" @%s"), *PropertyComment.Replace(TEXT("\n"), TEXT(", "))); - } - } + GeneratedFileContent += FBlueprintIntelliSenseGenerator::GetAnnotations(Struct); // definition GeneratedFileContent += TEXT("\r\nlocal M = {}\r\n\r\n"); diff --git a/Plugins/UnLua/Source/UnLuaIntelliSense/UnLuaIntelliSense.Build.cs b/Plugins/UnLua/Source/UnLuaIntelliSense/UnLuaIntelliSense.Build.cs index 7b84fc4d..da4d35c7 100644 --- a/Plugins/UnLua/Source/UnLuaIntelliSense/UnLuaIntelliSense.Build.cs +++ b/Plugins/UnLua/Source/UnLuaIntelliSense/UnLuaIntelliSense.Build.cs @@ -28,6 +28,7 @@ public UnLuaIntelliSense(ReadOnlyTargetRules Target) : base(Target) new[] { "Programs/UnrealHeaderTool/Public", + "UnLuaEditor/Public" } ); @@ -36,7 +37,7 @@ public UnLuaIntelliSense(ReadOnlyTargetRules Target) : base(Target) new[] { "UnLuaIntelliSense/Private", - "UnLua/Private", + "UnLua/Private" } ); @@ -45,7 +46,7 @@ public UnLuaIntelliSense(ReadOnlyTargetRules Target) : base(Target) new[] { "Core", - "CoreUObject", + "CoreUObject" } ); diff --git a/TPSProject.sln.DotSettings b/TPSProject.sln.DotSettings index bca0cee2..e850187a 100644 --- a/TPSProject.sln.DotSettings +++ b/TPSProject.sln.DotSettings @@ -13,4 +13,5 @@ True True True + True