BITKit/Packages/Runtime/Console/BITConsole.cs

232 lines
7.1 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
using BITKit;
using BITKit.UX;
using System.Linq;
using UnityEngine.InputSystem;
using Cysharp.Threading.Tasks;
using System.Text;
using System.IO;
namespace BITKit.Console
{
public class BITConsole : UXPanel
{
[BITCommand]
public static void Clear()
{
singleton.outputString.Clear();
singleton.text.text = string.Empty;
}
static BITConsole singleton;
const string textFieldName = "TextField";
const string commandListViewName = "commands-listview";
const string textName = "Text";
const string scrollViewName = "context-scrollview";
public InputActionReference inputAction;
public InputActionReference nextOrPreviousAction;
public int logLineLimit = 64;
ListView commandListView;
TextField textField;
Label text;
ScrollView scrollView;
bool isActived;
List<string> outputString = new();
void Awake()
{
singleton = this;
var visualElement = document.rootVisualElement;
textField = visualElement.Q<TextField>(textFieldName);
commandListView = visualElement.Q<ListView>(commandListViewName);
text = visualElement.Q<Label>(textName);
scrollView = visualElement.Q<ScrollView>(scrollViewName);
textField.RegisterValueChangedCallback(OnTextFieldValieChanged);
textField.RegisterCallback<KeyDownEvent>(OnKeyDown);
commandListView.onSelectionChange += OnSelectionChange;
inputAction.action.performed += Toggle;
nextOrPreviousAction.action.performed += OnNextCommand;
text.text = string.Empty;
Application.logMessageReceived += LogCallback;
BIT4Log.OnNextLine += () =>
{
if (outputString.Count is not 0 && outputString.Last() != string.Empty)
outputString.Add(string.Empty);
};
commandListView.SetActive(false);
}
void OnDestroy()
{
inputAction.action.performed -= Toggle;
Application.logMessageReceived -= LogCallback;
}
public async override void Set(bool active)
{
base.Set(active);
isActived = active;
await UniTask.WaitForEndOfFrame(this);
if (active)
{
textField.SetValueWithoutNotify(string.Empty);
textField.Focus();
scrollView.ScrollToBottom();
}
else
{
text.Blur();
}
}
void OnTextFieldValieChanged(ChangeEvent<string> callback)
{
if (callback.newValue.IsValid())
{
var commands = BITCommand.GetMethodInfos(callback.newValue).Select(x => x.Name).ToList();
if (commands.Count is 0)
{
commandListView.SetActive(false);
}
else
{
commandListView.itemsSource = commands;
commandListView.SetActive(true);
}
}
else
{
commandListView.SetActive(false);
}
}
void OnDropdownValueChanged(ChangeEvent<string> callback)
{
textField.SetValueWithoutNotify(callback.newValue);
OnTextFieldValieChanged(callback);
textField.Focus();
}
void OnNextCommand(InputAction.CallbackContext context)
{
if (context.started)
{
var index = context.ReadValue<Vector2>().y;
}
}
void OnKeyDown(KeyDownEvent keyDownEvent)
{
switch (keyDownEvent.keyCode)
{
case KeyCode.Return:
var cmd = textField.text;
LogCallback($">{cmd}", string.Empty, LogType.Log);
textField.SetValueWithoutNotify(string.Empty);
textField.Focus();
BITCommand.Excute(cmd);
break;
case KeyCode.Tab:
break;
}
}
void Toggle(InputAction.CallbackContext context)
{
if (context.performed)
{
if (isActived is false)
{
UXFramework.Enter<BITConsole>();
}
else
{
UXFramework.Return();
}
}
}
async void LogCallback(string condition, string stackTrace, LogType type)
{
var debugLevel = Data.Get<int>("DebugLevel");
switch (type)
{
case LogType.Error:
outputString.Add($"<color=red>{condition}</color>");
if (debugLevel is 2)
outputString.Add(stackTrace);
break;
case LogType.Warning:
outputString.Add($"<color=yellow>{condition}</color>");
if (debugLevel is 2)
outputString.Add(stackTrace);
break;
case LogType.Exception:
outputString.Add($"<color=red>{condition}</color>");
outputString.Add($"<color=red>{stackTrace}</color>");
break;
default:
outputString.Add(condition);
break;
}
var length = outputString.Count;
if (length > logLineLimit)
{
outputString = outputString.GetRange(length - logLineLimit, logLineLimit);
}
StringBuilder stringBuilder = new();
outputString.ForEach(x => stringBuilder.AppendLine(x));
try
{
if (BITApp.CancellationTokenSource is not null)
{
await UniTask.SwitchToMainThread(BITApp.CancellationTokenSource.Token);
scrollView.ScrollToBottomAutomatic();
text.text = stringBuilder.ToString();
}
}
catch (System.OperationCanceledException)
{
}
catch (System.Exception)
{
throw;
}
}
void Update()
{
var pos = textField.worldTransform.GetPosition();
var size = textField.layout.size;
commandListView.style.left = 0;
commandListView.style.top = 0;
pos.y += size.y;
commandListView.transform.position = pos;
commandListView.style.width = size.x;
}
void OnSelectionChange(IEnumerable<object> selected)
{
var _selected = selected.First() as string;
textField.SetValueWithoutNotify(_selected);
commandListView.itemsSource?.Clear();
commandListView.SetActive(false);
}
}
}