using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
using System.Collections.Generic;
using UnityEngine.Events;
namespace UnityConsole
{
///
/// The interactive front-end of the console.
///
[DisallowMultipleComponent]
[RequireComponent(typeof(ConsoleController))]
public class ConsoleUI : MonoBehaviour, IScrollHandler
{
public event Action onToggleConsole;
public event Action onSubmitCommand;
public event Action onClearConsole;
public Scrollbar scrollbar;
public Text outputText;
public ScrollRect outputArea;
public InputField inputField;
///
/// Indicates whether the console is currently open or close.
///
public bool isConsoleOpen => enabled;
void Awake()
{
inputField.onEndEdit.AddListener(OnSubmit);
Show(false);
}
///
/// Opens or closes the console.
///
public void ToggleConsole()
{
ClearInput();
enabled = !enabled;
}
///
/// Opens the console.
///
public void OpenConsole()
{
enabled = true;
}
///
/// Closes the console.
///
public void CloseConsole()
{
enabled = false;
}
void OnEnable()
{
OnToggle(true);
}
void OnDisable()
{
OnToggle(false);
}
private void OnToggle(bool open)
{
Show(open);
if (open)
{
inputField.ActivateInputField();
}
else
{
ClearInput();
}
onToggleConsole?.Invoke(open);
}
private void Show(bool show)
{
inputField.gameObject.SetActive(show);
outputArea.gameObject.SetActive(show);
scrollbar.gameObject.SetActive(show);
}
///
/// What to do when the user wants to submit a command.
///
public void OnSubmit(string input)
{
if (EventSystem.current.alreadySelecting)
{
// if user selected something else, don't treat as a submit
return;
}
input = input.Replace('\n', ' ').Replace('\r', ' ');
if (input.Length > 0)
{
onSubmitCommand?.Invoke(input);
scrollbar.value = 0;
ClearInput();
}
inputField.ActivateInputField();
}
///
/// What to do when the user uses the scrollwheel while hovering the console input.
///
public void OnScroll(PointerEventData eventData)
{
scrollbar.value += 0.08f * eventData.scrollDelta.y;
}
///
/// Displays the given message as a new entry in the console output.
///
public void AddNewOutputLine(string line)
{
int length = outputText.text.Length;
if (length > 8192)
outputText.text = outputText.text.Substring(length - 8192);
outputText.text += Environment.NewLine + line;
}
///
/// Clears the console output.
///
public void ClearOutput()
{
outputText.text = "";
outputText.SetLayoutDirty();
onClearConsole?.Invoke();
}
///
/// Clears the console input.
///
public void ClearInput()
{
SetInputText("");
}
///
/// Writes the given string into the console input, ready to be user submitted.
///
public void SetInputText(string input)
{
inputField.MoveTextStart(false);
inputField.text = input;
inputField.MoveTextEnd(false);
inputField.caretPosition = inputField.text.Length;
}
public void TabComplete()
{
List commandsPrefix = ConsoleCommandsDatabase.CommandsMatchingPrefix(inputField.text);
List commandsContaining = ConsoleCommandsDatabase.CommandsContainingStrings(
new string[]
{
inputField.text
}, true);
if (commandsPrefix.Count == 0)
{
if (commandsContaining.Count == 0)
{
AddNewOutputLine("No command contains \"" + inputField.text + "\"");
return;
}
commandsPrefix = commandsContaining;
commandsContaining.Clear();
}
if (commandsPrefix.Count == 1)
{
SetInputText(commandsPrefix[0]);
}
else
{
string prefix = LongestCommonPrefix(commandsPrefix);
if (string.Equals(inputField.text, prefix, StringComparison.OrdinalIgnoreCase))
{
AddNewOutputLine("Did you mean...");
commandsPrefix.Sort();
foreach (var cmd in commandsPrefix)
{
AddNewOutputLine(" " + cmd);
}
if (commandsContaining.Count != 0)
{
AddNewOutputLine("Or others containing this term...");
commandsContaining.Sort();
foreach (var cmd in commandsContaining)
{
AddNewOutputLine(" " + cmd);
}
}
}
else
{
SetInputText(prefix);
}
}
}
private static string LongestCommonPrefix(List strs)
{
if (strs == null || strs.Count == 0)
{
return "";
}
int minLength = int.MaxValue;
foreach (var str in strs)
{
minLength = Math.Min(minLength, str.Length);
}
int left = 1;
int right = minLength;
while (left <= right)
{
int mid = (left + right) / 2;
if (IsCommonPrefix(strs, mid))
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
return strs[0].Substring(0, (left + right) / 2);
}
private static bool IsCommonPrefix(List strs, int len)
{
string str = strs[0].Substring(0, len);
for (int index = 1; index < strs.Count; ++index)
{
if (!strs[index].StartsWith(str))
{
return false;
}
}
return true;
}
}
}