More work on automatic self-documentation
This commit is contained in:
@@ -14,18 +14,18 @@ class UWing_GraphNode_SetArgs : public UObject, public IWingHandler
|
|||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UPROPERTY(meta=(Description="Path to a graph node (function entry, function result, custom event, or tunnel)"))
|
UPROPERTY(meta=(Description="Path to a graph node (FunctionEntry, FunctionResult, CustomEvent, or Tunnel)"))
|
||||||
FString Node;
|
FString Node;
|
||||||
|
|
||||||
UPROPERTY(meta=(Description="Args e.g. 'int x,float y'"))
|
UPROPERTY(meta=(Description="Parameter list, such as 'int x,float y'"))
|
||||||
FString Args;
|
FString Args;
|
||||||
|
|
||||||
UPROPERTY(meta=(Optional, Description="Also rename the node (e.g. custom event name)"))
|
UPROPERTY(meta=(Optional, Description="Also rename the node (which renames a Function or Custom Event)"))
|
||||||
FString Rename;
|
FString Rename;
|
||||||
|
|
||||||
virtual FString GetDescription() const override
|
virtual FString GetDescription() const override
|
||||||
{
|
{
|
||||||
return TEXT("Set the user-defined pins (arguments or return values) on a function entry, result, custom event, or tunnel node.");
|
return TEXT("Set the parameter list of a FunctionEntry, FunctionResult, CustomEvent, or Tunnel node.");
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Handle() override
|
virtual void Handle() override
|
||||||
@@ -37,6 +37,7 @@ public:
|
|||||||
if (!WingFunctionArgs::HasArgs(NodeObj))
|
if (!WingFunctionArgs::HasArgs(NodeObj))
|
||||||
{
|
{
|
||||||
UWingServer::Printf(TEXT("ERROR: Node does not support editable args\n"));
|
UWingServer::Printf(TEXT("ERROR: Node does not support editable args\n"));
|
||||||
|
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ bool WingFunctionArgs::ParseArgs(const FString& Args, TArray<FParsedArg>& OutArg
|
|||||||
FString TypeStr, NameStr;
|
FString TypeStr, NameStr;
|
||||||
if (!Token.Split(TEXT(" "), &TypeStr, &NameStr))
|
if (!Token.Split(TEXT(" "), &TypeStr, &NameStr))
|
||||||
{
|
{
|
||||||
UWingServer::Printf(TEXT("ERROR: Expected 'type name' but got '%s'\n"), *Token);
|
UWingServer::Printf(TEXT("ERROR: Malformed parameter list near '%s'\n"), *Token);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ bool WingFunctionArgs::ParseArgs(const FString& Args, TArray<FParsedArg>& OutArg
|
|||||||
|
|
||||||
if (TypeStr.IsEmpty() || NameStr.IsEmpty())
|
if (TypeStr.IsEmpty() || NameStr.IsEmpty())
|
||||||
{
|
{
|
||||||
UWingServer::Printf(TEXT("ERROR: Expected 'type name' but got '%s'\n"), *Token);
|
UWingServer::Printf(TEXT("ERROR: Malformed parameter list near '%s'\n"), *Token);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,13 +85,18 @@ bool WingFunctionArgs::SetArgs(UEdGraphNode* Node, const FString& Args)
|
|||||||
UK2Node_EditablePinBase* Editable = Cast<UK2Node_EditablePinBase>(Node);
|
UK2Node_EditablePinBase* Editable = Cast<UK2Node_EditablePinBase>(Node);
|
||||||
if (!Editable || !Editable->IsEditable())
|
if (!Editable || !Editable->IsEditable())
|
||||||
{
|
{
|
||||||
UWingServer::Printf(TEXT("ERROR: Node does not support editable pins\n"));
|
UWingServer::Printf(TEXT("ERROR: Node does not contain an editable parameter list\n"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the args string.
|
// Parse the args string.
|
||||||
TArray<FParsedArg> NewArgs;
|
TArray<FParsedArg> NewArgs;
|
||||||
if (!ParseArgs(Args, NewArgs)) return false;
|
if (!ParseArgs(Args, NewArgs))
|
||||||
|
{
|
||||||
|
UWingServer::SuggestManual(WingManual::Section::ParameterLists);
|
||||||
|
UWingServer::SuggestManual(WingManual::Section::Types);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
EEdGraphPinDirection Direction = GetPinDirection(Editable);
|
EEdGraphPinDirection Direction = GetPinDirection(Editable);
|
||||||
|
|
||||||
@@ -117,7 +122,9 @@ bool WingFunctionArgs::CheckArgs(const FString &Args)
|
|||||||
TArray<FParsedArg> NewArgs;
|
TArray<FParsedArg> NewArgs;
|
||||||
if (!ParseArgs(Args, NewArgs))
|
if (!ParseArgs(Args, NewArgs))
|
||||||
{
|
{
|
||||||
UWingServer::Printf(TEXT("Invalid function arguments: %s\n"), *Args);
|
UWingServer::Printf(TEXT("ERROR: Invalid parameter list: %s\n"), *Args);
|
||||||
|
UWingServer::SuggestManual(WingManual::Section::ParameterLists);
|
||||||
|
UWingServer::SuggestManual(WingManual::Section::Types);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ TSet<WingManual::Section> WingManual::AllSections()
|
|||||||
return {
|
return {
|
||||||
Section::Paths,
|
Section::Paths,
|
||||||
Section::Types,
|
Section::Types,
|
||||||
Section::FunctionArguments,
|
Section::ParameterLists,
|
||||||
Section::IdentifierSanitization,
|
Section::IdentifierSanitization,
|
||||||
Section::Whitespace,
|
Section::Whitespace,
|
||||||
Section::MaterialEditing,
|
Section::MaterialEditing,
|
||||||
@@ -170,12 +170,12 @@ void WingManual::PrintManual(TSet<Section> Sections, UClass *Handler, bool Abrid
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Sections.Contains(Section::FunctionArguments))
|
if (Sections.Contains(Section::ParameterLists))
|
||||||
{
|
{
|
||||||
if (Abridged)
|
if (Abridged)
|
||||||
{
|
{
|
||||||
UWingServer::Print(TEXT(
|
UWingServer::Print(TEXT(
|
||||||
"\n FUNCTION ARGUMENTS: Here is an example argument list:"
|
"\n PARAMETER LISTS: Here is an example parameter list:"
|
||||||
"\n double D,PlayerController P,Array<Int> A"
|
"\n double D,PlayerController P,Array<Int> A"
|
||||||
"\n"
|
"\n"
|
||||||
));
|
));
|
||||||
@@ -183,10 +183,10 @@ void WingManual::PrintManual(TSet<Section> Sections, UClass *Handler, bool Abrid
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
UWingServer::Print(TEXT(
|
UWingServer::Print(TEXT(
|
||||||
"\n FUNCTION ARGUMENTS AND RETURN VALUES:"
|
"\n PARAMETER LISTS:"
|
||||||
"\n"
|
"\n"
|
||||||
"\n Function argument lists are expressed as comma-separated"
|
"\n Parameter lists (including function arguments and function return"
|
||||||
"\n lists of type-name pairs:"
|
"\n values) are expressed as comma-separated lists of type-name pairs:"
|
||||||
"\n"
|
"\n"
|
||||||
"\n Double D,PlayerController P,Array<Int> A"
|
"\n Double D,PlayerController P,Array<Int> A"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -206,9 +206,9 @@ void WingManual::PrintManual(TSet<Section> Sections, UClass *Handler, bool Abrid
|
|||||||
if (Abridged)
|
if (Abridged)
|
||||||
{
|
{
|
||||||
UWingServer::Print(TEXT(
|
UWingServer::Print(TEXT(
|
||||||
"\n IDENTIFIER SANITIZATION:\n"
|
"\n IDENTIFIER SANITIZATION:"
|
||||||
"\n Identifiers in unreal can contain whitespace and punctuation.\n"
|
"\n Identifiers in unreal can contain whitespace and punctuation."
|
||||||
"\n We sanitize these characters on output:\n"
|
"\n We sanitize these characters on output:"
|
||||||
"\n"
|
"\n"
|
||||||
"\n space → ·"
|
"\n space → ·"
|
||||||
"\n < → ◁"
|
"\n < → ◁"
|
||||||
@@ -224,9 +224,9 @@ void WingManual::PrintManual(TSet<Section> Sections, UClass *Handler, bool Abrid
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
UWingServer::Print(TEXT(
|
UWingServer::Print(TEXT(
|
||||||
"\n IDENTIFIER SANITIZATION:\n"
|
"\n IDENTIFIER SANITIZATION:"
|
||||||
"\n"
|
"\n"
|
||||||
"\n Identifiers in Unreal can contain spaces and punctuation marks.\n"
|
"\n Identifiers in Unreal can contain spaces and punctuation marks."
|
||||||
"\n Those punctuation marks could confuse our parsers. For example,"
|
"\n Those punctuation marks could confuse our parsers. For example,"
|
||||||
"\n How would we parse Array<X> if the typename X contained a less-than?"
|
"\n How would we parse Array<X> if the typename X contained a less-than?"
|
||||||
"\n So, we automatically translate these characters on output:"
|
"\n So, we automatically translate these characters on output:"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "WingTypes.h"
|
#include "WingTypes.h"
|
||||||
#include "WingUtils.h"
|
#include "WingUtils.h"
|
||||||
#include "WingServer.h"
|
#include "WingServer.h"
|
||||||
|
#include "WingManual.h"
|
||||||
#include "Editor.h"
|
#include "Editor.h"
|
||||||
#include "EdGraphSchema_K2.h"
|
#include "EdGraphSchema_K2.h"
|
||||||
#include "Engine/Blueprint.h"
|
#include "Engine/Blueprint.h"
|
||||||
@@ -420,6 +421,12 @@ FString UWingTypes::TypeToTextOrDie(const UObject* Obj)
|
|||||||
// Tokenizer, Parser, and Resolve Short Name
|
// Tokenizer, Parser, and Resolve Short Name
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void UWingTypes::PrintParseError(const TCHAR* Message)
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR parsing type '%s' — %s\n"), *ParseInput, Message);
|
||||||
|
UWingServer::SuggestManual(WingManual::Section::Types);
|
||||||
|
}
|
||||||
|
|
||||||
void UWingTypes::Tokenize(const FString& Input)
|
void UWingTypes::Tokenize(const FString& Input)
|
||||||
{
|
{
|
||||||
Tokens.Empty();
|
Tokens.Empty();
|
||||||
@@ -485,7 +492,7 @@ bool UWingTypes::ParseEOF()
|
|||||||
{
|
{
|
||||||
if (Cursor != Tokens.Num())
|
if (Cursor != Tokens.Num())
|
||||||
{
|
{
|
||||||
Error = TEXT("Extra tokens at end of input");
|
PrintParseError(TEXT("extra tokens at end of input"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -495,7 +502,7 @@ bool UWingTypes::ParseChar(TCHAR c)
|
|||||||
{
|
{
|
||||||
if (!TokenIs(c))
|
if (!TokenIs(c))
|
||||||
{
|
{
|
||||||
Error = FString::Printf(TEXT("Expected %c"), c);
|
PrintParseError(*FString::Printf(TEXT("expected '%c'"), c));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Cursor++;
|
Cursor++;
|
||||||
@@ -506,7 +513,7 @@ bool UWingTypes::ParsePlainIdentifier(FEdGraphPinType& OutType)
|
|||||||
{
|
{
|
||||||
if (!TokenIsID())
|
if (!TokenIsID())
|
||||||
{
|
{
|
||||||
Error = TEXT("Expected Identifier");
|
PrintParseError(TEXT("expected identifier"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
FString Name = Tokens[Cursor++];
|
FString Name = Tokens[Cursor++];
|
||||||
@@ -520,7 +527,7 @@ bool UWingTypes::ParseWrapped(FName Wrapper, FEdGraphPinType& OutType)
|
|||||||
if (!ParsePlainIdentifier(OutType)) return false;
|
if (!ParsePlainIdentifier(OutType)) return false;
|
||||||
if (OutType.PinCategory != UEdGraphSchema_K2::PC_Object)
|
if (OutType.PinCategory != UEdGraphSchema_K2::PC_Object)
|
||||||
{
|
{
|
||||||
Error = FString::Printf(TEXT("%s is not an object type"), *OutType.PinSubCategoryObject->GetName());
|
PrintParseError(*FString::Printf(TEXT("'%s' is not an object type"), *OutType.PinSubCategoryObject->GetName()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!ParseChar('>')) return false;
|
if (!ParseChar('>')) return false;
|
||||||
@@ -599,7 +606,7 @@ bool UWingTypes::ResolveShortName(const FString &Name, FEdGraphPinType &OutType)
|
|||||||
Info* TypeInfo = ShortToInfo.Find(Name.ToLower());
|
Info* TypeInfo = ShortToInfo.Find(Name.ToLower());
|
||||||
if (!TypeInfo)
|
if (!TypeInfo)
|
||||||
{
|
{
|
||||||
Error = FString::Printf(TEXT("Unrecognized type '%s'"), *Name);
|
PrintParseError(*FString::Printf(TEXT("unrecognized type '%s'"), *Name));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,7 +622,7 @@ bool UWingTypes::ResolveShortName(const FString &Name, FEdGraphPinType &OutType)
|
|||||||
UObject* Obj = LoadObject<UObject>(nullptr, *TypeInfo->PinSubCategoryObject);
|
UObject* Obj = LoadObject<UObject>(nullptr, *TypeInfo->PinSubCategoryObject);
|
||||||
if (!Obj)
|
if (!Obj)
|
||||||
{
|
{
|
||||||
Error = FString::Printf(TEXT("Failed to load type '%s' at path '%s'"), *Name, *TypeInfo->PinSubCategoryObject);
|
PrintParseError(*FString::Printf(TEXT("failed to load type '%s' at path '%s'"), *Name, *TypeInfo->PinSubCategoryObject));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -666,12 +673,11 @@ bool UWingTypes::TextToType(const FString& Text, FEdGraphPinType& OutPinType, co
|
|||||||
|
|
||||||
UWingTypes* Types = GEditor->GetEditorSubsystem<UWingTypes>();
|
UWingTypes* Types = GEditor->GetEditorSubsystem<UWingTypes>();
|
||||||
check(Types);
|
check(Types);
|
||||||
Types->Error.Empty();
|
Types->ParseInput = Text;
|
||||||
Types->Tokenize(Text);
|
Types->Tokenize(Text);
|
||||||
OutPinType = FEdGraphPinType();
|
OutPinType = FEdGraphPinType();
|
||||||
if (!Types->ParseType(OutPinType))
|
if (!Types->ParseType(OutPinType))
|
||||||
{
|
{
|
||||||
UWingServer::Printf(TEXT("%s\n"), *Types->Error);
|
|
||||||
OutPinType = FEdGraphPinType(); return false;
|
OutPinType = FEdGraphPinType(); return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -679,7 +685,8 @@ bool UWingTypes::TextToType(const FString& Text, FEdGraphPinType& OutPinType, co
|
|||||||
{
|
{
|
||||||
if (OutPinType.IsContainer())
|
if (OutPinType.IsContainer())
|
||||||
{
|
{
|
||||||
UWingServer::Printf(TEXT("ERROR: Type %s is a container, not allowed here\n"), *Text);
|
UWingServer::Printf(TEXT("ERROR: Type '%s' is a container, not allowed here\n"), *Text);
|
||||||
|
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
||||||
OutPinType = FEdGraphPinType(); return false;
|
OutPinType = FEdGraphPinType(); return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -688,8 +695,9 @@ bool UWingTypes::TextToType(const FString& Text, FEdGraphPinType& OutPinType, co
|
|||||||
{
|
{
|
||||||
if (OutPinType.PinCategory != Require.PinCategory)
|
if (OutPinType.PinCategory != Require.PinCategory)
|
||||||
{
|
{
|
||||||
UWingServer::Printf(TEXT("ERROR: Need a type which is an %s, got a %s instead."),
|
UWingServer::Printf(TEXT("ERROR: Need a type which is an %s, got a %s instead.\n"),
|
||||||
*Require.PinCategory.ToString(), *OutPinType.PinCategory.ToString());
|
*Require.PinCategory.ToString(), *OutPinType.PinCategory.ToString());
|
||||||
|
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
||||||
OutPinType = FEdGraphPinType(); return false;
|
OutPinType = FEdGraphPinType(); return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -699,6 +707,7 @@ bool UWingTypes::TextToType(const FString& Text, FEdGraphPinType& OutPinType, co
|
|||||||
if (!IsChildOf(OutPinType, Require.IsChildOf))
|
if (!IsChildOf(OutPinType, Require.IsChildOf))
|
||||||
{
|
{
|
||||||
UWingServer::Printf(TEXT("ERROR: Type must derive from %s\n"), *WingUtils::FormatName(Require.IsChildOf));
|
UWingServer::Printf(TEXT("ERROR: Type must derive from %s\n"), *WingUtils::FormatName(Require.IsChildOf));
|
||||||
|
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
||||||
OutPinType = FEdGraphPinType(); return false;
|
OutPinType = FEdGraphPinType(); return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -708,6 +717,7 @@ bool UWingTypes::TextToType(const FString& Text, FEdGraphPinType& OutPinType, co
|
|||||||
if (!IsBlueprintType(OutPinType))
|
if (!IsBlueprintType(OutPinType))
|
||||||
{
|
{
|
||||||
UWingServer::Printf(TEXT("ERROR: Not a blueprint type: %s\n"), *Text);
|
UWingServer::Printf(TEXT("ERROR: Not a blueprint type: %s\n"), *Text);
|
||||||
|
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
||||||
OutPinType = FEdGraphPinType(); return false;
|
OutPinType = FEdGraphPinType(); return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -717,6 +727,7 @@ bool UWingTypes::TextToType(const FString& Text, FEdGraphPinType& OutPinType, co
|
|||||||
if (!IsBlueprintable(OutPinType))
|
if (!IsBlueprintable(OutPinType))
|
||||||
{
|
{
|
||||||
UWingServer::Printf(TEXT("ERROR: Not a blueprintable type: %s\n"), *Text);
|
UWingServer::Printf(TEXT("ERROR: Not a blueprintable type: %s\n"), *Text);
|
||||||
|
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
||||||
OutPinType = FEdGraphPinType(); return false;
|
OutPinType = FEdGraphPinType(); return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -733,6 +744,7 @@ UClass* UWingTypes::TextToOneObjectType(const FString& Text, const Requirements
|
|||||||
(PinType.IsContainer()))
|
(PinType.IsContainer()))
|
||||||
{
|
{
|
||||||
UWingServer::Printf(TEXT("ERROR: '%s' is not an object class\n"), *Text);
|
UWingServer::Printf(TEXT("ERROR: '%s' is not an object class\n"), *Text);
|
||||||
|
UWingServer::SuggestManual(WingManual::Section::Types);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return Class;
|
return Class;
|
||||||
@@ -747,6 +759,7 @@ UClass* UWingTypes::TextToOneInterfaceType(const FString& Text, const Requiremen
|
|||||||
(PinType.IsContainer()))
|
(PinType.IsContainer()))
|
||||||
{
|
{
|
||||||
UWingServer::Printf(TEXT("ERROR: '%s' is not an interface class\n"), *Text);
|
UWingServer::Printf(TEXT("ERROR: '%s' is not an interface class\n"), *Text);
|
||||||
|
UWingServer::SuggestManual(WingManual::Section::Types);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return Class;
|
return Class;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ public:
|
|||||||
HandlerHelp,
|
HandlerHelp,
|
||||||
Paths,
|
Paths,
|
||||||
Types,
|
Types,
|
||||||
FunctionArguments,
|
ParameterLists,
|
||||||
IdentifierSanitization,
|
IdentifierSanitization,
|
||||||
Whitespace,
|
Whitespace,
|
||||||
MaterialEditing,
|
MaterialEditing,
|
||||||
|
|||||||
@@ -183,5 +183,6 @@ private:
|
|||||||
// These fields are only used during the parsing of a type.
|
// These fields are only used during the parsing of a type.
|
||||||
TArray<FString> Tokens;
|
TArray<FString> Tokens;
|
||||||
int32 Cursor = 0;
|
int32 Cursor = 0;
|
||||||
FString Error;
|
FString ParseInput;
|
||||||
|
void PrintParseError(const TCHAR* Message);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user