Decompiled source of BetterTerminal v1.1.3

plugins/BetterTerminal/BetterTerminal.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.Json;
using System.Text.RegularExpressions;
using AIGraph;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BetterTerminal.TerminalItems;
using GameData;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using LevelGeneration;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("STFO")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("BetterTerminal")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+2642f2721028b39a90b2dee3ed12b0c02c2e1d56")]
[assembly: AssemblyProduct("BetterTerminal")]
[assembly: AssemblyTitle("BetterTerminal")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace BetterTerminal
{
	[BepInPlugin("BetterTerminal", "BetterTerminal", "1.1.3")]
	public class Plugin : BasePlugin
	{
		[HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "TryUpdateLineForAutoComplete")]
		internal static class AutoCompletePatch
		{
			private static LG_ComputerTerminalCommandInterpreter? _selectionInterpreter;

			private static readonly List<string> SelectionCandidates = new List<string>();

			private static readonly List<string> RenderedSelectionLines = new List<string>();

			private static string _selectionPrefix = string.Empty;

			private static string _selectionLine = string.Empty;

			private static int _selectionIndex;

			private static int _selectionScreenLineCount;

			private static void Postfix(LG_ComputerTerminalCommandInterpreter __instance, string input, ref string autoCompletedLine, ref bool __result)
			{
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Expected O, but got Unknown
				ManualLogSource modLog = ModLog;
				bool flag = default(bool);
				BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(46, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB] INPUT='");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(input);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' NATIVE_RESULT=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(__result);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" NATIVE_OUTPUT='");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(autoCompletedLine);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'");
				}
				modLog.LogDebug(val);
				if (!EnableFuzzySearch.Value || string.IsNullOrWhiteSpace(input))
				{
					ModLog.LogDebug((object)"[TAB] FUZZY DISABLED OR EMPTY INPUT");
					return;
				}
				string text = input.TrimEnd().ToUpperInvariant();
				int num = text.LastIndexOf('|');
				int i;
				for (i = num + 1; i < text.Length && text[i] == ' '; i++)
				{
				}
				string text2 = text.Substring(0, i);
				string text3 = text.Substring(i);
				if (text3.Length == 0)
				{
					return;
				}
				int num2 = text3.IndexOf(' ');
				if (num2 < 0)
				{
					if (__result || !EnableCommandFuzzySearch.Value)
					{
						ModLog.LogDebug((object)"[TAB] KEEPING NATIVE COMMAND AUTOCOMPLETE");
					}
					else
					{
						CompleteCommand(__instance, text3, text2, num >= 0, ref autoCompletedLine, ref __result);
					}
				}
				else if (!EnableIdentifierFuzzySearch.Value)
				{
					ModLog.LogDebug((object)"[TAB] IDENTIFIER FUZZY DISABLED");
				}
				else
				{
					CompleteArgument(__instance, text3, num2, text2, ref autoCompletedLine, ref __result);
				}
			}

			private static void CompleteArgument(LG_ComputerTerminalCommandInterpreter interpreter, string input, int firstSpace, string segmentPrefix, ref string output, ref bool result)
			{
				if (!Enum.TryParse<CommandType>(input.Substring(0, firstSpace), ignoreCase: true, out var result2))
				{
					return;
				}
				if (((uint)(result2 - 1) <= 2u || (uint)(result2 - 5) <= 1u) ? true : false)
				{
					CompleteIdentifier(interpreter, input, firstSpace, segmentPrefix, ref output, ref result);
					return;
				}
				string[] array = input.Split(' ', StringSplitOptions.RemoveEmptyEntries);
				IEnumerable<string> enumerable = null;
				bool flag = (uint)(result2 - 11) <= 1u;
				if (flag && array.Length == 2)
				{
					enumerable = from name in Enum.GetNames<PipelineField>()
						select name.ToUpperInvariant();
				}
				else if (result2 == CommandType.Sort && array.Length == 3)
				{
					enumerable = new string[1] { "DESC" };
				}
				else if (result2 == CommandType.Help && array.Length == 2)
				{
					enumerable = from name in Enum.GetNames<HelpTopic>()
						select name.ToUpperInvariant();
				}
				else if (result2 == CommandType.BetterTerminal && array.Length == 2)
				{
					enumerable = from name in Enum.GetNames<BetterTerminalAction>()
						select name.ToUpperInvariant();
				}
				else if (result2 == CommandType.Docs && array.Length == 2)
				{
					enumerable = from name in Enum.GetNames<DocsAction>()
						select name.ToUpperInvariant();
				}
				else if (result2 == CommandType.History && array.Length == 2)
				{
					enumerable = from name in Enum.GetNames<HistoryAction>()
						select name.ToUpperInvariant();
				}
				else if (result2 == CommandType.Config && array.Length == 2)
				{
					enumerable = ConfigCommandPatch.AutoCompleteKeys;
				}
				else if (result2 == CommandType.Config && array.Length == 3)
				{
					enumerable = ConfigCommandPatch.AutoCompleteValues(array[1]);
				}
				if (enumerable != null)
				{
					int num = input.LastIndexOf(' ');
					string input2 = input.Substring(num + 1);
					if (TryFindBestMatches(input2, enumerable, "ARGUMENT", out List<string> matches))
					{
						string prefix = BuildArgumentPrefix(segmentPrefix, input, num);
						ApplyMatches(interpreter, input2, prefix, matches, ref output, ref result);
					}
				}
			}

			private static void CompleteCommand(LG_ComputerTerminalCommandInterpreter interpreter, string input, string prefix, bool pipelineStage, ref string output, ref bool result)
			{
				//IL_006d: Unknown result type (might be due to invalid IL or missing references)
				List<string> list = new List<string>();
				if (pipelineStage && EnablePipelines.Value)
				{
					PipelineStage[] values = Enum.GetValues<PipelineStage>();
					for (int i = 0; i < values.Length; i++)
					{
						PipelineStage pipelineStage2 = values[i];
						list.Add(pipelineStage2.ToString().ToUpperInvariant());
					}
				}
				else
				{
					Enumerator<string, TERM_Command> enumerator = interpreter.m_commandsPerString.Keys.GetEnumerator();
					while (enumerator.MoveNext())
					{
						string current = enumerator.Current;
						if (!LG_ComputerTerminalCommandInterpreter.CommandIsAlwaysHidden(interpreter.m_commandsPerString[current]))
						{
							list.Add(current.ToUpperInvariant());
						}
					}
					list.AddRange(ModCommands.Names);
				}
				if (!TryFindBestMatches(input, list, "COMMAND", out List<string> matches))
				{
					ModLog.LogDebug((object)"[TAB] NO COMMAND MATCHES");
				}
				else
				{
					ApplyMatches(interpreter, input, prefix, matches, ref output, ref result);
				}
			}

			private static void CompleteIdentifier(LG_ComputerTerminalCommandInterpreter interpreter, string input, int firstSpace, string segmentPrefix, ref string output, ref bool result)
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: Expected O, but got Unknown
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				//IL_007a: Expected O, but got Unknown
				//IL_0194: Unknown result type (might be due to invalid IL or missing references)
				//IL_019b: Expected O, but got Unknown
				string text = input.Substring(0, firstSpace);
				bool flag = default(bool);
				BepInExDebugLogInterpolatedStringHandler val;
				if (!Enum.TryParse<CommandType>(text, ignoreCase: true, out var result2))
				{
					ManualLogSource modLog = ModLog;
					val = new BepInExDebugLogInterpolatedStringHandler(46, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB] UNKNOWN COMMAND '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' FOR IDENTIFIER SEARCH");
					}
					modLog.LogDebug(val);
					return;
				}
				flag = (((uint)(result2 - 1) <= 2u || (uint)(result2 - 5) <= 1u) ? true : false);
				if (!flag)
				{
					ManualLogSource modLog2 = ModLog;
					val = new BepInExDebugLogInterpolatedStringHandler(51, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB] COMMAND '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<CommandType>(result2);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' DOES NOT SUPPORT IDENTIFIER SEARCH");
					}
					modLog2.LogDebug(val);
					return;
				}
				int num = input.LastIndexOf(' ');
				if (num == input.Length - 1)
				{
					return;
				}
				LG_LevelInteractionManager current = LG_LevelInteractionManager.Current;
				Dictionary<string, iTerminalItem> val2 = ((current != null) ? current.m_terminalItemsByKeyString : null);
				if (val2 == null)
				{
					ModLog.LogDebug((object)"[TAB] TERMINAL ITEM DICTIONARY IS NULL");
					return;
				}
				string text2 = input.Substring(num + 1);
				bool flag2 = text2.IndexOfAny(new char[2] { '_', '-' }) >= 0;
				HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
				Enumerator<string, iTerminalItem> enumerator = val2.Keys.GetEnumerator();
				while (enumerator.MoveNext())
				{
					string text3 = enumerator.Current.ToUpperInvariant();
					if (flag2)
					{
						hashSet.Add(text3);
						continue;
					}
					string[] array = text3.Split(new char[2] { '_', '-' }, StringSplitOptions.RemoveEmptyEntries);
					foreach (string item in array)
					{
						hashSet.Add(item);
					}
				}
				ManualLogSource modLog3 = ModLog;
				val = new BepInExDebugLogInterpolatedStringHandler(34, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB] CHECKING ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(hashSet.Count);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" IDENTIFIERS FOR '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text2);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'");
				}
				modLog3.LogDebug(val);
				if (!TryFindBestMatches(text2, hashSet, "IDENTIFIER", out List<string> matches))
				{
					ModLog.LogDebug((object)"[TAB] NO IDENTIFIER MATCHES");
					return;
				}
				string prefix = BuildArgumentPrefix(segmentPrefix, input, num);
				ApplyMatches(interpreter, text2, prefix, matches, ref output, ref result);
			}

			private static string BuildArgumentPrefix(string segmentPrefix, string input, int activeWordSeparator)
			{
				string[] value = input.Substring(0, activeWordSeparator).Split(' ', StringSplitOptions.RemoveEmptyEntries);
				return segmentPrefix + string.Join(" ", value) + " ";
			}

			private static bool TryFindBestMatches(string input, IEnumerable<string> candidates, string candidateType, out List<string> matches)
			{
				//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00da: Expected O, but got Unknown
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_0067: Expected O, but got Unknown
				//IL_018b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0192: Expected O, but got Unknown
				//IL_0261: Unknown result type (might be due to invalid IL or missing references)
				//IL_0268: Expected O, but got Unknown
				string text = input.ToUpperInvariant();
				matches = new List<string>();
				List<string> list = new List<string>();
				List<(string, int)> list2 = new List<(string, int)>();
				bool flag = default(bool);
				BepInExDebugLogInterpolatedStringHandler val;
				foreach (string candidate in candidates)
				{
					if (string.IsNullOrWhiteSpace(candidate))
					{
						continue;
					}
					string text2 = candidate.ToUpperInvariant();
					if (text2.StartsWith(text, StringComparison.OrdinalIgnoreCase))
					{
						list.Add(candidate);
						ManualLogSource modLog = ModLog;
						val = new BepInExDebugLogInterpolatedStringHandler(40, 2, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB:");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(candidateType);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ITEM='");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(candidate);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' PREFIX=True ACCEPTED=True");
						}
						modLog.LogDebug(val);
						continue;
					}
					int num = Levenshtein.Compute(text, text2);
					bool flag2 = num <= MaximumLevenshteinDistance.Value;
					ManualLogSource modLog2 = ModLog;
					val = new BepInExDebugLogInterpolatedStringHandler(34, 4, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB:");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(candidateType);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ITEM='");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(candidate);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' DISTANCE=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ACCEPTED=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(flag2);
					}
					modLog2.LogDebug(val);
					if (flag2)
					{
						list2.Add((candidate, num));
					}
				}
				if (list.Count > 0)
				{
					list.Sort(StringComparer.OrdinalIgnoreCase);
					matches.AddRange(list);
					ManualLogSource modLog3 = ModLog;
					val = new BepInExDebugLogInterpolatedStringHandler(31, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB:");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(candidateType);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] PREFIX_COUNT=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(matches.Count);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" MATCHES=[");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(string.Join(", ", matches));
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("]");
					}
					modLog3.LogDebug(val);
					return true;
				}
				list2.Sort(delegate((string Candidate, int Distance) left, (string Candidate, int Distance) right)
				{
					int num2 = left.Distance.CompareTo(right.Distance);
					return (num2 == 0) ? StringComparer.OrdinalIgnoreCase.Compare(left.Candidate, right.Candidate) : num2;
				});
				foreach (var item2 in list2)
				{
					string item = item2.Item1;
					matches.Add(item);
				}
				ManualLogSource modLog4 = ModLog;
				val = new BepInExDebugLogInterpolatedStringHandler(33, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB:");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(candidateType);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ACCEPTED_COUNT=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(matches.Count);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" MATCHES=[");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(string.Join(", ", matches));
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("]");
				}
				modLog4.LogDebug(val);
				return matches.Count > 0;
			}

			private static void ApplyMatches(LG_ComputerTerminalCommandInterpreter interpreter, string input, string prefix, List<string> matches, ref string output, ref bool result)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Expected O, but got Unknown
				//IL_0122: Unknown result type (might be due to invalid IL or missing references)
				//IL_0128: Expected O, but got Unknown
				//IL_0081: Unknown result type (might be due to invalid IL or missing references)
				//IL_0087: Expected O, but got Unknown
				bool flag = default(bool);
				BepInExDebugLogInterpolatedStringHandler val;
				if (matches.Count == 1)
				{
					ManualLogSource modLog = ModLog;
					val = new BepInExDebugLogInterpolatedStringHandler(30, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB] SINGLE MATCH SELECTED='");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(matches[0]);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'");
					}
					modLog.LogDebug(val);
					ClearSelection();
					output = prefix + matches[0];
					result = true;
					return;
				}
				if (AmbiguousMatches.Value == AmbiguousMatchMode.CommonPrefix)
				{
					ClearSelection();
					string text = FindCommonPrefix(matches);
					ManualLogSource modLog2 = ModLog;
					val = new BepInExDebugLogInterpolatedStringHandler(39, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB] COMMON PREFIX='");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' CANDIDATE_COUNT=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(matches.Count);
					}
					modLog2.LogDebug(val);
					if (text.Length > input.Length)
					{
						output = prefix + text;
						result = true;
					}
					return;
				}
				_selectionInterpreter = interpreter;
				_selectionPrefix = prefix;
				_selectionIndex = 0;
				SelectionCandidates.Clear();
				SelectionCandidates.AddRange(matches);
				_selectionLine = prefix + SelectionCandidates[_selectionIndex];
				ManualLogSource modLog3 = ModLog;
				val = new BepInExDebugLogInterpolatedStringHandler(48, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TAB] ARROW SELECTION STARTED COUNT=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(SelectionCandidates.Count);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" SELECTED='");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(_selectionLine);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'");
				}
				modLog3.LogDebug(val);
				RenderSelectionList();
				output = _selectionLine;
				result = true;
			}

			private static string BuildSelectionList(List<string> candidates, int selectedIndex)
			{
				List<string> list = new List<string> { "FUZZY MATCHES - USE UP/DOWN ARROWS:" };
				for (int i = 0; i < candidates.Count; i++)
				{
					string value = ((i == selectedIndex) ? "->" : "  ");
					list.Add($"{value} {i + 1}. {candidates[i]}");
				}
				return string.Join("\n", list);
			}

			private static string FindCommonPrefix(List<string> candidates)
			{
				string text = candidates[0];
				for (int i = 1; i < candidates.Count; i++)
				{
					if (text.Length <= 0)
					{
						break;
					}
					string text2 = candidates[i];
					int num = Math.Min(text.Length, text2.Length);
					int j;
					for (j = 0; j < num && char.ToUpperInvariant(text[j]) == char.ToUpperInvariant(text2[j]); j++)
					{
					}
					text = text.Substring(0, j);
				}
				return text;
			}

			internal static bool TryStepSelection(LG_ComputerTerminalCommandInterpreter interpreter, bool stepPrevious, ref string result)
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Expected O, but got Unknown
				//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c3: Expected O, but got Unknown
				bool flag = default(bool);
				BepInExDebugLogInterpolatedStringHandler val;
				if (AmbiguousMatches.Value != AmbiguousMatchMode.ArrowSelection || SelectionCandidates.Count < 2)
				{
					ManualLogSource modLog = ModLog;
					val = new BepInExDebugLogInterpolatedStringHandler(39, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[ARROW] SELECTION INACTIVE MODE=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<AmbiguousMatchMode>(AmbiguousMatches.Value);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" COUNT=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(SelectionCandidates.Count);
					}
					modLog.LogDebug(val);
					return false;
				}
				int num = ((!stepPrevious) ? 1 : (-1));
				_selectionIndex = (_selectionIndex + num + SelectionCandidates.Count) % SelectionCandidates.Count;
				_selectionLine = _selectionPrefix + SelectionCandidates[_selectionIndex];
				ManualLogSource modLog2 = ModLog;
				val = new BepInExDebugLogInterpolatedStringHandler(37, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[ARROW] DIRECTION=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(stepPrevious ? "UP" : "DOWN");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" INDEX=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_selectionIndex);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" SELECTED='");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(_selectionLine);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'");
				}
				modLog2.LogDebug(val);
				RenderSelectionList();
				result = _selectionLine;
				return true;
			}

			private static void RenderSelectionList()
			{
				RemoveSelectionList();
				if (_selectionInterpreter != null && SelectionCandidates.Count >= 2)
				{
					string[] array = BuildSelectionList(SelectionCandidates, _selectionIndex).Split('\n');
					string[] array2 = array;
					foreach (string text in array2)
					{
						_selectionInterpreter.m_screenBuffer.Add(text);
						RenderedSelectionLines.Add(text);
					}
					_selectionScreenLineCount = array.Length;
				}
			}

			private static void RemoveSelectionList()
			{
				if (_selectionInterpreter == null || _selectionScreenLineCount == 0)
				{
					return;
				}
				for (int num = RenderedSelectionLines.Count - 1; num >= 0; num--)
				{
					int num2 = _selectionInterpreter.m_screenBuffer.Count - 1;
					if (num2 < 0 || !string.Equals(_selectionInterpreter.m_screenBuffer[num2], RenderedSelectionLines[num], StringComparison.Ordinal))
					{
						ModLog.LogDebug((object)"[SELECTION] SCREEN BUFFER CHANGED; SKIPPING UNSAFE LINE REMOVAL");
						break;
					}
					_selectionInterpreter.m_screenBuffer.RemoveAt(num2);
				}
				RenderedSelectionLines.Clear();
				_selectionScreenLineCount = 0;
			}

			internal static void ClearSelection()
			{
				RemoveSelectionList();
				_selectionInterpreter = null;
				_selectionPrefix = string.Empty;
				_selectionLine = string.Empty;
				_selectionIndex = 0;
				_selectionScreenLineCount = 0;
				SelectionCandidates.Clear();
				RenderedSelectionLines.Clear();
			}
		}

		[HarmonyPatch(typeof(LG_ComputerTerminal), "Update")]
		internal static class TerminalUpdatePatch
		{
			private static bool Prefix(LG_ComputerTerminal __instance)
			{
				if (!EnableHistorySearch.Value || TerminalInputReservationRegistry.IsReserved(__instance.SyncID))
				{
					return true;
				}
				if (HistorySearchManager.IsActive(__instance.SyncID))
				{
					return !HistorySearchManager.HandleUpdate(__instance);
				}
				if (InputMapper.GetButtonDown.Invoke((InputAction)15, (eFocusState)8) && HistorySearchManager.TryOpen(__instance))
				{
					return false;
				}
				return true;
			}

			private static void Postfix(LG_ComputerTerminal __instance)
			{
				//IL_0049: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Expected O, but got Unknown
				if (HistorySearchManager.IsActive(__instance.SyncID) || TerminalInputReservationRegistry.IsReserved(__instance.SyncID))
				{
					return;
				}
				bool flag = InputMapper.GetButtonDown.Invoke((InputAction)15, (eFocusState)8);
				bool flag2 = InputMapper.GetButtonDown.Invoke((InputAction)16, (eFocusState)8);
				if (flag || flag2)
				{
					ManualLogSource modLog = ModLog;
					bool flag3 = default(bool);
					BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(33, 3, ref flag3);
					if (flag3)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[ARROW INPUT] UP=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(flag);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" DOWN=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(flag2);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" TERMINAL=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<uint>(__instance.SyncID);
					}
					modLog.LogDebug(val);
					string result = string.Empty;
					if (AutoCompletePatch.TryStepSelection(__instance.m_command, flag, ref result))
					{
						__instance.m_currentLine = result;
						__instance.m_command.m_inputBufferStep = 0;
					}
				}
			}
		}

		internal const string PluginVersion = "1.1.3";

		private Harmony? _harmony;

		internal static ConfigFile Settings { get; private set; }

		internal static ManualLogSource ModLog { get; private set; }

		internal static ConfigEntry<bool> EnableFuzzySearch { get; private set; }

		internal static ConfigEntry<bool> EnableCommandFuzzySearch { get; private set; }

		internal static ConfigEntry<bool> EnableIdentifierFuzzySearch { get; private set; }

		internal static ConfigEntry<AmbiguousMatchMode> AmbiguousMatches { get; private set; }

		internal static ConfigEntry<int> MaximumLevenshteinDistance { get; private set; }

		internal static ConfigEntry<bool> LogConsumablePickups { get; private set; }

		internal static ConfigEntry<bool> EnableConsumableTerminalItems { get; private set; }

		internal static ConfigEntry<bool> ShowConsumablesInNativeList { get; private set; }

		internal static ConfigEntry<bool> EnableGlowStickTerminalItems { get; private set; }

		internal static ConfigEntry<bool> EnableCFoamGrenadeTerminalItems { get; private set; }

		internal static ConfigEntry<bool> EnableCFoamMineTerminalItems { get; private set; }

		internal static ConfigEntry<bool> EnableExplosiveMineTerminalItems { get; private set; }

		internal static ConfigEntry<bool> EnableFogRepellerTerminalItems { get; private set; }

		internal static ConfigEntry<bool> EnableLockMelterTerminalItems { get; private set; }

		internal static ConfigEntry<bool> EnableLongRangeFlashlightTerminalItems { get; private set; }

		internal static ConfigEntry<bool> EnableHealthSyringeTerminalItems { get; private set; }

		internal static ConfigEntry<bool> EnableBoostSyringeTerminalItems { get; private set; }

		internal static ConfigEntry<bool> EnablePipelines { get; private set; }

		internal static ConfigEntry<bool> EnableHistorySearch { get; private set; }

		internal static ConfigEntry<int> MaximumHistoryEntries { get; private set; }

		internal static ConfigEntry<int> MaximumVisibleHistoryResults { get; private set; }

		internal static ConfigEntry<HistoryPersistenceMode> HistoryPersistence { get; private set; }

		internal static ConfigEntry<string> Language { get; private set; }

		internal static ConfigEntry<bool> ShowNeofetchOnTerminalStart { get; private set; }

		internal static ConfigEntry<NeofetchMode> NeofetchDisplayMode { get; private set; }

		internal static ConfigEntry<bool> EnableIdleScreenImage { get; private set; }

		internal static ConfigEntry<IdleScreenColorMode> IdleScreenColors { get; private set; }

		internal static ConfigEntry<int> ImageIntensityPercent { get; private set; }

		internal static ConfigEntry<int> ImageOpacityPercent { get; private set; }

		internal static ConfigEntry<int> ImageRotationDegrees { get; private set; }

		internal static ConfigEntry<bool> ImageFlipHorizontal { get; private set; }

		internal static ConfigEntry<bool> ImageFlipVertical { get; private set; }

		internal static ConfigEntry<bool> EnableTerminalBackground { get; private set; }

		internal static ConfigEntry<string> TerminalTextColor { get; private set; }

		internal static ConfigEntry<int> TerminalTextIntensityPercent { get; private set; }

		public override void Load()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			Settings = ((BasePlugin)this).Config;
			ModLog = ((BasePlugin)this).Log;
			BindConfiguration();
			LocalizationService.Initialize();
			HistoryStore.Initialize();
			NeofetchService.Initialize();
			IdleScreenService.Initialize();
			_harmony = new Harmony("BetterTerminal");
			_harmony.PatchAll();
			((BasePlugin)this).Log.LogInfo((object)"BetterTerminal loaded");
		}

		private void BindConfiguration()
		{
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Expected O, but got Unknown
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Expected O, but got Unknown
			//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d1: Expected O, but got Unknown
			//IL_03fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0404: Expected O, but got Unknown
			//IL_04d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04db: Expected O, but got Unknown
			Language = ((BasePlugin)this).Config.Bind<string>("Localization", "Language", "en", "JSON language filename without extension. Example: en, es.");
			EnableFuzzySearch = ((BasePlugin)this).Config.Bind<bool>("Fuzzy Search", "Enabled", true, "Enables or disables all terminal fuzzy search features.");
			EnableCommandFuzzySearch = ((BasePlugin)this).Config.Bind<bool>("Fuzzy Search", "Commands", true, "Allows autocomplete to correct command names.");
			EnableIdentifierFuzzySearch = ((BasePlugin)this).Config.Bind<bool>("Fuzzy Search", "Identifiers", true, "Allows autocomplete to correct active identifier words used by LIST, QUERY, PING, MARK, and UNMARK.");
			AmbiguousMatches = ((BasePlugin)this).Config.Bind<AmbiguousMatchMode>("Fuzzy Search", "AmbiguousMatches", AmbiguousMatchMode.CommonPrefix, "CommonPrefix completes the shared prefix. ArrowSelection lets the user choose with arrow keys.");
			MaximumLevenshteinDistance = ((BasePlugin)this).Config.Bind<int>("Fuzzy Search", "MaximumLevenshteinDistance", 2, new ConfigDescription("Maximum fuzzy-search distance. Higher values produce less precise matches.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>()));
			LogConsumablePickups = ((BasePlugin)this).Config.Bind<bool>("Terminal Items", "DiagnosticLogging", false, "Logs uncollected consumable data for diagnostics and type identification.");
			EnableConsumableTerminalItems = ((BasePlugin)this).Config.Bind<bool>("Terminal Items", "Enabled", true, "Enables LIST, QUERY, and PING for uncollected consumables.");
			ShowConsumablesInNativeList = ((BasePlugin)this).Config.Bind<bool>("Terminal Items", "ShowInNativeList", false, "Includes registered consumables in broad native LIST searches such as LIST U. LIST CONSUMABLES and pipelines remain available when disabled.");
			EnableGlowStickTerminalItems = ((BasePlugin)this).Config.Bind<bool>("Terminal Items", "GlowSticks", true, "Registers uncollected glow sticks with terminals.");
			EnableCFoamGrenadeTerminalItems = ((BasePlugin)this).Config.Bind<bool>("Terminal Items", "CFoamGrenades", true, "Registers uncollected C-Foam grenades with terminals.");
			EnableCFoamMineTerminalItems = ((BasePlugin)this).Config.Bind<bool>("Terminal Items", "CFoamMines", true, "Registers uncollected C-Foam tripmines with terminals.");
			EnableExplosiveMineTerminalItems = ((BasePlugin)this).Config.Bind<bool>("Terminal Items", "Mines", true, "Registers uncollected explosive tripmines with terminals.");
			EnableFogRepellerTerminalItems = ((BasePlugin)this).Config.Bind<bool>("Terminal Items", "FogRepellers", true, "Registers uncollected fog repellers with terminals.");
			EnableLockMelterTerminalItems = ((BasePlugin)this).Config.Bind<bool>("Terminal Items", "LockMelters", true, "Registers uncollected lock melters with terminals.");
			EnableLongRangeFlashlightTerminalItems = ((BasePlugin)this).Config.Bind<bool>("Terminal Items", "LongRangeFlashlights", true, "Registers uncollected long-range flashlights with terminals.");
			EnableHealthSyringeTerminalItems = ((BasePlugin)this).Config.Bind<bool>("Terminal Items", "I2LPSyringes", true, "Registers uncollected I2-LP syringes with terminals.");
			EnableBoostSyringeTerminalItems = ((BasePlugin)this).Config.Bind<bool>("Terminal Items", "IIxSyringes", true, "Registers uncollected IIx syringes with terminals.");
			EnablePipelines = ((BasePlugin)this).Config.Bind<bool>("Pipelines", "Enabled", true, "Enables typed command pipelines.");
			EnableHistorySearch = ((BasePlugin)this).Config.Bind<bool>("History", "Enabled", true, "Opens interactive history search when Up is pressed on an empty line.");
			MaximumHistoryEntries = ((BasePlugin)this).Config.Bind<int>("History", "MaximumEntries", 500, new ConfigDescription("Maximum commands retained during the session.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 5000), Array.Empty<object>()));
			MaximumVisibleHistoryResults = ((BasePlugin)this).Config.Bind<int>("History", "MaximumVisibleResults", 15, new ConfigDescription("Maximum visible results in history search.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(3, 50), Array.Empty<object>()));
			HistoryPersistence = ((BasePlugin)this).Config.Bind<HistoryPersistenceMode>("History", "Persistence", HistoryPersistenceMode.Session, "Session keeps commands only until GTFO closes. Disk restores history between sessions.");
			ShowNeofetchOnTerminalStart = ((BasePlugin)this).Config.Bind<bool>("Neofetch", "ShowOnTerminalStart", true, "Shows neofetch when terminal interaction begins.");
			NeofetchDisplayMode = ((BasePlugin)this).Config.Bind<NeofetchMode>("Neofetch", "Mode", NeofetchMode.Normal, "Normal uses bundled artwork. Custom reads BepInEx/config/BetterTerminal/neofetch.txt.");
			EnableIdleScreenImage = ((BasePlugin)this).Config.Bind<bool>("Idle Screen", "Enabled", true, "Shows idle-screen.png on the login display while the terminal is not in use.");
			IdleScreenColors = ((BasePlugin)this).Config.Bind<IdleScreenColorMode>("Idle Screen", "ColorMode", IdleScreenColorMode.Image, "Image preserves PNG RGB colors. Terminal applies the original GTFO display tint.");
			ImageIntensityPercent = ((BasePlugin)this).Config.Bind<int>("Terminal Appearance", "ImageIntensityPercent", 35, new ConfigDescription("Image RGB intensity.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
			ImageOpacityPercent = ((BasePlugin)this).Config.Bind<int>("Terminal Appearance", "ImageOpacityPercent", 25, new ConfigDescription("Interactive background opacity.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			ImageRotationDegrees = ((BasePlugin)this).Config.Bind<int>("Terminal Appearance", "ImageRotationDegrees", 0, "Additional rotation: 0, 90, 180, or 270 degrees.");
			ImageFlipHorizontal = ((BasePlugin)this).Config.Bind<bool>("Terminal Appearance", "FlipHorizontal", false, "Flips the image horizontally after correcting GTFO display UVs.");
			ImageFlipVertical = ((BasePlugin)this).Config.Bind<bool>("Terminal Appearance", "FlipVertical", false, "Flips the image vertically after correcting GTFO display UVs.");
			EnableTerminalBackground = ((BasePlugin)this).Config.Bind<bool>("Terminal Appearance", "InteractiveBackground", false, "Shows idle-screen.png as a background during terminal interaction.");
			TerminalTextColor = ((BasePlugin)this).Config.Bind<string>("Terminal Appearance", "TextColor", "DEFAULT", "Terminal text color as RGB/RGBA hex, for example #80FFD0. DEFAULT preserves GTFO colors.");
			TerminalTextIntensityPercent = ((BasePlugin)this).Config.Bind<int>("Terminal Appearance", "TextIntensityPercent", 100, new ConfigDescription("Custom text RGB intensity. Lower values reduce bloom without changing hue.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
		}
	}
	public enum CommandType
	{
		Unknown,
		Ping,
		Query,
		List,
		Config,
		Mark,
		Unmark,
		Commands,
		Help,
		Neofetch,
		IdleScreen,
		Where,
		Sort,
		Take,
		Count,
		Run,
		Stfo,
		BetterTerminal,
		Docs,
		History
	}
	public enum AmbiguousMatchMode
	{
		CommonPrefix,
		ArrowSelection
	}
	public enum HelpTopic
	{
		BetterTerminal,
		Search,
		History,
		Pipelines,
		Markers,
		Consumables,
		Appearance,
		Config,
		Stfo,
		Docs
	}
	public enum BetterTerminalAction
	{
		Status
	}
	public enum DocsAction
	{
		Open
	}
	public enum ConfigProfile
	{
		Vanilla,
		Convenient,
		Full
	}
	public enum HistoryPersistenceMode
	{
		Session,
		Disk
	}
	public enum HistoryAction
	{
		Clear
	}
	public enum TerminalItemCategory
	{
		All,
		Consumable,
		Native
	}
	public static class CommandTypeExtensions
	{
		public static string Token(this CommandType command)
		{
			return command.ToString().ToUpperInvariant();
		}
	}
	[HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")]
	internal static class CommandsListPatch
	{
		private static void Postfix(LG_ComputerTerminalCommandInterpreter __instance, string inputString)
		{
			CommandType result;
			bool flag = !Enum.TryParse<CommandType>(inputString.Trim().ToUpperInvariant(), ignoreCase: true, out result);
			if (!flag)
			{
				bool flag2 = (uint)(result - 7) <= 1u;
				flag = !flag2;
			}
			if (!flag)
			{
				string[] array = ModCommands.BuildCommandsSection().Split('\n');
				foreach (string text in array)
				{
					__instance.m_screenBuffer.Add(text);
				}
				__instance.ResetLinesSinceCommand();
			}
		}

		internal static IReadOnlyList<string> BuildLines(LG_ComputerTerminalCommandInterpreter interpreter, CommandType commandType)
		{
			List<string> list = new List<string>();
			if (commandType == CommandType.Help)
			{
				list.Add(LocalizationService.Text("help.intro"));
				list.Add(LocalizationService.Text("help.navigation"));
				list.Add(string.Empty);
			}
			list.Add(LocalizationService.Text("commands.available"));
			list.Add(string.Empty);
			list.AddRange(BuildNativeCommands(interpreter));
			list.AddRange(ModCommands.BuildCommandsSection().Split('\n'));
			return list;
		}

		private static IEnumerable<string> BuildNativeCommands(LG_ComputerTerminalCommandInterpreter interpreter)
		{
			SortedSet<string> sortedSet = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
			Enumerator<string, TERM_Command> enumerator = interpreter.m_commandsPerString.Keys.GetEnumerator();
			while (enumerator.MoveNext())
			{
				string current = enumerator.Current;
				sortedSet.Add(current.ToUpperInvariant());
			}
			foreach (string item in sortedSet)
			{
				yield return item;
			}
		}
	}
	[HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")]
	internal static class ConfigCommandPatch
	{
		internal static readonly string[] AutoCompleteKeys = new string[39]
		{
			"RELOAD", "SEARCH", "HISTORY", "ITEMS", "APPEARANCE", "PROFILE", "RESET", "ENABLED", "COMMANDS", "IDENTIFIERS",
			"GLOWSTICKS", "CFOAMGRENADES", "CFOAMMINES", "MINES", "FOGREPELLERS", "LOCKMELTERS", "FLASHLIGHTS", "I2LPSYRINGES", "IIXSYRINGES", "CONSUMABLESINLIST",
			"PIPELINES", "HISTORYLIMIT", "HISTORYVISIBLE", "HISTORYMODE", "LANGUAGE", "NEOFETCH", "NEOFETCHMODE", "IDLESCREEN", "IDLECOLORS", "BACKGROUND",
			"IMAGEINTENSITY", "IMAGEOPACITY", "IMAGEROTATION", "IMAGEFLIPH", "IMAGEFLIPV", "TEXTCOLOR", "TEXTINTENSITY", "DISTANCE", "MODE"
		};

		internal static IEnumerable<string>? AutoCompleteValues(string key)
		{
			switch (key)
			{
			case "PROFILE":
				return from name in Enum.GetNames<ConfigProfile>()
					select name.ToUpperInvariant();
			case "RESET":
				return new string[2] { "ALL", "APPEARANCE" };
			case "NEOFETCHMODE":
				return from name in Enum.GetNames<NeofetchMode>()
					select name.ToUpperInvariant();
			case "IDLECOLORS":
				return from name in Enum.GetNames<IdleScreenColorMode>()
					select name.ToUpperInvariant();
			case "MODE":
				return from name in Enum.GetNames<AmbiguousMatchMode>()
					select name.ToUpperInvariant();
			case "HISTORYMODE":
				return from name in Enum.GetNames<HistoryPersistenceMode>()
					select name.ToUpperInvariant();
			case "IMAGEROTATION":
				return new string[4] { "0", "90", "180", "270" };
			case "TEXTCOLOR":
				return new string[1] { "DEFAULT" };
			case "LANGUAGE":
				return new string[2] { "EN", "ES" };
			case "ENABLED":
			case "HISTORY":
			case "ITEMS":
			case "MINES":
			case "FOGREPELLERS":
			case "I2LPSYRINGES":
			case "BACKGROUND":
			case "GLOWSTICKS":
			case "IDLESCREEN":
			case "IMAGEFLIPH":
			case "IMAGEFLIPV":
			case "CFOAMMINES":
			case "IDENTIFIERS":
			case "LOCKMELTERS":
			case "FLASHLIGHTS":
			case "IIXSYRINGES":
			case "CFOAMGRENADES":
			case "PIPELINES":
			case "COMMANDS":
			case "NEOFETCH":
			case "CONSUMABLESINLIST":
				return new string[2] { "ON", "OFF" };
			default:
				return null;
			}
		}

		private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString)
		{
			string text = inputString.Trim().ToUpperInvariant();
			string[] array = text.Split(' ', StringSplitOptions.RemoveEmptyEntries);
			if (array.Length == 0 || !Enum.TryParse<CommandType>(array[0], ignoreCase: true, out var result) || result != CommandType.Config)
			{
				return true;
			}
			Plugin.AutoCompletePatch.ClearSelection();
			WriteImmediate(__instance, text, Execute(array));
			return false;
		}

		private static void WriteImmediate(LG_ComputerTerminalCommandInterpreter interpreter, string commandLine, string response)
		{
			TerminalCommandOutput.WriteImmediate(interpreter, commandLine, response.Split('\n'));
		}

		private static string Execute(string[] arguments)
		{
			if (arguments.Length == 1)
			{
				return CurrentConfiguration();
			}
			if (arguments.Length == 2 && arguments[1] == "RELOAD")
			{
				Plugin.Settings.Reload();
				HistoryStore.ReloadForPersistenceChange();
				LocalizationService.Reload();
				NeofetchService.Reload();
				IdleScreenService.Reload();
				TerminalAppearanceService.RefreshAll();
				ConsumableTerminalRegistry.RefreshAll();
				return LocalizationService.Text("config.reloaded") + "\n" + CurrentConfiguration();
			}
			bool flag = arguments.Length == 2;
			if (flag)
			{
				bool flag2;
				switch (arguments[1])
				{
				case "SEARCH":
				case "HISTORY":
				case "ITEMS":
				case "APPEARANCE":
					flag2 = true;
					break;
				default:
					flag2 = false;
					break;
				}
				flag = flag2;
			}
			if (flag)
			{
				return Section(arguments[1]);
			}
			if (arguments.Length == 2 && arguments[1] == "RESET")
			{
				return ResetConfiguration("ALL");
			}
			if (arguments.Length == 3 && arguments[1] == "RESET")
			{
				return ResetConfiguration(arguments[2]);
			}
			if (arguments.Length == 3 && arguments[1] == "PROFILE")
			{
				return ApplyProfile(arguments[2]);
			}
			if (arguments.Length != 3)
			{
				return Help();
			}
			return arguments[1] switch
			{
				"ENABLED" => SetBoolean(Plugin.EnableFuzzySearch, arguments[2], "ENABLED"), 
				"COMMANDS" => SetBoolean(Plugin.EnableCommandFuzzySearch, arguments[2], "COMMANDS"), 
				"IDENTIFIERS" => SetBoolean(Plugin.EnableIdentifierFuzzySearch, arguments[2], "IDENTIFIERS"), 
				"ITEMS" => SetTerminalItemBoolean(Plugin.EnableConsumableTerminalItems, arguments[2], "ITEMS"), 
				"GLOWSTICKS" => SetTerminalItemBoolean(Plugin.EnableGlowStickTerminalItems, arguments[2], "GLOWSTICKS"), 
				"CFOAMGRENADES" => SetTerminalItemBoolean(Plugin.EnableCFoamGrenadeTerminalItems, arguments[2], "CFOAMGRENADES"), 
				"CFOAMMINES" => SetTerminalItemBoolean(Plugin.EnableCFoamMineTerminalItems, arguments[2], "CFOAMMINES"), 
				"MINES" => SetTerminalItemBoolean(Plugin.EnableExplosiveMineTerminalItems, arguments[2], "MINES"), 
				"FOGREPELLERS" => SetTerminalItemBoolean(Plugin.EnableFogRepellerTerminalItems, arguments[2], "FOGREPELLERS"), 
				"LOCKMELTERS" => SetTerminalItemBoolean(Plugin.EnableLockMelterTerminalItems, arguments[2], "LOCKMELTERS"), 
				"FLASHLIGHTS" => SetTerminalItemBoolean(Plugin.EnableLongRangeFlashlightTerminalItems, arguments[2], "FLASHLIGHTS"), 
				"I2LPSYRINGES" => SetTerminalItemBoolean(Plugin.EnableHealthSyringeTerminalItems, arguments[2], "I2LPSYRINGES"), 
				"IIXSYRINGES" => SetTerminalItemBoolean(Plugin.EnableBoostSyringeTerminalItems, arguments[2], "IIXSYRINGES"), 
				"CONSUMABLESINLIST" => SetTerminalItemBoolean(Plugin.ShowConsumablesInNativeList, arguments[2], "CONSUMABLESINLIST"), 
				"PIPELINES" => SetBoolean(Plugin.EnablePipelines, arguments[2], "PIPELINES"), 
				"HISTORY" => SetBoolean(Plugin.EnableHistorySearch, arguments[2], "HISTORY"), 
				"HISTORYLIMIT" => SetInteger(Plugin.MaximumHistoryEntries, arguments[2], "HISTORYLIMIT", 10, 5000), 
				"HISTORYVISIBLE" => SetInteger(Plugin.MaximumVisibleHistoryResults, arguments[2], "HISTORYVISIBLE", 3, 50), 
				"HISTORYMODE" => SetHistoryPersistence(arguments[2]), 
				"LANGUAGE" => SetLanguage(arguments[2]), 
				"NEOFETCH" => SetBoolean(Plugin.ShowNeofetchOnTerminalStart, arguments[2], "NEOFETCH"), 
				"NEOFETCHMODE" => SetNeofetchMode(arguments[2]), 
				"IDLESCREEN" => SetIdleScreen(arguments[2]), 
				"IDLECOLORS" => SetIdleScreenColorMode(arguments[2]), 
				"BACKGROUND" => SetAppearanceBoolean(Plugin.EnableTerminalBackground, arguments[2], "BACKGROUND"), 
				"IMAGEFLIPH" => SetAppearanceBoolean(Plugin.ImageFlipHorizontal, arguments[2], "IMAGEFLIPH"), 
				"IMAGEFLIPV" => SetAppearanceBoolean(Plugin.ImageFlipVertical, arguments[2], "IMAGEFLIPV"), 
				"IMAGEINTENSITY" => SetAppearanceInteger(Plugin.ImageIntensityPercent, arguments[2], "IMAGEINTENSITY", 1, 100), 
				"IMAGEOPACITY" => SetAppearanceInteger(Plugin.ImageOpacityPercent, arguments[2], "IMAGEOPACITY", 0, 100), 
				"IMAGEROTATION" => SetImageRotation(arguments[2]), 
				"TEXTCOLOR" => SetTextColor(arguments[2]), 
				"TEXTINTENSITY" => SetAppearanceInteger(Plugin.TerminalTextIntensityPercent, arguments[2], "TEXTINTENSITY", 1, 100), 
				"DISTANCE" => SetDistance(arguments[2]), 
				"MODE" => SetMode(arguments[2]), 
				_ => Help(), 
			};
		}

		private static string SetTerminalItemBoolean(ConfigEntry<bool> entry, string value, string key)
		{
			string result = SetBoolean(entry, value, key);
			if ((value == "ON" || value == "OFF") ? true : false)
			{
				ConsumableTerminalRegistry.RefreshAll();
			}
			return result;
		}

		private static string SetBoolean(ConfigEntry<bool> entry, string value, string key)
		{
			if ((!(value == "ON") && !(value == "OFF")) || 1 == 0)
			{
				return "INVALID VALUE FOR " + key + ". USE ON OR OFF.";
			}
			entry.Value = value == "ON";
			return key + ": " + value;
		}

		private static string SetDistance(string value)
		{
			int result;
			bool flag = !int.TryParse(value, out result);
			if (!flag)
			{
				bool flag2 = ((result < 1 || result > 10) ? true : false);
				flag = flag2;
			}
			if (flag)
			{
				return "INVALID DISTANCE. USE A VALUE FROM 1 TO 10.";
			}
			Plugin.MaximumLevenshteinDistance.Value = result;
			return $"MAXIMUM LEVENSHTEIN DISTANCE: {result}";
		}

		private static string SetInteger(ConfigEntry<int> entry, string value, string key, int minimum, int maximum)
		{
			if (int.TryParse(value, out var result) && result >= minimum && result <= maximum)
			{
				entry.Value = result;
				return $"{key}: {result}";
			}
			return $"INVALID {key}. USE A VALUE FROM {minimum} TO {maximum}.";
		}

		private static string SetMode(string value)
		{
			if (!Enum.TryParse<AmbiguousMatchMode>(value, ignoreCase: true, out var result))
			{
				return "INVALID MODE. USE COMMONPREFIX OR ARROWSELECTION.";
			}
			Plugin.AmbiguousMatches.Value = result;
			return "AMBIGUOUS MATCHES: " + result.ToString().ToUpperInvariant();
		}

		private static string SetHistoryPersistence(string value)
		{
			if (!Enum.TryParse<HistoryPersistenceMode>(value, ignoreCase: true, out var result))
			{
				return LocalizationService.Text("history.mode_invalid");
			}
			Plugin.HistoryPersistence.Value = result;
			HistoryStore.ReloadForPersistenceChange();
			return LocalizationService.Text("history.mode_changed", result.ToString().ToUpperInvariant());
		}

		private static string SetLanguage(string value)
		{
			if (!LocalizationService.TrySetLanguage(value))
			{
				return LocalizationService.Text("config.language_missing", value.ToUpperInvariant());
			}
			return LocalizationService.Text("config.language_changed", value.ToUpperInvariant());
		}

		private static string SetNeofetchMode(string value)
		{
			if (!Enum.TryParse<NeofetchMode>(value, ignoreCase: true, out var result))
			{
				return "INVALID NEOFETCH MODE. USE NORMAL OR CUSTOM.";
			}
			Plugin.NeofetchDisplayMode.Value = result;
			NeofetchService.Reload();
			return "NEOFETCH MODE: " + result.ToString().ToUpperInvariant();
		}

		private static string SetIdleScreen(string value)
		{
			string result = SetBoolean(Plugin.EnableIdleScreenImage, value, "IDLESCREEN");
			IdleScreenService.RefreshAll();
			return result;
		}

		private static string SetIdleScreenColorMode(string value)
		{
			if (!Enum.TryParse<IdleScreenColorMode>(value, ignoreCase: true, out var result))
			{
				return LocalizationService.Text("config.idle_colors_invalid");
			}
			Plugin.IdleScreenColors.Value = result;
			IdleScreenService.Reload();
			return LocalizationService.Text("config.idle_colors_changed", result.ToString().ToUpperInvariant());
		}

		private static string SetAppearanceBoolean(ConfigEntry<bool> entry, string value, string key)
		{
			string result = SetBoolean(entry, value, key);
			if ((value == "ON" || value == "OFF") ? true : false)
			{
				RefreshAppearance();
			}
			return result;
		}

		private static string SetAppearanceInteger(ConfigEntry<int> entry, string value, string key, int minimum, int maximum)
		{
			string result = SetInteger(entry, value, key, minimum, maximum);
			if (int.TryParse(value, out var result2) && result2 >= minimum && result2 <= maximum)
			{
				RefreshAppearance();
			}
			return result;
		}

		private static string SetImageRotation(string value)
		{
			int result;
			bool flag = !int.TryParse(value, out result);
			if (!flag)
			{
				bool flag2;
				switch (result)
				{
				case 0:
				case 90:
				case 180:
				case 270:
					flag2 = true;
					break;
				default:
					flag2 = false;
					break;
				}
				flag = !flag2;
			}
			if (flag)
			{
				return LocalizationService.Text("config.image_rotation_invalid");
			}
			Plugin.ImageRotationDegrees.Value = result;
			RefreshAppearance();
			return $"IMAGE ROTATION: {result}";
		}

		private static string SetTextColor(string value)
		{
			Color val = default(Color);
			if (!value.Equals("DEFAULT", StringComparison.OrdinalIgnoreCase) && !ColorUtility.TryParseHtmlString(value.StartsWith('#') ? value : ("#" + value), ref val))
			{
				return LocalizationService.Text("config.text_color_invalid");
			}
			Plugin.TerminalTextColor.Value = value;
			TerminalAppearanceService.RefreshAll();
			return "TEXT COLOR: " + value.ToUpperInvariant();
		}

		private static string Section(string section)
		{
			return section switch
			{
				"SEARCH" => string.Join("\n", $"ENABLED: {Plugin.EnableFuzzySearch.Value}", $"COMMANDS: {Plugin.EnableCommandFuzzySearch.Value}", $"IDENTIFIERS: {Plugin.EnableIdentifierFuzzySearch.Value}", $"MODE: {Plugin.AmbiguousMatches.Value}", $"DISTANCE: {Plugin.MaximumLevenshteinDistance.Value}"), 
				"HISTORY" => string.Join("\n", $"ENABLED: {Plugin.EnableHistorySearch.Value}", "MODE: " + Plugin.HistoryPersistence.Value.ToString().ToUpperInvariant(), $"LIMIT: {Plugin.MaximumHistoryEntries.Value}", $"VISIBLE RESULTS: {Plugin.MaximumVisibleHistoryResults.Value}"), 
				"ITEMS" => string.Join("\n", $"ENABLED: {Plugin.EnableConsumableTerminalItems.Value}", $"GLOW STICKS: {Plugin.EnableGlowStickTerminalItems.Value}", $"C-FOAM GRENADES: {Plugin.EnableCFoamGrenadeTerminalItems.Value}", $"C-FOAM MINES: {Plugin.EnableCFoamMineTerminalItems.Value}", $"EXPLOSIVE MINES: {Plugin.EnableExplosiveMineTerminalItems.Value}", $"FOG REPELLERS: {Plugin.EnableFogRepellerTerminalItems.Value}", $"LOCK MELTERS: {Plugin.EnableLockMelterTerminalItems.Value}", $"FLASHLIGHTS: {Plugin.EnableLongRangeFlashlightTerminalItems.Value}", $"CONSUMABLES IN NATIVE LIST: {Plugin.ShowConsumablesInNativeList.Value}"), 
				"APPEARANCE" => string.Join("\n", $"NEOFETCH: {Plugin.ShowNeofetchOnTerminalStart.Value}", $"IDLE SCREEN: {Plugin.EnableIdleScreenImage.Value}", $"BACKGROUND: {Plugin.EnableTerminalBackground.Value}", "TEXT COLOR: " + Plugin.TerminalTextColor.Value, $"TEXT INTENSITY: {Plugin.TerminalTextIntensityPercent.Value}%"), 
				_ => Help(), 
			};
		}

		private static string ApplyProfile(string profile)
		{
			bool flag;
			switch (profile)
			{
			case "VANILLA":
			case "CONVENIENT":
			case "FULL":
				flag = true;
				break;
			default:
				flag = false;
				break;
			}
			if (!flag)
			{
				return "INVALID PROFILE. USE VANILLA, CONVENIENT OR FULL.";
			}
			flag = ((profile == "CONVENIENT" || profile == "FULL") ? true : false);
			bool value = flag;
			bool value2 = profile == "FULL";
			Plugin.EnableFuzzySearch.Value = true;
			Plugin.EnableCommandFuzzySearch.Value = true;
			Plugin.EnableIdentifierFuzzySearch.Value = true;
			Plugin.EnableHistorySearch.Value = true;
			Plugin.EnablePipelines.Value = value;
			Plugin.EnableConsumableTerminalItems.Value = value;
			Plugin.ShowNeofetchOnTerminalStart.Value = value2;
			Plugin.EnableIdleScreenImage.Value = value2;
			Plugin.EnableTerminalBackground.Value = false;
			Plugin.Settings.Save();
			ConsumableTerminalRegistry.RefreshAll();
			RefreshAppearance();
			return "PROFILE APPLIED: " + profile;
		}

		private static string ResetConfiguration(string section)
		{
			string normalized = section.ToUpperInvariant();
			IEnumerable<ConfigEntryBase> enumerable = from pair in (IEnumerable<KeyValuePair<ConfigDefinition, ConfigEntryBase>>)Plugin.Settings
				where normalized == "ALL" || pair.Key.Section.Equals(normalized, StringComparison.OrdinalIgnoreCase) || (normalized == "APPEARANCE" && pair.Key.Section == "Terminal Appearance")
				select pair.Value;
			int num = 0;
			foreach (ConfigEntryBase item in enumerable)
			{
				item.BoxedValue = item.DefaultValue;
				num++;
			}
			Plugin.Settings.Save();
			LocalizationService.Reload();
			ConsumableTerminalRegistry.RefreshAll();
			RefreshAppearance();
			if (num != 0)
			{
				return $"CONFIGURATION RESET: {normalized} ({num} SETTINGS)";
			}
			return "UNKNOWN CONFIGURATION SECTION.";
		}

		private static void RefreshAppearance()
		{
			IdleScreenService.Reload();
			TerminalAppearanceService.RefreshAll();
		}

		private static string CurrentConfiguration()
		{
			return string.Join("\n", LocalizationService.Text("config.header"), "LANGUAGE: " + Plugin.Language.Value.ToUpperInvariant(), "ENABLED: " + Plugin.EnableFuzzySearch.Value.ToString().ToUpperInvariant(), "COMMANDS: " + Plugin.EnableCommandFuzzySearch.Value.ToString().ToUpperInvariant(), "IDENTIFIERS: " + Plugin.EnableIdentifierFuzzySearch.Value.ToString().ToUpperInvariant(), "AMBIGUOUS MATCHES: " + Plugin.AmbiguousMatches.Value.ToString().ToUpperInvariant(), $"MAXIMUM LEVENSHTEIN DISTANCE: {Plugin.MaximumLevenshteinDistance.Value}", "TERMINAL ITEMS: " + Plugin.EnableConsumableTerminalItems.Value.ToString().ToUpperInvariant(), "GLOW STICKS: " + Plugin.EnableGlowStickTerminalItems.Value.ToString().ToUpperInvariant(), "C-FOAM GRENADES: " + Plugin.EnableCFoamGrenadeTerminalItems.Value.ToString().ToUpperInvariant(), "C-FOAM MINES: " + Plugin.EnableCFoamMineTerminalItems.Value.ToString().ToUpperInvariant(), "MINES: " + Plugin.EnableExplosiveMineTerminalItems.Value.ToString().ToUpperInvariant(), "FOG REPELLERS: " + Plugin.EnableFogRepellerTerminalItems.Value.ToString().ToUpperInvariant(), "LOCK MELTERS: " + Plugin.EnableLockMelterTerminalItems.Value.ToString().ToUpperInvariant(), "LONG RANGE FLASHLIGHTS: " + Plugin.EnableLongRangeFlashlightTerminalItems.Value.ToString().ToUpperInvariant(), "I2-LP SYRINGES: " + Plugin.EnableHealthSyringeTerminalItems.Value.ToString().ToUpperInvariant(), "IIX SYRINGES: " + Plugin.EnableBoostSyringeTerminalItems.Value.ToString().ToUpperInvariant(), "CONSUMABLES IN NATIVE LIST: " + Plugin.ShowConsumablesInNativeList.Value.ToString().ToUpperInvariant(), "PIPELINES: " + Plugin.EnablePipelines.Value.ToString().ToUpperInvariant(), "HISTORY SEARCH: " + Plugin.EnableHistorySearch.Value.ToString().ToUpperInvariant(), "HISTORY MODE: " + Plugin.HistoryPersistence.Value.ToString().ToUpperInvariant(), $"HISTORY LIMIT: {Plugin.MaximumHistoryEntries.Value}", $"HISTORY VISIBLE RESULTS: {Plugin.MaximumVisibleHistoryResults.Value}", "NEOFETCH ON TERMINAL START: " + Plugin.ShowNeofetchOnTerminalStart.Value.ToString().ToUpperInvariant(), "NEOFETCH MODE: " + Plugin.NeofetchDisplayMode.Value.ToString().ToUpperInvariant(), "NEOFETCH NORMAL FILE: " + NeofetchService.DefaultFilePath, "NEOFETCH CUSTOM FILE: " + NeofetchService.FilePath, "IDLE SCREEN: " + Plugin.EnableIdleScreenImage.Value.ToString().ToUpperInvariant(), LocalizationService.Text("config.idle_colors_value", Plugin.IdleScreenColors.Value.ToString().ToUpperInvariant()), "IDLE SCREEN FILE: " + IdleScreenService.FilePath, "INTERACTIVE BACKGROUND: " + Plugin.EnableTerminalBackground.Value.ToString().ToUpperInvariant(), $"IMAGE INTENSITY: {Plugin.ImageIntensityPercent.Value}%", $"IMAGE OPACITY: {Plugin.ImageOpacityPercent.Value}%", $"IMAGE ROTATION: {Plugin.ImageRotationDegrees.Value}", "IMAGE FLIP HORIZONTAL: " + Plugin.ImageFlipHorizontal.Value.ToString().ToUpperInvariant(), "IMAGE FLIP VERTICAL: " + Plugin.ImageFlipVertical.Value.ToString().ToUpperInvariant(), "TEXT COLOR: " + Plugin.TerminalTextColor.Value.ToUpperInvariant(), $"TEXT INTENSITY: {Plugin.TerminalTextIntensityPercent.Value}%");
		}

		private static string Help()
		{
			return string.Join("\n", LocalizationService.Text("config.help_header"), "CONFIG", "CONFIG RELOAD", "CONFIG SEARCH|HISTORY|ITEMS|APPEARANCE", "CONFIG PROFILE VANILLA|CONVENIENT|FULL", "CONFIG RESET [APPEARANCE|ALL]", "CONFIG ENABLED ON|OFF", "CONFIG COMMANDS ON|OFF", "CONFIG IDENTIFIERS ON|OFF", "CONFIG ITEMS ON|OFF", "CONFIG GLOWSTICKS ON|OFF", "CONFIG CFOAMGRENADES ON|OFF", "CONFIG CFOAMMINES ON|OFF", "CONFIG MINES ON|OFF", "CONFIG FOGREPELLERS ON|OFF", "CONFIG LOCKMELTERS ON|OFF", "CONFIG FLASHLIGHTS ON|OFF", "CONFIG I2LPSYRINGES ON|OFF", "CONFIG IIXSYRINGES ON|OFF", "CONFIG CONSUMABLESINLIST ON|OFF", "CONFIG PIPELINES ON|OFF", "CONFIG HISTORY ON|OFF", "CONFIG HISTORYMODE SESSION|DISK", "HISTORY CLEAR", "CONFIG HISTORYLIMIT 10-5000", "CONFIG HISTORYVISIBLE 3-50", "CONFIG LANGUAGE NAME", "CONFIG NEOFETCH ON|OFF", "CONFIG NEOFETCHMODE NORMAL|CUSTOM", "CONFIG IDLESCREEN ON|OFF", "CONFIG IDLECOLORS IMAGE|TERMINAL", "CONFIG BACKGROUND ON|OFF", "CONFIG IMAGEINTENSITY 1-100", "CONFIG IMAGEOPACITY 0-100", "CONFIG IMAGEROTATION 0|90|180|270", "CONFIG IMAGEFLIPH ON|OFF", "CONFIG IMAGEFLIPV ON|OFF", "CONFIG TEXTCOLOR DEFAULT|RRGGBB|RRGGBBAA", "CONFIG TEXTINTENSITY 1-100", "CONFIG MODE COMMONPREFIX|ARROWSELECTION", "CONFIG DISTANCE 1-10");
		}
	}
	[HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")]
	internal static class HelpAndDocsCommandPatch
	{
		internal const string DocumentationUrl = "https://alexandermakunin.github.io/BetterTerminal/";

		private static readonly HashSet<string> Topics = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "BETTERTERMINAL", "SEARCH", "HISTORY", "PIPELINES", "MARKERS", "CONSUMABLES", "APPEARANCE", "CONFIG", "STFO", "DOCS" };

		[HarmonyPriority(800)]
		private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString)
		{
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Expected O, but got Unknown
			string[] array = inputString.Trim().ToUpperInvariant().Split(' ', StringSplitOptions.RemoveEmptyEntries);
			if (array.Length == 0)
			{
				return true;
			}
			if (array[0] == CommandType.Help.Token() && array.Length == 2 && Topics.Contains(array[1]))
			{
				Write(__instance, inputString, HelpTopic(array[1]));
				return false;
			}
			if (array[0] == CommandType.BetterTerminal.Token())
			{
				Write(__instance, inputString, (array.Length == 2 && array[1] == "STATUS") ? Status() : HelpTopic("BETTERTERMINAL"));
				return false;
			}
			if (array[0] != CommandType.Docs.Token())
			{
				return true;
			}
			List<string> list = new List<string>();
			list.Add(LocalizationService.Text("docs.url", "https://alexandermakunin.github.io/BetterTerminal/"));
			List<string> list2 = list;
			if (array.Length == 2 && array[1] == "OPEN")
			{
				try
				{
					Process.Start(new ProcessStartInfo("https://alexandermakunin.github.io/BetterTerminal/")
					{
						UseShellExecute = true
					});
					list2.Add(LocalizationService.Text("docs.opened"));
				}
				catch (Exception ex)
				{
					ManualLogSource modLog = Plugin.ModLog;
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(20, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[DOCS] OPEN FAILED: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					}
					modLog.LogWarning(val);
					list2.Add(LocalizationService.Text("docs.open_failed"));
				}
			}
			else if (array.Length > 1)
			{
				list2.Add(LocalizationService.Text("docs.usage"));
			}
			Write(__instance, inputString, list2);
			return false;
		}

		private static IEnumerable<string> HelpTopic(string topic)
		{
			return topic switch
			{
				"SEARCH" => Lines("help.search"), 
				"HISTORY" => Lines("help.history"), 
				"PIPELINES" => Lines("help.pipelines"), 
				"MARKERS" => Lines("help.markers"), 
				"CONSUMABLES" => Lines("help.consumables"), 
				"APPEARANCE" => Lines("help.appearance"), 
				"CONFIG" => Lines("help.config"), 
				"STFO" => Lines("help.stfo"), 
				"DOCS" => Lines("help.docs"), 
				_ => Lines("help.betterterminal"), 
			};
		}

		private static IEnumerable<string> Lines(string key)
		{
			return LocalizationService.Text(key).Split('\n');
		}

		private static IEnumerable<string> Status()
		{
			bool stfoInstalled = AppDomain.CurrentDomain.GetAssemblies().Any((Assembly assembly) => assembly.GetName().Name?.Equals("STFO", StringComparison.OrdinalIgnoreCase) ?? false);
			yield return "BETTERTERMINAL 1.1.3";
			yield return "LANGUAGE: " + Plugin.Language.Value.ToUpperInvariant();
			yield return $"FUZZY SEARCH: {Plugin.EnableFuzzySearch.Value}";
			yield return $"PIPELINES: {Plugin.EnablePipelines.Value}";
			yield return $"HISTORY: {Plugin.EnableHistorySearch.Value}";
			yield return $"REGISTERED CONSUMABLES: {ConsumableTerminalRegistry.RegisteredCount}";
			yield return $"ACTIVE MAP MARKERS: {ConsumableTerminalRegistry.ActiveMapMarkerCount}";
			yield return "STFO: " + (stfoInstalled ? "INSTALLED" : "NOT INSTALLED");
			yield return "CONFIG: " + Plugin.Settings.ConfigFilePath;
			yield return "LOCALIZATION: " + LocalizationService.DirectoryPath;
			yield return "DOCS: https://alexandermakunin.github.io/BetterTerminal/";
		}

		private static void Write(LG_ComputerTerminalCommandInterpreter interpreter, string input, IEnumerable<string> lines)
		{
			TerminalCommandOutput.WriteImmediate(interpreter, input.Trim().ToUpperInvariant(), lines);
		}
	}
	internal sealed class HistorySearchSession
	{
		internal string Query { get; set; } = string.Empty;

		internal int SelectedIndex { get; set; }

		internal List<string> Matches { get; } = new List<string>();

		internal List<string> RenderedLines { get; } = new List<string>();
	}
	internal static class HistorySearchManager
	{
		private static readonly Dictionary<uint, HistorySearchSession> Sessions = new Dictionary<uint, HistorySearchSession>();

		internal static bool IsActive(uint terminalId)
		{
			return Sessions.ContainsKey(terminalId);
		}

		internal static bool TryOpen(LG_ComputerTerminal terminal)
		{
			if (!string.IsNullOrEmpty(terminal.m_currentLine) || HistoryStore.GetRecent().Count == 0)
			{
				return false;
			}
			Sessions[terminal.SyncID] = new HistorySearchSession();
			terminal.m_command.ShowInputLine = false;
			terminal.m_command.ShowCustomLine = true;
			terminal.m_command.CustomLineBlinkEnabled = true;
			Refresh(terminal);
			return true;
		}

		internal static bool HandleUpdate(LG_ComputerTerminal terminal)
		{
			if (!Sessions.TryGetValue(terminal.SyncID, out HistorySearchSession value))
			{
				return false;
			}
			if (InputMapper.GetButtonDown.Invoke((InputAction)20, (eFocusState)8))
			{
				Close(terminal, null);
				return true;
			}
			bool flag = InputMapper.GetButtonDown.Invoke((InputAction)15, (eFocusState)8);
			bool flag2 = InputMapper.GetButtonDown.Invoke((InputAction)16, (eFocusState)8);
			if (flag || flag2)
			{
				if (value.Matches.Count > 0)
				{
					value.SelectedIndex = (value.SelectedIndex + ((!flag) ? 1 : (-1)) + value.Matches.Count) % value.Matches.Count;
					Render(terminal, value);
				}
				return true;
			}
			string inputString = Input.inputString;
			if (string.IsNullOrEmpty(inputString))
			{
				return false;
			}
			string text = inputString;
			foreach (char c in text)
			{
				bool flag3;
				switch (c)
				{
				case '\b':
					if (value.Query.Length > 0)
					{
						HistorySearchSession historySearchSession = value;
						string query = value.Query;
						historySearchSession.Query = query.Substring(0, query.Length - 1);
					}
					continue;
				case '\n':
				case '\r':
					flag3 = true;
					break;
				default:
					flag3 = false;
					break;
				}
				if (flag3)
				{
					string selected = ((value.Matches.Count == 0) ? null : value.Matches[value.SelectedIndex]);
					Close(terminal, selected);
					return true;
				}
				if (!char.IsControl(c))
				{
					value.Query += char.ToUpperInvariant(c);
				}
			}
			Refresh(terminal);
			return true;
		}

		private static void Refresh(LG_ComputerTerminal terminal)
		{
			HistorySearchSession session = Sessions[terminal.SyncID];
			session.Matches.Clear();
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			string[] source = session.Query.Split(' ', StringSplitOptions.RemoveEmptyEntries);
			IReadOnlyList<string> recent = HistoryStore.GetRecent();
			for (int num = recent.Count - 1; num >= 0; num--)
			{
				string command = recent[num];
				if (command.Length != 0 && hashSet.Add(command) && !source.Any((string term) => !command.Contains(term, StringComparison.OrdinalIgnoreCase)))
				{
					session.Matches.Add(command);
				}
			}
			session.Matches.Sort(delegate(string left, string right)
			{
				bool flag = left.StartsWith(session.Query, StringComparison.OrdinalIgnoreCase);
				bool flag2 = right.StartsWith(session.Query, StringComparison.OrdinalIgnoreCase);
				return (flag != flag2) ? ((!flag) ? 1 : (-1)) : 0;
			});
			session.SelectedIndex = Math.Clamp(session.SelectedIndex, 0, Math.Max(0, session.Matches.Count - 1));
			Render(terminal, session);
		}

		private static void Render(LG_ComputerTerminal terminal, HistorySearchSession session)
		{
			RemoveRenderedLines(terminal.m_command, session);
			session.RenderedLines.Add(LocalizationService.Text("history.title"));
			int num = Math.Max(1, Plugin.MaximumVisibleHistoryResults.Value);
			int num2 = Math.Max(0, session.SelectedIndex - num + 1);
			int num3 = Math.Min(session.Matches.Count, num2 + num);
			for (int i = num2; i < num3; i++)
			{
				string text = ((i == session.SelectedIndex) ? "->" : "  ");
				session.RenderedLines.Add(text + " " + session.Matches[i]);
			}
			if (session.Matches.Count == 0)
			{
				session.RenderedLines.Add(LocalizationService.Text("history.no_matches"));
			}
			foreach (string renderedLine in session.RenderedLines)
			{
				terminal.m_command.m_screenBuffer.Add(renderedLine);
			}
			terminal.m_command.CustomLineText = "HISTORY> " + session.Query;
			terminal.m_command.ResetLinesSinceCommand();
		}

		private static void Close(LG_ComputerTerminal terminal, string? selected)
		{
			if (Sessions.Remove(terminal.SyncID, out HistorySearchSession value))
			{
				RemoveRenderedLines(terminal.m_command, value);
				terminal.m_command.ShowCustomLine = false;
				terminal.m_command.CustomLineBlinkEnabled = false;
				terminal.m_command.CustomLineText = string.Empty;
				terminal.m_command.ShowInputLine = true;
				terminal.m_currentLine = selected ?? string.Empty;
				terminal.m_command.m_inputBufferStep = 0;
			}
		}

		private static void RemoveRenderedLines(LG_ComputerTerminalCommandInterpreter interpreter, HistorySearchSession session)
		{
			int num = interpreter.m_screenBuffer.Count - session.RenderedLines.Count;
			bool flag = num >= 0;
			int num2 = 0;
			while (flag && num2 < session.RenderedLines.Count)
			{
				flag = string.Equals(interpreter.m_screenBuffer[num + num2], session.RenderedLines[num2], StringComparison.Ordinal);
				num2++;
			}
			if (flag && session.RenderedLines.Count > 0)
			{
				interpreter.m_screenBuffer.RemoveRange(num, session.RenderedLines.Count);
			}
			else if (session.RenderedLines.Count > 0)
			{
				Plugin.ModLog.LogWarning((object)"[HISTORY] SCREEN BUFFER CHANGED; TEMPORARY HISTORY BLOCK WAS NOT REMOVED.");
			}
			session.RenderedLines.Clear();
		}
	}
	[HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")]
	internal static class HistoryRecorderPatch
	{
		private static void Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString)
		{
			if (Plugin.EnableHistorySearch.Value && !HistoryStore.RecordingSuppressed && __instance.m_terminal != null && !TerminalInputReservationRegistry.IsReserved(__instance.m_terminal.SyncID))
			{
				string[] array = inputString.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries);
				if (array.Length != 2 || !Enum.TryParse<CommandType>(array[0], ignoreCase: true, out var result) || result != CommandType.History || !Enum.TryParse<HistoryAction>(array[1], ignoreCase: true, out var result2) || result2 != HistoryAction.Clear)
				{
					HistoryStore.Record(inputString);
				}
			}
		}
	}
	internal static class HistoryStore
	{
		private static readonly List<string> Entries = new List<string>();

		private static string FilePath => Path.Combine(Paths.ConfigPath, "BetterTerminal", "history.txt");

		internal static bool RecordingSuppressed { get; set; }

		internal static void Initialize()
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Expected O, but got Unknown
			Entries.Clear();
			if (Plugin.HistoryPersistence.Value == HistoryPersistenceMode.Session)
			{
				return;
			}
			try
			{
				Directory.CreateDirectory(Path.GetDirectoryName(FilePath));
				if (File.Exists(FilePath))
				{
					Entries.AddRange((from command in File.ReadLines(FilePath)
						select command.Trim().ToUpperInvariant() into command
						where command.Length > 0
						select command).TakeLast(Plugin.MaximumHistoryEntries.Value));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource modLog = Plugin.ModLog;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(34, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[HISTORY] COULD NOT LOAD HISTORY: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				modLog.LogWarning(val);
			}
		}

		internal static IReadOnlyList<string> GetRecent()
		{
			return Entries;
		}

		internal static void Record(string command)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			string text = command.Trim().ToUpperInvariant();
			if (text.Length == 0)
			{
				return;
			}
			Entries.Add(text);
			int num = Entries.Count - Plugin.MaximumHistoryEntries.Value;
			if (num > 0)
			{
				Entries.RemoveRange(0, num);
			}
			if (Plugin.HistoryPersistence.Value != HistoryPersistenceMode.Disk)
			{
				return;
			}
			try
			{
				File.WriteAllLines(FilePath, Entries);
			}
			catch (Exception ex)
			{
				ManualLogSource modLog = Plugin.ModLog;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(34, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[HISTORY] COULD NOT SAVE HISTORY: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				modLog.LogWarning(val);
			}
		}

		internal static void Clear()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			Entries.Clear();
			try
			{
				if (File.Exists(FilePath))
				{
					File.Delete(FilePath);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource modLog = Plugin.ModLog;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(36, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[HISTORY] COULD NOT DELETE HISTORY: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				modLog.LogWarning(val);
			}
		}

		internal static void ReloadForPersistenceChange()
		{
			Initialize();
		}
	}
	[HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")]
	internal static class HistoryCommandPatch
	{
		private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString)
		{
			string[] array = inputString.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries);
			if (array.Length == 0 || !Enum.TryParse<CommandType>(array[0], ignoreCase: true, out var result) || result != CommandType.History)
			{
				return true;
			}
			string text;
			if (array.Length == 2 && Enum.TryParse<HistoryAction>(array[1], ignoreCase: true, out var result2) && result2 == HistoryAction.Clear)
			{
				HistoryStore.Clear();
				text = LocalizationService.Text("history.cleared");
			}
			else
			{
				text = LocalizationService.Text("history.usage");
			}
			TerminalCommandOutput.WriteImmediate(__instance, inputString.Trim(), new string[1] { text });
			return false;
		}
	}
	[HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")]
	internal static class LimitedListPatch
	{
		private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Expected O, but got Unknown
			string text = inputString.Trim().ToUpperInvariant();
			string[] array = text.Split(' ', StringSplitOptions.RemoveEmptyEntries);
			CommandType result = default(CommandType);
			bool flag = array.Length != 3 || !Enum.TryParse<CommandType>(array[0], ignoreCase: true, out result);
			if (!flag)
			{
				bool flag2 = (uint)(result - 2) <= 1u;
				flag = !flag2;
			}
			if (flag)
			{
				return true;
			}
			if (!int.TryParse(array[2], out var result2) || result2 <= 0)
			{
				return true;
			}
			List<TerminalItemMatch> list = TerminalItemSearch.Find(array[1]);
			int num = Math.Min(result2, list.Count);
			BepInExDebugLogInterpolatedStringHandler val;
			if (result == CommandType.Query)
			{
				ManualLogSource modLog = Plugin.ModLog;
				val = new BepInExDebugLogInterpolatedStringHandler(40, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[QUERY LIMIT] TYPE=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(array[1]);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" REQUESTED=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(result2);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" RETURNED=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
				}
				modLog.LogDebug(val);
				if (num == 0)
				{
					WriteNoResults(__instance, text, array[1]);
					return false;
				}
				for (int i = 0; i < num; i++)
				{
					TerminalCommandOutput.EvaluateNativeWithoutHistory(__instance, CommandType.Query.Token() + " " + list[i].Identifier);
				}
				__instance.m_inputBuffer.Add(text);
				__instance.m_inputBufferStep = 0;
				return false;
			}
			__instance.m_inputBuffer.Add(text);
			__instance.m_inputBufferStep = 0;
			__instance.m_screenBuffer.Add(text);
			__instance.m_screenBuffer.Add(LocalizationService.Text("items.first_ids", num, array[1]));
			for (int j = 0; j < num; j++)
			{
				__instance.m_screenBuffer.Add(list[j].Identifier);
			}
			if (num == 0)
			{
				__instance.m_screenBuffer.Add(LocalizationService.Text("items.none", array[1]));
			}
			if (__instance.m_terminal != null)
			{
				__instance.m_terminal.m_currentLine = string.Empty;
			}
			__instance.ResetLinesSinceCommand();
			ManualLogSource modLog2 = Plugin.ModLog;
			val = new BepInExDebugLogInterpolatedStringHandler(39, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[LIST LIMIT] TYPE=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(array[1]);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" REQUESTED=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(result2);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" RETURNED=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
			}
			modLog2.LogDebug(val);
			return false;
		}

		private static void WriteNoResults(LG_ComputerTerminalCommandInterpreter interpreter, string commandLine, string itemType)
		{
			interpreter.m_inputBuffer.Add(commandLine);
			interpreter.m_inputBufferStep = 0;
			interpreter.m_screenBuffer.Add(commandLine);
			interpreter.m_screenBuffer.Add(LocalizationService.Text("items.none", itemType));
			if (interpreter.m_terminal != null)
			{
				interpreter.m_terminal.m_currentLine = string.Empty;
			}
			interpreter.ResetLinesSinceCommand();
		}
	}
	internal sealed record ModCommand(string Name, string DescriptionKey);
	internal static class ModCommands
	{
		private static readonly List<ModCommand> All = new List<ModCommand>
		{
			new ModCommand(CommandType.Config.Token(), "commands.config"),
			new ModCommand(CommandType.History.Token(), "commands.history_command"),
			new ModCommand(CommandType.Neofetch.Token(), "commands.neofetch"),
			new ModCommand(CommandType.IdleScreen.Token(), "commands.idlescreen"),
			new ModCommand(CommandType.Mark.Token(), "commands.mark"),
			new ModCommand(CommandType.Unmark.Token(), "commands.unmark"),
			new ModCommand(CommandType.BetterTerminal.Token(), "commands.betterterminal"),
			new ModCommand(CommandType.Docs.Token(), "commands.docs")
		};

		internal static IEnumerable<string> Names => All.Select((ModCommand command) => command.Name);

		internal static void Register(string name, string description)
		{
			if (!All.Any((ModCommand command) => command.Name.Equals(name, StringComparison.OrdinalIgnoreCase)))
			{
				All.Add(new ModCommand(name.ToUpperInvariant(), description.ToUpperInvariant()));
			}
		}

		internal static string BuildCommandsSection()
		{
			List<string> list = new List<string>
			{
				string.Empty,
				"---------------- BETTERTERMINAL ----------------"
			};
			foreach (ModCommand item in All)
			{
				list.Add($"{item.Name,-16} {LocalizationService.Text(item.DescriptionKey)}");
			}
			list.Add(CommandType.Query.Token() + " TYPE_MIN-MAX  " + LocalizationService.Text("commands.query_range"));
			list.Add(CommandType.Query.Token() + " TYPE COUNT    " + LocalizationService.Text("commands.query_count"));
			list.Add(CommandType.List.Token() + " TYPE_MIN-MAX   " + LocalizationService.Text("commands.list_range"));
			list.Add(CommandType.List.Token() + " TYPE COUNT     " + LocalizationService.Text("commands.list_count"));
			list.Add($"{CommandType.List.Token()} | {CommandType.Where.Token()} FIELD VALUE | {CommandType.Sort.Token()} FIELD | {CommandType.Take.Token()} N");
			list.Add(LocalizationService.Text("commands.pipeline_outputs"));
			list.Add("UP ON EMPTY LINE    " + LocalizationService.Text("commands.history"));
			list.Add(LocalizationService.Text("commands.config_hint"));
			list.Add("------------------------------------------------");
			return string.Join("\n", list);
		}
	}
	internal enum PipelineStage
	{
		Where,
		Sort,
		Take,
		Count,
		Query,
		Ping,
		Mark,
		Unmark
	}
	internal enum PipelineField
	{
		Text,
		Id,
		Type,
		Zone,
		Area,
		Status
	}
	internal sealed record PipelineItem(string Id, string Type, string Zone, string Area, string Status, iTerminalItem Item);
	internal enum PipelineDataType
	{
		Items,
		Text
	}
	[HarmonyPatch(typeof(LG_ComputerTerminalCommandInterpreter), "EvaluateInput")]
	[HarmonyPriority(800)]
	internal static class PipelineCommandPatch
	{
		private static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, string inputString)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			if (!Plugin.EnablePipelines.Value || !inputString.Contains('|'))
			{
				return true;
			}
			if (!CanHandle(inputString))
			{
				return true;
			}
			int count = __instance.m_screenBuffer.Count;
			try
			{
				return Execute(__instance, inputString);
			}
			catch (Exception ex)
			{
				int num = __instance.m_screenBuffer.Count - count;
				if (num > 0)
				{
					__instance.m_screenBuffer.RemoveRange(count, num);
				}
				ManualLogSource modLog = Plugin.ModLog;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(59, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[PIPELINE] FAILED BEFORE COMPLETION; FALLING BACK TO GTFO: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				modLog.LogError(val);
				return true;
			}
		}

		private static bool Execute(LG_ComputerTerminalCommandInterpreter __instance, string inputString)
		{
			string text = inputString.Trim().ToUpperInvariant();
			string[] array = text.Split('|', StringSplitOptions.TrimEntries);
			if (array.Length < 2)
			{
				WriteError(__instance, text, LocalizationService.Text("pipeline.must_start_list"));
				return false;
			}
			if (!TryCreateSource(__instance, array[0], out PipelineDataType dataType, out List<PipelineItem> items, out List<string> textLines, out string error))
			{
				WriteError(__instance, text, error);
				return false;
			}
			bool flag = false;
			List<string> list = new List<string>();
			for (int i = 1; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(' ', StringSplitOptions.RemoveEmptyEntries);
				if (array2.Length == 0)
				{
					continue;
				}
				if (!Enum.TryParse<PipelineStage>(array2[0], ignoreCase: true, out var result))
				{
					if (PipelineExtensionRegistry.TryExecute(array2[0], array2, items, out PipelineExtensionResult result2))
					{
						list.AddRange(result2.OutputLines);
						if (!result2.Succeeded)
						{
							TerminalCommandOutput.WriteImmediate(__instance, text, list);
							return false;
						}
						items = result2.Items;
						continue;
					}
					WriteError(__instance, text, LocalizationService.Text("pipeline.unknown_stage", array2[0]));
					return false;
				}
				switch (result)
				{
				case PipelineStage.Where:
					if (dataType == PipelineDataType.Text)
					{
						if (!TryApplyTextWhere(textLines, array[i], out textLines, out error))
						{
							WriteError(__instance, text, error);
							return false;
						}
					}
					else if (!TryApplyWhere(items, array[i], out items, out error))
					{
						WriteError(__instance, text, error);
						return false;
					}
					break;
				case PipelineStage.Sort:
					if (dataType == PipelineDataType.Text)
					{
						textLines = ((array2.Length == 2 && array2[1].Equals("DESC", StringComparison.OrdinalIgnoreCase)) ? textLines.OrderByDescending<string, string>((string line) => line, StringComparer.OrdinalIgnoreCase).ToList() : textLines.OrderBy<string, string>((string line) => line, StringComparer.OrdinalIgnoreCase).ToList());
					}
					else if (!TryApplySort(items, array2, out items, out error))
					{
						WriteError(__instance, text, error);
						return false;
					}
					break;
				case PipelineStage.Take:
				{
					if (array2.Length != 2 || !int.TryParse(array2[1], out var result3) || result3 < 0)
					{
						WriteError(__instance, text, "USE: TAKE N");
						return false;
					}
					if (dataType == PipelineDataType.Text)
					{
						textLines = textLines.Take(result3).ToList();
					}
					else
					{
						items = items.Take(result3).ToList();
					}
					break;
				}
				case PipelineStage.Count:
					if (i != array.Length - 1)
					{
						WriteError(__instance, text, LocalizationService.Text("pipeline.count_last"));
						return false;
					}
					TerminalCommandOutput.WriteImmediate(__instance, text, new string[1] { $"COUNT: {((dataType == PipelineDataType.Text) ? textLines.Count : items.Count)}" });
					return false;
				case PipelineStage.Query:
					if (dataType != PipelineDataType.Items)
					{
						WriteError(__instance, text, "QUERY REQUIRES AN ITEM STREAM.");
						return false;
					}
					if (i != array.Length - 1)
					{
						WriteError(__instance, text, LocalizationService.Text("pipeline.query_last"));
						return false;
					}
					flag = true;
					break;
				case PipelineStage.Ping:
				{
					if (dataType != PipelineDataType.Items)
					{
						WriteError(__instance, text, "PING REQUIRES AN ITEM STREAM.");
						return false;
					}
					if (i != array.Length - 1 || items.Count != 1)
					{
						WriteError(__instance, text, LocalizationService.Text("pipeline.ping_single"));
						return false;
					}
					if (!ConsumableTerminalRegistry.TryPlayPing(items[0].Id, out string message))
					{
						items[0].Item.PlayPing();
						message = LocalizationService.Text("pipeline.ping_started", items[0].Id);
					}
					TerminalCommandOutput.WriteImmediate(__instance, text, new string[1] { message });
					return false;
				}
				case PipelineStage.Mark:
				{
					if (dataType != PipelineDataType.Items)
					{
						WriteError(__instance, text, "MARK REQUIRES AN ITEM STREAM.");
						return false;
					}
					if (i != array.Length - 1)
					{
						WriteError(__instance, text, LocalizationService.Text("pipeline.mark_last"));
						return false;
					}
					List<string> list2 = new List<string>();
					foreach (PipelineItem item in items)
					{
						if (ConsumableTerminalRegistry.TrySetMapMarker(item.Id, item.Item, out string message2, replaceExisting: false))
						{
							list2.Add(item.Id);
						}
						else
						{
							list.Add(message2);
						}
					}
					list.Add(LocalizationService.Text("pipeline.marked", list2.Count));
					if (list2.Count > 1)
					{
						object[] array3 = new object[1];
						array3[0] = list2[list2.Count - 1];
						list.Add(LocalizationService.Text("pipeline.last_ping", array3));
					}
					TerminalCommandOutput.WriteImmediate(__instance, text, list);
					return false;
				}
				case PipelineStage.Unmark:
					if (dataType != PipelineDataType.Items)
					{
						WriteError(__instance, text, "UNMARK REQUIRES AN ITEM STREAM.");
						return false;
					}
					if (i != array.Length - 1)
					{
						WriteError(__instance, text, LocalizationService.Text("pipeline.unmark_last"));
						return false;
					}
					foreach (PipelineItem item2 in items)
					{
						list.Add(ConsumableTerminalRegistry.ClearMapMarker(item2.Id));
					}
					TerminalCommandOutput.WriteImmediate(__instance, text, list);
					return false;
				}
			}
			object obj;
			if (dataType != PipelineDataType.Text)
			{
				obj = (flag ? BuildQueryLines(__instance, items) : BuildListLines(items));
			}
			else
			{
				IEnumerable<string> enumerable = textLines;
				obj = enumerable;
			}
			IEnumerable<string> second = (IEnumerable<string>)obj;
			TerminalCommandOutput.WriteImmediate(__instance, text, list.Concat(second));
			return false;
		}

		private static bool CanHandle(string inputString)
		{
			string[] array = inputString.Split('|', StringSplitOptions.TrimEntries);
			if (array.Length < 2 || array.Any(string.IsNullOrWhiteSpace))
			{
				return false;
			}
			string[] array2 = array[0].Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
			if (array2.Length == 0 || !Enum.TryParse<CommandType>(array2[0], ignoreCase: true, out var result) || result == CommandType.Unknown)
			{
				return false;
			}
			for (int i = 1; i < array.Length; i++)
			{
				string text = array[i].Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)[0];
				if (!Enum.TryParse<PipelineStage>(text, ignoreCase: true, out var _) && !PipelineExtensionRegistry.IsRegistered(text))
				{
					return false;
				}
			}
			return true;
		}

		private static bool TryCreateSource(LG_ComputerTerminalCommandInterpreter interpreter, string source, out PipelineDataType dataType, out List<PipelineItem> items, out List<string> textLines, out string error)
		{
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			dataType = PipelineDataType.Items;
			items = new List<PipelineItem>();
			textLines = new List<string>();
			error = string.Empty;
			string[] array = source.Split(' ', StringSplitOptions.RemoveEmptyEntries);
			if (array.Length == 0 || !Enum.TryParse<CommandType>(array[0], ignoreCase: true, out var result))
			{
				error = LocalizationService.Text("pipeline.unknown_stage", array.FirstOrDefault() ?? string.Empty);
				return false;
			}
			if ((uint)(result - 7) <= 1u)
			{
				if (array.Length != 1)
				{
					error = "USE: " + result.ToString().ToUpperInvariant();
					return false;
				}
				dataType = PipelineDataType.Text;
				textLines = CommandsListPatch.BuildLines(interpreter, result).ToList();
				return true;
			}
			if (result != CommandType.List)
			{
				int count = interpreter.m_screenBuffer.Count;
				TerminalCommandOutput.EvaluateNativeWithoutHistory(interpreter, source);
				int num = interpreter.m_screenBuffer.Count - count;
				if (num > 0)
				{
					for (int i = count; i < interpreter.m_screenBuffer.Count; i++)
					{
						textLines.Add(interpreter.m_screenBuffer[i]);
					}
					interpreter.m_screenBuffer.RemoveRange(count, num);
				}
				dataType = PipelineDataType.Text;
				return true;
			}
			TerminalItemCategory terminalItemCategory = TerminalItemCategory.All;
			List<string> list = new List<string>();
			foreach (string item in array.Skip(1))
			{
				if (TryParseCategory(item, out var category))
				{
					terminalItemCategory = category;
				}
				else
				{
					list.Add(item);
				}
			}
			ConsumableTerminalRegistry.RefreshAll();
			LG_LevelInteractionManager current2 = LG_LevelInteractionManager.Current;
			Dictionary<string, iTerminalItem> val = ((current2 != null) ? current2.m_terminalItemsByKeyString : null);
			if (val == null)
			{
				error = LocalizationService.Text("pipeline.registry_unavailable");
				return false;
			}
			Enumerator<string, iTerminalItem> enumerator2 = val.Keys.GetEnumerator();
			while (enumerator2.MoveNext())
			{
				string current3 = enumerator2.Current;
				string normalizedId = current3.ToUpperInvariant();
				bool flag = ConsumableTerminalRegistry.IsConsumableIdentifier(normalizedId);
				if ((terminalItemCategory != TerminalItemCategory.Consumable || flag) && !(terminalItemCategory == TerminalItemCategory.Native && flag) && !list.Any((string filter) => !normalizedId.Contains(filter, StringComparison.OrdinalIgnoreCase)))
				{
					iTerminalItem val2 = val[current3];
					AIG_CourseNode spawnNode = val2.SpawnNode;
					string zone = ((spawnNode == null) ? "UNKNOWN" : spawnNode.m_zone.Alias.ToString());
					object area;
					if (spawnNode == null)
					{
						area = null;
					}
					else
					{
						LG_Area area2 = spawnNode.m_area;
						area = ((area2 != null) ? area2.m_geoArea : null);
					}
					string area3 = NormalizeArea((string?)area);
					items.Add(new PipelineItem(normalizedId, GetTypeFromId(normalizedId), zone, area3, ((object)val2.FloorItemStatus/*cast due to .constrained prefix*/).ToString().ToUpperInvariant(), val2));
				}
			}
			items.Sort((PipelineItem left, PipelineItem right) => StringComparer.Ordinal.Compare(left.Id, right.Id));
			return true;
		}

		private static bool TryApplyTextWhere(List<string> source, string stage, out List<string> result, out string error)
		{
			result = source;
			error = string.Empty;
			string text = stage.Substring(5).Trim();
			string text2 = PipelineField.Text.ToString();
			if (!text.StartsWith(text2, StringComparison.OrdinalIgnoreCase))
			{
				error = "USE: WHERE TEXT VALUE, WHERE TEXT_VALUE OR WHERE TEXT-VALUE";
				return false;
			}
			string text3 = text.Substring(text2.Length);
			bool flag = text3.Length < 2;
			if (!flag)
			{
				char c = text3[0];
				bool flag2 = ((c == ' ' || c == '-' || c == '_') ? true : false);
				flag = !flag2;
			}
			if (flag)
			{
				error = "USE: WHERE TEXT VALUE, WHERE TEXT_VALUE OR WHERE TEXT-VALUE";
				return false;
			}
			string value = text3.Substring(1).Trim().Trim('"');
			if (value.Length == 0)
			{
				error = "WHERE TEXT REQUIRES A VALUE.";
				return false;
			}
			result = source.Where((string line) => line.Contains(value, StringComparison.OrdinalIgnoreCase)).ToList();
			return true;
		}

		private static bool TryApplyWhere(List<PipelineItem> source, string stage, out List<PipelineItem> result, out string error)
		{
			result = source;
			error = string.Empty;
			if (!TryParseWhereExpression(stage.Substring(5).Trim(), out PipelineField field, out string value))
			{
				error = "USE: WHERE FIELD VALUE, WHERE FIELD_VALUE OR WHERE FIELD-VALUE";
				return false;
			}
			result = source.Where((PipelineItem item) => GetField(item, field).Contains(value, StringComparison.OrdinalIgnoreCase)).ToList();
			return true;
		}

		private static bool TryApplySort(List<PipelineItem> source, string[] arguments, out List<PipelineItem> result, out string error)
		{
			result = source;
			error = string.Empty;
			int num = arguments.Length;
			bool flag = ((num < 2 || num > 3) ? true : false);
			if (flag || !Enum.TryParse<PipelineField>(arguments[1], ignoreCase: true, out var field))
			{
				error = "USE: SORT ID|TYPE|ZONE|AREA|STATUS [DESC]";
				return false;
			}
			bool flag2 = arguments.Length == 3 && arguments[2] == "DESC";
			if (arguments.Length == 3 && !flag2)
			{
				error = "SORT DIRECTION MUST BE DESC.";
				return false;
			}
			if (field == PipelineField.Zone)
			{
				result = (flag2 ? source.OrderByDescending((PipelineItem item) => ParseZone(item.Zone)).ToList() : source.OrderBy((PipelineItem item) => ParseZone(item.Zone)).ToList());
			}
			else
			{
				result = (flag2 ? source.OrderByDescending<PipelineItem, string>((PipelineItem item) => GetField(item, field), StringComparer.OrdinalIgnoreCase).ToList() : source.OrderBy<PipelineItem, string>((PipelineItem item) => GetField(item, field), StringComparer.OrdinalIgnoreCase).ToList());
			}
			return true;
		}

		private static IEnumerable<string> BuildListLines(List<PipelineItem> items)
		{
			yield return $"{"ID",-30} {"TYPE",-24} {"ZONE",-8} {"AREA",-6} STATUS";
			foreach (PipelineItem item in items)
			{
				yield return $"{item.Id,-30} {item.Type,-24} {item.Zone,-8} {item.Area,-6} {item.Status}";
			}
			yield return $"COUNT: {items.Count}";
		}

		private static bool TryParseWhereExpression(string expression, out PipelineField field, out string value)
		{
			field = PipelineField.Text;
			value = string.Empty;
			PipelineField[] values = Enum.GetValues<PipelineField>();
			for (int i = 0; i < values.Length; i++)
			{
				PipelineField pipelineField = values[i];
				string text = pipelineField.ToString().ToUpperInvariant();
				if (expression.StartsWith(text, StringComparison.Ordinal))
				{
					string text2 = expression.Substring(text.Length);
					bool flag = text2.Length == 0;
					if (!flag)
					{
						char c = text2[0];
						bool flag2 = ((c == ' ' || c == '-' || c == '_') ? true : false);
						flag = !flag2;
					}
					if (!flag)
					{
						field = pipelineField;
						value = text2.Substring(1).Trim().Trim('"')
							.Replace(' ', '_');
						return value.Length > 0;
					}
				}
			}
			return false;
		}

		private static int ParseZone(string zone)
		{
			if (!int.TryParse(zone, out var result))
			{
				return int.MaxValue;
			}
			return result;
		}

		private static string NormalizeArea(string? area)
		{
			if (string.IsNullOrWhiteSpace(area))
			{
				return "UNKNOWN";
			}
			string text = area.Trim().ToUpperInvariant();
			if (text.StartsWith("AREA ", StringComparison.Ordinal))
			{
				text = text.Substring(5);
			}
			return text.Replace(' ', '_');
		}

		private static IEnumerable<string> BuildQueryLines(LG_ComputerTerminalCommandInterpreter interpreter, List<PipelineItem> items)
		{
			foreach (PipelineItem item in items)
			{
				if (ConsumableTerminalRegistry.TryGetQueryLines(item.Id, out IReadOnlyList<string> lines))
				{
					foreach (string item2 in lines)
					{
						yield return item2;
					}
					yield return string.Empty;
					continue;
				}
				foreach (string item3 in CaptureNativeQuery(interpreter, item))
				{
					yield return item3;
				}
				yield return string.Empty;
			}
		}

		private static IEnumerable<string> CaptureNativeQuery(LG_ComputerTerminalCommandInterpreter interpreter, PipelineItem item)
		{
			int count = interpreter.m_screenBuffer.Count;
			TerminalCommandOutput.EvaluateNativeWithoutHistory(interpreter, CommandType.Query.Token() + " " + item.Id);
			int num = interpreter.m_screenBuffer.Count - count;
			if (num > 0)
			{
				string[] array = new string[num];
				for (int i = 0; i < num; i++)
				{
					array[i] = interpreter.m_screenBuffer[count + i];
				}
				interpreter.m_screenBuffer.RemoveRange(count, num);
				string[] array2 = array;
				for (int j = 0; j < array2.Length; j++)
				{
					yield return array2[j];
				}
			}
			else
			{
				yield return "ID: " + item.Id;
				yield return "TYPE: " + item.Type;
				yield return "LOCATION: ZONE_" + item.Zone + " AREA_" + item.Area;
				yield return "STATUS: " + item.Status;
			}
		}

		private static bool TryParseCategory(string token, out TerminalItemCategory category)
		{
			if (Enum.TryParse<TerminalItemCategory>(token.Trim().TrimEnd('S'), ignoreCase: true, out category) && category != TerminalItemCategory.All)
			{
				return true;
			}
			category = TerminalItemCategory.All;
			return false;
		}

		private static string GetTypeFromId(string id)
		{
			int num = id.LastIndexOf('_');
			if (num <= 0 || !int.TryParse(id.Substring(num + 1), out var _))
			{
				return id;
			}
			return id.Substring(0, num);
		}

		private static string GetField(PipelineItem item, PipelineField field)
		{
			return field s