Skip to content

Commit

Permalink
Bugfix: Handle UXML root tag without namespace (#23)
Browse files Browse the repository at this point in the history
* added tests and different serialization option

* changelog update

* example update

* remove comment
  • Loading branch information
ErnSur authored Mar 18, 2023
1 parent 778cce7 commit 11a31f7
Show file tree
Hide file tree
Showing 26 changed files with 243 additions and 62 deletions.
22 changes: 11 additions & 11 deletions Assets/Sandbox/CodeGen/CodeGenExample.gen.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
// -----------------------
// script auto-generated
// any changes to this file will be lost on next code generation
// com.quickeye.ui-toolkit-plus ver: 2.0.0
// com.quickeye.ui-toolkit-plus ver: 3.0.3
// -----------------------
using UnityEngine.UIElements;

namespace SampleAsmDefName
{
partial class CodeGenExample
{
private Label _title;
private VisualElement _menu;
private Button _confirmButton;
private QuickEye.UIToolkit.Tab _normalTab;
private QuickEye.UIToolkit.TabGroup _dropTab;
private Label title;
private VisualElement menu;
private Button confirmButton;
private QuickEye.UIToolkit.Tab normalTab;
private QuickEye.UIToolkit.TabGroup dropTab;

protected void AssignQueryResults(VisualElement root)
{
_title = root.Q<Label>("title");
_menu = root.Q<VisualElement>("menu");
_confirmButton = root.Q<Button>("confirm-button");
_normalTab = root.Q<QuickEye.UIToolkit.Tab>("normal-tab");
_dropTab = root.Q<QuickEye.UIToolkit.TabGroup>("drop--tab");
title = root.Q<Label>("title");
menu = root.Q<VisualElement>("menu");
confirmButton = root.Q<Button>("confirm-button");
normalTab = root.Q<QuickEye.UIToolkit.Tab>("normal-tab");
dropTab = root.Q<QuickEye.UIToolkit.TabGroup>("drop--tab");
}
}
}
2 changes: 1 addition & 1 deletion Assets/Sandbox/CodeGen/CodeGenExample.gen.cs.meta

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

2 changes: 1 addition & 1 deletion Assets/Sandbox/CodeGen/CodeGenExample.uxml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" quick-eye="QuickEye.UIToolkit" xsi="http://www.w3.org/2001/XMLSchema-instance" editor-extension-mode="False">
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" quick-eye="QuickEye.UIToolkit" xsi="http://www.w3.org/2001/XMLSchema-instance" editor-extension-mode="False" gen-cs-file="9b5172de3610e482c94f864fb486ebbb">
<ui:VisualElement>
<ui:Label text="Label" display-tooltip-when-elided="true" name="title" />
</ui:VisualElement>
Expand Down
7 changes: 4 additions & 3 deletions Packages/com.quickeye.ui-toolkit-plus/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
## [3.0.2] - 2022-12-10
## [3.0.3] - 2023-03-18
## Fixed
- System no longer throws exceptions when it processes files with root UXML element without namespace

## [3.0.2] - 2022-12-10
## Fixed
- Moved Editor element `ToolbarDropdownButton` to Editor assembly.


## [3.0.1] - 2022-11-27

## Added
- Package description

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;

[assembly:InternalsVisibleTo("QuickEye.UIToolkit.Editor.Tests")]

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

Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public static void GenerateCs(string uxmlFilePath, bool pingAsset)
return;
}

var inlineSettings = InlineSettings.FromXml(File.ReadAllText(uxmlFilePath));
var inlineSettings = InlineSettings.FromXmlFile(uxmlFilePath);
var codeStyle = GetFinalCodeStyleRulesFor(inlineSettings);
var className = Path.GetFileNameWithoutExtension(uxmlFilePath);
var classNamespace = CsNamespaceUtils.GetCsNamespace(uxmlFilePath, out _);
Expand Down Expand Up @@ -90,7 +90,7 @@ private static void TryUpdateGenCsGuid(string uxmlFilePath, string genCsFilePath
if (inlineSettings.GenCsGuid != genCsGuid)
{
inlineSettings.GenCsGuid = genCsGuid;
inlineSettings.WriteXmlAttributes(uxmlFilePath);
inlineSettings.WriteTo(uxmlFilePath);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using UnityEngine;

namespace QuickEye.UxmlBridgeGen
{
[XmlRoot("UXML", Namespace = "UnityEngine.UIElements")]
[Serializable]
public class InlineSettings
{
static readonly Dictionary<string, FieldInfo> SerializableFields;

static InlineSettings()
{
SerializableFields =
(from field in typeof(InlineSettings).GetFields(BindingFlags.Instance | BindingFlags.Public)
let attr = field.GetCustomAttribute<XmlAttributeAttribute>()
where attr != null
select (attr.AttributeName, field)).ToDictionary(t => t.AttributeName, t => t.field);
}

[XmlAttribute("gen-cs-namespace")]
public string CsNamespace;

Expand All @@ -37,49 +49,52 @@ public class InlineSettings
[XmlAttribute("gen-cs-class-style")]
public string ClassStyle;

public static void test(string uxmlPath)
public static InlineSettings FromXmlFile(string xmlFilePath)
{
var root = FromXml(File.ReadAllText(uxmlPath));
Debug.Log($"ns {root.CsNamespace}");
root.GenCsGuid = null;
root.WriteXmlAttributes(uxmlPath);
return FromXml(File.ReadAllText(xmlFilePath));
}

public static InlineSettings FromXml(string xml)
{
var stream = new StringReader(xml);
var inlineSettings = new InlineSettings();
using (var sr = new StringReader(xml))
{
using (var xr = XmlReader.Create(sr))
{
// Move to the root element
xr.MoveToContent();
foreach (var kvp in SerializableFields)
{
kvp.Value.SetValue(inlineSettings, xr.GetAttribute(kvp.Key));
}
}
}

var serializer = new XmlSerializer(typeof(InlineSettings));
var root = (InlineSettings)serializer.Deserialize(stream);
return root;
return inlineSettings;
}

public void WriteXmlAttributes(string uxmlPath)
public void WriteTo(string uxmlPath)
{
var root = XDocument.Parse(File.ReadAllText(uxmlPath)).Root;
if (root == null)
return;
foreach (var (attributeName, value) in GetSerializableAttributes())
{
if (value != null)
root.SetAttributeValue(attributeName, value);
else
root.Attribute(attributeName)?.Remove();
}
AddTo(root);

Write(uxmlPath, root);
}

private (string attributeName, string value)[] GetSerializableAttributes()
public void AddTo(XElement uxmlRootElement)
{
var serializableAttributes = from field in GetType().GetFields(BindingFlags.Instance | BindingFlags.Public)
let attr = field.GetCustomAttribute<XmlAttributeAttribute>()
where attr != null
select (attr.AttributeName, field.GetValue(this) as string);
return serializableAttributes.ToArray();
foreach (var (attributeName, fieldInfo) in SerializableFields)
{
var value = fieldInfo.GetValue(this);
if (value != null)
uxmlRootElement.SetAttributeValue(attributeName, value);
else
uxmlRootElement.Attribute(attributeName)?.Remove();
}
}


private static void Write(string uxmlPath, XElement root)
{
using (var writer = new XmlTextWriter(uxmlPath, Encoding.UTF8))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
using System;
using System.IO;
using UnityEditor;
using UnityEngine;

namespace QuickEye.UxmlBridgeGen
{
internal static class InlineSettingsUtils
{
public static bool TryGetGenCsFilePath(string uxmlPath, out string genCsPath, out bool isMissing)
{
var root = InlineSettings.FromXml(File.ReadAllText(uxmlPath));
var root = InlineSettings.FromXmlFile(uxmlPath);
return root.TryGetGenCsFilePath(out genCsPath, out isMissing);
}

public static bool TryGetGenCsFilePath(this InlineSettings settings, out string genCsPath, out bool isMissing)
{
if (settings.GenCsGuid == null)
Expand All @@ -32,26 +33,26 @@ public static bool TryGetGenCsFilePath(this InlineSettings settings, out string
isMissing = false;
return true;
}

public static string GetCsNamespace(string uxmlPath)
{
var root = InlineSettings.FromXml(File.ReadAllText(uxmlPath));
var root = InlineSettings.FromXmlFile(uxmlPath);
return root.CsNamespace;
}

public static void WriteCsNamespace(string uxmlPath, string csNamespace)
{
var root = InlineSettings.FromXml(File.ReadAllText(uxmlPath));
var root = InlineSettings.FromXmlFile(uxmlPath);
root.CsNamespace = csNamespace;
root.WriteXmlAttributes(uxmlPath);
root.WriteTo(uxmlPath);
}

public static CodeStyleRules GetCodeStyleRules(string uxml)
{
var root = InlineSettings.FromXml(uxml);
return GetCodeStyleRules(root);
}

public static CodeStyleRules GetCodeStyleRules(this InlineSettings settings)
{
return new CodeStyleRules
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace QuickEye.UxmlBridgeGen
{
internal static class PackageInfo
{
public const string Version = "3.0.2";
public const string Version = "3.0.3";
public const string Name = "com.quickeye.ui-toolkit-plus";
public const string DisplayName = "UI Toolkit Plus";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public UxmlHeaderDrawer(Editor editor) : base(editor)
private void Setup(Editor editor)
{
_firstTargetUxmlPath = ((ScriptedImporter)editor.target).assetPath;
_inlineSettings = InlineSettings.FromXml(File.ReadAllText(_firstTargetUxmlPath));
_inlineSettings = InlineSettings.FromXmlFile(_firstTargetUxmlPath);
InlineSettingsUtils.TryGetGenCsFilePath(_firstTargetUxmlPath, out var firstTargetGenCsPath,
out _firstTargetGenCsMissing);
_firstTargetGenCs = AssetDatabase.LoadAssetAtPath<MonoScript>(firstTargetGenCsPath);
Expand Down Expand Up @@ -87,7 +87,7 @@ private void GenCsField()
"Yes", "No"))
{
_inlineSettings.GenCsGuid = AssetDatabase.AssetPathToGUID(newFilePath);
_inlineSettings.WriteXmlAttributes(_firstTargetUxmlPath);
_inlineSettings.WriteTo(_firstTargetUxmlPath);
Setup(Editor);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using System.Collections.Generic;
using System.IO;
using System.Xml.Linq;
using NUnit.Framework;
using QuickEye.UxmlBridgeGen;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

namespace QuickEye.UIToolkit.Tests
{
public class InlineSettingsTests
{
const string ResourcesDir = "uxml-bridge-tests/";

static readonly Dictionary<UxmlFileType, string> UxmlContents = new Dictionary<UxmlFileType, string>()
{
{ UxmlFileType.Default, LoadUxml("Default") },
{ UxmlFileType.NoRootNamespace, LoadUxml("NoRootNamespace") },
{ UxmlFileType.WithCustomSettings, LoadUxml("WithCustomSettings") }
};

static readonly InlineSettings CustomSettings = new InlineSettings()
{
CsNamespace = "test.test",
GenCsGuid = "guid",
PrivateFieldPrefix = "pf-prefix",
PrivateFieldSuffix = "pf-suffix",
PrivateFieldStyle = CaseStyle.LowerCamelCase.ToString(),
ClassPrefix = "c-prefix",
ClassSuffix = "c-suffix",
ClassStyle = CaseStyle.UpperCamelCase.ToString(),
};

[TestCase(UxmlFileType.Default, false)]
[TestCase(UxmlFileType.NoRootNamespace, false)]
[TestCase(UxmlFileType.WithCustomSettings, true)]
public void Deserialize_Settings(UxmlFileType fileType, bool hasCustomSettings)
{
var uxml = UxmlContents[fileType];

var settings = InlineSettings.FromXml(uxml);

Assert.IsNotNull(settings);
if (hasCustomSettings)
{
AssertAreSettingsEqual(CustomSettings, settings);
}
}

[Test]
public void Serialize_Settings()
{
var uxml = UxmlContents[UxmlFileType.Default];
var root = XDocument.Parse(uxml).Root;
var settings = InlineSettings.FromXml(uxml);

AssertAreSettingsEqual(new InlineSettings(), settings);
CustomSettings.AddTo(root);
settings = InlineSettings.FromXml(root.ToString());
AssertAreSettingsEqual(CustomSettings, settings);
}

private void AssertAreSettingsEqual(InlineSettings expected, InlineSettings actual)
{
var json = JsonUtility.ToJson(actual);
var expectedJson = JsonUtility.ToJson(expected);
Assert.AreEqual(expectedJson, json);
}

private static string LoadUxml(string fileName)
{
var asset = Resources.Load<VisualTreeAsset>(ResourcesDir + fileName);
var path = AssetDatabase.GetAssetPath(asset);
return File.ReadAllText(path);
}

public enum UxmlFileType
{
Default,
NoRootNamespace,
WithCustomSettings
}
}
}

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

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"UnityEngine.TestRunner",
"UnityEditor.TestRunner",
"QuickEye.UIToolkit.Editor",
"QuickEye.UIToolkit"
"QuickEye.UIToolkit",
"QuickEye.UxmlBridgeGen"
],
"includePlatforms": [
"Editor"
Expand Down

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

Loading

0 comments on commit 11a31f7

Please sign in to comment.