All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.com.github.ajalt.clikt.parameters.groups.ChoiceGroup.kt Maven / Gradle / Ivy

package com.github.ajalt.clikt.parameters.groups

import com.github.ajalt.clikt.core.BadParameterValue
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.Context
import com.github.ajalt.clikt.core.MissingParameter
import com.github.ajalt.clikt.parameters.internal.NullableLateinit
import com.github.ajalt.clikt.parameters.options.Option
import com.github.ajalt.clikt.parameters.options.OptionDelegate
import com.github.ajalt.clikt.parameters.options.RawOption
import com.github.ajalt.clikt.parameters.options.switch
import com.github.ajalt.clikt.parameters.types.choice
import com.github.ajalt.clikt.parsers.OptionParser
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

class ChoiceGroup(
        internal val option: OptionDelegate,
        internal val groups: Map,
        internal val transform: (GroupT?) -> OutT
) : ParameterGroupDelegate {
    override val groupName: String? = null
    override val groupHelp: String? = null
    private var value: OutT by NullableLateinit("Cannot read from option delegate before parsing command line")
    private var chosenGroup: OptionGroup? = null

    override fun provideDelegate(thisRef: CliktCommand, prop: KProperty<*>): ReadOnlyProperty {
        option.provideDelegate(thisRef, prop) // infer the option name and register it
        thisRef.registerOptionGroup(this)
        for ((_, group) in groups) {
            for (option in group.options) {
                option.parameterGroup = this
                option.groupName = group.groupName
                thisRef.registerOption(option)
            }
        }
        return this
    }

    override fun getValue(thisRef: CliktCommand, property: KProperty<*>): OutT = value

    override fun finalize(context: Context, invocationsByOption: Map>) {
        val key = option.value
        if (key == null) {
            value = transform(null)
            // Finalize the group so that default groups have their options finalized
            (value as? OptionGroup)?.let { g ->
                g.finalize(context, invocationsByOption.filterKeys { it in g.options })
                chosenGroup = g
            }
            return
        }

        val group = groups[key]
                ?: throw BadParameterValue(
                        "invalid choice: $key. (choose from ${groups.keys.joinToString()})",
                        option,
                        context
                )
        group.finalize(context, invocationsByOption.filterKeys { it in group.options })
        chosenGroup = group
        value = transform(group)
    }

    override fun postValidate(context: Context) {
        chosenGroup?.options?.forEach { it.postValidate(context) }
    }
}

/**
 * Convert the option to an option group based on a fixed set of values.
 *
 * ### Example:
 *
 * ```
 * option().groupChoice(mapOf("foo" to FooOptionGroup(), "bar" to BarOptionGroup()))
 * ```
 *
 * @see com.github.ajalt.clikt.parameters.types.choice
 */
fun  RawOption.groupChoice(choices: Map): ChoiceGroup {
    return ChoiceGroup(choice(choices.mapValues { it.key }), choices) { it }
}

/**
 * Convert the option to an option group based on a fixed set of values.
 *
 * ### Example:
 *
 * ```
 * option().groupChoice("foo" to FooOptionGroup(), "bar" to BarOptionGroup())
 * ```
 *
 * @see com.github.ajalt.clikt.parameters.types.choice
 */
fun  RawOption.groupChoice(vararg choices: Pair): ChoiceGroup {
    return groupChoice(choices.toMap())
}

/**
 * If a [groupChoice] or [groupSwitch] option is not called on the command line, throw a
 * [MissingParameter] exception.
 *
 * ### Example:
 *
 * ```
 * option().groupChoice("foo" to FooOptionGroup(), "bar" to BarOptionGroup()).required()
 * ```
 */
fun  ChoiceGroup.required(): ChoiceGroup {
    return ChoiceGroup(option, groups) { it ?: throw MissingParameter(option) }
}

/**
 * Convert the option into a set of flags that each map to an option group.
 *
 * ### Example:
 *
 * ```
 * option().groupSwitch(mapOf("--foo" to FooOptionGroup(), "--bar" to BarOptionGroup()))
 * ```
 */
fun  RawOption.groupSwitch(choices: Map): ChoiceGroup {
    return ChoiceGroup(switch(choices.mapValues { it.key }), choices) { it }
}

/**
 * Convert the option into a set of flags that each map to an option group.
 *
 * ### Example:
 *
 * ```
 * option().groupSwitch("--foo" to FooOptionGroup(), "--bar" to BarOptionGroup())
 * ```
 */
fun  RawOption.groupSwitch(vararg choices: Pair): ChoiceGroup {
    return groupSwitch(choices.toMap())
}

/**
 * If a [groupChoice] or [groupSwitch] option is not called on the command line, use the value of
 * the group with a switch or choice [name].
 *
 * ### Example:
 *
 * ```
 * option().groupChoice("foo" to FooOptionGroup(), "bar" to BarOptionGroup()).defaultByName("foo")
 * option().groupSwitch("--foo" to FooOptionGroup(), "--bar" to BarOptionGroup()).defaultByName("--bar")
 * ```
 *
 * @throws IllegalArgumentException if [name] is not one of the option's choice/switch names.
 */
fun  ChoiceGroup.defaultByName(name: String): ChoiceGroup {
    require(name in groups) { "invalid default name $name (must be one of ${groups.keys})" }
    return ChoiceGroup(option, groups) { it ?: groups.getValue(name) }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy