Skip to content

Commit

Permalink
Fix null reference exception when no element is selected
Browse files Browse the repository at this point in the history
  • Loading branch information
Eastrall committed Mar 5, 2022
1 parent a8fb7c6 commit 48f5c42
Show file tree
Hide file tree
Showing 11 changed files with 110 additions and 55 deletions.
7 changes: 2 additions & 5 deletions Editor/Scripts/Generator/RosalinaBindingsGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
using UnityEngine;
using UnityEngine.UIElements;

internal class RosalinaBindingsGenerator : IRosalinaGenerator
internal class RosalinaBindingsGenerator
{
private static readonly string GeneratedCodeHeader = @$"//------------------------------------------------------------------------------
// <auto-generated>
Expand Down Expand Up @@ -64,9 +64,6 @@ public RosalinaGenerationResult Generate(UIDocumentAsset document, string output
ClassDeclarationSyntax @class = SyntaxFactory.ClassDeclaration(document.Name)
.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
.AddModifiers(SyntaxFactory.Token(SyntaxKind.PartialKeyword))
//.AddBaseListTypes(
// SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseName(typeof(MonoBehaviour).Name))
//)
.AddMembers(documentVariable)
.AddMembers(classMembers);

Expand Down Expand Up @@ -138,7 +135,7 @@ private static InitializationStatement[] GenerateInitializeStatements(UxmlDocume
MemberAccessExpressionSyntax documentQueryMethodAccess = CreateRootQueryMethodAccessor();
IEnumerable<UxmlNode> childNodes = uxmlDocument.GetChildren();

foreach (var node in childNodes)
foreach (UxmlNode node in childNodes)
{
var uiProperty = new UIPropertyDescriptor(node.Type, node.Name);
Type uiPropertyType = UIPropertyTypes.GetUIElementType(uiProperty.Type);
Expand Down
9 changes: 6 additions & 3 deletions Editor/Scripts/Generator/RosalinaScriptGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
using System.IO;
using UnityEngine;

internal class RosalinaScriptGenerator : IRosalinaGenerator
internal class RosalinaScriptGenerator
{
private const string InitializeMethodName = "InitializeDocument";
private const string UnityInitializeHookName = "OnEnable";

public RosalinaGenerationResult Generate(UIDocumentAsset document, string outputFileName)
{
if (document is null)
Expand All @@ -21,11 +24,11 @@ public RosalinaGenerationResult Generate(UIDocumentAsset document, string output

var initializeDocumentMethod = SyntaxFactory.ExpressionStatement(
SyntaxFactory.InvocationExpression(
SyntaxFactory.IdentifierName("InitializeDocument")
SyntaxFactory.IdentifierName(InitializeMethodName)
)
);

MethodDeclarationSyntax onEnableMethod = RosalinaSyntaxFactory.CreateMethod("void", "OnEnable", SyntaxKind.PrivateKeyword)
MethodDeclarationSyntax onEnableMethod = RosalinaSyntaxFactory.CreateMethod("void", UnityInitializeHookName, SyntaxKind.PrivateKeyword)
.WithBody(SyntaxFactory.Block(initializeDocumentMethod));

ClassDeclarationSyntax @class = SyntaxFactory.ClassDeclaration(document.Name)
Expand Down
6 changes: 0 additions & 6 deletions Editor/Scripts/IRosalinaGenerator.cs

This file was deleted.

8 changes: 3 additions & 5 deletions Editor/Scripts/MenuItems/RosalinaGenerateBindingsMenuItem.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
Expand All @@ -13,16 +12,15 @@ private static void GenerateUIBindings()
{
string assetPath = AssetDatabase.GetAssetPath(Selection.activeObject);
var document = new UIDocumentAsset(assetPath);
IRosalinaGenerator generator = new RosalinaBindingsGenerator();

try
{
EditorUtility.DisplayProgressBar("Rosalina", $"Generating {document.Name} UI bindings...", 50);
Debug.Log($"[Rosalina]: Generating UI bindings for {assetPath}");

RosalinaGenerationResult result = generator.Generate(document, $"{document.Name}.g.cs");
RosalinaGenerationResult result = RosalinaGenerator.GenerateBindings(document, $"{document.Name}.g.cs");
result.Save();

File.WriteAllText(result.OutputFilePath, result.Code);
AssetDatabase.Refresh();

Debug.Log($"[Rosalina]: Done generating UI bindings: {document.Name} (output: {result.OutputFilePath})");
Expand All @@ -40,6 +38,6 @@ private static void GenerateUIBindings()
[MenuItem(MenuItemPath, true)]
private static bool GenerateUIBindingsValidation()
{
return Selection.activeObject.GetType() == typeof(VisualTreeAsset);
return Selection.activeObject != null && Selection.activeObject.GetType() == typeof(VisualTreeAsset);
}
}
70 changes: 42 additions & 28 deletions Editor/Scripts/MenuItems/RosalinaGenerateScriptMenuItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,7 @@ public static void GenerateUIScript()

try
{
bool refreshAssetDatabase = false;
string scriptName = $"{document.Name}.cs";
string scriptPath = Path.Combine(document.Path, scriptName);
string generatedBindingsScriptName = $"{document.Name}.g.cs";
string generatedBindingsScriptPath = Path.Combine(document.Path, generatedBindingsScriptName);

if (!File.Exists(generatedBindingsScriptPath) && AskGenerateBindings())
{
Debug.Log($"[Rosalina]: Generating UI code behind for {generatedBindingsScriptPath}");
RosalinaGenerationResult result = new RosalinaBindingsGenerator().Generate(document, generatedBindingsScriptName);

File.WriteAllText(result.OutputFilePath, result.Code);
Debug.Log($"[Rosalina]: Done generating: {document.Name} (output: {result.OutputFilePath})");
refreshAssetDatabase = true;
}

if (!File.Exists(scriptPath) || File.Exists(scriptPath) && AskOverrideExistingScript())
{
Debug.Log($"[Rosalina]: Generating UI script for {scriptPath}");
RosalinaGenerationResult result = new RosalinaScriptGenerator().Generate(document, scriptName);

File.WriteAllText(result.OutputFilePath, result.Code);
Debug.Log($"[Rosalina]: Done generating: {document.Name} (output: {result.OutputFilePath})");
refreshAssetDatabase = true;
}

if (refreshAssetDatabase)
if (TryGenerateBindings(document) || TryGenerateScript(document))
{
AssetDatabase.Refresh();
}
Expand All @@ -60,7 +34,47 @@ public static void GenerateUIScript()
[MenuItem(MenuItemPath, true)]
public static bool GenerateUIScriptValidation()
{
return Selection.activeObject.GetType() == typeof(VisualTreeAsset);
return Selection.activeObject != null && Selection.activeObject.GetType() == typeof(VisualTreeAsset);
}

private static bool TryGenerateBindings(UIDocumentAsset document)
{
string generatedBindingsScriptName = $"{document.Name}.g.cs";
string generatedBindingsScriptPath = Path.Combine(document.Path, generatedBindingsScriptName);

if (!File.Exists(generatedBindingsScriptPath) && AskGenerateBindings())
{
Debug.Log($"[Rosalina]: Generating UI code behind for {generatedBindingsScriptPath}");

RosalinaGenerationResult result = RosalinaGenerator.GenerateBindings(document, generatedBindingsScriptName);
result.Save();

Debug.Log($"[Rosalina]: Done generating: {document.Name} (output: {result.OutputFilePath})");

return true;
}

return false;
}

private static bool TryGenerateScript(UIDocumentAsset document)
{
string scriptName = $"{document.Name}.cs";
string scriptPath = Path.Combine(document.Path, scriptName);

if (!File.Exists(scriptPath) || File.Exists(scriptPath) && AskOverrideExistingScript())
{
Debug.Log($"[Rosalina]: Generating UI script for {scriptPath}");

RosalinaGenerationResult result = RosalinaGenerator.GenerateScript(document, scriptName);
result.Save();

Debug.Log($"[Rosalina]: Done generating: {document.Name} (output: {result.OutputFilePath})");

return true;
}

return false;
}

private static bool AskOverrideExistingScript()
Expand Down
5 changes: 2 additions & 3 deletions Editor/Scripts/RosalinaAssetProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,15 @@ private static void OnPostprocessAllAssets(string[] importedAssets, string[] del
{
string uiDocumentPath = uiFilesChanged[i];
var document = new UIDocumentAsset(uiDocumentPath);
IRosalinaGenerator generator = new RosalinaBindingsGenerator();

try
{
EditorUtility.DisplayProgressBar("Rosalina", $"Generating {document.Name} bindings...", GeneratePercentage(i, uiFilesChanged.Length));
Debug.Log($"[Rosalina]: Generating UI bindings for {uiDocumentPath}");

RosalinaGenerationResult result = generator.Generate(document, $"{document.Name}.g.cs");
RosalinaGenerationResult result = RosalinaGenerator.GenerateBindings(document, $"{document.Name}.g.cs");
result.Save();

File.WriteAllText(result.OutputFilePath, result.Code);
Debug.Log($"[Rosalina]: Done generating: {document.Name} (output: {result.OutputFilePath})");
}
catch (Exception ex)
Expand Down
2 changes: 1 addition & 1 deletion Editor/Scripts/RosalinaConstants.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
public class RosalinaConstants
{
public const string Version = "1.0.0";
public const string Version = "1.0.1";
}
26 changes: 25 additions & 1 deletion Editor/Scripts/RosalinaGenerationResult.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,36 @@
internal class RosalinaGenerationResult
using System.IO;

/// <summary>
/// Describes a generation result.
/// </summary>
internal class RosalinaGenerationResult
{
/// <summary>
/// Gets the generated code.
/// </summary>
public string Code { get; }

/// <summary>
/// Gets the output file path.
/// </summary>
public string OutputFilePath { get; }

/// <summary>
/// Creates a new <see cref="RosalinaGenerationResult"/> instance.
/// </summary>
/// <param name="code">Generated code.</param>
/// <param name="outputFilePath">Output file path.</param>
public RosalinaGenerationResult(string code, string outputFilePath)
{
Code = code;
OutputFilePath = outputFilePath;
}

/// <summary>
/// Saves the result to the output path.
/// </summary>
public void Save()
{
File.WriteAllText(OutputFilePath, Code);
}
}
24 changes: 24 additions & 0 deletions Editor/Scripts/RosalinaGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
internal static class RosalinaGenerator
{
/// <summary>
/// Generates a C# script containing the bindings of the given UI document.
/// </summary>
/// <param name="document">UI Document.</param>
/// <param name="outputFileName">C# script output file.</param>
/// <returns>Rosalina generation result.</returns>
public static RosalinaGenerationResult GenerateBindings(UIDocumentAsset document, string outputFileName)
{
return new RosalinaBindingsGenerator().Generate(document, outputFileName);
}

/// <summary>
/// Geneartes a C# script for the UI logic.
/// </summary>
/// <param name="document">UI Document asset information.</param>
/// <param name="outputFileName">Output file name.</param>
/// <returns>Rosalina generation result.</returns>
public static RosalinaGenerationResult GenerateScript(UIDocumentAsset document, string outputFileName)
{
return new RosalinaScriptGenerator().Generate(document, outputFileName);
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
{
"name": "com.eastylabs.rosalina",
"version": "1.0.0",
"version": "1.0.1",
"type": "tool",
"displayName": "Rosalina",
"unity": "2021.2",
"description": "Rosalina is an UI Toolkit extension tool that generates C# binding scripts based on a UXML template."
"description": "Rosalina is an UI Toolkit extension tool that generates C# binding scripts based on a UXML template.",
"hideInEditor": true,
"unityRelease": "7f1"
}

0 comments on commit 48f5c42

Please sign in to comment.