Starting to convert old search functions to new ones

This commit is contained in:
2026-03-29 01:14:58 -04:00
parent 2ad86bac1d
commit 843e16b177
18 changed files with 62 additions and 64 deletions

Binary file not shown.

View File

@@ -50,7 +50,7 @@ public:
// Check that the proposed name is valid // Check that the proposed name is valid
TArray<UWingComponentReference*> AllComponents = UWingComponentReference::GetAll(BP); TArray<UWingComponentReference*> AllComponents = UWingComponentReference::GetAll(BP);
if (!WingUtils::FindExactlyNoneNamed(Component, AllComponents, TEXT("Component"))) return; if (!WingUtils::FindNoneWithExternalID(Component, AllComponents, TEXT("Component"))) return;
FString InternalName = WingUtils::CheckProposedName(Component); FString InternalName = WingUtils::CheckProposedName(Component);
if (InternalName.IsEmpty()) return; if (InternalName.IsEmpty()) return;
@@ -65,7 +65,7 @@ public:
if (!UWingComponentReference::CheckValidComponentClass(ComponentClass)) return; if (!UWingComponentReference::CheckValidComponentClass(ComponentClass)) return;
// Find the specified parent component // Find the specified parent component
UWingComponentReference* ParentComp = WingUtils::FindExactlyOneNamed(Parent, AllComponents, TEXT("Component")); UWingComponentReference* ParentComp = WingUtils::FindOneWithExternalID(Parent, AllComponents, TEXT("Component"));
if (!ParentComp) return; if (!ParentComp) return;
// Create the SCS node // Create the SCS node

View File

@@ -42,7 +42,7 @@ public:
// Find the new parent among all components (if specified) // Find the new parent among all components (if specified)
UBlueprint *BP = CompRef->BP; UBlueprint *BP = CompRef->BP;
TArray<UWingComponentReference*> AllComponents = UWingComponentReference::GetAll(BP); TArray<UWingComponentReference*> AllComponents = UWingComponentReference::GetAll(BP);
UWingComponentReference* NewParent = WingUtils::FindExactlyOneNamed(Parent, AllComponents, TEXT("Component")); UWingComponentReference* NewParent = WingUtils::FindOneWithExternalID(Parent, AllComponents, TEXT("Component"));
if (!NewParent) return; if (!NewParent) return;
if (!CompRef->ReparentComponent(NewParent)) return; if (!CompRef->ReparentComponent(NewParent)) return;

View File

@@ -76,7 +76,7 @@ public:
} }
// Check graph name uniqueness and legality // Check graph name uniqueness and legality
if (!WingUtils::FindExactlyNoneNamed(Graph, WingUtils::AllGraphs(BP), TEXT("Graph"))) if (!WingUtils::FindNoneWithExternalID(Graph, WingUtils::AllGraphs(BP), TEXT("Graph")))
return; return;
FString InternalName = WingUtils::CheckProposedName(Graph); FString InternalName = WingUtils::CheckProposedName(Graph);
if (InternalName.IsEmpty()) return; if (InternalName.IsEmpty()) return;

View File

@@ -45,7 +45,7 @@ public:
if (!BP) return; if (!BP) return;
// Check validity of the proposed name // Check validity of the proposed name
if (!WingUtils::FindExactlyNoneNamed(Name, BP->NewVariables, TEXT("Variable"))) return; if (!WingUtils::FindNoneWithExternalID(Name, BP->NewVariables, TEXT("Variable"))) return;
FString InternalName = WingUtils::CheckProposedName(Name); FString InternalName = WingUtils::CheckProposedName(Name);
if (InternalName.IsEmpty()) return; if (InternalName.IsEmpty()) return;
FName VarFName(InternalName); FName VarFName(InternalName);

View File

@@ -43,8 +43,8 @@ public:
if (!BP) return; if (!BP) return;
// Check for valid proposed name // Check for valid proposed name
if (!WingUtils::FindExactlyNoneNamed(Dispatcher, BP->NewVariables, TEXT("Variable"))) return; if (!WingUtils::FindNoneWithExternalID(Dispatcher, BP->NewVariables, TEXT("Variable"))) return;
if (!WingUtils::FindExactlyNoneNamed(Dispatcher, WingUtils::AllGraphs(BP), TEXT("Graph"))) return; if (!WingUtils::FindNoneWithExternalID(Dispatcher, WingUtils::AllGraphs(BP), TEXT("Graph"))) return;
FString InternalName = WingUtils::CheckProposedName(Dispatcher); FString InternalName = WingUtils::CheckProposedName(Dispatcher);
if (InternalName.IsEmpty()) return; if (InternalName.IsEmpty()) return;
FName VarFName(InternalName); FName VarFName(InternalName);

View File

@@ -37,9 +37,9 @@ public:
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>(); UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
if (!BP) return; if (!BP) return;
FBPVariableDescription* Var = WingUtils::FindExactlyOneNamed(Dispatcher, BP->NewVariables, TEXT("Dispatcher")); FBPVariableDescription* Var = WingUtils::FindOneWithExternalID(Dispatcher, BP->NewVariables, TEXT("Dispatcher"));
if (!Var) return; if (!Var) return;
TObjectPtr<UEdGraph>* SigGraph = WingUtils::FindExactlyOneNamed(Dispatcher, BP->DelegateSignatureGraphs, TEXT("Dispatcher Signature Graph")); TObjectPtr<UEdGraph>* SigGraph = WingUtils::FindOneWithExternalID(Dispatcher, BP->DelegateSignatureGraphs, TEXT("Dispatcher Signature Graph"));
if (!SigGraph) return; if (!SigGraph) return;
UEdGraph* Graph = *SigGraph; UEdGraph* Graph = *SigGraph;

View File

@@ -39,9 +39,9 @@ public:
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>(); UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
if (!BP) return; if (!BP) return;
FBPVariableDescription* Var = WingUtils::FindExactlyOneNamed(Dispatcher, BP->NewVariables, TEXT("Dispatcher")); FBPVariableDescription* Var = WingUtils::FindOneWithExternalID(Dispatcher, BP->NewVariables, TEXT("Dispatcher"));
if (!Var) return; if (!Var) return;
TObjectPtr<UEdGraph>* SigGraph = WingUtils::FindExactlyOneNamed(Dispatcher, BP->DelegateSignatureGraphs, TEXT("Dispatcher Signature Graph")); TObjectPtr<UEdGraph>* SigGraph = WingUtils::FindOneWithExternalID(Dispatcher, BP->DelegateSignatureGraphs, TEXT("Dispatcher Signature Graph"));
if (!SigGraph) return; if (!SigGraph) return;
TWeakObjectPtr<UK2Node_EditablePinBase> EntryNode; TWeakObjectPtr<UK2Node_EditablePinBase> EntryNode;

View File

@@ -41,9 +41,9 @@ public:
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>(); UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
if (!BP) return; if (!BP) return;
FBPVariableDescription* Var = WingUtils::FindExactlyOneNamed(Dispatcher, BP->NewVariables, TEXT("Dispatcher")); FBPVariableDescription* Var = WingUtils::FindOneWithExternalID(Dispatcher, BP->NewVariables, TEXT("Dispatcher"));
if (!Var) return; if (!Var) return;
TObjectPtr<UEdGraph>* SigGraph = WingUtils::FindExactlyOneNamed(Dispatcher, BP->DelegateSignatureGraphs, TEXT("Dispatcher Signature Graph")); TObjectPtr<UEdGraph>* SigGraph = WingUtils::FindOneWithExternalID(Dispatcher, BP->DelegateSignatureGraphs, TEXT("Dispatcher Signature Graph"));
if (!SigGraph) return; if (!SigGraph) return;
// Make sure the argument types are valid. // Make sure the argument types are valid.

