package dev.isxander.yacl3.dsl import dev.isxander.yacl3.api.* import net.minecraft.network.chat.CommonComponents import net.minecraft.network.chat.Component import java.util.concurrent.CompletableFuture import kotlin.properties.ReadOnlyProperty interface Buildable { val built: CompletableFuture fun build(): T } fun CompletableFuture.onReady(block: (T) -> Unit) = this.whenComplete { result, _ -> result?.let(block) } operator fun CompletableFuture>.get(id: String): CompletableFuture = thenCompose { it[id] } typealias FutureOption = CompletableFuture> fun CompletableFuture.futureRef(id: String): FutureOption = thenCompose { it.futureRef(id) } fun CompletableFuture.futureRef(): RegisterableDelegateProvider> = RegisterableDelegateProvider({ this.futureRef(it) }, null) fun YetAnotherConfigLib(id: String, block: RootDsl.() -> Unit) = RootDslImpl(id).apply(block).build() interface ParentRegistrar { fun register(id: String, registrant: T): T fun register(id: String, block: DSL.() -> Unit): T /** Registers a registrant via delegation - if id is not provided, the delegated property name is used */ fun registering(id: String? = null, block: DSL.() -> Unit): RegisterableActionDelegateProvider /** Creates a delegated future reference to a registrant that may or may not exist yet */ val futureRef: ReadOnlyProperty> /** Creates a future reference to a registrant that may or may not exist yet */ fun futureRef(id: String): CompletableFuture /** Gets a registrant with the id, if it exists */ fun ref(id: String): T? /** Creates a delegated property that returns a registrant with a matching id, or null if it does not exist at the time of calling */ val ref: ReadOnlyProperty operator fun get(id: String): CompletableFuture } interface OptionRegistrar { /** Registers an option that has already been built. */ fun > register(id: String, option: OPT): OPT /** Registers a regular option */ fun register(id: String, block: OptionDsl.() -> Unit): Option /** Registers a regular option via delegation */ fun registering(id: String? = null, block: OptionDsl.() -> Unit): RegisterableActionDelegateProvider, Option> fun futureRef(id: String): CompletableFuture> fun futureRef(): RegisterableDelegateProvider>> fun ref(id: String? = null): ReadOnlyProperty?> fun registerLabel(id: String): LabelOption val registeringLabel: RegisterableDelegateProvider fun registerLabel(id: String, text: Component): LabelOption fun registerLabel(id: String, builder: TextLineBuilderDsl.() -> Unit): LabelOption fun registerButton(id: String, block: ButtonOptionDsl.() -> Unit): ButtonOption fun registeringButton(id: String? = null, block: ButtonOptionDsl.() -> Unit): RegisterableActionDelegateProvider } typealias CategoryRegistrar = ParentRegistrar typealias GroupRegistrar = ParentRegistrar interface RootDsl { val rootKey: String val rootId: String val thisRoot: CompletableFuture val categories: CategoryRegistrar fun title(component: Component) fun title(block: () -> Component) fun screenInit(block: () -> Unit) fun save(block: () -> Unit) } interface CategoryDsl : Buildable { val categoryKey: String val categoryId: String val thisCategory: CompletableFuture val groups: GroupRegistrar val rootOptions: OptionRegistrar fun name(component: Component) fun name(block: () -> Component) fun tooltip(vararg component: Component) fun tooltip(block: TextLineBuilderDsl.() -> Unit) } interface GroupDsl : Buildable { val groupKey: String val groupId: String val thisGroup: CompletableFuture val options: OptionRegistrar fun name(component: Component) fun name(block: () -> Component) fun description(description: OptionDescription) fun descriptionBuilder(block: OptionDescription.Builder.() -> Unit) fun OptionDescription.Builder.addDefaultText(lines: Int? = null) = addDefaultText("$groupKey.description", lines) } interface OptionDsl : Option.Builder, Buildable> { val optionKey: String val optionId: String val thisOption: CompletableFuture> fun OptionDescription.Builder.addDefaultText(lines: Int? = null) = addDefaultText("$optionKey.description", lines) } interface ButtonOptionDsl : ButtonOption.Builder, Buildable { val optionKey: String val optionId: String val thisOption: CompletableFuture fun OptionDescription.Builder.addDefaultText(lines: Int? = null) = addDefaultText("$optionKey.description", lines) } interface TextLineBuilderDsl { fun text(component: Component) fun text(block: () -> Component) operator fun Component.unaryPlus() class Delegate(private val tooltipFunction: (Component) -> Unit) : TextLineBuilderDsl { override fun text(component: Component) { tooltipFunction(component) } override fun text(block: () -> Component) { text(block()) } override fun Component.unaryPlus() { text(this) } } companion object { fun createText(block: TextLineBuilderDsl.() -> Unit): Component { val text = Component.empty() var first = true val builder = Delegate { if (!first) text.append(CommonComponents.NEW_LINE) text.append(it) first = false } block(builder) return text } } }