1

Define your Command

@Command.Define
class MyProgram {
	@Argument.Define(required = true, positional = true)
	public String name;

	@Argument.Define(type = StringArgumentType.class)
	public Optional<String> surname;

	@Argument.Define(names = {"age", "a"}, prefix = Argument.Prefix.PLUS)
	public int age = 18;
}

2

Put the stuff together

public static void main(String[] args) {
    var myProgram = ArgumentParser.parseFromInto(MyProgram.class, args);

    System.out.printf(
        "Welcome %s! You are %d years old.%n",
        myProgram.name, myProgram.age
    );

    // if no surname was specified, we'll show "none" instead
    System.out.printf("The surname of the user is %s.", myProgram.surname.orElse("none"));
}

3

And use it

$ my-program michael +a20
Welcome michael! You are 20 years old.
The surname of the user is none.

Features

Readable errors

Make the users of your software be glad they made that error. Completely customizable error messages with different error levels.
$ josh ! --number 2 sub1 --required 1 --number 121

 ┌─WARNING
my-program josh ! --number 2 sub1 --required 1 --number 121
 │ The user '!' was not found.
 └────────────────── ───── ── ─


Automated help messages

Detailed help messages automatically generated for you, based on the structure of your commands.
$ my-program --help

my-program:

   This is the description of my program. What do you think about it? Oh by the way,
   don't forget to use the argument!

   Example1Type(user/u) --test Integer --help/h --counter/c --number Double[0.0-15.23] {sub1}

Description:

   Example1Type(user/u):
      Specify the user/s to use.

   --help/h:
      Shows this message.

   --number Double[0.0-15.23]:
      The value that matters the most (not really). Hey, this thing is generated
      automatically as well!: A high precision floating point number.
      Must be between 0.0 and 15.23. (Inclusive)

Sub-Commands:

   sub1:
      Now this is the description of the subcommand inside the main command.


Here's some more extra information about my program. Really don't know how to fill this out...

Rich text formatting

Use tools that easily allow you to format text in descriptions with colors, and other text formatting when displaying it on the terminal.
command.setDescription(
	"<color=cyan>Hello <format=b,i>world!<format=reset> "
	+ "<format=u>Here's some more <color=black:magenta>text<format=reset>"
)
Hello world! Here's some more text

When setting the description of elements, you can use the formatting tags that Lanat provides you with. (As seen above). You are not limited with just coloring or formatting, tags can also be used to embed the description of other elements, for example. Note that new custom tags can be created as well, with their own functionality.

Design your own Argument Types

Effortlessly create your own sub-parsers that later will be used to parse the values an argument receives. Lanat comes with many Argument Types already made for you.

Heres's an example of how the Argument Types are used. In this case, by using the EnumArgumentType we can create an argument that takes an enum value.

Creating the type

/**
 * An argument type that takes an enum value.
 * By supplying a default value in the constructor, the enum type is inferred.
 * <p>
 * The user can specify the enum value by its name, case insensitive.
 * </p>
 * @param <T> The enum type.
 */
public class EnumArgumentType<T extends Enum<T>> extends ArgumentType<T> {
	private final @NotNull T @NotNull [] values;

	/**
	 * Creates a new enum argument type.
	 * @param defaultValue The default value of the enum type. This is also used to infer the type of the enum.
	 */
	public EnumArgumentType(@NotNull T defaultValue) {
		super(defaultValue);
		this.values = defaultValue.getDeclaringClass().getEnumConstants();
	}

	@Override
	public T parseValues(@NotNull String @NotNull [] args) {
		for (var enumValue : this.values) {
			if (enumValue.name().equalsIgnoreCase(args[0])) {
				return enumValue;
			}
		}
		this.addError("Invalid enum value: '" + args[0] + "'.");
		return null;
	}

	@Override
	public @NotNull TextFormatter getRepresentation() {
		final var fmt = new TextFormatter("(");
		for (var i = 0; i < this.values.length; i++) {
			final var value = this.values[i];

			// if value is the default value, make it bold and yellow
			if (value == this.getInitialValue())
				fmt.concat(new TextFormatter(value.name())
					.withForegroundColor(Color.YELLOW)
					.addFormat(FormatOption.BOLD)
				);
			else
				fmt.concat(value.name());


			if (i < this.values.length - 1)
				fmt.concat(" | ");
		}
		return fmt.concat(")");
	}

Using the type

Create an enum with the options you want to allow the user to choose from.
enum Options {
	ACTIVATE,
	DEACTIVATE,
	TOGGLE // this is the default value
}

Then, create an EnumArgumentType with the default value we want to use specified in the constructor.

Once created, we can use it in an Argument.

Argument.create(
	new EnumArgumentType<>(Options.TOGGLE),
	"option"
);

Finally, let Lanat take care of the rest! If the user writes the name of the enum value, it will be parsed correctly and you'll get the actual enum value as a result once parsed.

Here's how the argument would look like in the help message generated:

--option (ACTIVATE | DEACTIVATE | )

And much more!

Get started

Add the repository

https://repsy.io/mvn/darvil/java

And add the dependency!

com.darvil:lanat:+

Let's begin

If you aren't feeling brave, feel free to check out the wiki, which includes a full tutorial on how to get started with the basics of Lanat (and the not so-basic stuff!)

Documentation
Created by darvil82

Source code of this site can be found here