1

Define your Command

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

	@Argument.Define(type = String.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.
$ my-program 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 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 a valid enum value.
 * <p>
 * The user can specify any of the enum values by their names.
 * The names are case-insensitive.
 * </p>
 * @param <T> The enum type.
 */
public class EnumArgumentType<T extends Enum<T>> extends SingleValueListArgumentType<T> {
	/**
	 * Creates a new enum argument type.
	 * @param clazz The class of the enum type to use.
	 */
	public EnumArgumentType(@NotNull Class<T> clazz) {
		super(clazz.getEnumConstants());
		this.setDefault(clazz);
	}

	/**
	 * Sets the default value of the enum type by using the {@link Default} annotation.
	 * @param clazz The class of the enum type to use.
	 */
	private void setDefault(@NotNull Class<T> clazz) {
		var defaultFields = Arrays.stream(clazz.getDeclaredFields())
			.filter(f -> f.isAnnotationPresent(Default.class))
			.toList();

		if (defaultFields.isEmpty())
			return;

		if (defaultFields.size() > 1)
			throw new IllegalArgumentException("Only one default value can be set.");

		this.setInitialValue(
			Arrays.stream(this.listValues)
				.filter(v -> v.name().equals(defaultFields.get(0).getName()))
				.findFirst()
				.orElseThrow()
		);
	}

	@Override
	protected @NotNull String valueToString(@NotNull T value) {
		try {
			return Optional.ofNullable(value.getClass().getField(value.name()).getAnnotation(WithName.class))
				.map(WithName::value)

Using the type

Create an enum with the options you want to allow the user to choose from. You can also specify the default value by annotating the enum value properly.
enum Option {
	ACTIVATE,
	DEACTIVATE,
	@EnumArgumentType.Default
	TOGGLE
}
Then, simply define the argument in your command and use the enum as the type of the argument.
public class MyCommand extends CommandTemplate {
	@Argument.Define
	public Option 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