2020-10-28 06:39:26 +11:00
|
|
|
|
using System;
|
2021-03-18 17:17:29 +11:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Reflection;
|
2020-10-25 20:57:34 +11:00
|
|
|
|
using System.Text;
|
2021-03-18 17:17:29 +11:00
|
|
|
|
using UnityExplorer.Core.CSharp;
|
|
|
|
|
using UnityExplorer.UI.CSConsole;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using UnityExplorer.Core.Input;
|
2020-10-28 06:39:26 +11:00
|
|
|
|
using UnityEngine;
|
2020-10-27 00:54:08 +11:00
|
|
|
|
using UnityEngine.EventSystems;
|
2020-10-28 06:39:26 +11:00
|
|
|
|
using UnityEngine.UI;
|
2021-03-18 17:17:29 +11:00
|
|
|
|
using UnityExplorer.UI.Reusable;
|
|
|
|
|
using UnityExplorer.UI.Main.CSConsole;
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
2021-03-18 17:17:29 +11:00
|
|
|
|
namespace UnityExplorer.UI.Main
|
2020-10-25 20:57:34 +11:00
|
|
|
|
{
|
2021-03-18 17:17:29 +11:00
|
|
|
|
public class CSharpConsole : BaseMenuPage
|
2020-10-28 06:39:26 +11:00
|
|
|
|
{
|
2021-03-18 17:17:29 +11:00
|
|
|
|
public override string Name => "C# Console";
|
|
|
|
|
|
|
|
|
|
public static CSharpConsole Instance { get; private set; }
|
|
|
|
|
|
|
|
|
|
//public UI.CSConsole.CSharpConsole m_codeEditor;
|
|
|
|
|
public ScriptEvaluator m_evaluator;
|
|
|
|
|
|
|
|
|
|
public static List<string> UsingDirectives;
|
|
|
|
|
|
|
|
|
|
public static readonly string[] DefaultUsing = new string[]
|
|
|
|
|
{
|
|
|
|
|
"System",
|
|
|
|
|
"System.Linq",
|
|
|
|
|
"System.Collections",
|
|
|
|
|
"System.Collections.Generic",
|
|
|
|
|
"System.Reflection",
|
|
|
|
|
"UnityEngine",
|
|
|
|
|
#if CPP
|
|
|
|
|
"UnhollowerBaseLib",
|
|
|
|
|
"UnhollowerRuntimeLib",
|
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
public override void Init()
|
|
|
|
|
{
|
|
|
|
|
Instance = this;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
//m_codeEditor = new UI.CSConsole.CSharpConsole();
|
|
|
|
|
InitConsole();
|
|
|
|
|
|
|
|
|
|
AutoCompleter.Init();
|
|
|
|
|
|
|
|
|
|
ResetConsole();
|
|
|
|
|
|
|
|
|
|
// Make sure compiler is supported on this platform
|
|
|
|
|
m_evaluator.Compile("");
|
|
|
|
|
|
|
|
|
|
foreach (string use in DefaultUsing)
|
|
|
|
|
{
|
|
|
|
|
AddUsing(use);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
ExplorerCore.LogWarning($"Error setting up console!\r\nMessage: {e.Message}");
|
|
|
|
|
MainMenu.Instance.Pages.RemoveAll(it => it is CSharpConsole);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void Update()
|
|
|
|
|
{
|
|
|
|
|
UpdateConsole();
|
|
|
|
|
AutoCompleter.Update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void AddUsing(string asm)
|
|
|
|
|
{
|
|
|
|
|
if (!UsingDirectives.Contains(asm))
|
|
|
|
|
{
|
|
|
|
|
Evaluate($"using {asm};", true);
|
|
|
|
|
UsingDirectives.Add(asm);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Evaluate(string code, bool suppressWarning = false)
|
|
|
|
|
{
|
|
|
|
|
m_evaluator.Compile(code, out Mono.CSharp.CompiledMethod compiled);
|
|
|
|
|
|
|
|
|
|
if (compiled == null)
|
|
|
|
|
{
|
|
|
|
|
if (!suppressWarning)
|
|
|
|
|
ExplorerCore.LogWarning("Unable to compile the code!");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
object ret = VoidType.Value;
|
|
|
|
|
compiled.Invoke(ref ret);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
if (!suppressWarning)
|
|
|
|
|
ExplorerCore.LogWarning($"Exception executing code: {e.GetType()}, {e.Message}\r\n{e.StackTrace}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void ResetConsole()
|
|
|
|
|
{
|
|
|
|
|
if (m_evaluator != null)
|
|
|
|
|
{
|
|
|
|
|
m_evaluator.Dispose();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_evaluator = new ScriptEvaluator(new StringWriter(new StringBuilder())) { InteractiveBaseClass = typeof(ScriptInteraction) };
|
|
|
|
|
|
|
|
|
|
UsingDirectives = new List<string>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// =================================================================================================
|
|
|
|
|
|
|
|
|
|
// UI stuff
|
|
|
|
|
|
2020-11-10 20:18:14 +11:00
|
|
|
|
public InputField InputField { get; internal set; }
|
2020-11-11 00:16:01 +11:00
|
|
|
|
public Text InputText { get; internal set; }
|
|
|
|
|
public int CurrentIndent { get; private set; }
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
2020-11-12 16:15:41 +11:00
|
|
|
|
public static bool EnableCtrlRShortcut { get; set; } = true;
|
|
|
|
|
public static bool EnableAutoIndent { get; set; } = true;
|
|
|
|
|
public static bool EnableAutocompletes { get; set; } = true;
|
|
|
|
|
public static List<Suggestion> AutoCompletes = new List<Suggestion>();
|
|
|
|
|
|
2020-11-11 20:16:43 +11:00
|
|
|
|
public string HighlightedText => inputHighlightText.text;
|
2020-11-10 20:18:14 +11:00
|
|
|
|
private Text inputHighlightText;
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
2021-03-18 17:17:29 +11:00
|
|
|
|
private CSLexerHighlighter highlightLexer;
|
2020-10-26 01:07:59 +11:00
|
|
|
|
|
2020-11-12 16:15:41 +11:00
|
|
|
|
internal int m_lastCaretPos;
|
|
|
|
|
internal int m_fixCaretPos;
|
|
|
|
|
internal bool m_fixwanted;
|
|
|
|
|
internal float m_lastSelectAlpha;
|
|
|
|
|
|
2020-11-10 20:18:14 +11:00
|
|
|
|
private static readonly KeyCode[] onFocusKeys =
|
2020-10-26 01:07:59 +11:00
|
|
|
|
{
|
|
|
|
|
KeyCode.Return, KeyCode.Backspace, KeyCode.UpArrow,
|
|
|
|
|
KeyCode.DownArrow, KeyCode.LeftArrow, KeyCode.RightArrow
|
|
|
|
|
};
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
2020-11-08 21:04:41 +11:00
|
|
|
|
internal const string STARTUP_TEXT = @"Welcome to the UnityExplorer C# Console.
|
|
|
|
|
|
|
|
|
|
The following helper methods are available:
|
|
|
|
|
|
|
|
|
|
* <color=#add490>Log(""message"")</color> logs a message to the debug console
|
|
|
|
|
|
|
|
|
|
* <color=#add490>CurrentTarget()</color> returns the currently inspected target on the Home page
|
|
|
|
|
|
|
|
|
|
* <color=#add490>AllTargets()</color> returns an object[] array containing all inspected instances
|
|
|
|
|
|
|
|
|
|
* <color=#add490>Inspect(someObject)</color> to inspect an instance, eg. Inspect(Camera.main);
|
|
|
|
|
|
|
|
|
|
* <color=#add490>Inspect(typeof(SomeClass))</color> to inspect a Class with static reflection
|
|
|
|
|
|
|
|
|
|
* <color=#add490>AddUsing(""SomeNamespace"")</color> adds a using directive to the C# console
|
|
|
|
|
|
|
|
|
|
* <color=#add490>GetUsing()</color> logs the current using directives to the debug console
|
|
|
|
|
|
|
|
|
|
* <color=#add490>Reset()</color> resets all using directives and variables
|
|
|
|
|
";
|
|
|
|
|
|
2021-03-18 17:17:29 +11:00
|
|
|
|
public void InitConsole()
|
2020-10-25 20:57:34 +11:00
|
|
|
|
{
|
2021-03-18 17:17:29 +11:00
|
|
|
|
highlightLexer = new CSLexerHighlighter();
|
2020-10-26 01:07:59 +11:00
|
|
|
|
|
2020-11-11 00:16:01 +11:00
|
|
|
|
ConstructUI();
|
2020-10-26 01:07:59 +11:00
|
|
|
|
|
2020-11-13 23:14:57 +11:00
|
|
|
|
InputField.onValueChanged.AddListener((string s) => { OnInputChanged(s); });
|
2020-10-25 20:57:34 +11:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-26 17:54:00 +11:00
|
|
|
|
internal static bool IsUserCopyPasting()
|
|
|
|
|
{
|
|
|
|
|
return (InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.RightControl))
|
|
|
|
|
&& InputManager.GetKeyDown(KeyCode.V);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-18 17:17:29 +11:00
|
|
|
|
public void UpdateConsole()
|
2020-10-25 20:57:34 +11:00
|
|
|
|
{
|
2021-02-26 17:54:00 +11:00
|
|
|
|
if (s_copyPasteBuffer != null)
|
|
|
|
|
{
|
|
|
|
|
if (!IsUserCopyPasting())
|
|
|
|
|
{
|
|
|
|
|
OnInputChanged(s_copyPasteBuffer);
|
|
|
|
|
|
|
|
|
|
s_copyPasteBuffer = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-12 16:15:41 +11:00
|
|
|
|
if (EnableCtrlRShortcut)
|
2020-10-25 20:57:34 +11:00
|
|
|
|
{
|
2020-11-12 16:15:41 +11:00
|
|
|
|
if ((InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.RightControl))
|
|
|
|
|
&& InputManager.GetKeyDown(KeyCode.R))
|
2020-10-25 20:57:34 +11:00
|
|
|
|
{
|
2020-11-12 16:15:41 +11:00
|
|
|
|
var text = InputField.text.Trim();
|
|
|
|
|
if (!string.IsNullOrEmpty(text))
|
2020-10-27 00:54:08 +11:00
|
|
|
|
{
|
2021-03-18 17:17:29 +11:00
|
|
|
|
Evaluate(text);
|
2020-11-12 16:15:41 +11:00
|
|
|
|
return;
|
2020-10-27 00:54:08 +11:00
|
|
|
|
}
|
2020-10-25 20:57:34 +11:00
|
|
|
|
}
|
2020-11-12 16:15:41 +11:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (EnableAutoIndent && InputManager.GetKeyDown(KeyCode.Return))
|
|
|
|
|
AutoIndentCaret();
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
2020-11-12 16:15:41 +11:00
|
|
|
|
if (EnableAutocompletes && InputField.isFocused)
|
|
|
|
|
{
|
|
|
|
|
if (InputManager.GetMouseButton(0) || onFocusKeys.Any(it => InputManager.GetKeyDown(it)))
|
|
|
|
|
UpdateAutocompletes();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_fixCaretPos > 0)
|
|
|
|
|
{
|
|
|
|
|
if (!m_fixwanted)
|
2020-11-13 23:50:24 +11:00
|
|
|
|
{
|
2020-11-15 21:11:43 +11:00
|
|
|
|
EventSystem.current.SetSelectedGameObject(InputField.gameObject, null);
|
2021-03-18 17:17:29 +11:00
|
|
|
|
m_fixwanted = true;
|
2020-11-13 23:50:24 +11:00
|
|
|
|
}
|
2020-11-12 16:15:41 +11:00
|
|
|
|
else
|
2020-10-27 00:54:08 +11:00
|
|
|
|
{
|
2020-11-12 16:15:41 +11:00
|
|
|
|
InputField.caretPosition = m_fixCaretPos;
|
|
|
|
|
InputField.selectionFocusPosition = m_fixCaretPos;
|
|
|
|
|
|
|
|
|
|
m_fixwanted = false;
|
|
|
|
|
m_fixCaretPos = -1;
|
|
|
|
|
|
|
|
|
|
var color = InputField.selectionColor;
|
|
|
|
|
color.a = m_lastSelectAlpha;
|
|
|
|
|
InputField.selectionColor = color;
|
2020-10-27 00:54:08 +11:00
|
|
|
|
}
|
2020-10-25 20:57:34 +11:00
|
|
|
|
}
|
2020-11-12 16:15:41 +11:00
|
|
|
|
else if (InputField.caretPosition > 0)
|
|
|
|
|
{
|
|
|
|
|
m_lastCaretPos = InputField.caretPosition;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal void UpdateAutocompletes()
|
|
|
|
|
{
|
|
|
|
|
AutoCompleter.CheckAutocomplete();
|
|
|
|
|
AutoCompleter.SetSuggestions(AutoCompletes.ToArray());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void UseAutocomplete(string suggestion)
|
|
|
|
|
{
|
|
|
|
|
string input = InputField.text;
|
|
|
|
|
input = input.Insert(m_lastCaretPos, suggestion);
|
|
|
|
|
InputField.text = input;
|
|
|
|
|
|
|
|
|
|
m_fixCaretPos = m_lastCaretPos += suggestion.Length;
|
|
|
|
|
|
|
|
|
|
var color = InputField.selectionColor;
|
|
|
|
|
m_lastSelectAlpha = color.a;
|
|
|
|
|
color.a = 0f;
|
|
|
|
|
InputField.selectionColor = color;
|
|
|
|
|
|
|
|
|
|
AutoCompleter.ClearAutocompletes();
|
2020-10-25 20:57:34 +11:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-26 17:54:00 +11:00
|
|
|
|
internal static string s_copyPasteBuffer;
|
|
|
|
|
|
|
|
|
|
public void OnInputChanged(string newText, bool forceUpdate = false)
|
2020-10-25 20:57:34 +11:00
|
|
|
|
{
|
2021-02-26 17:54:00 +11:00
|
|
|
|
if (IsUserCopyPasting())
|
|
|
|
|
{
|
|
|
|
|
//Console.WriteLine("Copy+Paste detected!");
|
|
|
|
|
s_copyPasteBuffer = newText;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
2021-02-26 17:54:00 +11:00
|
|
|
|
UpdateIndent(newText);
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
2020-10-27 00:54:08 +11:00
|
|
|
|
if (!forceUpdate && string.IsNullOrEmpty(newText))
|
|
|
|
|
inputHighlightText.text = string.Empty;
|
|
|
|
|
else
|
|
|
|
|
inputHighlightText.text = SyntaxHighlightContent(newText);
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
2020-11-12 16:15:41 +11:00
|
|
|
|
UpdateAutocompletes();
|
2020-10-25 20:57:34 +11:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-10 20:18:14 +11:00
|
|
|
|
private void UpdateIndent(string newText)
|
2020-10-25 20:57:34 +11:00
|
|
|
|
{
|
|
|
|
|
int caret = InputField.caretPosition;
|
2020-10-28 06:39:26 +11:00
|
|
|
|
|
2020-11-10 20:18:14 +11:00
|
|
|
|
int len = newText.Length;
|
|
|
|
|
if (caret < 0 || caret >= len)
|
2020-10-25 20:57:34 +11:00
|
|
|
|
{
|
2020-11-10 20:18:14 +11:00
|
|
|
|
while (caret >= 0 && caret >= len)
|
2020-10-25 20:57:34 +11:00
|
|
|
|
caret--;
|
|
|
|
|
|
2020-11-10 20:18:14 +11:00
|
|
|
|
if (caret < 0)
|
2020-10-25 20:57:34 +11:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CurrentIndent = 0;
|
|
|
|
|
|
2020-11-13 18:46:36 +11:00
|
|
|
|
bool stringState = false;
|
|
|
|
|
|
2020-11-10 20:18:14 +11:00
|
|
|
|
for (int i = 0; i < caret && i < newText.Length; i++)
|
2020-10-25 20:57:34 +11:00
|
|
|
|
{
|
2020-11-10 20:18:14 +11:00
|
|
|
|
char character = newText[i];
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
2020-11-13 18:46:36 +11:00
|
|
|
|
if (character == '"')
|
|
|
|
|
stringState = !stringState;
|
2021-03-18 17:17:29 +11:00
|
|
|
|
else if (!stringState && character == CSLexerHighlighter.indentOpen)
|
2020-10-26 01:07:59 +11:00
|
|
|
|
CurrentIndent++;
|
2021-03-18 17:17:29 +11:00
|
|
|
|
else if (!stringState && character == CSLexerHighlighter.indentClose)
|
2020-10-26 01:07:59 +11:00
|
|
|
|
CurrentIndent--;
|
2020-10-25 20:57:34 +11:00
|
|
|
|
}
|
2020-10-26 01:07:59 +11:00
|
|
|
|
|
|
|
|
|
if (CurrentIndent < 0)
|
|
|
|
|
CurrentIndent = 0;
|
2020-10-25 20:57:34 +11:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private const string CLOSE_COLOR_TAG = "</color>";
|
|
|
|
|
|
|
|
|
|
private string SyntaxHighlightContent(string inputText)
|
|
|
|
|
{
|
|
|
|
|
int offset = 0;
|
|
|
|
|
|
2021-02-26 17:54:00 +11:00
|
|
|
|
//Console.WriteLine("Highlighting input text:\r\n" + inputText);
|
|
|
|
|
|
|
|
|
|
string ret = "";
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
2020-11-11 00:16:01 +11:00
|
|
|
|
foreach (LexerMatchInfo match in highlightLexer.GetMatches(inputText))
|
2020-10-25 20:57:34 +11:00
|
|
|
|
{
|
|
|
|
|
for (int i = offset; i < match.startIndex; i++)
|
2021-02-26 17:54:00 +11:00
|
|
|
|
ret += inputText[i];
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
2021-02-26 17:54:00 +11:00
|
|
|
|
ret += $"{match.htmlColor}";
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
|
|
|
|
for (int i = match.startIndex; i < match.endIndex; i++)
|
2021-02-26 17:54:00 +11:00
|
|
|
|
ret += inputText[i];
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
2021-02-26 17:54:00 +11:00
|
|
|
|
ret += CLOSE_COLOR_TAG;
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
|
|
|
|
offset = match.endIndex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = offset; i < inputText.Length; i++)
|
2021-02-26 17:54:00 +11:00
|
|
|
|
ret += inputText[i];
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
2021-02-26 17:54:00 +11:00
|
|
|
|
return ret;
|
2020-10-25 20:57:34 +11:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AutoIndentCaret()
|
|
|
|
|
{
|
|
|
|
|
if (CurrentIndent > 0)
|
|
|
|
|
{
|
2020-10-28 06:39:26 +11:00
|
|
|
|
string indent = GetAutoIndentTab(CurrentIndent);
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
|
|
|
|
if (indent.Length > 0)
|
|
|
|
|
{
|
2020-10-28 06:39:26 +11:00
|
|
|
|
int caretPos = InputField.caretPosition;
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
2020-10-28 06:39:26 +11:00
|
|
|
|
string indentMinusOne = indent.Substring(0, indent.Length - 1);
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
|
|
|
|
// get last index of {
|
2020-10-26 01:07:59 +11:00
|
|
|
|
// chuck it on the next line if its not already
|
2020-10-28 06:39:26 +11:00
|
|
|
|
string text = InputField.text;
|
|
|
|
|
string sub = InputField.text.Substring(0, InputField.caretPosition);
|
|
|
|
|
int lastIndex = sub.LastIndexOf("{");
|
|
|
|
|
int offset = lastIndex - 1;
|
2020-10-25 20:57:34 +11:00
|
|
|
|
if (offset >= 0 && text[offset] != '\n' && text[offset] != '\t')
|
|
|
|
|
{
|
2020-10-28 06:39:26 +11:00
|
|
|
|
string open = "\n" + indentMinusOne;
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
|
|
|
|
InputField.text = text.Insert(offset + 1, open);
|
|
|
|
|
|
|
|
|
|
caretPos += open.Length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check if should add auto-close }
|
2021-03-18 17:17:29 +11:00
|
|
|
|
int numOpen = InputField.text.Where(x => x == CSLexerHighlighter.indentOpen).Count();
|
|
|
|
|
int numClose = InputField.text.Where(x => x == CSLexerHighlighter.indentClose).Count();
|
2020-10-26 01:07:59 +11:00
|
|
|
|
|
2020-10-25 20:57:34 +11:00
|
|
|
|
if (numOpen > numClose)
|
|
|
|
|
{
|
|
|
|
|
// add auto-indent closing
|
|
|
|
|
indentMinusOne = $"\n{indentMinusOne}}}";
|
|
|
|
|
InputField.text = InputField.text.Insert(caretPos, indentMinusOne);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// insert the actual auto indent now
|
|
|
|
|
InputField.text = InputField.text.Insert(caretPos, indent);
|
|
|
|
|
|
2020-11-10 20:18:14 +11:00
|
|
|
|
//InputField.stringPosition = caretPos + indent.Length;
|
|
|
|
|
InputField.caretPosition = caretPos + indent.Length;
|
2020-10-25 20:57:34 +11:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update line column and indent positions
|
2020-11-10 20:18:14 +11:00
|
|
|
|
UpdateIndent(InputField.text);
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
2020-11-11 00:16:01 +11:00
|
|
|
|
InputText.text = InputField.text;
|
2020-11-10 20:18:14 +11:00
|
|
|
|
//inputText.SetText(InputField.text, true);
|
2020-11-11 00:16:01 +11:00
|
|
|
|
InputText.Rebuild(CanvasUpdate.Prelayout);
|
2020-10-25 20:57:34 +11:00
|
|
|
|
InputField.ForceLabelUpdate();
|
|
|
|
|
InputField.Rebuild(CanvasUpdate.Prelayout);
|
2020-10-27 00:54:08 +11:00
|
|
|
|
|
2020-11-11 00:16:01 +11:00
|
|
|
|
OnInputChanged(InputText.text, true);
|
2020-10-25 20:57:34 +11:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string GetAutoIndentTab(int amount)
|
|
|
|
|
{
|
|
|
|
|
string tab = string.Empty;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < amount; i++)
|
2020-10-28 06:39:26 +11:00
|
|
|
|
{
|
2020-10-25 20:57:34 +11:00
|
|
|
|
tab += "\t";
|
2020-10-28 06:39:26 +11:00
|
|
|
|
}
|
2020-10-25 20:57:34 +11:00
|
|
|
|
|
|
|
|
|
return tab;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-08 21:04:41 +11:00
|
|
|
|
// ========== UI CONSTRUCTION =========== //
|
|
|
|
|
|
|
|
|
|
public void ConstructUI()
|
|
|
|
|
{
|
2021-03-18 17:17:29 +11:00
|
|
|
|
Content = UIFactory.CreateUIObject("C# Console", MainMenu.Instance.PageViewport);
|
2020-11-08 21:04:41 +11:00
|
|
|
|
|
2021-03-18 17:17:29 +11:00
|
|
|
|
var mainLayout = Content.AddComponent<LayoutElement>();
|
2020-11-14 00:46:26 +11:00
|
|
|
|
mainLayout.preferredHeight = 500;
|
2020-11-08 21:04:41 +11:00
|
|
|
|
mainLayout.flexibleHeight = 9000;
|
|
|
|
|
|
2021-03-18 17:17:29 +11:00
|
|
|
|
var mainGroup = Content.AddComponent<VerticalLayoutGroup>();
|
2020-11-08 21:04:41 +11:00
|
|
|
|
mainGroup.childControlHeight = true;
|
|
|
|
|
mainGroup.childControlWidth = true;
|
|
|
|
|
mainGroup.childForceExpandHeight = true;
|
|
|
|
|
mainGroup.childForceExpandWidth = true;
|
|
|
|
|
|
|
|
|
|
#region TOP BAR
|
|
|
|
|
|
|
|
|
|
// Main group object
|
|
|
|
|
|
2021-03-18 17:17:29 +11:00
|
|
|
|
var topBarObj = UIFactory.CreateHorizontalGroup(Content);
|
2020-11-08 21:04:41 +11:00
|
|
|
|
LayoutElement topBarLayout = topBarObj.AddComponent<LayoutElement>();
|
|
|
|
|
topBarLayout.minHeight = 50;
|
|
|
|
|
topBarLayout.flexibleHeight = 0;
|
|
|
|
|
|
|
|
|
|
var topBarGroup = topBarObj.GetComponent<HorizontalLayoutGroup>();
|
|
|
|
|
topBarGroup.padding.left = 30;
|
|
|
|
|
topBarGroup.padding.right = 30;
|
|
|
|
|
topBarGroup.padding.top = 8;
|
|
|
|
|
topBarGroup.padding.bottom = 8;
|
|
|
|
|
topBarGroup.spacing = 10;
|
|
|
|
|
topBarGroup.childForceExpandHeight = true;
|
|
|
|
|
topBarGroup.childForceExpandWidth = true;
|
|
|
|
|
topBarGroup.childControlWidth = true;
|
|
|
|
|
topBarGroup.childControlHeight = true;
|
|
|
|
|
topBarGroup.childAlignment = TextAnchor.LowerCenter;
|
|
|
|
|
|
|
|
|
|
var topBarLabel = UIFactory.CreateLabel(topBarObj, TextAnchor.MiddleLeft);
|
|
|
|
|
var topBarLabelLayout = topBarLabel.AddComponent<LayoutElement>();
|
2020-11-12 16:15:41 +11:00
|
|
|
|
topBarLabelLayout.preferredWidth = 150;
|
|
|
|
|
topBarLabelLayout.flexibleWidth = 5000;
|
2020-11-08 21:04:41 +11:00
|
|
|
|
var topBarText = topBarLabel.GetComponent<Text>();
|
|
|
|
|
topBarText.text = "C# Console";
|
|
|
|
|
topBarText.fontSize = 20;
|
|
|
|
|
|
2020-11-12 16:15:41 +11:00
|
|
|
|
// Enable Ctrl+R toggle
|
|
|
|
|
|
|
|
|
|
var ctrlRToggleObj = UIFactory.CreateToggle(topBarObj, out Toggle ctrlRToggle, out Text ctrlRToggleText);
|
|
|
|
|
ctrlRToggle.onValueChanged.AddListener(CtrlRToggleCallback);
|
|
|
|
|
void CtrlRToggleCallback(bool val)
|
|
|
|
|
{
|
|
|
|
|
EnableCtrlRShortcut = val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctrlRToggleText.text = "Run on Ctrl+R";
|
|
|
|
|
ctrlRToggleText.alignment = TextAnchor.UpperLeft;
|
|
|
|
|
var ctrlRLayout = ctrlRToggleObj.AddComponent<LayoutElement>();
|
|
|
|
|
ctrlRLayout.minWidth = 140;
|
|
|
|
|
ctrlRLayout.flexibleWidth = 0;
|
|
|
|
|
ctrlRLayout.minHeight = 25;
|
|
|
|
|
|
2020-11-08 21:04:41 +11:00
|
|
|
|
// Enable Suggestions toggle
|
|
|
|
|
|
|
|
|
|
var suggestToggleObj = UIFactory.CreateToggle(topBarObj, out Toggle suggestToggle, out Text suggestToggleText);
|
|
|
|
|
suggestToggle.onValueChanged.AddListener(SuggestToggleCallback);
|
|
|
|
|
void SuggestToggleCallback(bool val)
|
|
|
|
|
{
|
2020-11-12 16:15:41 +11:00
|
|
|
|
EnableAutocompletes = val;
|
2020-11-08 21:04:41 +11:00
|
|
|
|
AutoCompleter.Update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
suggestToggleText.text = "Suggestions";
|
|
|
|
|
suggestToggleText.alignment = TextAnchor.UpperLeft;
|
|
|
|
|
var suggestLayout = suggestToggleObj.AddComponent<LayoutElement>();
|
|
|
|
|
suggestLayout.minWidth = 120;
|
|
|
|
|
suggestLayout.flexibleWidth = 0;
|
2020-11-12 16:15:41 +11:00
|
|
|
|
suggestLayout.minHeight = 25;
|
2020-11-08 21:04:41 +11:00
|
|
|
|
|
|
|
|
|
// Enable Auto-indent toggle
|
|
|
|
|
|
|
|
|
|
var autoIndentToggleObj = UIFactory.CreateToggle(topBarObj, out Toggle autoIndentToggle, out Text autoIndentToggleText);
|
|
|
|
|
autoIndentToggle.onValueChanged.AddListener(OnIndentChanged);
|
2020-11-12 16:15:41 +11:00
|
|
|
|
void OnIndentChanged(bool val) => EnableAutoIndent = val;
|
2020-11-08 21:04:41 +11:00
|
|
|
|
|
2020-11-16 00:50:06 +11:00
|
|
|
|
autoIndentToggleText.text = "Auto-indent on Enter";
|
2020-11-08 21:04:41 +11:00
|
|
|
|
autoIndentToggleText.alignment = TextAnchor.UpperLeft;
|
|
|
|
|
|
|
|
|
|
var autoIndentLayout = autoIndentToggleObj.AddComponent<LayoutElement>();
|
2020-11-16 00:50:06 +11:00
|
|
|
|
autoIndentLayout.minWidth = 180;
|
2020-11-08 21:04:41 +11:00
|
|
|
|
autoIndentLayout.flexibleWidth = 0;
|
2020-11-12 16:15:41 +11:00
|
|
|
|
autoIndentLayout.minHeight = 25;
|
2020-11-08 21:04:41 +11:00
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region CONSOLE INPUT
|
|
|
|
|
|
2020-11-11 20:16:43 +11:00
|
|
|
|
int fontSize = 16;
|
2020-11-08 21:04:41 +11:00
|
|
|
|
|
2021-03-18 17:17:29 +11:00
|
|
|
|
var inputObj = UIFactory.CreateSrollInputField(Content, out InputFieldScroller consoleScroll, fontSize);
|
2020-11-08 21:04:41 +11:00
|
|
|
|
|
2020-11-11 20:16:43 +11:00
|
|
|
|
var inputField = consoleScroll.inputField;
|
2020-11-08 21:04:41 +11:00
|
|
|
|
|
2020-11-10 20:18:14 +11:00
|
|
|
|
var mainTextObj = inputField.textComponent.gameObject;
|
2020-11-11 20:16:43 +11:00
|
|
|
|
var mainTextInput = inputField.textComponent;
|
|
|
|
|
mainTextInput.supportRichText = false;
|
|
|
|
|
mainTextInput.color = new Color(1, 1, 1, 0.5f);
|
2020-11-08 21:04:41 +11:00
|
|
|
|
|
2020-11-10 20:18:14 +11:00
|
|
|
|
var placeHolderText = inputField.placeholder.GetComponent<Text>();
|
|
|
|
|
placeHolderText.text = STARTUP_TEXT;
|
2020-11-11 20:16:43 +11:00
|
|
|
|
placeHolderText.fontSize = fontSize;
|
2020-11-08 21:04:41 +11:00
|
|
|
|
|
|
|
|
|
var highlightTextObj = UIFactory.CreateUIObject("HighlightText", mainTextObj.gameObject);
|
|
|
|
|
var highlightTextRect = highlightTextObj.GetComponent<RectTransform>();
|
2020-11-10 20:18:14 +11:00
|
|
|
|
highlightTextRect.pivot = new Vector2(0, 1);
|
2020-11-08 21:04:41 +11:00
|
|
|
|
highlightTextRect.anchorMin = Vector2.zero;
|
|
|
|
|
highlightTextRect.anchorMax = Vector2.one;
|
2020-11-10 20:18:14 +11:00
|
|
|
|
highlightTextRect.offsetMin = new Vector2(20, 0);
|
|
|
|
|
highlightTextRect.offsetMax = new Vector2(14, 0);
|
2020-11-08 21:04:41 +11:00
|
|
|
|
|
2020-11-12 16:15:41 +11:00
|
|
|
|
var highlightTextInput = highlightTextObj.AddComponent<Text>();
|
2020-11-10 20:18:14 +11:00
|
|
|
|
highlightTextInput.supportRichText = true;
|
2020-11-11 20:16:43 +11:00
|
|
|
|
highlightTextInput.fontSize = fontSize;
|
2020-11-08 21:04:41 +11:00
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region COMPILE BUTTON
|
|
|
|
|
|
2021-03-18 17:17:29 +11:00
|
|
|
|
var compileBtnObj = UIFactory.CreateButton(Content);
|
2020-11-08 21:04:41 +11:00
|
|
|
|
var compileBtnLayout = compileBtnObj.AddComponent<LayoutElement>();
|
|
|
|
|
compileBtnLayout.preferredWidth = 80;
|
|
|
|
|
compileBtnLayout.flexibleWidth = 0;
|
|
|
|
|
compileBtnLayout.minHeight = 45;
|
|
|
|
|
compileBtnLayout.flexibleHeight = 0;
|
|
|
|
|
var compileButton = compileBtnObj.GetComponent<Button>();
|
|
|
|
|
var compileBtnColors = compileButton.colors;
|
|
|
|
|
compileBtnColors.normalColor = new Color(14f / 255f, 80f / 255f, 14f / 255f);
|
|
|
|
|
compileButton.colors = compileBtnColors;
|
|
|
|
|
var btnText = compileBtnObj.GetComponentInChildren<Text>();
|
|
|
|
|
btnText.text = "Run";
|
|
|
|
|
btnText.fontSize = 18;
|
|
|
|
|
btnText.color = Color.white;
|
|
|
|
|
|
|
|
|
|
// Set compile button callback now that we have the Input Field reference
|
|
|
|
|
compileButton.onClick.AddListener(CompileCallback);
|
|
|
|
|
void CompileCallback()
|
|
|
|
|
{
|
2020-11-10 20:18:14 +11:00
|
|
|
|
if (!string.IsNullOrEmpty(inputField.text))
|
2020-11-08 21:04:41 +11:00
|
|
|
|
{
|
2021-03-18 17:17:29 +11:00
|
|
|
|
Evaluate(inputField.text.Trim());
|
2020-11-08 21:04:41 +11:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2020-11-11 20:16:43 +11:00
|
|
|
|
//mainTextInput.supportRichText = false;
|
2020-11-08 21:04:41 +11:00
|
|
|
|
|
2020-11-10 20:18:14 +11:00
|
|
|
|
mainTextInput.font = UIManager.ConsoleFont;
|
2020-11-11 20:16:43 +11:00
|
|
|
|
placeHolderText.font = UIManager.ConsoleFont;
|
2020-11-10 20:18:14 +11:00
|
|
|
|
highlightTextInput.font = UIManager.ConsoleFont;
|
2020-11-08 21:04:41 +11:00
|
|
|
|
|
2020-11-11 00:16:01 +11:00
|
|
|
|
// reset this after formatting finalized
|
|
|
|
|
highlightTextRect.anchorMin = Vector2.zero;
|
|
|
|
|
highlightTextRect.anchorMax = Vector2.one;
|
|
|
|
|
highlightTextRect.offsetMin = Vector2.zero;
|
|
|
|
|
highlightTextRect.offsetMax = Vector2.zero;
|
|
|
|
|
|
2020-11-08 21:04:41 +11:00
|
|
|
|
// assign references
|
|
|
|
|
|
|
|
|
|
this.InputField = inputField;
|
|
|
|
|
|
2020-11-11 00:16:01 +11:00
|
|
|
|
this.InputText = mainTextInput;
|
2020-11-08 21:04:41 +11:00
|
|
|
|
this.inputHighlightText = highlightTextInput;
|
|
|
|
|
}
|
2021-03-18 17:17:29 +11:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ================================================================================================
|
|
|
|
|
|
|
|
|
|
private class VoidType
|
|
|
|
|
{
|
|
|
|
|
public static readonly VoidType Value = new VoidType();
|
|
|
|
|
private VoidType() { }
|
|
|
|
|
}
|
2020-10-25 20:57:34 +11:00
|
|
|
|
}
|
|
|
|
|
}
|