mirror of
https://github.com/claunia/SabreTools.git
synced 2025-12-16 19:14:27 +00:00
Extract out Help namespace
This commit is contained in:
@@ -1,14 +0,0 @@
|
||||
namespace SabreTools.Library.Help
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines the feature type to check for
|
||||
/// </summary>
|
||||
public enum FeatureType
|
||||
{
|
||||
Flag = 0,
|
||||
String,
|
||||
Int32,
|
||||
Int64,
|
||||
List,
|
||||
}
|
||||
}
|
||||
@@ -1,611 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace SabreTools.Library.Help
|
||||
{
|
||||
public class Feature
|
||||
{
|
||||
#region Protected instance variables
|
||||
|
||||
protected FeatureType _featureType;
|
||||
protected bool _foundOnce = false;
|
||||
protected object _value = null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Publicly facing variables
|
||||
|
||||
public string Name { get; protected set; }
|
||||
public List<string> Flags { get; protected set; }
|
||||
public string Description { get; protected set; }
|
||||
public string LongDescription { get; protected set; }
|
||||
public Dictionary<string, Feature> Features { get; protected set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Feature()
|
||||
{
|
||||
this.Name = null;
|
||||
this.Flags = new List<string>();
|
||||
this.Description = null;
|
||||
this.LongDescription = null;
|
||||
this._featureType = FeatureType.Flag;
|
||||
this.Features = new Dictionary<string, Feature>();
|
||||
}
|
||||
|
||||
public Feature(string name, string flag, string description, FeatureType featureType, string longDescription = null)
|
||||
{
|
||||
this.Name = name;
|
||||
this.Flags = new List<string>
|
||||
{
|
||||
flag
|
||||
};
|
||||
this.Description = description;
|
||||
this.LongDescription = longDescription;
|
||||
this._featureType = featureType;
|
||||
this.Features = new Dictionary<string, Feature>();
|
||||
}
|
||||
|
||||
public Feature(string name, List<string> flags, string description, FeatureType featureType, string longDescription = null)
|
||||
{
|
||||
this.Name = name;
|
||||
this.Flags = flags;
|
||||
this.Description = description;
|
||||
this.LongDescription = longDescription;
|
||||
this._featureType = featureType;
|
||||
this.Features = new Dictionary<string, Feature>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Accessors
|
||||
|
||||
/// <summary>
|
||||
/// Directly address a given subfeature
|
||||
/// </summary>
|
||||
public Feature this[string name]
|
||||
{
|
||||
get { return this.Features.ContainsKey(name) ? this.Features[name] : null; }
|
||||
set { this.Features[name] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directly address a given subfeature
|
||||
/// </summary>
|
||||
public Feature this[Feature subfeature]
|
||||
{
|
||||
get { return this.Features.ContainsKey(subfeature.Name) ? this.Features[subfeature.Name] : null; }
|
||||
set { this.Features[subfeature.Name] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a new feature for this feature
|
||||
/// </summary>
|
||||
/// <param name="feature"></param>
|
||||
public void AddFeature(Feature feature)
|
||||
{
|
||||
if (this.Features == null)
|
||||
this.Features = new Dictionary<string, Feature>();
|
||||
|
||||
lock (this.Features)
|
||||
{
|
||||
this.Features[feature.Name] = feature;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a new flag for this feature
|
||||
/// </summary>
|
||||
/// <param name="flag">Flag to add for this feature</param>
|
||||
public void AddFlag(string flag)
|
||||
{
|
||||
if (this.Flags == null)
|
||||
this.Flags = new List<string>();
|
||||
|
||||
lock (this.Flags)
|
||||
{
|
||||
this.Flags.Add(flag);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a set of new flags for this feature
|
||||
/// </summary>
|
||||
/// <param name="flags">List of flags to add to this feature</param>
|
||||
public void AddFlags(List<string> flags)
|
||||
{
|
||||
if (this.Flags == null)
|
||||
this.Flags = new List<string>();
|
||||
|
||||
lock (this.Flags)
|
||||
{
|
||||
this.Flags.AddRange(flags);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a flag exists for the current feature
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the flag to check</param>
|
||||
/// <returns>True if the flag was found, false otherwise</returns>
|
||||
public bool ContainsFlag(string name)
|
||||
{
|
||||
return this.Flags.Any(f => f == name || f.TrimStart('-') == name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the feature contains a flag that starts with the given character
|
||||
/// </summary>
|
||||
/// <param name="c">Character to check against</param>
|
||||
/// <returns>True if the flag was found, false otherwise</returns>
|
||||
public bool StartsWith(char c)
|
||||
{
|
||||
return this.Flags.Any(f => f.TrimStart('-').ToLowerInvariant()[0] == c);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Instance Methods
|
||||
|
||||
/// <summary>
|
||||
/// Output this feature only
|
||||
/// </summary>
|
||||
/// <param name="pre">Positive number representing number of spaces to put in front of the feature</param>
|
||||
/// <param name="midpoint">Positive number representing the column where the description should start</param>
|
||||
/// <param name="includeLongDescription">True if the long description should be formatted and output, false otherwise</param>
|
||||
public List<string> Output(int pre = 0, int midpoint = 0, bool includeLongDescription = false)
|
||||
{
|
||||
// Create the output list
|
||||
List<string> outputList = new List<string>();
|
||||
|
||||
// Build the output string first
|
||||
string output = string.Empty;
|
||||
|
||||
// Add the pre-space first
|
||||
output += CreatePadding(pre);
|
||||
|
||||
// Preprocess the flags, if necessary
|
||||
string[] newflags = new string[this.Flags.Count];
|
||||
this.Flags.CopyTo(newflags);
|
||||
switch (_featureType)
|
||||
{
|
||||
case FeatureType.Int32:
|
||||
case FeatureType.Int64:
|
||||
case FeatureType.List:
|
||||
case FeatureType.String:
|
||||
for (int i = 0; i < newflags.Length; i++)
|
||||
{
|
||||
newflags[i] += "=";
|
||||
}
|
||||
break;
|
||||
case FeatureType.Flag:
|
||||
default:
|
||||
// No-op
|
||||
break;
|
||||
}
|
||||
|
||||
// Now add all flags
|
||||
output += string.Join(", ", newflags);
|
||||
|
||||
// If we have a midpoint set, check to see if the string needs padding
|
||||
if (midpoint > 0 && output.Length < midpoint)
|
||||
output += CreatePadding(midpoint - output.Length);
|
||||
else
|
||||
output += " ";
|
||||
|
||||
// Append the description
|
||||
output += this.Description;
|
||||
|
||||
// Now append it to the list
|
||||
outputList.Add(output);
|
||||
|
||||
// If we are outputting the long description, format it and then add it as well
|
||||
if (includeLongDescription)
|
||||
{
|
||||
// Get the width of the console for wrapping reference
|
||||
int width = Console.WindowWidth - 1;
|
||||
|
||||
// Prepare the output string
|
||||
output = CreatePadding(pre + 4);
|
||||
|
||||
// Now split the input description and start processing
|
||||
string[] split = this.LongDescription.Split(' ');
|
||||
for (int i = 0; i < split.Length; i++)
|
||||
{
|
||||
// If we have a newline character, reset the line and continue
|
||||
if (split[i].Contains("\n"))
|
||||
{
|
||||
string[] subsplit = split[i].Replace("\r", string.Empty).Split('\n');
|
||||
for (int j = 0; j < subsplit.Length - 1; j++)
|
||||
{
|
||||
// Add the next word only if the total length doesn't go above the width of the screen
|
||||
if (output.Length + subsplit[j].Length < width)
|
||||
{
|
||||
output += (output.Length == pre + 4 ? string.Empty : " ") + subsplit[j];
|
||||
}
|
||||
// Otherwise, we want to cache the line to output and create a new blank string
|
||||
else
|
||||
{
|
||||
outputList.Add(output);
|
||||
output = CreatePadding(pre + 4);
|
||||
output += (output.Length == pre + 4 ? string.Empty : " ") + subsplit[j];
|
||||
}
|
||||
|
||||
outputList.Add(output);
|
||||
output = CreatePadding(pre + 4);
|
||||
}
|
||||
|
||||
#if NET_FRAMEWORK
|
||||
output += subsplit[subsplit.Length - 1];
|
||||
#else
|
||||
output += subsplit[^1];
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the next word only if the total length doesn't go above the width of the screen
|
||||
if (output.Length + split[i].Length < width)
|
||||
{
|
||||
output += (output.Length == pre + 4 ? string.Empty : " ") + split[i];
|
||||
}
|
||||
// Otherwise, we want to cache the line to output and create a new blank string
|
||||
else
|
||||
{
|
||||
outputList.Add(output);
|
||||
output = CreatePadding(pre + 4);
|
||||
output += (output.Length == pre + 4 ? string.Empty : " ") + split[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Add the last created output and a blank line for clarity
|
||||
outputList.Add(output);
|
||||
outputList.Add(string.Empty);
|
||||
}
|
||||
|
||||
return outputList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a padding space based on the given length
|
||||
/// </summary>
|
||||
/// <param name="spaces">Number of padding spaces to add</param>
|
||||
/// <returns>String with requested number of blank spaces</returns>
|
||||
private string CreatePadding(int spaces)
|
||||
{
|
||||
return string.Empty.PadRight(spaces);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Output this feature and all subfeatures
|
||||
/// </summary>
|
||||
/// <param name="tabLevel">Level of indentation for this feature</param>
|
||||
/// <param name="pre">Positive number representing number of spaces to put in front of the feature</param>
|
||||
/// <param name="midpoint">Positive number representing the column where the description should start</param>
|
||||
/// <param name="includeLongDescription">True if the long description should be formatted and output, false otherwise</param>
|
||||
public List<string> OutputRecursive(int tabLevel, int pre = 0, int midpoint = 0, bool includeLongDescription = false)
|
||||
{
|
||||
// Create the output list
|
||||
List<string> outputList = new List<string>();
|
||||
|
||||
// Build the output string first
|
||||
string output = string.Empty;
|
||||
|
||||
// Normalize based on the tab level
|
||||
int preAdjusted = pre;
|
||||
int midpointAdjusted = midpoint;
|
||||
if (tabLevel > 0)
|
||||
{
|
||||
preAdjusted += 4 * tabLevel;
|
||||
midpointAdjusted += 4 * tabLevel;
|
||||
}
|
||||
|
||||
// Add the pre-space first
|
||||
output += CreatePadding(preAdjusted);
|
||||
|
||||
// Preprocess the flags, if necessary
|
||||
string[] newflags = new string[this.Flags.Count];
|
||||
this.Flags.CopyTo(newflags);
|
||||
switch (_featureType)
|
||||
{
|
||||
case FeatureType.Int32:
|
||||
case FeatureType.Int64:
|
||||
case FeatureType.List:
|
||||
case FeatureType.String:
|
||||
for (int i = 0; i < newflags.Length; i++)
|
||||
{
|
||||
newflags[i] += "=";
|
||||
}
|
||||
break;
|
||||
case FeatureType.Flag:
|
||||
default:
|
||||
// No-op
|
||||
break;
|
||||
}
|
||||
|
||||
// Now add all flags
|
||||
output += string.Join(", ", newflags);
|
||||
|
||||
// If we have a midpoint set, check to see if the string needs padding
|
||||
if (midpoint > 0 && output.Length < midpointAdjusted)
|
||||
output += CreatePadding(midpointAdjusted - output.Length);
|
||||
else
|
||||
output += " ";
|
||||
|
||||
// Append the description
|
||||
output += this.Description;
|
||||
|
||||
// Now append it to the list
|
||||
outputList.Add(output);
|
||||
|
||||
// If we are outputting the long description, format it and then add it as well
|
||||
if (includeLongDescription)
|
||||
{
|
||||
// Get the width of the console for wrapping reference
|
||||
int width = Console.WindowWidth - 1;
|
||||
|
||||
// Prepare the output string
|
||||
output = CreatePadding(preAdjusted + 4);
|
||||
|
||||
// Now split the input description and start processing
|
||||
string[] split = this.LongDescription.Split(' ');
|
||||
for (int i = 0; i < split.Length; i++)
|
||||
{
|
||||
// If we have a newline character, reset the line and continue
|
||||
if (split[i].Contains("\n"))
|
||||
{
|
||||
string[] subsplit = split[i].Replace("\r", string.Empty).Split('\n');
|
||||
for (int j = 0; j < subsplit.Length - 1; j++)
|
||||
{
|
||||
// Add the next word only if the total length doesn't go above the width of the screen
|
||||
if (output.Length + subsplit[j].Length < width)
|
||||
{
|
||||
output += (output.Length == preAdjusted + 4 ? string.Empty : " ") + subsplit[j];
|
||||
}
|
||||
// Otherwise, we want to cache the line to output and create a new blank string
|
||||
else
|
||||
{
|
||||
outputList.Add(output);
|
||||
output = CreatePadding(preAdjusted + 4);
|
||||
output += (output.Length == preAdjusted + 4 ? string.Empty : " ") + subsplit[j];
|
||||
}
|
||||
|
||||
outputList.Add(output);
|
||||
output = CreatePadding(preAdjusted + 4);
|
||||
}
|
||||
|
||||
#if NET_FRAMEWORK
|
||||
output += subsplit[subsplit.Length - 1];
|
||||
#else
|
||||
output += subsplit[^1];
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the next word only if the total length doesn't go above the width of the screen
|
||||
if (output.Length + split[i].Length < width)
|
||||
{
|
||||
output += (output.Length == preAdjusted + 4 ? string.Empty : " ") + split[i];
|
||||
}
|
||||
// Otherwise, we want to cache the line to output and create a new blank string
|
||||
else
|
||||
{
|
||||
outputList.Add(output);
|
||||
output = CreatePadding(preAdjusted + 4);
|
||||
output += (output.Length == preAdjusted + 4 ? string.Empty : " ") + split[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Add the last created output and a blank line for clarity
|
||||
outputList.Add(output);
|
||||
outputList.Add(string.Empty);
|
||||
}
|
||||
|
||||
// Now let's append all subfeatures
|
||||
foreach (string feature in this.Features.Keys)
|
||||
{
|
||||
outputList.AddRange(this.Features[feature].OutputRecursive(tabLevel + 1, pre, midpoint, includeLongDescription));
|
||||
}
|
||||
|
||||
return outputList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate whether a flag is valid for this feature or not
|
||||
/// </summary>
|
||||
/// <param name="input">Input to check against</param>
|
||||
/// <param name="exact">True if just this feature should be checked, false if all subfeatures are checked as well</param>
|
||||
/// <param name="ignore">True if the existing flag should be ignored, false otherwise</param>
|
||||
/// <returns>True if the flag was valid, false otherwise</returns>
|
||||
public bool ValidateInput(string input, bool exact = false, bool ignore = false)
|
||||
{
|
||||
bool valid = false;
|
||||
|
||||
// Determine what we should be looking for
|
||||
switch (_featureType)
|
||||
{
|
||||
// If we have a flag, make sure it doesn't have an equal sign in it
|
||||
case FeatureType.Flag:
|
||||
valid = !input.Contains("=") && this.Flags.Contains(input);
|
||||
if (valid)
|
||||
{
|
||||
_value = true;
|
||||
|
||||
// If we've already found this feature before
|
||||
if (_foundOnce && !ignore)
|
||||
valid = false;
|
||||
|
||||
_foundOnce = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// If we have an Int32, try to parse it if at all possible
|
||||
case FeatureType.Int32:
|
||||
valid = input.Contains("=") && this.Flags.Contains(input.Split('=')[0]);
|
||||
if (valid)
|
||||
{
|
||||
if (!Int32.TryParse(input.Split('=')[1], out int value))
|
||||
value = Int32.MinValue;
|
||||
|
||||
_value = value;
|
||||
|
||||
// If we've already found this feature before
|
||||
if (_foundOnce && !ignore)
|
||||
valid = false;
|
||||
|
||||
_foundOnce = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// If we have an Int32, try to parse it if at all possible
|
||||
case FeatureType.Int64:
|
||||
valid = input.Contains("=") && this.Flags.Contains(input.Split('=')[0]);
|
||||
if (valid)
|
||||
{
|
||||
if (!Int64.TryParse(input.Split('=')[1], out long value))
|
||||
value = Int64.MinValue;
|
||||
|
||||
_value = value;
|
||||
|
||||
// If we've already found this feature before
|
||||
if (_foundOnce && !ignore)
|
||||
valid = false;
|
||||
|
||||
_foundOnce = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// If we have an input, make sure it has an equals sign in it
|
||||
case FeatureType.List:
|
||||
valid = input.Contains("=") && this.Flags.Contains(input.Split('=')[0]);
|
||||
if (valid)
|
||||
{
|
||||
if (_value == null)
|
||||
_value = new List<string>();
|
||||
|
||||
(_value as List<string>).Add(input.Split('=')[1]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case FeatureType.String:
|
||||
valid = input.Contains("=") && this.Flags.Contains(input.Split('=')[0]);
|
||||
if (valid)
|
||||
{
|
||||
_value = input.Split('=')[1];
|
||||
|
||||
// If we've already found this feature before
|
||||
if (_foundOnce && !ignore)
|
||||
valid = false;
|
||||
|
||||
_foundOnce = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// If we haven't found a valid flag and we're not looking for just this feature, check to see if any of the subfeatures are valid
|
||||
if (!valid && !exact)
|
||||
valid = this.Features.Keys.Any(k => this.Features[k].ValidateInput(input));
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the boolean value associated with this feature
|
||||
/// </summary>
|
||||
public bool GetBoolValue()
|
||||
{
|
||||
if (_featureType != FeatureType.Flag)
|
||||
throw new ArgumentException("Feature is not a flag");
|
||||
|
||||
return (_value as bool?) ?? false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value associated with this feature
|
||||
/// </summary>
|
||||
public string GetStringValue()
|
||||
{
|
||||
if (_featureType != FeatureType.String)
|
||||
throw new ArgumentException("Feature is not a string");
|
||||
|
||||
return (_value as string);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the Int32 value associated with this feature
|
||||
/// </summary>
|
||||
public int GetInt32Value()
|
||||
{
|
||||
if (_featureType != FeatureType.Int32)
|
||||
throw new ArgumentException("Feature is not an int");
|
||||
|
||||
return (_value as int?) ?? int.MinValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the Int64 value associated with this feature
|
||||
/// </summary>
|
||||
public long GetInt64Value()
|
||||
{
|
||||
if (_featureType != FeatureType.Int64)
|
||||
throw new ArgumentException("Feature is not a long");
|
||||
|
||||
return (_value as long?) ?? long.MinValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the List\<string\> value associated with this feature
|
||||
/// </summary>
|
||||
public List<string> GetListValue()
|
||||
{
|
||||
if (_featureType != FeatureType.List)
|
||||
throw new ArgumentException("Feature is not a list");
|
||||
|
||||
return (_value as List<string>) ?? new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if this feature has a valid value or not
|
||||
/// </summary>
|
||||
/// <returns>True if the feature is enabled, false otherwise</returns>
|
||||
public bool IsEnabled()
|
||||
{
|
||||
#if NET_FRAMEWORK
|
||||
switch (_featureType)
|
||||
{
|
||||
case FeatureType.Flag:
|
||||
return (_value as bool?) == true;
|
||||
case FeatureType.String:
|
||||
return (_value as string) != null;
|
||||
case FeatureType.Int32:
|
||||
return (_value as int?).HasValue && (_value as int?).Value != int.MinValue;
|
||||
case FeatureType.Int64:
|
||||
return (_value as long?).HasValue && (_value as long?).Value != long.MinValue;
|
||||
case FeatureType.List:
|
||||
return (_value as List<string>) != null;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return _featureType switch
|
||||
{
|
||||
FeatureType.Flag => (_value as bool?) == true,
|
||||
FeatureType.String => (_value as string) != null,
|
||||
FeatureType.Int32 => (_value as int?).HasValue && (_value as int?).Value != int.MinValue,
|
||||
FeatureType.Int64 => (_value as long?).HasValue && (_value as long?).Value != long.MinValue,
|
||||
FeatureType.List => (_value as List<string>) != null,
|
||||
_ => false,
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,340 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace SabreTools.Library.Help
|
||||
{
|
||||
public class Help
|
||||
{
|
||||
#region Private variables
|
||||
|
||||
private List<string> _header;
|
||||
private Dictionary<string, Feature> _features;
|
||||
private static string _barrier = "-----------------------------------------";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Help()
|
||||
{
|
||||
_header = new List<string>();
|
||||
_features = new Dictionary<string, Feature>();
|
||||
}
|
||||
|
||||
public Help(List<string> header)
|
||||
{
|
||||
_header = header;
|
||||
_features = new Dictionary<string, Feature>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Accessors
|
||||
|
||||
public Feature this[string name]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_features == null)
|
||||
_features = new Dictionary<string, Feature>();
|
||||
|
||||
if (!_features.ContainsKey(name))
|
||||
return null;
|
||||
|
||||
return _features[name];
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_features == null)
|
||||
_features = new Dictionary<string, Feature>();
|
||||
|
||||
_features[name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Feature this[Feature subfeature]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_features == null)
|
||||
_features = new Dictionary<string, Feature>();
|
||||
|
||||
if (!_features.ContainsKey(subfeature.Name))
|
||||
return null;
|
||||
|
||||
return _features[subfeature.Name];
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_features == null)
|
||||
_features = new Dictionary<string, Feature>();
|
||||
|
||||
_features[subfeature.Name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a new feature to the help
|
||||
/// </summary>
|
||||
/// <param name="feature">Feature object to map to</param>
|
||||
public void Add(Feature feature)
|
||||
{
|
||||
if (_features == null)
|
||||
_features = new Dictionary<string, Feature>();
|
||||
|
||||
lock (_features)
|
||||
{
|
||||
_features.Add(feature.Name, feature);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Instance Methods
|
||||
|
||||
/// <summary>
|
||||
/// Get the feature name for a given flag or short name
|
||||
/// </summary>
|
||||
/// <returns>Feature name</returns>
|
||||
public string GetFeatureName(string name)
|
||||
{
|
||||
return _features.Keys.FirstOrDefault(f => _features[f].ValidateInput(name, exact: true, ignore: true)) ?? string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Output top-level features only
|
||||
/// </summary>
|
||||
public void OutputGenericHelp()
|
||||
{
|
||||
// Start building the output list
|
||||
List<string> output = new List<string>();
|
||||
|
||||
// Append the header first
|
||||
output.AddRange(_header);
|
||||
|
||||
// Now append all available top-level flags
|
||||
output.Add("Available options:");
|
||||
foreach (string feature in _features.Keys)
|
||||
{
|
||||
output.AddRange(_features[feature].Output(pre: 2, midpoint: 30));
|
||||
}
|
||||
|
||||
// And append the generic ending
|
||||
output.Add(string.Empty);
|
||||
output.Add("For information on available flags, put the option name after help");
|
||||
|
||||
// Now write out everything in a staged manner
|
||||
WriteOutWithPauses(output);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Output all features recursively
|
||||
/// </summary>
|
||||
public void OutputAllHelp()
|
||||
{
|
||||
// Start building the output list
|
||||
List<string> output = new List<string>();
|
||||
|
||||
// Append the header first
|
||||
output.AddRange(_header);
|
||||
|
||||
// Now append all available flags recursively
|
||||
output.Add("Available options:");
|
||||
foreach (string feature in _features.Keys)
|
||||
{
|
||||
output.AddRange(_features[feature].OutputRecursive(0, pre: 2, midpoint: 30, includeLongDescription: true));
|
||||
}
|
||||
|
||||
// Now write out everything in a staged manner
|
||||
WriteOutWithPauses(output);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Output the SabreTools suite credits
|
||||
/// </summary>
|
||||
public void OutputCredits()
|
||||
{
|
||||
List<string> credits = new List<string>();
|
||||
credits.Add(_barrier);
|
||||
credits.Add("Credits");
|
||||
credits.Add(_barrier);
|
||||
credits.Add(string.Empty);
|
||||
credits.Add("Programmer / Lead: Matt Nadareski (darksabre76)");
|
||||
credits.Add("Additional code: emuLOAD, @tractivo, motoschifo");
|
||||
credits.Add("Testing: emuLOAD, @tractivo, Kludge, Obiwantje, edc");
|
||||
credits.Add("Suggestions: edc, AcidX, Amiga12, EliUmniCk");
|
||||
credits.Add("Based on work by: The Wizard of DATz");
|
||||
WriteOutWithPauses(credits);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Output a single feature recursively
|
||||
/// </summary>
|
||||
/// <param name="featurename">Name of the feature to output information for, if possible</param>
|
||||
/// <param name="includeLongDescription">True if the long description should be formatted and output, false otherwise</param>
|
||||
public void OutputIndividualFeature(string featurename, bool includeLongDescription = false)
|
||||
{
|
||||
// Start building the output list
|
||||
List<string> output = new List<string>();
|
||||
|
||||
// If the feature name is null, empty, or just consisting of `-` characters, just show everything
|
||||
if (string.IsNullOrEmpty(featurename?.TrimStart('-')))
|
||||
{
|
||||
OutputGenericHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
// Now try to find the feature that has the name included
|
||||
string realname = null;
|
||||
List<string> startsWith = new List<string>();
|
||||
foreach (string feature in _features.Keys)
|
||||
{
|
||||
// If we have a match to the feature name somehow
|
||||
if (feature == featurename)
|
||||
{
|
||||
realname = feature;
|
||||
break;
|
||||
}
|
||||
|
||||
// If we have a match within the flags
|
||||
else if (_features[feature].ContainsFlag(featurename))
|
||||
{
|
||||
realname = feature;
|
||||
break;
|
||||
}
|
||||
|
||||
// Otherwise, we want to get features with the same start
|
||||
else if (_features[feature].StartsWith(featurename.TrimStart('-')[0]))
|
||||
{
|
||||
startsWith.Add(feature);
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a real name found, append all available subflags recursively
|
||||
if (realname != null)
|
||||
{
|
||||
output.Add($"Available options for {realname}:");
|
||||
output.AddRange(_features[realname].OutputRecursive(0, pre: 2, midpoint: 30, includeLongDescription: includeLongDescription));
|
||||
}
|
||||
|
||||
// If no name was found but we have possible matches, show them
|
||||
else if (startsWith.Count > 0)
|
||||
{
|
||||
output.Add($"\"{featurename}\" not found. Did you mean:");
|
||||
foreach (string possible in startsWith)
|
||||
{
|
||||
output.AddRange(_features[possible].Output(pre: 2, midpoint: 30, includeLongDescription: includeLongDescription));
|
||||
}
|
||||
}
|
||||
|
||||
// Now write out everything in a staged manner
|
||||
WriteOutWithPauses(output);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a flag is a top-level (main application) flag
|
||||
/// </summary>
|
||||
/// <param name="flag">Name of the flag to check</param>
|
||||
/// <returns>True if the feature was found, false otherwise</returns>
|
||||
public bool TopLevelFlag(string flag)
|
||||
{
|
||||
return _features.Keys.Any(f => _features[f].ValidateInput(flag, exact: true));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a list of enabled features
|
||||
/// </summary>
|
||||
/// <returns>List of Features representing what is enabled</returns>
|
||||
public Dictionary<string, Feature> GetEnabledFeatures()
|
||||
{
|
||||
Dictionary<string, Feature> enabled = new Dictionary<string, Feature>();
|
||||
|
||||
// Loop through the features
|
||||
foreach (KeyValuePair<string, Feature> feature in _features)
|
||||
{
|
||||
Dictionary<string, Feature> temp = GetEnabledSubfeatures(feature.Key, feature.Value);
|
||||
foreach (KeyValuePair<string, Feature> tempfeat in temp)
|
||||
{
|
||||
if (!enabled.ContainsKey(tempfeat.Key))
|
||||
enabled.Add(tempfeat.Key, null);
|
||||
|
||||
enabled[tempfeat.Key] = tempfeat.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a nested list of subfeatures from the current feature
|
||||
/// </summary>
|
||||
/// <param name="key">Name that should be assigned to the feature</param>
|
||||
/// <param name="feature">Feature with possible subfeatures to test</param>
|
||||
/// <returns>List of Features representing what is enabled</returns>
|
||||
private Dictionary<string, Feature> GetEnabledSubfeatures(string key, Feature feature)
|
||||
{
|
||||
Dictionary<string, Feature> enabled = new Dictionary<string, Feature>();
|
||||
|
||||
// First determine if the current feature is enabled
|
||||
if (feature.IsEnabled())
|
||||
enabled.Add(key, feature);
|
||||
|
||||
// Now loop through the subfeatures recursively
|
||||
foreach (KeyValuePair<string, Feature> sub in feature.Features)
|
||||
{
|
||||
Dictionary<string, Feature> temp = GetEnabledSubfeatures(sub.Key, sub.Value);
|
||||
foreach (KeyValuePair<string, Feature> tempfeat in temp)
|
||||
{
|
||||
if (!enabled.ContainsKey(tempfeat.Key))
|
||||
enabled.Add(tempfeat.Key, null);
|
||||
|
||||
enabled[tempfeat.Key] = tempfeat.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write out the help text with pauses, if needed
|
||||
/// </summary>
|
||||
/// <param name="helptext"></param>
|
||||
private void WriteOutWithPauses(List<string> helptext)
|
||||
{
|
||||
// Now output based on the size of the screen
|
||||
int i = 0;
|
||||
for (int line = 0; line < helptext.Count; line++)
|
||||
{
|
||||
string help = helptext[line];
|
||||
|
||||
Console.WriteLine(help);
|
||||
i++;
|
||||
|
||||
// If we're not being redirected and we reached the size of the screen, pause
|
||||
if (i == Console.WindowHeight - 3 && line != helptext.Count - 1)
|
||||
{
|
||||
i = 0;
|
||||
Pause();
|
||||
}
|
||||
}
|
||||
|
||||
Pause();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pause on console output
|
||||
/// </summary>
|
||||
private static void Pause()
|
||||
{
|
||||
if (!Console.IsOutputRedirected)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Press enter to continue...");
|
||||
Console.ReadLine();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using SabreTools.Library.Logging;
|
||||
|
||||
namespace SabreTools.Library.Help
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an actionable top-level feature
|
||||
/// </summary>
|
||||
public abstract class TopLevel : Feature
|
||||
{
|
||||
#region Fields
|
||||
|
||||
/// <summary>
|
||||
/// List of files, directories, and potential wildcard paths
|
||||
/// </summary>
|
||||
public List<string> Inputs = new List<string>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Logging
|
||||
|
||||
/// <summary>
|
||||
/// Logging object
|
||||
/// </summary>
|
||||
private readonly Logger logger;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public TopLevel()
|
||||
{
|
||||
logger = new Logger(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Processing
|
||||
|
||||
/// <summary>
|
||||
/// Process args list based on current feature
|
||||
/// </summary>
|
||||
public virtual bool ProcessArgs(string[] args, Help help)
|
||||
{
|
||||
for (int i = 1; i < args.Length; i++)
|
||||
{
|
||||
// Verify that the current flag is proper for the feature
|
||||
if (!ValidateInput(args[i]))
|
||||
{
|
||||
// Special precautions for files and directories
|
||||
if (File.Exists(args[i]) || Directory.Exists(args[i]))
|
||||
{
|
||||
Inputs.Add(args[i]);
|
||||
}
|
||||
|
||||
// Special precautions for wildcarded inputs (potential paths)
|
||||
else if (args[i].Contains("*") || args[i].Contains("?"))
|
||||
{
|
||||
Inputs.Add(args[i]);
|
||||
}
|
||||
|
||||
// Everything else isn't a file
|
||||
else
|
||||
{
|
||||
logger.Error($"Invalid input detected: {args[i]}");
|
||||
help.OutputIndividualFeature(this.Name);
|
||||
LoggerImpl.Close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process and extract variables based on current feature
|
||||
/// </summary>
|
||||
public virtual void ProcessFeatures(Dictionary<string, Feature> features) { }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Generic Extraction
|
||||
|
||||
/// <summary>
|
||||
/// Get boolean value from nullable feature
|
||||
/// </summary>
|
||||
protected bool GetBoolean(Dictionary<string, Feature> features, string key)
|
||||
{
|
||||
if (!features.ContainsKey(key))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get int value from nullable feature
|
||||
/// </summary>
|
||||
protected int GetInt32(Dictionary<string, Feature> features, string key)
|
||||
{
|
||||
if (!features.ContainsKey(key))
|
||||
return Int32.MinValue;
|
||||
|
||||
return features[key].GetInt32Value();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get long value from nullable feature
|
||||
/// </summary>
|
||||
protected long GetInt64(Dictionary<string, Feature> features, string key)
|
||||
{
|
||||
if (!features.ContainsKey(key))
|
||||
return Int64.MinValue;
|
||||
|
||||
return features[key].GetInt64Value();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get list value from nullable feature
|
||||
/// </summary>
|
||||
protected List<string> GetList(Dictionary<string, Feature> features, string key)
|
||||
{
|
||||
if (!features.ContainsKey(key))
|
||||
return new List<string>();
|
||||
|
||||
return features[key].GetListValue() ?? new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get string value from nullable feature
|
||||
/// </summary>
|
||||
protected string GetString(Dictionary<string, Feature> features, string key)
|
||||
{
|
||||
if (!features.ContainsKey(key))
|
||||
return null;
|
||||
|
||||
return features[key].GetStringValue();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -35,4 +35,8 @@
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Help\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user