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

org.incendo.cloud.kotlin.MutableCommandBuilder.kt Maven / Gradle / Ivy

The newest version!
//
// MIT License
//
// Copyright (c) 2024 Incendo
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package org.incendo.cloud.kotlin

import io.leangen.geantyref.TypeToken
import org.incendo.cloud.Command
import org.incendo.cloud.CommandManager
import org.incendo.cloud.component.CommandComponent
import org.incendo.cloud.component.TypedCommandComponent
import org.incendo.cloud.description.CommandDescription
import org.incendo.cloud.description.Description
import org.incendo.cloud.execution.CommandExecutionHandler
import org.incendo.cloud.key.CloudKey
import org.incendo.cloud.kotlin.extension.command
import org.incendo.cloud.kotlin.extension.senderType
import org.incendo.cloud.parser.ParserDescriptor
import org.incendo.cloud.parser.flag.CommandFlag
import org.incendo.cloud.permission.Permission
import kotlin.reflect.KClass

/**
 * A mutable [Command.Builder] wrapper, providing functions to assist in creating commands using the
 * Kotlin builder DSL style
 *
 * @property commandBuilder the command builder to mutate
 * @property commandManager the command manager which will own this command
 * @constructor Create a new [MutableCommandBuilder]
 */
public class MutableCommandBuilder(
    commandBuilder: Command.Builder,
    private val commandManager: CommandManager
) {
    /**
     * The command builder that is being mutated by this [MutableCommandBuilder] instance.
     *
     * This is public so that this can be returned to a command builder for interop with java apis.
     */
    public var commandBuilder: Command.Builder = commandBuilder
        private set

    /**
     * Create a new [MutableCommandBuilder]
     *
     * @param name name for the root command node
     * @param description description for the root command node
     * @param aliases aliases for the root command node
     * @param commandManager the command manager which will own this command
     */
    public constructor(
        name: String,
        description: Description = Description.empty(),
        aliases: Array = emptyArray(),
        commandManager: CommandManager
    ) : this(commandManager.commandBuilder(name, description, *aliases), commandManager)

    /**
     * Create a new [MutableCommandBuilder] and invoke the provided receiver lambda on it
     *
     * @param name name for the root command node
     * @param description description for the root command node
     * @param aliases aliases for the root command node
     * @param commandManager the command manager which will own this command
     * @param lambda receiver lambda which will be invoked on the new builder
     */
    public constructor(
        name: String,
        description: Description = Description.empty(),
        aliases: Array = emptyArray(),
        commandManager: CommandManager,
        lambda: MutableCommandBuilder.() -> Unit
    ) : this(name, description, aliases, commandManager) {
        lambda(this)
    }

    /**
     * Build a [Command] from the current state of this builder
     *
     * @return built command
     */
    public fun build(): Command = this.commandBuilder.build()

    /**
     * Invoke the provided receiver lambda on this builder, then build a [Command] from the
     * resulting state
     *
     * @param lambda receiver lambda which will be invoked on builder before building
     * @return built command
     */
    public fun build(lambda: MutableCommandBuilder.() -> Unit): Command {
        lambda(this)
        return this.commandBuilder.build()
    }

    /**
     * Modify this [MutableCommandBuilder]'s internal [Command.Builder] with a unary function
     *
     * @param mutator mutator function
     * @return this mutable builder
     */
    public fun mutate(
        mutator: (Command.Builder) -> Command.Builder
    ): MutableCommandBuilder {
        this.commandBuilder = mutator(this.commandBuilder)
        return this
    }

    private fun onlyMutate(mutator: (Command.Builder) -> Command.Builder) {
        mutate(mutator)
    }

    /**
     * Make a new copy of this [MutableCommandBuilder]
     *
     * @return a copy of this mutable builder
     */
    public fun copy(): MutableCommandBuilder =
        MutableCommandBuilder(this.commandBuilder, this.commandManager)

    /**
     * Make a new copy of this [MutableCommandBuilder] and invoke the provided receiver lambda on it
     *
     * @param lambda receiver lambda which will be invoked on the new builder
     * @return a copy of this mutable builder
     */
    public fun copy(lambda: MutableCommandBuilder.() -> Unit): MutableCommandBuilder =
        copy().apply { lambda(this) }

    /**
     * Make a new copy of this [MutableCommandBuilder], append a literal, and invoke the provided
     * receiver lambda on it
     *
     * @param literal name for the literal
     * @param description description for the literal
     * @param lambda receiver lambda which will be invoked on the new builder
     * @return a copy of this mutable builder
     */
    public fun copy(
        literal: String,
        description: Description,
        lambda: MutableCommandBuilder.() -> Unit
    ): MutableCommandBuilder =
        copy().apply {
            literal(literal, description)
            lambda(this)
        }

    /**
     * Make a new copy of this [MutableCommandBuilder], append a literal, and invoke the provided
     * receiver lambda on it
     *
     * @param literal name for the literal
     * @param lambda receiver lambda which will be invoked on the new builder
     * @return a copy of this mutable builder
     */
    public fun copy(
        literal: String,
        lambda: MutableCommandBuilder.() -> Unit
    ): MutableCommandBuilder =
        copy().apply {
            literal(literal)
            lambda(this)
        }

    /**
     * Build and register this command with the owning command manager
     *
     * @return this mutable builder
     * @see [CommandManager.command]
     */
    public fun register(): MutableCommandBuilder = apply { this.commandManager.command(this) }

    /**
     * Create a new copy of this mutable builder, act on it with a receiver lambda, and then
     * register it with the owning command manager
     *
     * @param lambda receiver lambda which will be invoked on the new builder
     * @return the new mutable builder
     * @see [CommandManager.command]
     */
    public fun registerCopy(lambda: MutableCommandBuilder.() -> Unit): MutableCommandBuilder =
        copy(lambda).register()

    /**
     * Create a new copy of this mutable builder, append a literal, act on it with a receiver
     * lambda, and then register it with the owning command manager
     *
     * @param literal name for the literal
     * @param lambda receiver lambda which will be invoked on the new builder
     * @return the new mutable builder
     * @see [CommandManager.command]
     */
    public fun registerCopy(
        literal: String,
        lambda: MutableCommandBuilder.() -> Unit
    ): MutableCommandBuilder = copy(literal, lambda).register()

    /**
     * Create a new copy of this mutable builder, append a literal, act on it with a receiver
     * lambda, and then register it with the owning command manager
     *
     * @param literal name for the literal
     * @param description description for the literal
     * @param lambda receiver lambda which will be invoked on the new builder
     * @return the new mutable builder
     * @see [CommandManager.command]
     */
    public fun registerCopy(
        literal: String,
        description: Description,
        lambda: MutableCommandBuilder.() -> Unit
    ): MutableCommandBuilder = copy(literal, description, lambda).register()

    /**
     * Set the value for a certain [CloudKey] in the command meta storage for this builder
     *
     * @param T value type
     * @param key the key to set a value for
     * @param value new value
     * @return this mutable builder
     */
    public fun  meta(key: CloudKey, value: T): MutableCommandBuilder =
        mutate {
            it.meta(key, value)
        }

    /**
     * Set the value for a certain [CloudKey] in the command meta storage for this builder
     *
     * @param T value type
     * @param value new value
     * @return this mutable builder
     */
    public infix fun  CloudKey.to(value: T): MutableCommandBuilder =
        meta(this, value)

    /**
     * Field to get and set the command description for this command builder
     */
    public var commandDescription: CommandDescription
        get() = this.commandBuilder.commandDescription()
        set(commandDescription) {
            onlyMutate {
                it.commandDescription(commandDescription)
            }
        }

    /**
     * Sets the command description meta for this command
     *
     * @param commandDescription command description
     * @return this mutable builder
     */
    public fun commandDescription(commandDescription: CommandDescription): MutableCommandBuilder = mutate {
        it.commandDescription(commandDescription)
    }

    /**
     * Specify a required sender type
     *
     * @param T sender type
     * @return this mutable builder
     */
    public inline fun  senderType(): MutableCommandBuilder = mutate {
        it.senderType(T::class)
    }

    /**
     * Specify a required sender type
     *
     * @param type sender type
     * @return this mutable builder
     */
    public fun senderType(type: KClass): MutableCommandBuilder = mutate {
        it.senderType(type)
    }

    /**
     * Field to get and set the required sender type for this command builder
     *
     */
    public var senderType: TypeToken?
        get() = this.commandBuilder.senderType()
        set(type) {
            if (type == null) throw UnsupportedOperationException("Cannot set a null sender type")
            onlyMutate { it.senderType(type) }
        }

    /**
     * Specify a required sender type
     *
     * @param type sender type
     * @return this mutable builder
     */
    public fun senderType(type: Class): MutableCommandBuilder = mutate {
        it.senderType(type)
    }

    /**
     * Specify a permission required to execute this command
     *
     * @param permission permission string
     * @return this mutable builder
     */
    public fun permission(permission: String): MutableCommandBuilder = mutate {
        it.permission(permission)
    }

    /**
     * Specify a permission required to execute this command
     *
     * @param permission command permission
     * @return this mutable builder
     */
    public fun permission(permission: Permission): MutableCommandBuilder = mutate {
        it.permission(permission)
    }

    /**
     * Field to get and set the required permission for this command builder
     *
     */
    public var permission: String
        get() = this.commandBuilder.commandPermission().toString()
        set(permission) = onlyMutate { it.permission(permission) }

    /**
     * Field to get and set the required permission for this command builder
     *
     */
    public var commandPermission: Permission
        get() = this.commandBuilder.commandPermission()
        set(permission) = onlyMutate { it.permission(permission) }

    /**
     * Adds a new component to this command
     *
     * @param component component to add
     * @return this mutable builder
     */
    public fun argument(
        component: CommandComponent
    ): MutableCommandBuilder = mutate { it.argument(component) }

    /**
     * Adds a new component to this command
     *
     * @param component component to add
     * @return this mutable builder
     */
    public fun  argument(
        component: CommandComponent.Builder
    ): MutableCommandBuilder = mutate { it.argument(component) }

    /**
     * Adds a new component to this command
     *
     * @param component component to add
     * @return this mutable builder
     */
    public fun required(
        component: CommandComponent.Builder
    ): MutableCommandBuilder = mutate { it.required(component) }

    /**
     * Adds a new component to this command
     *
     * @param component component to add
     * @return this mutable builder
     */
    public fun optional(
        component: CommandComponent.Builder
    ): MutableCommandBuilder = mutate { it.optional(component) }

    /**
     * Adds a new component to this command
     *
     * @param name the name of the component
     * @param parser the parser of the component
     * @param mutator mutator of the component
     * @param T the type of the component
     */
    public fun  required(
        name: String,
        parser: ParserDescriptor,
        mutator: CommandComponent.Builder.() -> Unit = {}
    ): MutableCommandBuilder = argument(CommandComponent.builder(name, parser).also(mutator))

    /**
     * Adds a new component to this command
     *
     * @param name the name of the component
     * @param parser the parser of the component
     * @param mutator mutator of the component
     * @param T the type of the component
     */
    public fun  optional(
        name: String,
        parser: ParserDescriptor,
        mutator: CommandComponent.Builder.() -> Unit = {}
    ): MutableCommandBuilder = argument(CommandComponent.builder(name, parser).optional().also(mutator))

    /**
     * Adds a new component to this command
     *
     * @param name the name of the component
     * @param parser the parser of the component
     * @param mutator mutator of the component
     * @param T the type of the component
     */
    public fun  required(
        name: CloudKey,
        parser: ParserDescriptor,
        mutator: CommandComponent.Builder.() -> Unit = {}
    ): MutableCommandBuilder = argument(CommandComponent.builder(name, parser).also(mutator))

    /**
     * Adds a new component to this command
     *
     * @param name the name of the component
     * @param parser the parser of the component
     * @param mutator mutator of the component
     * @param T the type of the component
     */
    public fun  optional(
        name: CloudKey,
        parser: ParserDescriptor,
        mutator: CommandComponent.Builder.() -> Unit = {}
    ): MutableCommandBuilder = argument(CommandComponent.builder(name, parser).optional().also(mutator))

    /**
     * Add a new argument to this command
     *
     * @param componentSupplier supplier of the component
     * @return this mutable builder
     */
    public fun argument(
        componentSupplier: () -> CommandComponent
    ): MutableCommandBuilder = argument(componentSupplier())

    /**
     * Add a new argument to this command
     *
     * @param T value type
     * @param componentSupplier supplier of the component
     * @return this mutable builder
     */
    public fun  required(
        componentSupplier: () -> CommandComponent.Builder
    ): MutableCommandBuilder = mutate { it.required(componentSupplier()) }

    /**
     * Add a new argument to this command
     *
     * @param componentSupplier supplier of the component
     * @return this mutable builder
     */
    public fun optional(
        componentSupplier: () -> CommandComponent.Builder
    ): MutableCommandBuilder = optional(componentSupplier())

    /**
     * Add a new literal argument to this command
     *
     * @param name main argument name
     * @param description literal description
     * @param aliases argument aliases
     * @return this mutable builder
     */
    public fun literal(
        name: String,
        description: Description = Description.empty(),
        vararg aliases: String
    ): MutableCommandBuilder = mutate { it.literal(name, description, *aliases) }

    /**
     * Set the [CommandExecutionHandler] for this builder
     *
     * @param handler command execution handler
     * @return this mutable builder
     */
    public fun handler(handler: CommandExecutionHandler): MutableCommandBuilder = mutate {
        it.handler(handler)
    }

    /**
     * Set the [CommandExecutionHandler] for this builder
     *
     * @param handler command execution handler
     * @return this mutable builder
     */
    public fun futureHandler(handler: CommandExecutionHandler.FutureCommandExecutionHandler): MutableCommandBuilder =
        mutate { it.futureHandler(handler) }

    /**
     * Sets a new command execution handler that invokes the given {@code handler} before the current
     * {@link #handler() handler}.
     *
     * @param handler the handler to invoke before the current handler
     * @return this mutable builder
     */
    public fun prependHandler(handler: CommandExecutionHandler): MutableCommandBuilder = mutate {
        it.prependHandler(handler)
    }

    /**
     * Sets a new command execution handler that invokes the given {@code handler} after the current
     * {@link #handler() handler}.
     *
     * @param handler the handler to invoke after the current handler
     * @return this mutable builder
     */
    public fun appendHandler(handler: CommandExecutionHandler): MutableCommandBuilder = mutate {
        it.appendHandler(handler)
    }

    /**
     * Add a new flag component to this command
     *
     * @param name name of the flag
     * @param aliases flag aliases
     * @param description description of the flag
     * @param parser parser for the flag
     * @param  the component value type
     * @return this mutable builder
     */
    public fun  flag(
        name: String,
        aliases: Array = emptyArray(),
        description: Description = Description.empty(),
        parser: ParserDescriptor
    ): MutableCommandBuilder = mutate {
        it.flag(
            this.commandManager
                .flagBuilder(name)
                .withAliases(*aliases)
                .withDescription(description)
                .withComponent(parser)
                .build()
        )
    }

    /**
     * Add a new flag component to this command
     *
     * @param name name of the flag
     * @param aliases flag aliases
     * @param description description of the flag
     * @param builderModifier flag builder modifier
     * @param T the component value type
     * @return this mutable builder
     */
    public fun  flag(
        name: String,
        aliases: Array = emptyArray(),
        description: Description = Description.empty(),
        builderModifier: CommandFlag.Builder.() -> CommandFlag.Builder
    ): MutableCommandBuilder = mutate {
        it.flag(
            this.commandManager
                .flagBuilder(name)
                .withAliases(*aliases)
                .withDescription(description)
                .builderModifier()
                .build()
        )
    }

    /**
     * Add a new flag component to this command
     *
     * @param name name of the flag
     * @param aliases flag aliases
     * @param description description of the flag
     * @param component component for the flag
     * @param  the component value type
     * @return this mutable builder
     */
    public fun  flag(
        name: String,
        aliases: Array = emptyArray(),
        description: Description = Description.empty(),
        component: TypedCommandComponent
    ): MutableCommandBuilder = mutate {
        it.flag(
            this.commandManager
                .flagBuilder(name)
                .withAliases(*aliases)
                .withDescription(description)
                .withComponent(component)
                .build()
        )
    }

    /**
     * Add a new flag component to this command
     *
     * @param name name of the flag
     * @param aliases flag aliases
     * @param description description of the flag
     * @param componentBuilder command component builder for the flag
     * @param  the component value type
     * @return this mutable builder
     */
    public fun  flag(
        name: String,
        aliases: Array = emptyArray(),
        description: Description = Description.empty(),
        componentBuilder: CommandComponent.Builder
    ): MutableCommandBuilder = mutate {
        it.flag(
            this.commandManager
                .flagBuilder(name)
                .withAliases(*aliases)
                .withDescription(description)
                .withComponent(componentBuilder)
                .build()
        )
    }

    /**
     * Add a new presence flag component to this command
     *
     * @param name name of the flag
     * @param aliases flag aliases
     * @param description description of the flag
     * @return this mutable builder
     */
    public fun flag(
        name: String,
        aliases: Array = emptyArray(),
        description: Description = Description.empty()
    ): MutableCommandBuilder = mutate {
        it.flag(
            this.commandManager
                .flagBuilder(name)
                .withAliases(*aliases)
                .withDescription(description)
                .build()
        )
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy