Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/BizHawk.Client.Common/lua/LuaDocumentation.cs
2 views
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Newtonsoft.Json;

namespace BizHawk.Client.Common
{
	public class LuaDocumentation : List<LibraryFunction>
	{
		public LuaDocumentation()
			:base() { }

		public string ToTASVideosWikiMarkup()
		{
			var sb = new StringBuilder();
			
			sb
				.AppendLine("[module:ListParents]")
				.AppendLine()
				.AppendLine("This page documents the the behavior and parameters of Lua functions available for the [BizHawk] emulator.")
				.AppendLine("__This is an autogenerated page, do not edit__")
				.AppendLine()
				.AppendLine();

			sb.AppendLine(@"All type names represent the standard .NET types of the same name. Except for func which represents a lua function and table which represents a lua table. For more information on .NET types can be found in MSDN documentation.

__Types and notation__
* ? (question mark)
** A question mark next to a value indicates that it is a Nullable type (only applies to types that are not normally nullable)
* [[]] (brackets)
** Brackets around a parameter indicate that the parameter is optional. optional parameters have an equals sign followed by the value that will be used if no value is supplied.
** Brackets after a parameter type indicate it is an array
* null
** null is equivalent to the lua nil
* Color
** This is a .NET System.Drawing.Color struct. The value passed from lua is any value acceptable in the Color constructor. This means either a string with the color name such as ""red"", or a 0xAARRGGBB integer value.  Unless specified, this is not a nullable value
* object
** A System.Object, literally anything qualifies for this parameter. However, the context of particular function may suggest a narrower range of useful values.
* luaf
** A Lua function. Note that these are always parameters, and never return values of a call
* table
** A standard Lua table
");

			foreach (var library in this.Select(x => new { Name = x.Library, Description = x.LibraryDescription }).Distinct())
			{
				sb
					.AppendFormat("%%TAB {0}%%", library.Name)
					.AppendLine()
					.AppendLine();
				if (!string.IsNullOrWhiteSpace(library.Description))
				{
					sb
						.Append(library.Description)
						.AppendLine()
						.AppendLine();
				}

				foreach (var func in this.Where(x => x.Library == library.Name))
				{
					sb
						.AppendFormat("__{0}.{1}__%%%", func.Library, func.Name)
						.AppendLine().AppendLine()
						.AppendFormat("* {0} {1}.{2}{3}", func.ReturnType, func.Library, func.Name, func.ParameterList)
						.AppendLine().AppendLine()
						.AppendFormat("* {0}", func.Description)
						.AppendLine().AppendLine();
				}
			}

			sb.Append("%%TAB_END%%");

			return sb.ToString();
		}

		private class SublimeCompletions
		{
			public SublimeCompletions()
			{
				Scope = "source.lua - string";
			}

			[JsonProperty(PropertyName = "scope")]
			public string Scope { get; set; }

			[JsonProperty(PropertyName = "completions")]
			public List<Completion> Completions = new List<Completion>();

			public class Completion
			{
				[JsonProperty(PropertyName = "trigger")]
				public string Trigger { get; set; }

				[JsonProperty(PropertyName = "contents")]
				public string Contents { get; set; }
			}
		}

		public string ToSublime2CompletionList()
		{
			var sc = new SublimeCompletions();

			foreach (var f in this.OrderBy(lf => lf.Library).ThenBy(lf => lf.Name))
			{
				var completion = new SublimeCompletions.Completion
				{
					Trigger = f.Library + "." + f.Name
				};

				var sb = new StringBuilder();

				if (f.ParameterList.Any())
				{
					sb
						.Append(string.Format("{0}.{1}(", f.Library, f.Name));

					var parameters = f.Method.GetParameters()
						.ToList();

					for (int i = 0; i < parameters.Count; i++)
					{
						sb
							.Append("${")
							.Append(i + 1)
							.Append(":");

						if (parameters[i].IsOptional)
						{
							sb.Append(string.Format("[{0}]", parameters[i].Name));
						}
						else
						{
							sb.Append(parameters[i].Name);
						}

						sb.Append("}");

						if (i < parameters.Count - 1)
						{
							sb.Append(",");
						}
					}

					sb.Append(")");
				}
				else
				{
					sb.Append(string.Format("{0}.{1}()", f.Library, f.Name));
				}

				completion.Contents = sb.ToString();
				sc.Completions.Add(completion);
			}

			return JsonConvert.SerializeObject(sc);
		}

		public string ToNotepadPlusPlusAutoComplete()
		{
			return string.Empty; // TODO
		}
	}

	public class LibraryFunction
	{
		private readonly LuaMethodAttributes _luaAttributes;
		private readonly MethodInfo _method;

		public LibraryFunction(string library, string libraryDescription, MethodInfo method)
		{
			_luaAttributes = method.GetCustomAttributes(typeof(LuaMethodAttributes), false)
				.First() as LuaMethodAttributes;
			_method = method;

			Library = library;
			LibraryDescription = libraryDescription;
		}

		public string Library { get; private set; }
		public string LibraryDescription { get; private set; }

		public MethodInfo Method {  get { return _method; } }

		public string Name
		{
			get { return _luaAttributes.Name; }
		}

		public string Description
		{
			get { return _luaAttributes.Description; }
		}

		private string _paramterList = null;

		public string ParameterList
		{
			get
			{
				if (_paramterList == null)
				{
					var parameters = _method.GetParameters();

					var list = new StringBuilder();
					list.Append('(');
					for (var i = 0; i < parameters.Length; i++)
					{
						var p = TypeCleanup(parameters[i].ToString());
						if (parameters[i].IsOptional)
						{
							var def = parameters[i].DefaultValue != null ? parameters[i].DefaultValue.ToString() : "null";
							list.AppendFormat("[{0} = {1}]", p, def);
						}
						else
						{
							list.Append(p);
						}

						if (i < parameters.Length - 1)
						{
							list.Append(", ");
						}
					}

					list.Append(')');
					_paramterList = list.ToString();
				}

				return _paramterList;
			}
		}

		private string TypeCleanup(string str)
		{
			return str
				.Replace("System", string.Empty)
				.Replace(" ", string.Empty)
				.Replace(".", string.Empty)
				.Replace("LuaInterface", string.Empty)
				.Replace("Object[]", "object[] ")
				.Replace("Object", "object ")
				.Replace("Nullable`1[Boolean]", "bool? ")
				.Replace("Boolean[]", "bool[] ")
				.Replace("Boolean", "bool ")
				.Replace("String", "string ")
				.Replace("LuaTable", "table ")
				.Replace("LuaFunction", "func ")
				.Replace("Nullable`1[Int32]", "int? ")
				.Replace("Nullable`1[UInt32]", "uint? ")
				.Replace("Byte", "byte ")
				.Replace("Int16", "short ")
				.Replace("Int32", "int ")
				.Replace("Int64", "long ")
				.Replace("Ushort", "ushort ")
				.Replace("Ulong", "ulong ")
				.Replace("UInt32", "uint ")
				.Replace("UInt64", "ulong ")
				.Replace("Double", "double ")
				.Replace("Uint", "uint ")
				.Replace("Nullable`1[DrawingColor]", "Color? ")
				.Replace("DrawingColor", "Color ")
				.ToLower();
		}

		public string ReturnType
		{
			get
			{
				var returnType = _method.ReturnType.ToString();
				return TypeCleanup(returnType).Trim();
			}
		}
	}
}