Files
MobileShooter/Packages/com.merry-yellow.code-assist/Editor/Input/Text2Yaml.cs
2025-12-26 17:56:05 -08:00

215 lines
7.4 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
#pragma warning disable IDE0005
using Serilog = Meryel.Serilog;
#pragma warning restore IDE0005
#nullable enable
namespace Meryel.UnityCodeAssist.Editor.Input
{
public class Text2Yaml
{
public static string Convert(IEnumerable<string> textLines)
{
var sb = new StringBuilder();
var stack = new Stack<(string typeName, string identifier, int indentation)>();
sb.AppendLine(@"%YAML 1.1");
sb.AppendLine(@"%TAG !u! tag:unity3d.com,2011:");
sb.AppendLine(@"--- !u!13 &1");
sb.AppendLine(@"InputManager:");
var regexIndentation = new Regex("^\\s*");
var regexString = new Regex("^(\\s+)(\\w+)\\s+\"([a-zA-Z0-9_ \\/\\.\\-]*)\"\\s+\\(string\\)$");
var regexValue = new Regex("^(\\s+)(\\w+)\\s+(-?[0-9.]*)\\s+\\(((bool)|(int)|(float)|(unsigned int))\\)$");
var regexType = new Regex("^(\\s+)(\\w+)\\s+\\((\\w+)\\)$");
var regexVectorSize = new Regex("(\\s+)size\\s+(\\d)+\\s+\\(int\\)");
//var regexVectorData = new Regex("(\\s+)data \\(InputAxis\\)"); // remove InputAxis to make it more generic
string curTextLine;
var curTextLineNo = 3;
var textIndentation = 1;
var indentationPrefix = new string(' ', textIndentation * 2);
stack.Push(("InputManager", "InputManager", textIndentation));
foreach (var line in textLines.Skip(4))
{
curTextLine = line;
curTextLineNo++;
// Skip empty lines
if (line.Length == 0)
continue;
// Check if type undeclared, scope goes down, indentation decrements
{
var indentationMatch = regexIndentation.Match(line);
if (indentationMatch.Success)
{
var indentation = indentationMatch.Groups[0].Value.Length;
if (indentation > textIndentation)
Error($"indentation({indentation}) > textIndentation({textIndentation})");
while (indentation < textIndentation)
{
stack.Pop();
textIndentation--;
var typeIndentation = textIndentation;
if (stack.TryPeek(out var curType2))
typeIndentation = curType2.indentation;
else if (line.Length > 0)
Error("stack empty at type undeclaration");
indentationPrefix = new string(' ', typeIndentation * 2);
}
}
else
{
Error($"{nameof(regexIndentation)} failed");
}
}
// Skip size field of vectors
if (stack.TryPeek(out var curType1) && curType1.typeName == "vector")
{
var vectorSizeMatch = regexVectorSize.Match(line);
if (vectorSizeMatch.Success)
{
continue;
}
}
// Read string fields
{
var stringMatch = regexString.Match(line);
if (stringMatch.Success)
{
AddLine(stringMatch.Groups[2] + ": " + stringMatch.Groups[3]);
continue;
}
}
// Read bool/int/float/unsignedInt fields
{
var valueMatch = regexValue.Match(line);
if (valueMatch.Success)
{
AddLine(valueMatch.Groups[2] + ": " + valueMatch.Groups[3]);
continue;
}
}
// Check if new type declared, scope goes up, indentation increases
{
var typeMatch = regexType.Match(line);
if (typeMatch.Success)
{
var identifier = typeMatch.Groups[2].Value;
var typeName = typeMatch.Groups[3].Value;
var isVectorData = false;
if (stack.TryPeek(out var curType2) && curType2.typeName == "vector" && identifier == "data")
isVectorData = true;
var typeIndentation = textIndentation;
if (stack.TryPeek(out var curType3))
typeIndentation = curType3.indentation;
else if (line.Length > 0)
Error("stack empty at type declaration");
if (!isVectorData)
{
AddLine(typeMatch.Groups[2] + ":");
}
else
{
var customIndentation = typeIndentation - 1;
if (customIndentation < 0)
Error($"customIndentation({customIndentation}) < 0");
var customIndentationPrefix = new string(' ', customIndentation * 2);
AddLine("- serializedVersion: 3", customIndentationPrefix);
}
textIndentation++;
typeIndentation++;
if (isVectorData)
typeIndentation--;
stack.Push((typeName, identifier, typeIndentation));
indentationPrefix = new string(' ', typeIndentation * 2);
continue;
}
}
Error("line failed to match all cases");
}
return sb.ToString();
void AddLine(string line, string? customIndentationPrefix = null)
{
string suffix;
if (stack.TryPeek(out var top))
suffix = $" # {textIndentation}, {top.indentation}, {top.typeName} {top.identifier}";
else
suffix = $" # {textIndentation}, nil";
if (customIndentationPrefix != null)
sb.AppendLine(customIndentationPrefix + line + suffix);
else
sb.AppendLine(indentationPrefix + line + suffix);
}
void Error(string message)
{
var errorMessage = $"Text2Yaml error '{message}' at lineNo: {curTextLineNo}, line: '{curTextLine}' at {Environment.StackTrace}";
//throw new Exception(errorMessage);
Serilog.Log.Warning(errorMessage);
}
}
}
public static partial class Extensions
{
public static bool TryPeek<T>(this Stack<T> stack, /*[MaybeNullWhen(false)]*/ out T result)
{
if (stack.Count > 0)
{
result = stack.Peek();
return true;
}
else
{
result = default!;
return false;
}
}
}
}