diff --git a/.vscode/launch.json b/.vscode/launch.json
deleted file mode 100644
index 5e9f299..0000000
--- a/.vscode/launch.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- // Use IntelliSense to learn about possible attributes.
- // Hover to view descriptions of existing attributes.
- // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
- "version": "0.2.0",
- "configurations": [
- {
- "name": ".NET Core Launch (console)",
- "type": "coreclr",
- "request": "launch",
- "preLaunchTask": "build",
- "program": "${workspaceFolder}/examples/Args/bin/Debug/net8.0/Args.dll",
- "args": ["a", "--bar", "a", "a"],
- "cwd": "${workspaceFolder}",
- "stopAtEntry": false,
- "console": "externalTerminal",
- }
-
-
-
- ]
-}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
deleted file mode 100644
index 8fe9072..0000000
--- a/.vscode/tasks.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "version": "2.0.0",
- "tasks": [
- {
- "type": "dotnet",
- "task": "build",
- "group": {
- "kind": "build",
- "isDefault": true
- },
- "problemMatcher": [],
- "label": "build"
- },
- ]
-}
\ No newline at end of file
diff --git a/Terminal/Arguments/Argument.cs b/Terminal/Arguments/Argument.cs
index ff3dc42..90027d0 100644
--- a/Terminal/Arguments/Argument.cs
+++ b/Terminal/Arguments/Argument.cs
@@ -1,137 +1,67 @@
namespace OxDED.Terminal.Arguments;
///
-/// Represents an optional argument (-f, --foo).
+/// Represents a required argument in a specific order.
///
-public class Argument : ICloneable, IEquatable {
+public class Argument : ICloneable {
///
- /// The keys of this argument (f, foo).
+ /// The name (key) of this argument.
///
- public string[] keys;
+ public string name;
///
- /// The parameters of this argument.
+ /// The description of this argument.
///
- public ArgumentParameter[] parameters;
+ public string? description;
+ internal string? value;
///
- /// The description of this argument.
+ /// If this argument has a value (should be yes).
///
- public string? description = null;
+ public bool HasValue { get => value != null; }
///
- /// Creates an argument.
+ /// The value of this argument (error if it isn't parsed).
///
- /// The key of this argument.
- /// The description of this argument (optional).
- /// The parameters of this argument (default: empty).
- public Argument(string key, string? description = null, IEnumerable? parameters = null) {
- keys = [key];
- this.description = description;
- this.parameters = parameters == null ? [] : [.. parameters];
- }
+ ///
+ public string Value { get {
+ if (HasValue) {
+ return value!;
+ } else {
+ throw new InvalidOperationException("This argument has not yet been parsed");
+ }
+ } }
+
///
- /// Creates an argument.
+ /// Creates a argument.
///
- /// The keys of this argument.
+ /// The name of this argument.
/// The description of this argument (optional).
- /// The parameters of this argument (default: empty).
- public Argument(IEnumerable keys, string? description = null, IEnumerable? parameters = null) {
- this.keys = [.. keys];
+ public Argument(string name, string? description = null) {
+ this.name = name;
this.description = description;
- this.parameters = parameters == null ? [] : [.. parameters];
}
///
- /// Sets the key of this argument.
+ /// Sets the name of this argument.
///
- /// The new key.
+ /// The new name of this argument.
/// This argument.
- public Argument Key(string key) {
- keys = [key];
- return this;
- }
- ///
- /// Sets the keys of this argument.
- ///
- /// The new keys.
- /// This argument.
- public Argument Keys(IEnumerable keys) {
- this.keys = [.. keys];
+ public Argument Name(string name) {
+ this.name = name;
return this;
}
///
/// Sets the description of this argument.
///
- /// The new description.
+ /// The new description of this argument.
/// This argument.
public Argument Description(string? description) {
this.description = description;
return this;
}
- ///
- /// Sets the parameters of this argument.
- ///
- /// The new parameters.
- /// This argument.
- public Argument Parameters(IEnumerable parameters) {
- this.parameters = [.. parameters];
- return this;
- }
- ///
- /// Adds a parameter to this argument.
- ///
- /// The parameter to add.
- /// This argument.
- public Argument AddParameter(ArgumentParameter parameter) {
- parameters = [.. parameters, parameter];
- return this;
- }
- ///
- /// If this argument's parameters have values (should be yes).
- ///
- public bool HasValue { get => parameters.All((ArgumentParameter parameter) => parameter.HasValue); }
- ///
- public static bool operator ==(Argument? left, Argument? right) {
- if (left is null && right is null) {
- return true;
- } else if (left is null) {
- return false;
- }
- return left.Equals(right);
- }
- ///
- public static bool operator !=(Argument? left, Argument? right) {
- return !(left == right);
- }
- ///
- ///
- /// Checks if the that color is identical to this one.
- ///
- public bool Equals(Argument? other) {
- if (other is null) {
- return false;
- }
- if (ReferenceEquals(this, other)) {
- return true;
- }
- if (GetType() != other.GetType()) {
- return false;
- }
- return keys == other.keys;
- }
- ///
- ///
- /// Checks if the that color is identical to this one.
- ///
- public override bool Equals(object? obj) {
- return Equals(obj as Color);
- }
- ///
- public override int GetHashCode() {
- return keys.GetHashCode();
- }
///
///
/// Calls .
///
+
public object Clone() {
return CloneArgument();
}
@@ -142,6 +72,6 @@ public object Clone() {
/// The new copy of this color.
///
public Argument CloneArgument() {
- return new Argument(keys, description, parameters);
+ return new Argument(name, description);
}
}
\ No newline at end of file
diff --git a/Terminal/Arguments/ArgumentFormatter.cs b/Terminal/Arguments/ArgumentFormatter.cs
new file mode 100644
index 0000000..b364ed0
--- /dev/null
+++ b/Terminal/Arguments/ArgumentFormatter.cs
@@ -0,0 +1,174 @@
+namespace OxDED.Terminal.Arguments;
+
+///
+/// Represents a format for arguments and options.
+///
+public partial class ArgumentFormatter {
+ public string? name;
+ public string? description;
+ public string? version;
+
+ ///
+ /// The options of this format.
+ ///
+ public List Options { get; private set; }
+ ///
+ /// The arguments of this format.
+ ///
+ public List Arguments { get; private set; }
+
+ ///
+ /// Creates a new argument format.
+ ///
+ public ArgumentFormatter(List? arguments = null, List? options = null) {
+ Options = options ?? [];
+ Arguments = arguments ?? [];
+ }
+
+ public OptionFormat Option() {
+ return new(this);
+ }
+ public ArgumentFormat Argument() {
+ return new(this);
+ }
+
+ public ArgumentFormatter Name(string name) {
+ this.name = name;
+ return this;
+ }
+ public ArgumentFormatter Description(string? description) {
+ this.description = description;
+ return this;
+ }
+ public ArgumentFormatter Version(string? version) {
+ this.version = version;
+ return this;
+ }
+
+ public ArgumentFormatter AddHelpOption(bool quit = true, IEnumerable? keys = null) {
+ Option()
+ .Keys(keys ?? ["-h", "--help"])
+ .Description("Shows this help message.")
+ .Finish();
+ return this;
+ }
+ public ArgumentFormatter AddVersionOption(bool quit = true, IEnumerable? keys = null) {
+ Option()
+ .Keys(keys ?? ["-v", "--version"])
+ .Description("Shows the version of this application.")
+ .Finish();
+ return this;
+ }
+
+ // public ArgumentFormatter
+}
+
+public partial class ArgumentFormatter {
+ public class ArgumentFormat {
+ public string description;
+ public string name;
+
+ public ArgumentFormatter ArgumentFormatter { get; private set; }
+
+ public ArgumentFormat(ArgumentFormatter argumentFormatter) {
+ ArgumentFormatter = argumentFormatter;
+ }
+
+ public ArgumentFormat Name(string name) {
+ this.name = name;
+ return this;
+ }
+ public ArgumentFormat Description(string description) {
+ this.description = description;
+ return this;
+ }
+
+ public ArgumentFormatter Finish() {
+ ArgumentFormatter.Arguments = [.. ArgumentFormatter.Arguments, this];
+ return ArgumentFormatter;
+ }
+ }
+}
+
+public partial class ArgumentFormatter {
+ public class OptionFormat {
+ public string[] keys;
+ public string description;
+ public ParameterFormat[] parameters;
+
+ public ArgumentFormatter ArgumentFormatter { get; private set; }
+
+ public OptionFormat(ArgumentFormatter argumentFormatter) {
+ ArgumentFormatter = argumentFormatter;
+ }
+
+ public OptionFormat Key(string key) {
+ keys = [.. keys, key];
+ return this;
+ }
+ public OptionFormat Keys(IEnumerable keys) {
+ this.keys = [.. this.keys, .. keys];
+ return this;
+ }
+ public OptionFormat Description(string description) {
+ this.description = description;
+ return this;
+ }
+ public ParameterFormat Parameter() {
+ return new(this);
+ }
+
+ public ArgumentFormatter Finish() {
+ ArgumentFormatter.Options = [.. ArgumentFormatter.Options, this];
+ return ArgumentFormatter;
+ }
+
+ public class ParameterFormat {
+ public string name { get; set; }
+ public string description { get; set; }
+ public bool required { get; set; }
+
+ public OptionFormat OptionFormat { get; private set; }
+
+ public ParameterFormat(OptionFormat optionBuilder) {
+ OptionFormat = optionBuilder;
+ }
+
+ public ParameterFormat Name(string name) {
+ this.name = name;
+ return this;
+ }
+ public ParameterFormat Description(string description) {
+ this.description = description;
+ return this;
+ }
+ public ParameterFormat Required(bool required) {
+ this.required = required;
+ return this;
+ }
+
+ public OptionFormat Finish() {
+ OptionFormat.parameters = [.. OptionFormat.parameters, this];
+ return OptionFormat;
+ }
+ }
+ }
+}
+
+public class HelpOptionFormat : ArgumentFormatter.OptionFormat {
+ public HelpOptionFormat(ArgumentFormatter argumentFormatter) : base(argumentFormatter) { }
+ public bool quit;
+ public HelpOptionFormat Quit(bool quit) {
+ this.quit = quit;
+ return this;
+ }
+}
+
+public class VersionOptionFormat : ArgumentFormatter.OptionFormat {
+ public VersionOptionFormat(ArgumentFormatter argumentFormatter) : base(argumentFormatter) { }
+ public bool quit;
+ public VersionOptionFormat Quit(bool quit) {
+ this.quit = quit;
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/Terminal/Arguments/ArgumentParameter.cs b/Terminal/Arguments/ArgumentParameter.cs
deleted file mode 100644
index c23555e..0000000
--- a/Terminal/Arguments/ArgumentParameter.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-namespace OxDED.Terminal.Arguments;
-
-///
-/// A parameter for an .
-///
-public class ArgumentParameter {
- ///
- /// The name of this argument parameter.
- ///
- public string name;
- ///
- /// The description of this argument parameter.
- ///
- public string? description;
- internal string? value;
- ///
- /// If this argument parameter has a value (should be yes).
- ///
- public bool HasValue { get => value != null; }
- ///
- /// The value of this argument parameter (error if it isn't parsed).
- ///
- ///
- public string Value { get {
- if (HasValue) {
- return value!;
- } else {
- throw new InvalidOperationException("This argument parameter has not been parsed.");
- }
- } }
- ///
- /// Creates an argument parameter.
- ///
- /// The name of this parameter.
- /// The description of this parameter (optional).
- public ArgumentParameter(string name, string? description = null) {
- this.name = name;
- this.description = description;
- }
- ///
- /// Sets the name of this parameter.
- ///
- /// The new name of this parameter.
- /// This parameter.
- public ArgumentParameter Name(string name) {
- this.name = name;
- return this;
- }
- ///
- /// Sets the description of this parameter.
- ///
- /// The new description of this parameter.
- /// This parameter.
- public ArgumentParameter Description(string? description) {
- this.description = description;
- return this;
- }
-}
\ No newline at end of file
diff --git a/Terminal/Arguments/ArgumentParser.cs b/Terminal/Arguments/ArgumentParser.cs
index a7d1224..b281545 100644
--- a/Terminal/Arguments/ArgumentParser.cs
+++ b/Terminal/Arguments/ArgumentParser.cs
@@ -1,420 +1,12 @@
namespace OxDED.Terminal.Arguments;
-// TODO: add docs
-
-///
-/// Helps you with parsing arguments.
-///
-public class ArgumentParser
-{
- ///
- /// This is the name of the application.
- ///
- public string? name = null;
- ///
- /// The description of the application.
- ///
- public string? description = null;
- private Argument? versionArgument = null;
- private Argument? helpArgument = null;
- ///
- /// The version of the application.
- ///
- public string? version = null;
- ///
- /// The arguments of the parser.
- ///
- public Dictionary arguments = [];
- ///
- /// The positional arguments of the parser.
- ///
- public List positionalArguments = [];
- ///
- /// Sets the help argument of the application parser.
- ///
- ///
- ///
- ///
- ///
- public ArgumentParser Help(IEnumerable? keys = null, bool showDescription = true, bool showVersion = false, bool shouldExit = true)
- {
- if (helpArgument != null)
- {
- RemoveArgument(helpArgument);
- }
- helpArgument = new Argument(keys ?? ["h", "help"], "Shows all the available arguments.");
- AddArgument(helpArgument, (Argument arg) =>
- {
- WriteHelp(showDescription, showVersion);
- if (shouldExit)
- {
- Environment.Exit(0);
- }
- });
- return this;
- }
- ///
- /// Sets the version of the application parser. And adds an argument.
- ///
- /// The version of the application.
- /// The keys for the parameter (default: v, version).
- ///
- ///
-
- public ArgumentParser Version(string version, IEnumerable? keys = null, bool shouldExit = true)
- {
- if (versionArgument != null)
- {
- RemoveArgument(versionArgument);
- }
- versionArgument = new Argument(keys ?? ["v", "version"], name == null ? "Shows the version of this application." : $"Shows the version of {name}."); // TODO: add documentation to first assign a name
- AddArgument(versionArgument, (Argument arg) =>
- {
- WriteVersion();
- if (shouldExit)
- {
- Environment.Exit(0);
- }
- });
- this.version = version;
- return this;
- }
- ///
- /// Sets the description of the application parser.
- ///
- public ArgumentParser Description(string? description)
- {
- this.description = description;
- return this;
- }
- ///
- /// Sets the name of the application parser.
- ///
- public ArgumentParser Name(string? name)
- {
- this.name = name;
- return this;
- }
- ///
- /// Removes a positional argument.
- ///
- public ArgumentParser RemovePositionalArgument(int position) {
- positionalArguments.RemoveAt(position);
- return this;
- }
- ///
- /// Removes a positional argument.
- ///
- public ArgumentParser RemovePositionalArgument(PositionalArgument argument) {
- positionalArguments.Remove(argument);
- return this;
- }
- ///
- /// Removes an argument.
- ///
- public ArgumentParser RemoveArgument(Argument argument)
- {
- foreach (string key in argument.keys)
- {
- arguments.Remove(key);
- }
- return this;
- }
- ///
- /// Adds an argument.
- ///
- public ArgumentParser AddArgument(Argument argument, ArgumentCallback? callback = null)
- {
- foreach (string key in argument.keys)
- {
- arguments.Add(key, argument);
- }
- if (callback != null)
- {
- OnArgument += (Argument arg) =>
- {
- if (arg.keys == argument.keys)
- {
- callback?.Invoke(arg);
- }
- };
- }
- return this;
- }
- ///
- /// Adds a positional argument.
- ///
- public ArgumentParser AddPositionalArgument(PositionalArgument argument, PositionalArgumentCallback? callback = null)
- {
- positionalArguments.Add(argument);
- if (callback != null)
- {
- OnPositionalArgument += (PositionalArgument arg) =>
- {
- if (arg.name == argument.name)
- {
- callback?.Invoke(arg);
- }
- };
- }
- return this;
- }
- ///
- /// Writes the help menu to the terminal.
- ///
- public void WriteHelp(bool showDescription = true, bool showVersion = false)
- {
- Terminal.WriteLine(GetHelp(showDescription, showVersion));
- }
- ///
- /// Writes the version to the terminal.
- ///
- public void WriteVersion()
- {
- Terminal.WriteLine(GetVersion());
- }
- private static string GetArgumentHelp(PositionalArgument arg, bool isRed = false)
- {
- return $"{(isRed ? Color.LightRed.ToForegroundANSI() : Color.Orange.ToForegroundANSI())}\u2520{ANSI.Styles.ResetAll} {arg.name}{(arg.description == null ? "" : ": "+arg.description)}\n";
- }
- private static string GetArgumentHelpName(string[] keys)
- {
- string result = "";
- for (int i = 0; i < keys.Length; i++)
- {
- string key = keys[i];
- result += key.Length == 1 ? "-" : "--";
- result += key;
- if (i != keys.Length - 1)
- {
- result += ", ";
- }
- }
- return result;
- }
- private static string GetArgumentHelp(Argument arg)
- {
- string result = $"{Color.DarkGreen.ToForegroundANSI()}\u2520{ANSI.Styles.ResetAll} {GetArgumentHelpName(arg.keys)}{(arg.description == null ? "" : ": "+arg.description)}\n";
- foreach (ArgumentParameter para in arg.parameters)
- {
- result += $"{Color.DarkGreen.ToForegroundANSI()}\u2503 \u2560{ANSI.Styles.ResetAll} {para.name}{(para.description == null ? "" : ": "+para.description)}\n";
- }
- return result;
+public class ArgumentParser {
+ public ArgumentFormatter Register { get; private set; }
+ public ArgumentParser(ArgumentFormatter register) {
+ Register = register;
}
- private string GetHelp(bool showDescription = true, bool showVersion = false, int positionalIndex = -1)
- {
- string result = $"{ANSI.Styles.Bold}{name}{ANSI.Styles.ResetBold} {((showVersion && version != null) ? version : "")}{((showDescription && description != null) ? '\n' + description : "")}\n\n";
- if (positionalArguments.Count > 0)
- {
- result += $"{Color.Orange.ToForegroundANSI()}\u250E\u2500\u2500{ANSI.Styles.ResetAll} Required Arguments\n";
- for (int i = 0; i < positionalArguments.Count; i++)
- {
- PositionalArgument arg = positionalArguments[i];
- if (positionalIndex <= i && positionalIndex != -1)
- {
- result += GetArgumentHelp(arg, true);
- }
- else
- {
- result += GetArgumentHelp(arg, false);
- }
+ public void Parse(string[] args) {
- }
- result += "\n";
- }
- if (arguments.Count > 0 || helpArgument != null || versionArgument != null)
- {
- result += $"{Color.DarkGreen.ToForegroundANSI()}\u250E\u2500\u2500{ANSI.Styles.ResetAll} Arguments\n";
- if (helpArgument != null)
- {
- result += $"\u2520 {GetArgumentHelpName(helpArgument.keys)}: {helpArgument.description}\n";
- }
- if (versionArgument != null)
- {
- result += $"\u2520 {GetArgumentHelpName(versionArgument.keys)}: {versionArgument.description}\n";
- }
- if (arguments.Count > 0)
- {
- foreach (Argument argument in arguments.Values.Distinct())
- {
- if (argument == versionArgument || argument == helpArgument)
- {
- continue;
- }
- result += GetArgumentHelp(argument);
- }
- }
- }
- return result;
}
- private string GetVersion()
- {
- return $"{ANSI.Styles.Bold}{name}{ANSI.Styles.ResetBold} {version ?? ""}{(description != null ? '\n' + description : "")}";
- }
- ///
- /// An event that is called when an argument is parsed.
- ///
- public event ArgumentCallback? OnArgument;
- ///
- /// An event that is called when a positional argument is parsed.
- ///
- public event PositionalArgumentCallback? OnPositionalArgument;
- ///
- /// An event that is called when the format is invalid.
- ///
- public event InvalidFormatCallback? OnInvalidFormatCallback;
- private void WriteInvalid(string message)
- {
- WriteHelp(false);
- OnInvalidFormatCallback?.Invoke(message);
- Terminal.WriteLine("\n" + message, new Style { ForegroundColor = Color.Red });
- Environment.Exit(1);
- }
- private void WriteNoArgument(string message, int positionalIndex)
- {
- Terminal.WriteLine(GetHelp(false, false, positionalIndex));
- OnInvalidFormatCallback?.Invoke(message);
- Terminal.WriteLine("\n" + message, new Style { ForegroundColor = Color.Red });
- Environment.Exit(1);
- }
- ///
- /// Parses the arguments.
- ///
- public bool Parse(string arguments)
- {
- return Parse(arguments.Split(' '));
- }
- ///
- /// Parses the arguments.
- ///
- public bool Parse(string[] arguments)
- {
- int positionalArgumentIndex = 0;
- Argument? parsingArgument = null;
- List parameters = [];
- bool isParsingArgument = false;
- foreach (string argument in arguments)
- {
- if (!isParsingArgument)
- {
- if (argument.StartsWith("--") && argument.Length > 2)
- {
- parsingArgument = GetArgument(argument[2..]);
- if (parsingArgument == null)
- {
- WriteInvalid("No such argument as: --" + argument[2..] + ".");
- return false;
- }
- else
- {
- isParsingArgument = true;
- }
- }
- else if (argument.StartsWith('-') && argument.Length > 1)
- {
- if (argument.Length >= 3)
- {
- WriteInvalid("Invalid symbol usage (-): " + argument + ".\n Should it be (--)?");
- }
- parsingArgument = GetArgument(argument[1].ToString());
- if (parsingArgument == null)
- {
- WriteInvalid("No such argument as: -" + argument[1] + ".");
- return false;
- }
- else
- {
- isParsingArgument = true;
- }
-
- }
- else
- {
- PositionalArgument? positionalArgument = GetPositionalArgument(positionalArgumentIndex);
- if (positionalArgument != null)
- {
- positionalArgument.value = argument;
- OnPositionalArgument?.Invoke(positionalArgument);
- positionalArgumentIndex++;
- }
- else
- {
- WriteInvalid("Too much positional arguments.");
- return false;
- }
- }
- }
- if (isParsingArgument)
- {
- if (!(parameters.Count - 1 >= parsingArgument!.parameters.Length))
- {
- parameters.Add(argument);
- }
- if (parameters.Count - 1 >= parsingArgument!.parameters.Length)
- {
- for (int j = 0; j < parsingArgument!.parameters.Length; j++)
- {
- parsingArgument!.parameters[j].value = parameters[j + 1];
- }
- OnArgument?.Invoke(parsingArgument);
- isParsingArgument = false;
- parameters = [];
- parsingArgument = null;
- }
- }
- }
- if (isParsingArgument)
- {
- WriteInvalid("Invalid argument parameters for " + parameters[0] + ".");
- return false;
- }
- if (positionalArguments.Count != positionalArgumentIndex)
- {
- WriteNoArgument("Not enough positional arguments.", positionalArgumentIndex);
- return false;
- }
-
- return true;
- }
- ///
- /// Gets an argument that is registered (null if it isn't registered).
- ///
- public Argument? GetArgument(string key)
- {
- if (!arguments.TryGetValue(key, out Argument? value))
- {
- return null;
- }
- return value;
- }
- ///
- /// Gets a positional argument at a location (in order as registered) (if there is one).
- ///
- public PositionalArgument? GetPositionalArgument(int pos)
- {
- return positionalArguments.Count > pos ? positionalArguments[pos] : null;
- }
- ///
- /// True if an argument is registered (not used).
- ///
- public bool HasArgument(string key)
- {
- return GetArgument(key) != null;
- }
- ///
- /// Gets all the registered arguments (not used).
- ///
- public Argument[] GetArguments()
- {
- return [.. arguments.Values.Distinct()];
- }
- ///
- /// Gets all the registered positional arguments.
- ///
- public PositionalArgument[] GetPositionalArguments()
- {
- return [.. positionalArguments];
- }
-
}
\ No newline at end of file
diff --git a/Terminal/Arguments/ArgumentParser_old.cs b/Terminal/Arguments/ArgumentParser_old.cs
new file mode 100644
index 0000000..e439b39
--- /dev/null
+++ b/Terminal/Arguments/ArgumentParser_old.cs
@@ -0,0 +1,348 @@
+namespace OxDED.Terminal.Arguments;
+
+///
+/// Helps you with parsing arguments.
+///
+public class ArgumentParserOld {
+ ///
+ /// This is the name of the application.
+ ///
+ public string? name = null;
+ ///
+ /// The description of the application.
+ ///
+ public string? description = null;
+ private Option? versionArgument = null;
+ private Option? helpArgument = null;
+ ///
+ /// The version of the application.
+ ///
+ public string? version = null;
+ ///
+ /// The arguments of the parser.
+ ///
+ public Dictionary options = [];
+ ///
+ /// The arguments of the parser.
+ ///
+ public List arguments = [];
+ ///
+ /// Sets the help argument of the application parser.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public ArgumentParserOld Help(IEnumerable? keys = null, bool showDescription = true, bool showVersion = false, bool shouldExit = true) {
+ if (helpArgument != null) {
+ RemoveOption(helpArgument);
+ }
+ helpArgument = new Option(keys ?? ["h", "help"], "Shows all the available arguments.");
+ AddOption(helpArgument, (Option arg) => {
+ WriteHelp(showDescription, showVersion);
+ if (shouldExit) {
+ Environment.Exit(0);
+ }
+ });
+ return this;
+ }
+ ///
+ /// Sets the version of the application parser. And adds an argument.
+ ///
+ /// The version of the application.
+ /// The keys for the parameter (default: v, version).
+ ///
+ ///
+
+ public ArgumentParserOld Version(string version, IEnumerable? keys = null, bool shouldExit = true) {
+ if (versionArgument != null) {
+ RemoveOption(versionArgument);
+ }
+ versionArgument = new Option(keys ?? ["v", "version"], name == null ? "Shows the version of this application." : $"Shows the version of {name}."); // TODO: add documentation to first assign a name
+ AddOption(versionArgument, (Option arg) => {
+ WriteVersion();
+ if (shouldExit) {
+ Environment.Exit(0);
+ }
+ });
+ this.version = version;
+ return this;
+ }
+ ///
+ /// Sets the description of the application parser.
+ ///
+ public ArgumentParserOld Description(string? description) {
+ this.description = description;
+ return this;
+ }
+ ///
+ /// Sets the name of the application parser.
+ ///
+ public ArgumentParserOld Name(string? name) {
+ this.name = name;
+ return this;
+ }
+ ///
+ /// Removes a argument.
+ ///
+ public ArgumentParserOld RemoveArgument(int position) {
+ arguments.RemoveAt(position);
+ return this;
+ }
+ ///
+ /// Removes a argument.
+ ///
+ public ArgumentParserOld RemoveArgument(Argument argument) {
+ arguments.Remove(argument);
+ return this;
+ }
+ ///
+ /// Removes an argument.
+ ///
+ public ArgumentParserOld RemoveOption(Option argument) {
+ foreach (string key in argument.keys) {
+ options.Remove(key);
+ }
+ return this;
+ }
+ ///
+ /// Adds an argument.
+ ///
+ public ArgumentParserOld AddOption(Option argument, OptionCallback? callback = null) {
+ foreach (string key in argument.keys) {
+ options.Add(key, argument);
+ }
+ if (callback != null) {
+ OnOption += (Option arg) => {
+ if (arg.keys == argument.keys) {
+ callback?.Invoke(arg);
+ }
+ };
+ }
+ return this;
+ }
+ ///
+ /// Adds a argument.
+ ///
+ public ArgumentParserOld AddArgument(Argument argument, ArgumentCallback? callback = null) {
+ arguments.Add(argument);
+ if (callback != null) {
+ OnArgument += (Argument arg) => {
+ if (arg.name == argument.name) {
+ callback?.Invoke(arg);
+ }
+ };
+ }
+ return this;
+ }
+ ///
+ /// Writes the help menu to the terminal.
+ ///
+ public void WriteHelp(bool showDescription = true, bool showVersion = false) {
+ Terminal.WriteLine(GetHelp(showDescription, showVersion));
+ }
+ ///
+ /// Writes the version to the terminal.
+ ///
+ public void WriteVersion() {
+ Terminal.WriteLine(GetVersion());
+ }
+ private static string GetArgumentHelp(Argument arg, bool isRed = false) {
+ return $"{(isRed ? Color.LightRed.ToForegroundANSI() : Color.Orange.ToForegroundANSI())}\u2520{ANSI.Styles.ResetAll} {arg.name}{(arg.description == null ? "" : ": "+arg.description)}\n";
+ }
+ private static string GetArgumentHelpName(string[] keys) {
+ string result = "";
+ for (int i = 0; i < keys.Length; i++) {
+ string key = keys[i];
+ result += key.Length == 1 ? "-" : "--";
+ result += key;
+ if (i != keys.Length - 1) {
+ result += ", ";
+ }
+ }
+ return result;
+ }
+ private static string GetArgumentHelp(Option arg) {
+ string result = $"{Color.DarkGreen.ToForegroundANSI()}\u2520{ANSI.Styles.ResetAll} {GetArgumentHelpName(arg.keys)}{(arg.description == null ? "" : ": "+arg.description)}\n";
+ foreach (OptionParameter para in arg.parameters) {
+ result += $"{Color.DarkGreen.ToForegroundANSI()}\u2503 \u2560{ANSI.Styles.ResetAll} {para.name}{(para.description == null ? "" : ": "+para.description)}\n";
+ }
+ return result;
+ }
+ private string GetHelp(bool showDescription = true, bool showVersion = false, int positionalIndex = -1) {
+ string result = $"{ANSI.Styles.Bold}{name}{ANSI.Styles.ResetBold} {((showVersion && version != null) ? version : "")}{((showDescription && description != null) ? '\n' + description : "")}\n\n";
+
+ if (arguments.Count > 0) {
+ result += $"{Color.Orange.ToForegroundANSI()}\u250E\u2500\u2500{ANSI.Styles.ResetAll} Required Arguments\n";
+ for (int i = 0; i < arguments.Count; i++) {
+ Argument arg = arguments[i];
+ if (positionalIndex <= i && positionalIndex != -1) {
+ result += GetArgumentHelp(arg, true);
+ }
+ else {
+ result += GetArgumentHelp(arg, false);
+ }
+
+ }
+ result += "\n";
+ }
+ if (options.Count > 0 || helpArgument != null || versionArgument != null) {
+ result += $"{Color.DarkGreen.ToForegroundANSI()}\u250E\u2500\u2500{ANSI.Styles.ResetAll} Arguments\n";
+ if (helpArgument != null) {
+ result += $"\u2520 {GetArgumentHelpName(helpArgument.keys)}: {helpArgument.description}\n";
+ }
+ if (versionArgument != null) {
+ result += $"\u2520 {GetArgumentHelpName(versionArgument.keys)}: {versionArgument.description}\n";
+ }
+ if (options.Count > 0) {
+ foreach (Option argument in options.Values.Distinct()) {
+ if (argument == versionArgument || argument == helpArgument) {
+ continue;
+ }
+ result += GetArgumentHelp(argument);
+ }
+ }
+ }
+ return result;
+ }
+ private string GetVersion() {
+ return $"{ANSI.Styles.Bold}{name}{ANSI.Styles.ResetBold} {version ?? ""}{(description != null ? '\n' + description : "")}";
+ }
+ ///
+ /// An event that is called when an option is parsed.
+ ///
+ public event OptionCallback? OnOption;
+ ///
+ /// An event that is called when a argument is parsed.
+ ///
+ public event ArgumentCallback? OnArgument;
+ ///
+ /// An event that is called when the format is invalid.
+ ///
+ public event InvalidFormatCallback? OnInvalidFormatCallback;
+ private void WriteInvalid(string message) {
+ WriteHelp(false);
+ OnInvalidFormatCallback?.Invoke(message);
+ Terminal.WriteLine("\n" + message, new Style { ForegroundColor = Color.Red });
+ Environment.Exit(1);
+ }
+ private void WriteNoArgument(string message, int positionalIndex) {
+ Terminal.WriteLine(GetHelp(false, false, positionalIndex));
+ OnInvalidFormatCallback?.Invoke(message);
+ Terminal.WriteLine("\n" + message, new Style { ForegroundColor = Color.Red });
+ Environment.Exit(1);
+ }
+ ///
+ /// Parses the arguments.
+ ///
+ public bool Parse(string arguments) {
+ return Parse(arguments.Split(' '));
+ }
+ ///
+ /// Parses the arguments.
+ ///
+ public bool Parse(string[] arguments) {
+ int argumentIndex = 0;
+ Option? parsingOption = null;
+ List parameters = [];
+ bool isParsingArgument = false;
+ foreach (string raw in arguments) {
+ if (!isParsingArgument) {
+ if (raw.StartsWith("--") && raw.Length > 2) {
+ parsingOption = GetArgument(raw[2..]);
+ if (parsingOption == null) {
+ WriteInvalid("No such argument as: --" + raw[2..] + ".");
+ return false;
+ }
+ else {
+ isParsingArgument = true;
+ }
+ }
+ else if (raw.StartsWith('-') && raw.Length > 1) {
+ if (raw.Length >= 3) {
+ WriteInvalid("Invalid symbol usage (-): " + raw + ".\n Should it be (--)?");
+ }
+ parsingOption = GetArgument(raw[1].ToString());
+ if (parsingOption == null) {
+ WriteInvalid("No such argument as: -" + raw[1] + ".");
+ return false;
+ }
+ else {
+ isParsingArgument = true;
+ }
+
+ }
+ else {
+ Argument? argument = GetArgument(argumentIndex);
+ if (argument != null) {
+ argument.value = raw;
+ OnArgument?.Invoke(argument);
+ argumentIndex++;
+ }
+ else {
+ WriteInvalid("Too much arguments.");
+ return false;
+ }
+ }
+ }
+ if (isParsingArgument) {
+ if (!(parameters.Count - 1 >= parsingOption!.parameters.Length)) {
+ parameters.Add(raw);
+ }
+ if (parameters.Count - 1 >= parsingOption!.parameters.Length) {
+ for (int j = 0; j < parsingOption!.parameters.Length; j++) {
+ parsingOption!.parameters[j].value = parameters[j + 1];
+ }
+ OnOption?.Invoke(parsingOption);
+ isParsingArgument = false;
+ parameters = [];
+ parsingOption = null;
+ }
+ }
+ }
+ if (isParsingArgument) {
+ WriteInvalid("Invalid option parameters for " + parameters[0] + ".");
+ return false;
+ }
+ if (this.arguments.Count != argumentIndex) {
+ WriteNoArgument("Not enough arguments.", argumentIndex);
+ return false;
+ }
+
+ return true;
+ }
+ ///
+ /// Gets an argument that is registered (null if it isn't registered).
+ ///
+ public Option? GetArgument(string key) {
+ if (!options.TryGetValue(key, out Option? value)) {
+ return null;
+ }
+ return value;
+ }
+ ///
+ /// Gets a argument at a location (in order as registered) (if there is one).
+ ///
+ public Argument? GetArgument(int pos) {
+ return arguments.Count > pos ? arguments[pos] : null;
+ }
+ ///
+ /// True if an argument is registered (not used).
+ ///
+ public bool HasArgument(string key) {
+ return GetArgument(key) != null;
+ }
+ ///
+ /// Gets all the registered arguments (not used).
+ ///
+ public Option[] GetOptions() {
+ return [.. options.Values.Distinct()];
+ }
+ ///
+ /// Gets all the registered arguments.
+ ///
+ public Argument[] GetArguments() {
+ return [.. arguments];
+ }
+
+}
\ No newline at end of file
diff --git a/Terminal/Arguments/Delegates.cs b/Terminal/Arguments/Delegates.cs
index 58d6c9d..afafe01 100644
--- a/Terminal/Arguments/Delegates.cs
+++ b/Terminal/Arguments/Delegates.cs
@@ -4,12 +4,12 @@ namespace OxDED.Terminal.Arguments;
/// An callback for when an argument has been parsed.
///
/// The argument that has been parsed.
-public delegate void ArgumentCallback(Argument argument);
+public delegate void OptionCallback(Option argument);
///
/// An callback for when an postitional argument has been parsed.
///
/// The positional argument that has been parsed.
-public delegate void PositionalArgumentCallback(PositionalArgument argument);
+public delegate void ArgumentCallback(Argument argument);
///
/// An callback for when the parsing has failed.
///
diff --git a/Terminal/Arguments/Option.cs b/Terminal/Arguments/Option.cs
new file mode 100644
index 0000000..07bfcd9
--- /dev/null
+++ b/Terminal/Arguments/Option.cs
@@ -0,0 +1,157 @@
+namespace OxDED.Terminal.Arguments;
+
+///
+/// Represents an optional argument (e.g. -f, --foo).
+///
+public partial class Option : ICloneable, IEquatable