View File

@@ -72,13 +72,13 @@ public:
// Check that the name is unique among existing widgets. // Check that the name is unique among existing widgets.
TArray<UWidget*> AllWidgets; TArray<UWidget*> AllWidgets;
Tree->GetAllWidgets(AllWidgets); Tree->GetAllWidgets(AllWidgets);
if (!WingUtils::FindExactlyNoneNamed(Name, AllWidgets, TEXT("Widget"))) return; if (!WingUtils::FindNoneWithExternalID(Name, AllWidgets, TEXT("Widget"))) return;
// If a parent is specified, find it and verify it's a panel. // If a parent is specified, find it and verify it's a panel.
UPanelWidget* ParentPanel = nullptr; UPanelWidget* ParentPanel = nullptr;
if (!Parent.IsEmpty()) if (!Parent.IsEmpty())
{ {
UWidget* ParentWidget = WingUtils::FindExactlyOneNamed(Parent, AllWidgets, TEXT("Widget")); UWidget* ParentWidget = WingUtils::FindOneWithExternalID(Parent, AllWidgets, TEXT("Widget"));
if (!ParentWidget) return; if (!ParentWidget) return;
if (!WingWidgets::CheckCanBeParent(ParentWidget)) return; if (!WingWidgets::CheckCanBeParent(ParentWidget)) return;
ParentPanel = Cast<UPanelWidget>(ParentWidget); ParentPanel = Cast<UPanelWidget>(ParentWidget);

View File

@@ -56,7 +56,7 @@ public:
FString WidgetName = WingUtils::FormatName(TargetWidget); FString WidgetName = WingUtils::FormatName(TargetWidget);
// Find the new parent and verify it's a panel with room. // Find the new parent and verify it's a panel with room.
UWidget* ParentWidget = WingUtils::FindExactlyOneNamed(Parent, AllWidgets, TEXT("Widget")); UWidget* ParentWidget = WingUtils::FindOneWithExternalID(Parent, AllWidgets, TEXT("Widget"));
if (!ParentWidget) return; if (!ParentWidget) return;
if (!WingWidgets::CheckCanBeParent(ParentWidget)) return; if (!WingWidgets::CheckCanBeParent(ParentWidget)) return;
UPanelWidget* ParentPanel = Cast<UPanelWidget>(ParentWidget); UPanelWidget* ParentPanel = Cast<UPanelWidget>(ParentWidget);

View File

@@ -7,7 +7,7 @@
FWingBlueprintVar::FWingBlueprintVar(UBlueprint* BP, const FString& VarName) FWingBlueprintVar::FWingBlueprintVar(UBlueprint* BP, const FString& VarName)
{ {
Desc = WingUtils::FindExactlyOneNamed(VarName, BP->NewVariables, TEXT("Variable")); Desc = WingUtils::FindOneWithExternalID(VarName, BP->NewVariables, TEXT("Variable"));
if (!Desc) return; if (!Desc) return;
if (Desc->VarType.PinCategory == UEdGraphSchema_K2::PC_MCDelegate) if (Desc->VarType.PinCategory == UEdGraphSchema_K2::PC_MCDelegate)
{ {

View File

@@ -89,7 +89,7 @@ WingFetcher& WingFetcher::Walk(const FString& Path)
{ {
UWingServer::Printf(TEXT("ERROR: Paths may not contain whitespace.")); UWingServer::Printf(TEXT("ERROR: Paths may not contain whitespace."));
UWingServer::SuggestManual(WingManual::Section::Paths); UWingServer::SuggestManual(WingManual::Section::Paths);
UWingServer::SuggestManual(WingManual::Section::IdentifierSanitization); UWingServer::SuggestManual(WingManual::Section::EscapeSequences);
return SetError(); return SetError();
} }
TArray<FString> Segments; TArray<FString> Segments;
@@ -224,7 +224,7 @@ WingFetcher& WingFetcher::Graph(const FString& Value)
} }
TArray<UEdGraph*> Graphs = WingUtils::AllGraphs(BP); TArray<UEdGraph*> Graphs = WingUtils::AllGraphs(BP);
UEdGraph* Found = WingUtils::FindExactlyOneNamed(Value, Graphs, TEXT("graph")); UEdGraph* Found = WingUtils::FindOneWithExternalID(Value, Graphs, TEXT("graph"));
if (!Found) if (!Found)
{ {
UWingServer::Printf(TEXT("Graphs that exist in blueprint:\n")); UWingServer::Printf(TEXT("Graphs that exist in blueprint:\n"));
@@ -253,7 +253,7 @@ WingFetcher& WingFetcher::Node(const FString& Value)
// Get the nodes from the graph. // Get the nodes from the graph.
TArray<UEdGraphNode *> AllNodes = WingUtils::AllNodes(Graph); TArray<UEdGraphNode *> AllNodes = WingUtils::AllNodes(Graph);
UEdGraphNode *Node = WingUtils::FindExactlyOneNamed(Value, AllNodes, TEXT("node")); UEdGraphNode *Node = WingUtils::FindOneWithExternalID(Value, AllNodes, TEXT("node"));
if (Node == nullptr) if (Node == nullptr)
{ {
UWingServer::Printf(TEXT("Nodes that exist in graph:\n")); UWingServer::Printf(TEXT("Nodes that exist in graph:\n"));
@@ -277,7 +277,7 @@ WingFetcher& WingFetcher::Pin(const FString& Value)
TypeMismatch(TEXT("pin"), TEXT("node")); TypeMismatch(TEXT("pin"), TEXT("node"));
return SetError(); return SetError();
} }
UEdGraphPin *Found = WingUtils::FindExactlyOneNamed(Value, N->Pins, TEXT("pin")); UEdGraphPin *Found = WingUtils::FindOneWithExternalID(Value, N->Pins, TEXT("pin"));
if (!Found) if (!Found)
{ {
UWingServer::Printf(TEXT("Pins that exist in the node:\n")); UWingServer::Printf(TEXT("Pins that exist in the node:\n"));
@@ -303,7 +303,7 @@ WingFetcher& WingFetcher::Component(const FString& Value)
} }
TArray<UWingComponentReference*> AllComponents = UWingComponentReference::GetAll(BP); TArray<UWingComponentReference*> AllComponents = UWingComponentReference::GetAll(BP);
UWingComponentReference* Found = WingUtils::FindExactlyOneNamed(Value, AllComponents, TEXT("component")); UWingComponentReference* Found = WingUtils::FindOneWithExternalID(Value, AllComponents, TEXT("component"));
if (!Found) if (!Found)
{ {
UWingServer::Printf(TEXT("Components that exist in the blueprint:\n")); UWingServer::Printf(TEXT("Components that exist in the blueprint:\n"));
@@ -331,7 +331,7 @@ WingFetcher& WingFetcher::Widget(const FString& Value)
TArray<UWidget*> AllWidgets; TArray<UWidget*> AllWidgets;
WidgetBP->WidgetTree->GetAllWidgets(AllWidgets); WidgetBP->WidgetTree->GetAllWidgets(AllWidgets);
UWidget* Found = WingUtils::FindExactlyOneNamed(Value, AllWidgets, TEXT("widget")); UWidget* Found = WingUtils::FindOneWithExternalID(Value, AllWidgets, TEXT("widget"));
if (!Found) if (!Found)
{ {
UWingServer::Printf(TEXT("Widgets that exist in the blueprint:\n")); UWingServer::Printf(TEXT("Widgets that exist in the blueprint:\n"));

View File

@@ -9,7 +9,7 @@ TSet<WingManual::Section> WingManual::AllSections()
Section::Paths, Section::Paths,
Section::Types, Section::Types,
Section::ParameterLists, Section::ParameterLists,
Section::IdentifierSanitization, Section::EscapeSequences,
Section::Whitespace, Section::Whitespace,
Section::MaterialEditing, Section::MaterialEditing,
Section::ImportantCommands, Section::ImportantCommands,
@@ -111,9 +111,9 @@ void WingManual::PrintManual(TSet<Section> Sections, UClass *Handler, bool Abrid
"\n with an asset name, followed by steps separated by ," "\n with an asset name, followed by steps separated by ,"
"\n that navigate into the asset. Some Examples:" "\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"
"\n /Game/Chars/BP_Manny,component:Camera·Boom" "\n /Game/Chars/BP_Manny,component:Camera.Boom"
"\n" "\n"
"\n The navigation steps supported are:" "\n The navigation steps supported are:"
"\n" "\n"
@@ -201,47 +201,45 @@ void WingManual::PrintManual(TSet<Section> Sections, UClass *Handler, bool Abrid
} }
} }
if (Sections.Contains(Section::IdentifierSanitization)) if (Sections.Contains(Section::EscapeSequences))
{ {
if (Abridged) if (Abridged)
{ {
UWingServer::Print(TEXT( UWingServer::Print(TEXT(
"\n IDENTIFIER SANITIZATION:" "\n USING HTML ESCAPE SEQUENCES:"
"\n Identifiers in unreal can contain whitespace and punctuation." "\n When we output FNames, we use HTML escape sequences for the"
"\n We sanitize these characters on output:" "\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 space → ·" "\n FName(TEXT(\"No_Change\")) --> No_Change"
"\n < → ◁" "\n FName(TEXT(\"ίδιος\")) --> ίδιος"
"\n > " "\n FName(TEXT(\"✡✢❄\")) --> &#10017;&#10018;&#10052;"
"\n , → ▾" "\n FName(TEXT(\"Hello.There\")) --> Hello&period;There"
"\n FName(TEXT(\"Hello There\")) --> Hello.There"
"\n FName(TEXT(\"Hello\n\")) --> Hello&NewLine;"
"\n " "\n "
"\n We do the reverse translation on input. Therefore, you will always" "\n When sending FNames to UE Wingman, you *must* escape the marks"
"\n see sanitized versions of identifiers, and you must always use" "\n listed above and control characters, but you *may* escape"
"\n sanitized versions of identifiers:" "\n any character. To send an FName with a space in it, either"
"\n use &#32; 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" "\n"
)); ));
} }
else else
{ {
UWingServer::Print(TEXT( UWingServer::Print(TEXT(
"\n IDENTIFIER SANITIZATION:" "\n USING HTML ESCAPE SEQUENCES:"
"\n When we output FNames, we use HTML escape sequences for the"
"\n following marks: \\\"'(),.:;<=>&, and for certain other characters."
"\n We also translate spaces to periods."
"\n" "\n"
"\n Identifiers in Unreal can contain spaces and punctuation marks." "\n When sending FNames to UE Wingman, you *must* escape the marks"
"\n Those punctuation marks could confuse our parsers. For example," "\n listed above, but you *may* escape any character. To send an FName"
"\n How would we parse Array<X> if the typename X contained a less-than?" "\n with a space in it, either use &#32; or a period."
"\n So, we automatically translate these characters on output:"
"\n"
"\n space → ·"
"\n < → ◁"
"\n > → ▷"
"\n , → ▾"
"\n "
"\n We do the reverse translation on input. Therefore, you will always"
"\n see sanitized versions of identifiers, and you must always use"
"\n sanitized versions of identifiers:"
"\n"
"\n Correct: /Game/Testing/BP_Test,graph:Get·Cursor·Location"
"\n Wrong: /Game/Testing/BP_Test,graph:Get Cursor Location"
"\n" "\n"
)); ));
} }

View File

@@ -307,7 +307,7 @@ FString WingTokenizer::CheckInternalizeID(const FString &ExternalID)
if (!Error.IsEmpty()) if (!Error.IsEmpty())
{ {
UWingServer::Printf(TEXT("%s\n"), *Error); UWingServer::Printf(TEXT("%s\n"), *Error);
UWingServer::SuggestManual(WingManual::Section::IdentifierSanitization); UWingServer::SuggestManual(WingManual::Section::EscapeSequences);
} }
return InternalID; return InternalID;
} }

View File

@@ -77,7 +77,7 @@ FString WingUtils::CheckProposedName(const FString &ExternalID)
{ {
UWingServer::Printf(TEXT("ERROR: id %s would not be a readable id, may not create item with this name"), UWingServer::Printf(TEXT("ERROR: id %s would not be a readable id, may not create item with this name"),
*ExternalID); *ExternalID);
UWingServer::SuggestManual(WingManual::Section::IdentifierSanitization); UWingServer::SuggestManual(WingManual::Section::EscapeSequences);
return FString(); return FString();
} }
return InternalID; return InternalID;

View File

@@ -10,7 +10,7 @@ public:
Paths, Paths,
Types, Types,
ParameterLists, ParameterLists,
IdentifierSanitization, EscapeSequences,
Whitespace, Whitespace,
MaterialEditing, MaterialEditing,
ImportantCommands, ImportantCommands,

View File

@@ -69,7 +69,7 @@ public:
static FName GetFName(const UWidget *Widget) { return Widget->GetFName(); } static FName GetFName(const UWidget *Widget) { return Widget->GetFName(); }
template<typename ArrayType> template<typename ArrayType>
static auto FindOneWithInternalID(FName InternalID, ArrayType &Array, const TCHAR *Kind) static auto FindOneWithInternalID(FName InternalID, ArrayType &&Array, const TCHAR *Kind)
{ {
decltype(EltAsPtr(Array, Array[0])) Result = nullptr; decltype(EltAsPtr(Array, Array[0])) Result = nullptr;
int Count = 0; int Count = 0;
@@ -79,7 +79,7 @@ public:
} }
template<typename ArrayType> template<typename ArrayType>
static auto FindOneWithExternalID(const FString &ExternalID, ArrayType &Array, const TCHAR *Kind) static auto FindOneWithExternalID(const FString &ExternalID, ArrayType &&Array, const TCHAR *Kind)
{ {
decltype(EltAsPtr(Array, Array[0])) Result = nullptr; decltype(EltAsPtr(Array, Array[0])) Result = nullptr;
FName InternalID = CheckInternalizeID(ExternalID); FName InternalID = CheckInternalizeID(ExternalID);
@@ -88,7 +88,7 @@ public:
} }
template<typename ArrayType> template<typename ArrayType>
static bool FindNoneWithInternalID(FName InternalID, ArrayType &Array, const TCHAR *Kind) static bool FindNoneWithInternalID(FName InternalID, ArrayType &&Array, const TCHAR *Kind)
{ {
for (auto &Elt : Array) if (GetFName(Elt) == InternalID) for (auto &Elt : Array) if (GetFName(Elt) == InternalID)
return CheckExactlyNoneNamed(1, Kind, InternalID); return CheckExactlyNoneNamed(1, Kind, InternalID);
@@ -96,7 +96,7 @@ public:
} }
template<typename ArrayType> template<typename ArrayType>
static bool FindNoneWithExternalID(const FString &ExternalID, ArrayType &Array, const TCHAR *Kind) static bool FindNoneWithExternalID(const FString &ExternalID, ArrayType &&Array, const TCHAR *Kind)
{ {
FName InternalID = CheckInternalizeID(ExternalID); FName InternalID = CheckInternalizeID(ExternalID);
if (InternalID.IsNone()) return false; if (InternalID.IsNone()) return false;