ArgParser.java

/*
 * Copyright 2022 Terminal Utils Authors
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package net.morimekta.terminal.args;

import net.morimekta.collect.UnmodifiableList;
import net.morimekta.strings.NamingUtil;
import net.morimekta.terminal.args.impl.ArgParserImpl;

import java.util.List;
import java.util.function.Consumer;

/**
 * Interface for parsing command-line arguments. Supports options, flags,
 * positional arguments, and sub-commands.
 */
public interface ArgParser {
    /**
     * @param program     The program name for the argument parser.
     * @param version     The program version.
     * @param description The program description.
     * @return The argument parser builder.
     */
    static ArgParser.Builder argParser(String program, String version, String description) {
        return new ArgParserImpl.BuilderImpl(null, program, version, description);
    }

    /**
     * The name of the program. Should be essentially what the user types on
     * the command line to invoke the program.
     *
     * @return The program name.
     */
    String getProgram();

    /**
     * The program version string.
     *
     * @return The program version.
     */
    String getVersion();

    /**
     * Short description of the program. Should be the string that is shown
     * on the top of the program usage help, usually just a few words. Should
     * be capitalized.
     *
     * @return The program description.
     */
    String getDescription();

    /**
     * @return The parent argument parser if any.
     */
    ArgParser getParent();

    /**
     * @return List of options on the argument parser.
     */
    List<Option> getOptions();

    /**
     * @return List of arguments on the argument parser.
     */
    List<Arg> getArguments();

    /**
     * @param <SubCommandDef> The subcommand definition.
     * @return The set of subcommands. Null of subcommands not configured.
     */
    <SubCommandDef> SubCommandSet<SubCommandDef> getSubCommandSet();

    /**
     * Validate all options and arguments.
     */
    void validate() throws ArgException;

    /**
     * Parse arguments from the main method.
     *
     * @param args The argument list.
     * @return The argument parser.
     */
    ArgParser parse(List<String> args);

    /**
     * Parse arguments from the main method.
     *
     * @param args The argument list.
     * @return The argument parser.
     */
    default ArgParser parse(String... args) {
        return parse(UnmodifiableList.asList(args));
    }

    /**
     * Builder for an argument parser.
     */
    interface Builder extends ArgParserBuilder {
        /**
         * An argument
         *
         * @param arg The argument to add.
         * @param <A> The base argument type.
         * @return The argument parser builder.
         */
        <A extends Arg> Builder add(A arg);

        /**
         * Add an argument builder.
         *
         * @param argBuilder The argument to add.
         * @param <A>        The base argument type.
         * @return The argument parser builder.
         */
        <A extends Arg> Builder add(Arg.Builder<A> argBuilder);

        /**
         * Which naming format to use as default for generating flag names.
         *
         * @param format The maing format.
         * @return The argument parser builder.
         */
        Builder generateArgsNameFormat(ArgNameFormat format);

        /**
         * Generate arguments to fill in the POJO config object.
         *
         * @param config The config object to fill in.
         * @return The argument parser builder.
         */
        Builder generateArgs(Object config);

        /**
         * Start adding sub-commands, and get the sub-command builder. The
         * sub-command-set method can only be called once.
         *
         * @param name            Name to for sub-command name in short usage.
         * @param usage           Usage string for sub-commands.
         * @param consumer        Consumer to accept subcommand after parsing.
         * @param <SubCommandDef> The subcommand type.
         * @return The sub-command builder.
         */
        <SubCommandDef> SubCommandSet.Builder<SubCommandDef> withSubCommands(
                String name,
                String usage,
                Consumer<SubCommandDef> consumer);
    }
}