Overhaul of manual-generation code
This commit is contained in:
@@ -12,6 +12,9 @@ class UWing_Documentation_Manual : public UWingHandler
|
|||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
UPROPERTY(EditAnywhere, meta=(Optional, Description="If specified, print only this section of the manual"))
|
||||||
|
FString Section;
|
||||||
|
|
||||||
virtual void Register() override
|
virtual void Register() override
|
||||||
{
|
{
|
||||||
UWingServer::AddHandler(this,
|
UWingServer::AddHandler(this,
|
||||||
@@ -19,6 +22,23 @@ public:
|
|||||||
}
|
}
|
||||||
virtual void Handle() override
|
virtual void Handle() override
|
||||||
{
|
{
|
||||||
WingManual::PrintManual({WingManual::Section::All}, nullptr, false);
|
if (Section.IsEmpty())
|
||||||
|
{
|
||||||
|
UWingManualSections::FetcherPaths();
|
||||||
|
UWingManualSections::ExpressingTypes();
|
||||||
|
UWingManualSections::VariableDeclarations();
|
||||||
|
UWingManualSections::EscapeSequencesInFNames();
|
||||||
|
UWingManualSections::MaterialEditing();
|
||||||
|
UWingManualSections::ImportantCommands();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FName SectionName(*Section);
|
||||||
|
if (!WingManual::PrintSection(SectionName))
|
||||||
|
{
|
||||||
|
WingOut::Stdout.Printf(TEXT("ERROR: Unknown manual section '%s'\nAvailable sections: "), *Section);
|
||||||
|
WingManual::PrintSectionNames(WingManual::GetSections());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ void WingFetcher::PathFailed(const TCHAR* Expected)
|
|||||||
Errors.Printf(TEXT("ERROR: Path specifies a %s, but expected %s\n"), *Obj.Get()->GetClass()->GetName(), Expected);
|
Errors.Printf(TEXT("ERROR: Path specifies a %s, but expected %s\n"), *Obj.Get()->GetClass()->GetName(), Expected);
|
||||||
else
|
else
|
||||||
Errors.Printf(TEXT("ERROR: Path led to a null pointer\n"));
|
Errors.Printf(TEXT("ERROR: Path led to a null pointer\n"));
|
||||||
UWingServer::SuggestManual(WingManual::Section::Paths);
|
UWingServer::SuggestManual(GET_FUNCTION_NAME_CHECKED(UWingManualSections, FetcherPaths));
|
||||||
SetError();
|
SetError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ WingFetcher& WingFetcher::TypeMismatch(const TCHAR* Walker, const TCHAR* Expecte
|
|||||||
Errors.Printf(TEXT("ERROR: Input to '%s' is %s, but expected %s\n"), Walker, *Obj.Get()->GetClass()->GetName(), Expected);
|
Errors.Printf(TEXT("ERROR: Input to '%s' is %s, but expected %s\n"), Walker, *Obj.Get()->GetClass()->GetName(), Expected);
|
||||||
else
|
else
|
||||||
Errors.Printf(TEXT("ERROR: Path led to a null pointer\n"));
|
Errors.Printf(TEXT("ERROR: Path led to a null pointer\n"));
|
||||||
UWingServer::SuggestManual(WingManual::Section::Paths);
|
UWingServer::SuggestManual(GET_FUNCTION_NAME_CHECKED(UWingManualSections, FetcherPaths));
|
||||||
SetError();
|
SetError();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -75,8 +75,8 @@ WingFetcher& WingFetcher::Walk(const FString& Path)
|
|||||||
if (Path.Contains(TEXT(" ")))
|
if (Path.Contains(TEXT(" ")))
|
||||||
{
|
{
|
||||||
Errors.Printf(TEXT("ERROR: Paths may not contain whitespace."));
|
Errors.Printf(TEXT("ERROR: Paths may not contain whitespace."));
|
||||||
UWingServer::SuggestManual(WingManual::Section::Paths);
|
UWingServer::SuggestManual(GET_FUNCTION_NAME_CHECKED(UWingManualSections, FetcherPaths));
|
||||||
UWingServer::SuggestManual(WingManual::Section::EscapeSequences);
|
UWingServer::SuggestManual(GET_FUNCTION_NAME_CHECKED(UWingManualSections, EscapeSequencesInFNames));
|
||||||
return SetError();
|
return SetError();
|
||||||
}
|
}
|
||||||
TArray<FString> Segments;
|
TArray<FString> Segments;
|
||||||
@@ -84,7 +84,7 @@ WingFetcher& WingFetcher::Walk(const FString& Path)
|
|||||||
if (Segments.Num() == 0)
|
if (Segments.Num() == 0)
|
||||||
{
|
{
|
||||||
Errors.Print(TEXT("ERROR: Empty path\n"));
|
Errors.Print(TEXT("ERROR: Empty path\n"));
|
||||||
UWingServer::SuggestManual(WingManual::Section::Paths);
|
UWingServer::SuggestManual(GET_FUNCTION_NAME_CHECKED(UWingManualSections, FetcherPaths));
|
||||||
return SetError();
|
return SetError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ WingFetcher& WingFetcher::Walk(const FString& Path)
|
|||||||
if (!Func)
|
if (!Func)
|
||||||
{
|
{
|
||||||
Errors.Printf(TEXT("ERROR: Unknown path step '%s'\n"), *Key);
|
Errors.Printf(TEXT("ERROR: Unknown path step '%s'\n"), *Key);
|
||||||
UWingServer::SuggestManual(WingManual::Section::Paths);
|
UWingServer::SuggestManual(GET_FUNCTION_NAME_CHECKED(UWingManualSections, FetcherPaths));
|
||||||
return SetError();
|
return SetError();
|
||||||
}
|
}
|
||||||
(this->*Func)(Value);
|
(this->*Func)(Value);
|
||||||
@@ -122,7 +122,7 @@ WingFetcher& WingFetcher::Asset(const FString& PackagePath)
|
|||||||
if (!PackagePath.StartsWith(TEXT("/")))
|
if (!PackagePath.StartsWith(TEXT("/")))
|
||||||
{
|
{
|
||||||
Errors.Printf(TEXT("ERROR: Path must start with '/', got '%s'\n"), *PackagePath);
|
Errors.Printf(TEXT("ERROR: Path must start with '/', got '%s'\n"), *PackagePath);
|
||||||
UWingServer::SuggestManual(WingManual::Section::Paths);
|
UWingServer::SuggestManual(GET_FUNCTION_NAME_CHECKED(UWingManualSections, FetcherPaths));
|
||||||
return SetError();
|
return SetError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ WingFetcher& WingFetcher::Graph(const FString& Value)
|
|||||||
if (!Value.IsEmpty())
|
if (!Value.IsEmpty())
|
||||||
{
|
{
|
||||||
Errors.Printf(TEXT("ERROR: Materials have only one graph, with a blank name.\n\n"));
|
Errors.Printf(TEXT("ERROR: Materials have only one graph, with a blank name.\n\n"));
|
||||||
UWingServer::SuggestManual(WingManual::Section::Paths);
|
UWingServer::SuggestManual(GET_FUNCTION_NAME_CHECKED(UWingManualSections, FetcherPaths));
|
||||||
return SetError();
|
return SetError();
|
||||||
}
|
}
|
||||||
WingUtils::EnsureMaterialGraph(Mat);
|
WingUtils::EnsureMaterialGraph(Mat);
|
||||||
|
|||||||
@@ -58,42 +58,14 @@ void WingManual::PrintHandlerHelp(const FWingHandlerConfig& Handler)
|
|||||||
WingOut::Stdout.Print(TEXT("\n"));
|
WingOut::Stdout.Print(TEXT("\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WingManual::PrintManual(TSet<Section> Sections, const FWingHandlerConfig* Handler, bool Abridged)
|
void UWingManualSections::FetcherPaths()
|
||||||
{
|
{
|
||||||
if (Sections.IsEmpty()) return;
|
|
||||||
|
|
||||||
const bool bPrintAll = Sections.Contains(Section::All);
|
|
||||||
|
|
||||||
if (Abridged)
|
|
||||||
{
|
|
||||||
WingOut::Stdout.Printf(TEXT("\n--- AUTOMATIC DOCUMENTATION ---\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Handler && (Sections.Contains(Section::HandlerHelp) || bPrintAll))
|
|
||||||
{
|
|
||||||
PrintHandlerHelp(*Handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Sections.Contains(Section::Paths) || bPrintAll)
|
|
||||||
{
|
|
||||||
if (Abridged)
|
|
||||||
{
|
|
||||||
WingOut::Stdout.Print(TEXT(
|
WingOut::Stdout.Print(TEXT(
|
||||||
"\n PATHS: Here are some example paths:"
|
"\n FETCHER PATHS:"
|
||||||
"\n /Game/Widgets/WB_Hotkeys,widget:Canvas·122"
|
|
||||||
"\n /Game/Testing/BP_Test,graph:Rescale·Actor,node:K2Node_CallFunction_0,pin:Scale"
|
|
||||||
"\n /Game/Chars/BP_Manny,component:Camera·Boom"
|
|
||||||
"\n"
|
"\n"
|
||||||
));
|
"\n Most commands require you to specify a 'fetcher path'."
|
||||||
}
|
"\n A fetcher path starts with an asset name, followed by"
|
||||||
else
|
"\n steps that navigate into the asset. Some Examples:"
|
||||||
{
|
|
||||||
WingOut::Stdout.Print(TEXT(
|
|
||||||
"\n PATHS:"
|
|
||||||
"\n"
|
|
||||||
"\n Most commands require you to specify a path. A path starts"
|
|
||||||
"\n with an asset name, followed by steps separated by ,"
|
|
||||||
"\n that navigate into the asset. Some Examples:"
|
|
||||||
"\n"
|
"\n"
|
||||||
"\n /Game/Widgets/WB_Hotkeys,widget:Canvas.122"
|
"\n /Game/Widgets/WB_Hotkeys,widget:Canvas.122"
|
||||||
"\n /Game/Testing/BP_Test,graph:Rescale.Actor,node:K2Node_CallFunction_0,pin:Scale"
|
"\n /Game/Testing/BP_Test,graph:Rescale.Actor,node:K2Node_CallFunction_0,pin:Scale"
|
||||||
@@ -107,9 +79,10 @@ void WingManual::PrintManual(TSet<Section> Sections, const FWingHandlerConfig* H
|
|||||||
"\n component — move from a blueprint to a component"
|
"\n component — move from a blueprint to a component"
|
||||||
"\n levelblueprint — move from a world to a blueprint"
|
"\n levelblueprint — move from a world to a blueprint"
|
||||||
"\n widget — move from a widget blueprint to a widget"
|
"\n widget — move from a widget blueprint to a widget"
|
||||||
|
"\n structprop — move into a struct property of an object"
|
||||||
"\n"
|
"\n"
|
||||||
"\n Notice that paths use sanitized identifiers. See the section"
|
"\n Notice that paths use escaped fnames. See the section"
|
||||||
"\n on identifier sanitization below for more information."
|
"\n on escape sequences in fnames below sfor more information."
|
||||||
"\n"
|
"\n"
|
||||||
"\n Steps do not always require a parameter. For example, materials"
|
"\n Steps do not always require a parameter. For example, materials"
|
||||||
"\n only have one graph, so you can just say:"
|
"\n only have one graph, so you can just say:"
|
||||||
@@ -117,29 +90,15 @@ void WingManual::PrintManual(TSet<Section> Sections, const FWingHandlerConfig* H
|
|||||||
"\n /Game/Materials/MyMaterial,graph"
|
"\n /Game/Materials/MyMaterial,graph"
|
||||||
"\n"
|
"\n"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (Sections.Contains(Section::Types) || bPrintAll)
|
void UWingManualSections::ExpressingTypes()
|
||||||
{
|
{
|
||||||
if (Abridged)
|
|
||||||
{
|
|
||||||
WingOut::Stdout.Print(TEXT(
|
WingOut::Stdout.Print(TEXT(
|
||||||
"\n TYPES: Here are some examples of valid types:"
|
"\n EXPRESSING TYPES:"
|
||||||
"\n Bool, String, Vector, Rotator, HitResult, Actor, Character,"
|
|
||||||
"\n PlayerController, EBlendMode, EMovementMode, BP_Manny, BP_Quinn,"
|
|
||||||
"\n Array<Int>, Set<String>, Map<Int,Actor>"
|
|
||||||
"\n Soft<ABP_Manny>, Class<Pawn>, SoftClass<Pawn>"
|
|
||||||
"\n"
|
"\n"
|
||||||
));
|
"\n To change the type of a variable, or to express function parameters,"
|
||||||
}
|
"\n you will use our syntax for types. Here are some valid examples:"
|
||||||
else
|
|
||||||
{
|
|
||||||
WingOut::Stdout.Print(TEXT(
|
|
||||||
"\n TYPES:"
|
|
||||||
"\n"
|
|
||||||
"\n To change variable types, or to express function prototypes, you will"
|
|
||||||
"\n use our syntax for types. Here are some valid examples:"
|
|
||||||
"\n"
|
"\n"
|
||||||
"\n Bool, String, Vector, Rotator, HitResult, Actor, Character,"
|
"\n Bool, String, Vector, Rotator, HitResult, Actor, Character,"
|
||||||
"\n PlayerController, EBlendMode, EMovementMode, BP_Manny, BP_Quinn,"
|
"\n PlayerController, EBlendMode, EMovementMode, BP_Manny, BP_Quinn,"
|
||||||
@@ -148,25 +107,14 @@ void WingManual::PrintManual(TSet<Section> Sections, const FWingHandlerConfig* H
|
|||||||
"\n"
|
"\n"
|
||||||
"\n Notice that it's 'Actor', not 'AActor'. Type names are not"
|
"\n Notice that it's 'Actor', not 'AActor'. Type names are not"
|
||||||
"\n case-sensitive. When a blueprint like /Game/Testing/BP_Foo"
|
"\n case-sensitive. When a blueprint like /Game/Testing/BP_Foo"
|
||||||
"\n is used as a type, the typename is BP_Foo."
|
"\n is used as a type, the typename is just BP_Foo. You can search"
|
||||||
|
"\n for valid types using the TypeName_Search command."
|
||||||
"\n"
|
"\n"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (Sections.Contains(Section::VariableDeclarations) || bPrintAll)
|
void UWingManualSections::VariableDeclarations()
|
||||||
{
|
{
|
||||||
if (Abridged)
|
|
||||||
{
|
|
||||||
WingOut::Stdout.Print(TEXT(
|
|
||||||
"\n VARIABLE DECLARATIONS: example variable declarations:"
|
|
||||||
"\n Array<Actor> Actors"
|
|
||||||
"\n Float F (InstanceEditable)"
|
|
||||||
"\n String S = This is the default value"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WingOut::Stdout.Print(TEXT(
|
WingOut::Stdout.Print(TEXT(
|
||||||
"\n VARIABLE DECLARATIONS:"
|
"\n VARIABLE DECLARATIONS:"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -179,48 +127,20 @@ void WingManual::PrintManual(TSet<Section> Sections, const FWingHandlerConfig* H
|
|||||||
"\n String S = This is the default value"
|
"\n String S = This is the default value"
|
||||||
"\n"
|
"\n"
|
||||||
"\n The commands Variables_Add, Variables_Modify,"
|
"\n The commands Variables_Add, Variables_Modify,"
|
||||||
"\n and Variables_Remove can be used to edit: "
|
"\n and Variables_Remove can be used to edit "
|
||||||
"\n blueprint variables, graph local variables, graph input"
|
"\n blueprint variables, graph local variables, graph input"
|
||||||
"\n variables, graph output variables, and custom"
|
"\n variables, graph output variables, and custom"
|
||||||
"\n event node input variables. Event dispatchers are"
|
"\n event node input variables. Event dispatchers are"
|
||||||
"\n also graphs, so they too can be edited."
|
"\n also graphs, so they too can be edited."
|
||||||
"\n"
|
"\n"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (Sections.Contains(Section::EscapeSequences) || bPrintAll)
|
void UWingManualSections::EscapeSequencesInFNames()
|
||||||
{
|
{
|
||||||
if (Abridged)
|
|
||||||
{
|
|
||||||
WingOut::Stdout.Print(TEXT(
|
WingOut::Stdout.Print(TEXT(
|
||||||
"\n USING HTML ESCAPE SEQUENCES:"
|
"\n ESCAPE SEQUENCES IN FNAMES:"
|
||||||
"\n When we output FNames, we use HTML escape sequences for the"
|
|
||||||
"\n following marks: \\\"'(),.:;<=>& We also escape control"
|
|
||||||
"\n characters, and some (but not all) unicode characters."
|
|
||||||
"\n We also translate spaces to periods. Examples:"
|
|
||||||
"\n"
|
"\n"
|
||||||
"\n FName(TEXT(\"No_Change\")) --> No_Change"
|
|
||||||
"\n FName(TEXT(\"ίδιος\")) --> ίδιος"
|
|
||||||
"\n FName(TEXT(\"✡✢❄\")) --> ✡✢❄"
|
|
||||||
"\n FName(TEXT(\"Hello.There\")) --> Hello.There"
|
|
||||||
"\n FName(TEXT(\"Hello There\")) --> Hello.There"
|
|
||||||
"\n FName(TEXT(\"Hello\n\")) --> Hello
"
|
|
||||||
"\n "
|
|
||||||
"\n When sending FNames to UE Wingman, you *must* escape the marks"
|
|
||||||
"\n listed above and control characters, but you *may* escape"
|
|
||||||
"\n any character. To send an FName with a space in it, either"
|
|
||||||
"\n use   or a period."
|
|
||||||
"\n"
|
|
||||||
"\n Currently, this escaping *only* applies to FNames. It"
|
|
||||||
"\n doesn't work to use escapes in asset names or file names."
|
|
||||||
"\n"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WingOut::Stdout.Print(TEXT(
|
|
||||||
"\n USING HTML ESCAPE SEQUENCES:"
|
|
||||||
"\n When we output FNames, we use HTML escape sequences for the"
|
"\n When we output FNames, we use HTML escape sequences for the"
|
||||||
"\n following marks: \\\"'(),.:;<=>&, and for certain other characters."
|
"\n following marks: \\\"'(),.:;<=>&, and for certain other characters."
|
||||||
"\n We also translate spaces to periods."
|
"\n We also translate spaces to periods."
|
||||||
@@ -230,34 +150,10 @@ void WingManual::PrintManual(TSet<Section> Sections, const FWingHandlerConfig* H
|
|||||||
"\n with a space in it, either use   or a period."
|
"\n with a space in it, either use   or a period."
|
||||||
"\n"
|
"\n"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (Sections.Contains(Section::Whitespace) || bPrintAll)
|
void UWingManualSections::MaterialEditing()
|
||||||
{
|
{
|
||||||
WingOut::Stdout.Print(TEXT(
|
|
||||||
"\n ABOUT WHITESPACE:"
|
|
||||||
"\n Do not put excess whitespace into paths, typenames, or"
|
|
||||||
"\n function prototypes, only use whitespace where it is required"
|
|
||||||
"\n by the syntax."
|
|
||||||
"\n"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Sections.Contains(Section::MaterialEditing) || bPrintAll)
|
|
||||||
{
|
|
||||||
if (Abridged)
|
|
||||||
{
|
|
||||||
WingOut::Stdout.Print(TEXT(
|
|
||||||
"\n MATERIAL EDITING:"
|
|
||||||
"\n We do not expose material expressions directly. Instead, use"
|
|
||||||
"\n Details_Dump and Details_Set on the material graph nodes to"
|
|
||||||
"\n edit material expression properties."
|
|
||||||
"\n"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WingOut::Stdout.Print(TEXT(
|
WingOut::Stdout.Print(TEXT(
|
||||||
"\n MATERIAL EDITING:"
|
"\n MATERIAL EDITING:"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -267,15 +163,18 @@ void WingManual::PrintManual(TSet<Section> Sections, const FWingHandlerConfig* H
|
|||||||
"\n properties which actually come from the material expressions."
|
"\n properties which actually come from the material expressions."
|
||||||
"\n You can edit these using Details_Set on the node."
|
"\n You can edit these using Details_Set on the node."
|
||||||
"\n"
|
"\n"
|
||||||
|
"\n Don't overlook custom HLSL nodes. These can accomplish in\n"
|
||||||
|
"\n a single node what would otherwise take many.\n"
|
||||||
|
"\n"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (Sections.Contains(Section::ImportantCommands) || bPrintAll)
|
void UWingManualSections::ImportantCommands()
|
||||||
{
|
{
|
||||||
WingOut::Stdout.Print(TEXT(
|
WingOut::Stdout.Print(TEXT(
|
||||||
"\n COMMANDS YOU SHOULD KNOW ABOUT AND REMEMBER:"
|
"\n IMPORTANT COMMANDS:"
|
||||||
"\n Documentation_Manual: this explanation"
|
"\n"
|
||||||
|
"\n Documentation_Manual: print manual sections"
|
||||||
"\n Documentation_Commands: a list of all the main commands"
|
"\n Documentation_Commands: a list of all the main commands"
|
||||||
"\n Documentation_CreateAssets: Additional commands that create new assets"
|
"\n Documentation_CreateAssets: Additional commands that create new assets"
|
||||||
"\n Blueprint_Dump: a summary of any blueprint"
|
"\n Blueprint_Dump: a summary of any blueprint"
|
||||||
@@ -283,16 +182,44 @@ void WingManual::PrintManual(TSet<Section> Sections, const FWingHandlerConfig* H
|
|||||||
"\n Details_Dump: Dump the details panel for a given object"
|
"\n Details_Dump: Dump the details panel for a given object"
|
||||||
"\n Details_Set: Manipulate the details panel for a given object"
|
"\n Details_Set: Manipulate the details panel for a given object"
|
||||||
"\n"
|
"\n"
|
||||||
"\n You can use Documentation_Commands(Query=SomeCommand,Verbose=true)"
|
"\n You can use Documentation_Commands(Query=Command,Verbose=true)"
|
||||||
"\n to get detailed help for a specific command."
|
"\n to get detailed help for a specific command."
|
||||||
"\n"
|
"\n"
|
||||||
|
"\n You can use Documentation_Manual(Section=Name) to print out"
|
||||||
|
"\n a specific manual section."
|
||||||
|
"\n"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Abridged)
|
TSet<FName> WingManual::GetSections()
|
||||||
|
{
|
||||||
|
TSet<FName> Result;
|
||||||
|
for (TFieldIterator<UFunction> It(UWingManualSections::StaticClass(), EFieldIterationFlags::None); It; ++It)
|
||||||
{
|
{
|
||||||
WingOut::Stdout.Printf(TEXT("\nUse command 'Documentation_Manual' to see the full manual.\n"));
|
Result.Add(It->GetFName());
|
||||||
}
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WingManual::PrintSectionNames(const TSet<FName>& Sections)
|
||||||
|
{
|
||||||
|
if (Sections.IsEmpty()) return;
|
||||||
|
bool bFirst = true;
|
||||||
|
for (const FName& Section : Sections)
|
||||||
|
{
|
||||||
|
if (!bFirst) WingOut::Stdout.Print(TEXT(", "));
|
||||||
|
bFirst = false;
|
||||||
|
WingOut::Stdout.Printf(TEXT("%s"), *Section.ToString());
|
||||||
|
}
|
||||||
|
WingOut::Stdout.Print(TEXT("\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WingManual::PrintSection(FName Section)
|
||||||
|
{
|
||||||
|
UFunction* Func = UWingManualSections::StaticClass()->FindFunctionByName(Section);
|
||||||
|
if (!Func) return false;
|
||||||
|
UWingManualSections::StaticClass()->GetDefaultObject()->ProcessEvent(Func, nullptr);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WingManual::Commands(EWingHandlerKind Kind, const FString& Query, bool Verbose)
|
void WingManual::Commands(EWingHandlerKind Kind, const FString& Query, bool Verbose)
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ FString UWingServer::HandleRequest(const FString& Line)
|
|||||||
LogCapture.bEnabled = true;
|
LogCapture.bEnabled = true;
|
||||||
WingOut::StdoutBuffer.Reset();
|
WingOut::StdoutBuffer.Reset();
|
||||||
SuggestedManualSections.Empty();
|
SuggestedManualSections.Empty();
|
||||||
|
bSuggestHandlerHelp = false;
|
||||||
LastHandler = nullptr;
|
LastHandler = nullptr;
|
||||||
|
|
||||||
TryCallHandler(Line);
|
TryCallHandler(Line);
|
||||||
@@ -186,10 +187,14 @@ FString UWingServer::HandleRequest(const FString& Line)
|
|||||||
WingOut::Stdout.Printf(TEXT("UE_LOG: %s\n"), *Msg);
|
WingOut::Stdout.Printf(TEXT("UE_LOG: %s\n"), *Msg);
|
||||||
}
|
}
|
||||||
LogCapture.CapturedErrors.Empty();
|
LogCapture.CapturedErrors.Empty();
|
||||||
|
if (bSuggestHandlerHelp && LastHandler)
|
||||||
|
{
|
||||||
|
WingManual::PrintHandlerHelp(*LastHandler);
|
||||||
|
}
|
||||||
if (!SuggestedManualSections.IsEmpty())
|
if (!SuggestedManualSections.IsEmpty())
|
||||||
{
|
{
|
||||||
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
WingOut::Stdout.Print(TEXT("Suggested manual sections: "));
|
||||||
WingManual::PrintManual(SuggestedManualSections, LastHandler, true);
|
WingManual::PrintSectionNames(SuggestedManualSections);
|
||||||
}
|
}
|
||||||
FString Result = WingOut::StdoutBuffer.ToString();
|
FString Result = WingOut::StdoutBuffer.ToString();
|
||||||
WingOut::StdoutBuffer.Reset();
|
WingOut::StdoutBuffer.Reset();
|
||||||
@@ -227,7 +232,7 @@ void UWingServer::TryCallHandler(const FString &Line)
|
|||||||
if (!Found)
|
if (!Found)
|
||||||
{
|
{
|
||||||
WingOut::Stdout.Printf(TEXT("Unknown command: %s"), *Command);
|
WingOut::Stdout.Printf(TEXT("Unknown command: %s"), *Command);
|
||||||
UWingServer::SuggestManual(WingManual::Section::ImportantCommands);
|
UWingServer::SuggestManual(GET_FUNCTION_NAME_CHECKED(UWingManualSections, ImportantCommands));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LastHandler = Found;
|
LastHandler = Found;
|
||||||
@@ -241,7 +246,7 @@ void UWingServer::TryCallHandler(const FString &Line)
|
|||||||
TArray<FWingProperty> Props = FWingProperty::GetVisible(Handler);
|
TArray<FWingProperty> Props = FWingProperty::GetVisible(Handler);
|
||||||
if (!FWingProperty::PopulateFromJson(Props, *Request, false, WingOut::Stdout))
|
if (!FWingProperty::PopulateFromJson(Props, *Request, false, WingOut::Stdout))
|
||||||
{
|
{
|
||||||
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
UWingServer::SuggestHandlerHelp();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -430,7 +430,7 @@ void UWingTypes::PrintParseError(WingTokenizer& Tok, const TCHAR* Message, WingO
|
|||||||
{
|
{
|
||||||
FString TypeText(Tok.GetRange(NAME_StartOfType, 1));
|
FString TypeText(Tok.GetRange(NAME_StartOfType, 1));
|
||||||
Errors.Printf(TEXT("ERROR parsing type '%s' — %s\n"), *TypeText, Message);
|
Errors.Printf(TEXT("ERROR parsing type '%s' — %s\n"), *TypeText, Message);
|
||||||
UWingServer::SuggestManual(WingManual::Section::Types);
|
UWingServer::SuggestManual(GET_FUNCTION_NAME_CHECKED(UWingManualSections, ExpressingTypes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -626,7 +626,7 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con
|
|||||||
if (IsNone && OutPinType.IsContainer())
|
if (IsNone && OutPinType.IsContainer())
|
||||||
{
|
{
|
||||||
Errors.Printf(TEXT("ERROR: 'None' is not allowed in an array/set/map\n"));
|
Errors.Printf(TEXT("ERROR: 'None' is not allowed in an array/set/map\n"));
|
||||||
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
UWingServer::SuggestHandlerHelp();
|
||||||
OutPinType = FEdGraphPinType(); return false;
|
OutPinType = FEdGraphPinType(); return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -634,7 +634,7 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con
|
|||||||
if (!Require.AllowNone && IsNone)
|
if (!Require.AllowNone && IsNone)
|
||||||
{
|
{
|
||||||
Errors.Printf(TEXT("ERROR: 'None' is not allowed here\n"));
|
Errors.Printf(TEXT("ERROR: 'None' is not allowed here\n"));
|
||||||
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
UWingServer::SuggestHandlerHelp();
|
||||||
OutPinType = FEdGraphPinType(); return false;
|
OutPinType = FEdGraphPinType(); return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -644,7 +644,7 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con
|
|||||||
{
|
{
|
||||||
FString Text(Tok.GetRange(NAME_StartOfType, 0));
|
FString Text(Tok.GetRange(NAME_StartOfType, 0));
|
||||||
Errors.Printf(TEXT("ERROR: Type '%s' is a container, not allowed here\n"), *Text);
|
Errors.Printf(TEXT("ERROR: Type '%s' is a container, not allowed here\n"), *Text);
|
||||||
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
UWingServer::SuggestHandlerHelp();
|
||||||
OutPinType = FEdGraphPinType(); return false;
|
OutPinType = FEdGraphPinType(); return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -655,7 +655,7 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con
|
|||||||
{
|
{
|
||||||
Errors.Printf(TEXT("ERROR: Need a type which is an %s, got a %s instead.\n"),
|
Errors.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);
|
UWingServer::SuggestHandlerHelp();
|
||||||
OutPinType = FEdGraphPinType(); return false;
|
OutPinType = FEdGraphPinType(); return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -668,13 +668,13 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con
|
|||||||
{
|
{
|
||||||
FString Text(Tok.GetRange(NAME_StartOfType, 0));
|
FString Text(Tok.GetRange(NAME_StartOfType, 0));
|
||||||
Errors.Printf(TEXT("ERROR: '%s' is an interface, not a class\n"), *Text);
|
Errors.Printf(TEXT("ERROR: '%s' is an interface, not a class\n"), *Text);
|
||||||
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
UWingServer::SuggestHandlerHelp();
|
||||||
OutPinType = FEdGraphPinType(); return false;
|
OutPinType = FEdGraphPinType(); return false;
|
||||||
}
|
}
|
||||||
if (!IsChildOf(OutPinType, Require.IsChildOf))
|
if (!IsChildOf(OutPinType, Require.IsChildOf))
|
||||||
{
|
{
|
||||||
Errors.Printf(TEXT("ERROR: Type must derive from %s\n"), *WingUtils::FormatName(Require.IsChildOf));
|
Errors.Printf(TEXT("ERROR: Type must derive from %s\n"), *WingUtils::FormatName(Require.IsChildOf));
|
||||||
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
UWingServer::SuggestHandlerHelp();
|
||||||
OutPinType = FEdGraphPinType(); return false;
|
OutPinType = FEdGraphPinType(); return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -685,7 +685,7 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con
|
|||||||
{
|
{
|
||||||
FString Text(Tok.GetRange(NAME_StartOfType, 0));
|
FString Text(Tok.GetRange(NAME_StartOfType, 0));
|
||||||
Errors.Printf(TEXT("ERROR: Not a blueprint type: %s\n"), *Text);
|
Errors.Printf(TEXT("ERROR: Not a blueprint type: %s\n"), *Text);
|
||||||
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
UWingServer::SuggestHandlerHelp();
|
||||||
OutPinType = FEdGraphPinType(); return false;
|
OutPinType = FEdGraphPinType(); return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -696,7 +696,7 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con
|
|||||||
{
|
{
|
||||||
FString Text(Tok.GetRange(NAME_StartOfType, 0));
|
FString Text(Tok.GetRange(NAME_StartOfType, 0));
|
||||||
Errors.Printf(TEXT("ERROR: Not a blueprintable type: %s\n"), *Text);
|
Errors.Printf(TEXT("ERROR: Not a blueprintable type: %s\n"), *Text);
|
||||||
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
UWingServer::SuggestHandlerHelp();
|
||||||
OutPinType = FEdGraphPinType(); return false;
|
OutPinType = FEdGraphPinType(); return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ FName WingUtils::CheckInternalizeID(const FString &ExternalID, WingOut Errors)
|
|||||||
if (!Error.IsEmpty())
|
if (!Error.IsEmpty())
|
||||||
{
|
{
|
||||||
Errors.Printf(TEXT("%s\n"), *Error);
|
Errors.Printf(TEXT("%s\n"), *Error);
|
||||||
UWingServer::SuggestManual(WingManual::Section::EscapeSequences);
|
UWingServer::SuggestManual(GET_FUNCTION_NAME_CHECKED(UWingManualSections, EscapeSequencesInFNames));
|
||||||
}
|
}
|
||||||
return InternalID;
|
return InternalID;
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ FName WingUtils::CheckProposedName(const FString &ExternalID, const TSet<FName>
|
|||||||
{
|
{
|
||||||
Errors.Printf(TEXT("ERROR: id %s would not be a readable id, may not create item with this name"),
|
Errors.Printf(TEXT("ERROR: id %s would not be a readable id, may not create item with this name"),
|
||||||
*ExternalID);
|
*ExternalID);
|
||||||
UWingServer::SuggestManual(WingManual::Section::EscapeSequences);
|
UWingServer::SuggestManual(GET_FUNCTION_NAME_CHECKED(UWingManualSections, EscapeSequencesInFNames));
|
||||||
return FName();
|
return FName();
|
||||||
}
|
}
|
||||||
if (InUse.Contains(InternalID))
|
if (InUse.Contains(InternalID))
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
|
#include "WingManual.generated.h"
|
||||||
|
|
||||||
struct FWingHandlerConfig;
|
struct FWingHandlerConfig;
|
||||||
enum class EWingHandlerKind;
|
enum class EWingHandlerKind;
|
||||||
@@ -7,23 +8,37 @@ enum class EWingHandlerKind;
|
|||||||
class WingManual
|
class WingManual
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum class Section
|
|
||||||
{
|
|
||||||
All,
|
|
||||||
HandlerHelp,
|
|
||||||
Paths,
|
|
||||||
Types,
|
|
||||||
VariableDeclarations,
|
|
||||||
EscapeSequences,
|
|
||||||
Whitespace,
|
|
||||||
MaterialEditing,
|
|
||||||
ImportantCommands,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void PrintHandlerPrototype(const FWingHandlerConfig& Handler);
|
static void PrintHandlerPrototype(const FWingHandlerConfig& Handler);
|
||||||
static void PrintHandlerArguments(const FWingHandlerConfig& Handler);
|
static void PrintHandlerArguments(const FWingHandlerConfig& Handler);
|
||||||
static void PrintHandlerDescription(const FWingHandlerConfig& Handler);
|
static void PrintHandlerDescription(const FWingHandlerConfig& Handler);
|
||||||
static void PrintHandlerHelp(const FWingHandlerConfig& Handler);
|
static void PrintHandlerHelp(const FWingHandlerConfig& Handler);
|
||||||
static void PrintManual(TSet<Section> Sections, const FWingHandlerConfig* Handler, bool Abridged);
|
|
||||||
static void Commands(EWingHandlerKind Kind, const FString& Query, bool Verbose);
|
static void Commands(EWingHandlerKind Kind, const FString& Query, bool Verbose);
|
||||||
|
static TSet<FName> GetSections();
|
||||||
|
static bool PrintSection(FName Section);
|
||||||
|
static void PrintSectionNames(const TSet<FName>& Sections);
|
||||||
|
};
|
||||||
|
|
||||||
|
UCLASS()
|
||||||
|
class UWingManualSections : public UObject
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UFUNCTION()
|
||||||
|
static void FetcherPaths();
|
||||||
|
|
||||||
|
UFUNCTION()
|
||||||
|
static void ExpressingTypes();
|
||||||
|
|
||||||
|
UFUNCTION()
|
||||||
|
static void VariableDeclarations();
|
||||||
|
|
||||||
|
UFUNCTION()
|
||||||
|
static void EscapeSequencesInFNames();
|
||||||
|
|
||||||
|
UFUNCTION()
|
||||||
|
static void MaterialEditing();
|
||||||
|
|
||||||
|
UFUNCTION()
|
||||||
|
static void ImportantCommands();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -48,7 +48,10 @@ public:
|
|||||||
static void AddTouchedObject(UObject* Obj) { GWingServer->Notifier.AddTouchedObject(Obj); }
|
static void AddTouchedObject(UObject* Obj) { GWingServer->Notifier.AddTouchedObject(Obj); }
|
||||||
|
|
||||||
/** Suggest that a manual section be printed after the handler finishes. */
|
/** Suggest that a manual section be printed after the handler finishes. */
|
||||||
static void SuggestManual(WingManual::Section Section) { GWingServer->SuggestedManualSections.Add(Section); }
|
static void SuggestManual(FName Section) { GWingServer->SuggestedManualSections.Add(Section); }
|
||||||
|
|
||||||
|
/** Suggest that handler help be printed after the handler finishes. */
|
||||||
|
static void SuggestHandlerHelp() { GWingServer->bSuggestHandlerHelp = true; }
|
||||||
|
|
||||||
/** Port the server is listening on. */
|
/** Port the server is listening on. */
|
||||||
int32 GetPort() const { return Port; }
|
int32 GetPort() const { return Port; }
|
||||||
@@ -64,7 +67,8 @@ private:
|
|||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
FWingNotifier Notifier;
|
FWingNotifier Notifier;
|
||||||
FWingHandlerConfig* LastHandler;
|
FWingHandlerConfig* LastHandler;
|
||||||
TSet<WingManual::Section> SuggestedManualSections;
|
bool bSuggestHandlerHelp;
|
||||||
|
TSet<FName> SuggestedManualSections;
|
||||||
FLogCaptureOutputDevice LogCapture; // installed once at startup, enabled per-request
|
FLogCaptureOutputDevice LogCapture; // installed once at startup, enabled per-request
|
||||||
TArray<FWingHandlerConfig> WingHandlerRegistry; // sorted by Name
|
TArray<FWingHandlerConfig> WingHandlerRegistry; // sorted by Name
|
||||||
void BuildWingHandlerRegistry();
|
void BuildWingHandlerRegistry();
|
||||||
|
|||||||
Reference in New Issue
Block a user