Adds a CLI Argument parser
This commit is contained in:
parent
4ac95f605b
commit
7d045bd49f
8 changed files with 328 additions and 1 deletions
98
lib/argparse/Args.dart
Normal file
98
lib/argparse/Args.dart
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
import 'package:libac_dart/argparse/types/Bool.dart';
|
||||||
|
import 'package:libac_dart/argparse/types/Integers.dart';
|
||||||
|
import 'package:libac_dart/argparse/types/String.dart';
|
||||||
|
|
||||||
|
abstract class Argument<T> {
|
||||||
|
bool hasValue = false;
|
||||||
|
String name;
|
||||||
|
|
||||||
|
String description;
|
||||||
|
|
||||||
|
Argument({required this.name, this.description = ""});
|
||||||
|
|
||||||
|
T getValue() {
|
||||||
|
throw new UnimplementedError("This argument type has no value");
|
||||||
|
}
|
||||||
|
|
||||||
|
Argument<T> clone() {
|
||||||
|
Argument<T> arg;
|
||||||
|
switch (getType()) {
|
||||||
|
case ArgumentType.BOOL:
|
||||||
|
{
|
||||||
|
arg = new BoolArgument(name: name) as Argument<T>;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ArgumentType.STRING:
|
||||||
|
{
|
||||||
|
arg = new StringArgument(name: name, value: getValue() as String)
|
||||||
|
as Argument<T>;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ArgumentType.INTEGER:
|
||||||
|
{
|
||||||
|
arg = new IntegerArgument(name: name, value: getValue() as int)
|
||||||
|
as Argument<T>;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ArgumentType.DOUBLE:
|
||||||
|
{
|
||||||
|
arg = new DoubleArgument(name: name, value: getValue() as double)
|
||||||
|
as Argument<T>;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgumentType getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ArgumentType { STRING, BOOL, INTEGER, DOUBLE }
|
||||||
|
|
||||||
|
class Arguments {
|
||||||
|
Map<String, Argument> _args = {};
|
||||||
|
|
||||||
|
void setArg(Argument arg) {
|
||||||
|
_args[arg.name] = arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get count => _args.length;
|
||||||
|
|
||||||
|
List<String> getArgNames() {
|
||||||
|
List<String> args = [];
|
||||||
|
for (MapEntry<String, Argument> entry in _args.entries) {
|
||||||
|
args.add(entry.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
Argument? getArg(String name) {
|
||||||
|
if (hasArg(name))
|
||||||
|
return _args[name];
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasArg(String name) {
|
||||||
|
return _args.containsKey(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool argHasValue(String name) {
|
||||||
|
if (hasArg(name)) {
|
||||||
|
Argument arg = getArg(name)!;
|
||||||
|
return arg.hasValue;
|
||||||
|
} else
|
||||||
|
throw new Exception("Warning: No such argument");
|
||||||
|
}
|
||||||
|
|
||||||
|
Arguments clone() {
|
||||||
|
Arguments args = Arguments();
|
||||||
|
for (MapEntry<String, Argument> entry in _args.entries) {
|
||||||
|
args.setArg(entry.value.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
}
|
20
lib/argparse/Builder.dart
Normal file
20
lib/argparse/Builder.dart
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import 'Args.dart';
|
||||||
|
|
||||||
|
class ArgumentsBuilder {
|
||||||
|
Arguments _args = Arguments();
|
||||||
|
|
||||||
|
ArgumentsBuilder._();
|
||||||
|
|
||||||
|
factory ArgumentsBuilder.builder() {
|
||||||
|
return ArgumentsBuilder._();
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgumentsBuilder withArgument(Argument arg) {
|
||||||
|
_args.setArg(arg);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Arguments build() {
|
||||||
|
return _args;
|
||||||
|
}
|
||||||
|
}
|
108
lib/argparse/CLIHelper.dart
Normal file
108
lib/argparse/CLIHelper.dart
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
import 'package:libac_dart/argparse/types/Bool.dart';
|
||||||
|
import 'package:libac_dart/argparse/types/Integers.dart';
|
||||||
|
import 'package:libac_dart/argparse/types/String.dart';
|
||||||
|
import 'package:libac_dart/nbt/Stream.dart';
|
||||||
|
|
||||||
|
import 'Args.dart';
|
||||||
|
|
||||||
|
class CLIHelper {
|
||||||
|
/// Generates usage info
|
||||||
|
///
|
||||||
|
/// This will create a standard CLI Usage info string that can be directly printed to the console after the program header
|
||||||
|
static String makeArgCLIHelp(Arguments defaults) {
|
||||||
|
StringBuilder builder = StringBuilder();
|
||||||
|
List<String> argNames = defaults.getArgNames();
|
||||||
|
|
||||||
|
for (String name in argNames) {
|
||||||
|
builder.append("--${name}");
|
||||||
|
|
||||||
|
Argument arg = defaults.getArg(name)!;
|
||||||
|
if (arg.hasValue) {
|
||||||
|
builder.append("=<T>");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.append("\t\t\t${arg.description}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses and returns the arguments list with keeping defaults in mind
|
||||||
|
static Future<Arguments> parseArgs(
|
||||||
|
List<String> args, Arguments defaults) async {
|
||||||
|
Arguments arguments = defaults.clone();
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
Argument arg = await _parseArgument(args[i]);
|
||||||
|
Argument? defArg;
|
||||||
|
if (defaults.hasArg(arg.name)) defArg = defaults.getArg(arg.name)!;
|
||||||
|
|
||||||
|
if (!arg.hasValue) {
|
||||||
|
if (defArg != null) {
|
||||||
|
arg = defArg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments.setArg(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<Argument> _parseArgument(String arg) async {
|
||||||
|
if (arg.startsWith("--")) {
|
||||||
|
var parts = arg.split("=");
|
||||||
|
String name = await _getNamePart(parts[0]);
|
||||||
|
if (parts.length == 1)
|
||||||
|
return BoolArgument(name: name);
|
||||||
|
else if (parts.length == 2) {
|
||||||
|
String value = await _getValuePart(parts[1]);
|
||||||
|
ArgumentType typeOfArg = await _getArgumentType(value);
|
||||||
|
|
||||||
|
switch (typeOfArg) {
|
||||||
|
case ArgumentType.INTEGER:
|
||||||
|
{
|
||||||
|
return IntegerArgument(name: name, value: int.parse(value));
|
||||||
|
}
|
||||||
|
case ArgumentType.BOOL:
|
||||||
|
{
|
||||||
|
return BoolArgument(name: name);
|
||||||
|
}
|
||||||
|
case ArgumentType.DOUBLE:
|
||||||
|
{
|
||||||
|
return DoubleArgument(name: name, value: double.parse(value));
|
||||||
|
}
|
||||||
|
case ArgumentType.STRING:
|
||||||
|
{
|
||||||
|
return StringArgument(name: name, value: value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
throw new Exception("Argument is malformed");
|
||||||
|
} else
|
||||||
|
throw new Exception("Not in a valid format");
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<String> _getNamePart(String value) async {
|
||||||
|
return value.substring(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<String> _getValuePart(String entry) async {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<ArgumentType> _getArgumentType(String input) async {
|
||||||
|
try {
|
||||||
|
int.parse(input);
|
||||||
|
return ArgumentType.INTEGER;
|
||||||
|
} catch (E) {}
|
||||||
|
try {
|
||||||
|
double.parse(input);
|
||||||
|
return ArgumentType.DOUBLE;
|
||||||
|
} catch (E) {}
|
||||||
|
|
||||||
|
if (input.isEmpty)
|
||||||
|
return ArgumentType.BOOL;
|
||||||
|
else
|
||||||
|
return ArgumentType.STRING;
|
||||||
|
}
|
||||||
|
}
|
4
lib/argparse/README.md
Normal file
4
lib/argparse/README.md
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
ArgParse
|
||||||
|
==========
|
||||||
|
_________
|
||||||
|
This is almost directly copied in its entirety from a known working argument parser I wrote in Java. This is located at https://github.com/AriasCreations/LibAC in package: `dev.zontreck.ariaslib.args`
|
24
lib/argparse/types/Bool.dart
Normal file
24
lib/argparse/types/Bool.dart
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import 'package:libac_dart/argparse/Args.dart';
|
||||||
|
|
||||||
|
class BoolArgument extends Argument<bool> {
|
||||||
|
bool _value = false;
|
||||||
|
BoolArgument({required super.name, super.description = ""}) {
|
||||||
|
hasValue = true;
|
||||||
|
_value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
ArgumentType getType() {
|
||||||
|
return ArgumentType.BOOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool getValue() {
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return "BooleanArgument{ ${name}=${_value} }";
|
||||||
|
}
|
||||||
|
}
|
49
lib/argparse/types/Integers.dart
Normal file
49
lib/argparse/types/Integers.dart
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import 'package:libac_dart/argparse/Args.dart';
|
||||||
|
|
||||||
|
class IntegerArgument extends Argument<int> {
|
||||||
|
final int value;
|
||||||
|
|
||||||
|
IntegerArgument(
|
||||||
|
{required super.name, required this.value, super.description = ""}) {
|
||||||
|
hasValue = value != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
ArgumentType getType() {
|
||||||
|
return ArgumentType.INTEGER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return "IntegerArgument{ ${name}=${value} }";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DoubleArgument extends Argument<double> {
|
||||||
|
final double value;
|
||||||
|
|
||||||
|
DoubleArgument(
|
||||||
|
{required super.name, required this.value, super.description = ""}) {
|
||||||
|
hasValue = value != 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
ArgumentType getType() {
|
||||||
|
return ArgumentType.DOUBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
double getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return "DoubleArgument{ ${name}=${value} }";
|
||||||
|
}
|
||||||
|
}
|
24
lib/argparse/types/String.dart
Normal file
24
lib/argparse/types/String.dart
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import 'package:libac_dart/argparse/Args.dart';
|
||||||
|
|
||||||
|
class StringArgument extends Argument<String> {
|
||||||
|
final String value;
|
||||||
|
|
||||||
|
StringArgument({required super.name, required this.value}) {
|
||||||
|
hasValue = value.isNotEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
ArgumentType getType() {
|
||||||
|
return ArgumentType.STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return "StringArgument{ ${name}=${value} }";
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
name: libac_dart
|
name: libac_dart
|
||||||
description: "Aria's Creations code library"
|
description: "Aria's Creations code library"
|
||||||
version: 1.0.37
|
version: 1.1.070224+2109
|
||||||
homepage: "https://zontreck.com"
|
homepage: "https://zontreck.com"
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue