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()
|
||||
|
||||
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;
|
||||
|
||||
UPROPERTY(meta=(Description="Args e.g. 'int x,float y'"))
|
||||
UPROPERTY(meta=(Description="Parameter list, such as 'int x,float y'"))
|
||||
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;
|
||||
|
||||
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
|
||||
@@ -37,6 +37,7 @@ public:
|
||||
if (!WingFunctionArgs::HasArgs(NodeObj))
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Node does not support editable args\n"));
|
||||
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ bool WingFunctionArgs::ParseArgs(const FString& Args, TArray<FParsedArg>& OutArg
|
||||
FString 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;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ bool WingFunctionArgs::ParseArgs(const FString& Args, TArray<FParsedArg>& OutArg
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -85,13 +85,18 @@ bool WingFunctionArgs::SetArgs(UEdGraphNode* Node, const FString& Args)
|
||||
UK2Node_EditablePinBase* Editable = Cast<UK2Node_EditablePinBase>(Node);
|
||||
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;
|
||||
}
|
||||
|
||||
// Parse the args string.
|
||||
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);
|
||||
|
||||
@@ -117,7 +122,9 @@ bool WingFunctionArgs::CheckArgs(const FString &Args)
|
||||
TArray<FParsedArg> 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 true;
|
||||
|
||||
@@ -8,7 +8,7 @@ TSet<WingManual::Section> WingManual::AllSections()
|
||||
return {
|
||||
Section::Paths,
|
||||
Section::Types,
|
||||
Section::FunctionArguments,
|
||||
Section::ParameterLists,
|
||||
Section::IdentifierSanitization,
|
||||
Section::Whitespace,
|
||||
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)
|
||||
{
|
||||
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"
|
||||
));
|
||||
@@ -183,10 +183,10 @@ void WingManual::PrintManual(TSet<Section> Sections, UClass *Handler, bool Abrid
|
||||
else
|
||||
{
|
||||
UWingServer::Print(TEXT(
|
||||
"\n FUNCTION ARGUMENTS AND RETURN VALUES:"
|
||||
"\n PARAMETER LISTS:"
|
||||
"\n"
|
||||
"\n Function argument lists are expressed as comma-separated"
|
||||
"\n lists of type-name pairs:"
|
||||
"\n Parameter lists (including function arguments and function return"
|
||||
"\n values) are expressed as comma-separated lists of type-name pairs:"
|
||||
"\n"
|
||||
"\n Double D,PlayerController P,Array<Int> A"
|
||||
"\n"
|
||||
@@ -206,9 +206,9 @@ void WingManual::PrintManual(TSet<Section> Sections, UClass *Handler, bool Abrid
|
||||
if (Abridged)
|
||||
{
|
||||
UWingServer::Print(TEXT(
|
||||
"\n IDENTIFIER SANITIZATION:\n"
|
||||
"\n Identifiers in unreal can contain whitespace and punctuation.\n"
|
||||
"\n We sanitize these characters on output:\n"
|
||||
"\n IDENTIFIER SANITIZATION:"
|
||||
"\n Identifiers in unreal can contain whitespace and punctuation."
|
||||
"\n We sanitize these characters on output:"
|
||||
"\n"
|
||||
"\n space → ·"
|
||||
"\n < → ◁"
|
||||
@@ -224,9 +224,9 @@ void WingManual::PrintManual(TSet<Section> Sections, UClass *Handler, bool Abrid
|
||||
else
|
||||
{
|
||||
UWingServer::Print(TEXT(
|
||||
"\n IDENTIFIER SANITIZATION:\n"
|
||||
"\n IDENTIFIER SANITIZATION:"
|
||||
"\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 How would we parse Array<X> if the typename X contained a less-than?"
|
||||
"\n So, we automatically translate these characters on output:"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "WingTypes.h"
|
||||
#include "WingUtils.h"
|
||||
#include "WingServer.h"
|
||||
#include "WingManual.h"
|
||||
#include "Editor.h"
|
||||
#include "EdGraphSchema_K2.h"
|
||||
#include "Engine/Blueprint.h"
|
||||
@@ -420,6 +421,12 @@ FString UWingTypes::TypeToTextOrDie(const UObject* Obj)
|
||||
// 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)
|
||||
{
|
||||
Tokens.Empty();
|
||||
@@ -485,7 +492,7 @@ bool UWingTypes::ParseEOF()
|
||||
{
|
||||
if (Cursor != Tokens.Num())
|
||||
{
|
||||
Error = TEXT("Extra tokens at end of input");
|
||||
PrintParseError(TEXT("extra tokens at end of input"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -495,7 +502,7 @@ bool UWingTypes::ParseChar(TCHAR c)
|
||||
{
|
||||
if (!TokenIs(c))
|
||||
{
|
||||
Error = FString::Printf(TEXT("Expected %c"), c);
|
||||
PrintParseError(*FString::Printf(TEXT("expected '%c'"), c));
|
||||
return false;
|
||||
}
|
||||
Cursor++;
|
||||
@@ -506,7 +513,7 @@ bool UWingTypes::ParsePlainIdentifier(FEdGraphPinType& OutType)
|
||||
{
|
||||
if (!TokenIsID())
|
||||
{
|
||||
Error = TEXT("Expected Identifier");
|
||||
PrintParseError(TEXT("expected identifier"));
|
||||
return false;
|
||||
}
|
||||
FString Name = Tokens[Cursor++];
|
||||
@@ -520,7 +527,7 @@ bool UWingTypes::ParseWrapped(FName Wrapper, FEdGraphPinType& OutType)
|
||||
if (!ParsePlainIdentifier(OutType)) return false;
|
||||
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;
|
||||
}
|
||||
if (!ParseChar('>')) return false;
|
||||
@@ -599,7 +606,7 @@ bool UWingTypes::ResolveShortName(const FString &Name, FEdGraphPinType &OutType)
|
||||
Info* TypeInfo = ShortToInfo.Find(Name.ToLower());
|
||||
if (!TypeInfo)
|
||||
{
|
||||
Error = FString::Printf(TEXT("Unrecognized type '%s'"), *Name);
|
||||
PrintParseError(*FString::Printf(TEXT("unrecognized type '%s'"), *Name));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -615,7 +622,7 @@ bool UWingTypes::ResolveShortName(const FString &Name, FEdGraphPinType &OutType)
|
||||
UObject* Obj = LoadObject<UObject>(nullptr, *TypeInfo->PinSubCategoryObject);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -666,12 +673,11 @@ bool UWingTypes::TextToType(const FString& Text, FEdGraphPinType& OutPinType, co
|
||||
|
||||
UWingTypes* Types = GEditor->GetEditorSubsystem<UWingTypes>();
|
||||
check(Types);
|
||||
Types->Error.Empty();
|
||||
Types->ParseInput = Text;
|
||||
Types->Tokenize(Text);
|
||||
OutPinType = FEdGraphPinType();
|
||||
if (!Types->ParseType(OutPinType))
|
||||
{
|
||||
UWingServer::Printf(TEXT("%s\n"), *Types->Error);
|
||||
OutPinType = FEdGraphPinType(); return false;
|
||||
}
|
||||
|
||||
@@ -679,7 +685,8 @@ bool UWingTypes::TextToType(const FString& Text, FEdGraphPinType& OutPinType, co
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -688,8 +695,9 @@ bool UWingTypes::TextToType(const FString& Text, FEdGraphPinType& OutPinType, co
|
||||
{
|
||||
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());
|
||||
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
||||
OutPinType = FEdGraphPinType(); return false;
|
||||
}
|
||||
}
|
||||
@@ -699,6 +707,7 @@ bool UWingTypes::TextToType(const FString& Text, FEdGraphPinType& OutPinType, co
|
||||
if (!IsChildOf(OutPinType, 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;
|
||||
}
|
||||
}
|
||||
@@ -708,6 +717,7 @@ bool UWingTypes::TextToType(const FString& Text, FEdGraphPinType& OutPinType, co
|
||||
if (!IsBlueprintType(OutPinType))
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Not a blueprint type: %s\n"), *Text);
|
||||
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
||||
OutPinType = FEdGraphPinType(); return false;
|
||||
}
|
||||
}
|
||||
@@ -717,6 +727,7 @@ bool UWingTypes::TextToType(const FString& Text, FEdGraphPinType& OutPinType, co
|
||||
if (!IsBlueprintable(OutPinType))
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Not a blueprintable type: %s\n"), *Text);
|
||||
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
||||
OutPinType = FEdGraphPinType(); return false;
|
||||
}
|
||||
}
|
||||
@@ -733,6 +744,7 @@ UClass* UWingTypes::TextToOneObjectType(const FString& Text, const Requirements
|
||||
(PinType.IsContainer()))
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: '%s' is not an object class\n"), *Text);
|
||||
UWingServer::SuggestManual(WingManual::Section::Types);
|
||||
return nullptr;
|
||||
}
|
||||
return Class;
|
||||
@@ -747,6 +759,7 @@ UClass* UWingTypes::TextToOneInterfaceType(const FString& Text, const Requiremen
|
||||
(PinType.IsContainer()))
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: '%s' is not an interface class\n"), *Text);
|
||||
UWingServer::SuggestManual(WingManual::Section::Types);
|
||||
return nullptr;
|
||||
}
|
||||
return Class;
|
||||
|
||||
@@ -9,7 +9,7 @@ public:
|
||||
HandlerHelp,
|
||||
Paths,
|
||||
Types,
|
||||
FunctionArguments,
|
||||
ParameterLists,
|
||||
IdentifierSanitization,
|
||||
Whitespace,
|
||||
MaterialEditing,
|
||||
|
||||
@@ -183,5 +183,6 @@ private:
|
||||
// These fields are only used during the parsing of a type.
|
||||
TArray<FString> Tokens;
|
||||
int32 Cursor = 0;
|
||||
FString Error;
|
||||
FString ParseInput;
|
||||
void PrintParseError(const TCHAR* Message);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user