Skip to content

Commit

Permalink
Add custom property support to AppConfig.
Browse files Browse the repository at this point in the history
This enables plugin authors to easily set and retrieve configuration options
for the end developer.

Closes #380.
  • Loading branch information
nanodeath committed Apr 27, 2021
1 parent adcda81 commit 1943730
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import kotlin.jvm.JvmStatic
* Object that encapsulates the configuration parameters for an [Application].
* This includes properties such as the shape of the cursor, the color of the cursor
* and if the cursor should blink or not.
*
* Typically you'll want to construct this using [AppConfigBuilder], not AppConfig's constructor.
*/
@Suppress("ArrayInDataClass")
data class AppConfig(
Expand Down Expand Up @@ -114,14 +116,33 @@ data class AppConfig(
* If set [iconPath] will contain the path of the resource that points
* to an icon image that will be used in the application window.
*/
val iconPath: String? = null
val iconPath: String? = null,
/**
* If set, contains custom properties that plugin authors can set and access.
*/
internal val customProperties: Map<AppConfigKey<*>, Any> = emptyMap()
) {

/**
* Tells whether bounds check should be performed or not.
* This depends on the various debug mode configurations.
*/
fun shouldCheckBounds() = debugMode.not() || (debugMode && debugConfig.relaxBoundsCheck.not())
fun shouldCheckBounds() = !debugMode || !debugConfig.relaxBoundsCheck

/**
* Retrieve a custom property set earlier using [AppConfigBuilder.withProperty]. If this property was
* never set, returns `null`.
*
* ### End Developers
*
* You probably don't need to call this API.
*/
fun <T : Any> getProperty(key: AppConfigKey<T>): T? {
val value: Any? = customProperties[key]
// This is actually a safe cast because of the way `withProperty` is defined.
@Suppress("UNCHECKED_CAST")
return value as T?
}

companion object {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.hexworks.zircon.api.application

/**
* This simple interface is used to set and retrieve custom properties on [AppConfig]
* in a typesafe way.
*/
interface AppConfigKey<T>
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,25 @@ data class AppConfigBuilder(
)
}

/**
* Adds a custom property into the AppConfig object. This can later be retrieved using [AppConfig.getProperty].
*
* ### End Developers
*
* You probably don't need to call this API.
*
* ### Plugin Developers
*
* Write extension methods off of [AppConfigBuilder] that call this API in order to enable end developers
* to pass configuration in through AppConfig that your plugin can later use. It's recommended that [key]
* be an `object` with minimal visibility (e.g. `internal`).
*/
fun <T : Any> withProperty(key: AppConfigKey<T>, value: T): AppConfigBuilder = also {
config = config.copy(
customProperties = config.customProperties + (key to value)
)
}

@Deprecated("This will be removed in the next version, as the behavior is inconsistent.")
fun withFullScreen(screenWidth: Int, screenHeight: Int) = also {
throw UnsupportedOperationException("Unstable api, use withFullScreen(true) instead")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import org.hexworks.zircon.api.builder.application.AppConfigBuilder
import org.hexworks.zircon.api.color.ANSITileColor
import org.junit.Test

private object TestAppConfigKey : AppConfigKey<String>
private object TestAppConfigKey2 : AppConfigKey<String>

class AppConfigTest {

@Test
Expand All @@ -29,6 +32,44 @@ class AppConfigTest {
.isEqualTo(HAS_CLIPBOARD)
}

@Test
fun propertyUnset() {
val appConfig = AppConfigBuilder.newBuilder().build()
assertThat(appConfig.getProperty(TestAppConfigKey))
.isNull()
}

@Test
fun propertySet() {
val appConfig = AppConfigBuilder.newBuilder()
.withProperty(TestAppConfigKey, "foo")
.build()
assertThat(appConfig.getProperty(TestAppConfigKey))
.isEqualTo("foo")
}

@Test
fun propertyOverwrite() {
val appConfig = AppConfigBuilder.newBuilder()
.withProperty(TestAppConfigKey, "foo")
.withProperty(TestAppConfigKey, "bar")
.build()
assertThat(appConfig.getProperty(TestAppConfigKey))
.isEqualTo("bar")
}

@Test
fun propertyMultiple() {
val appConfig = AppConfigBuilder.newBuilder()
.withProperty(TestAppConfigKey, "foo")
.withProperty(TestAppConfigKey2, "bar")
.build()
assertThat(appConfig.getProperty(TestAppConfigKey))
.isEqualTo("foo")
assertThat(appConfig.getProperty(TestAppConfigKey2))
.isEqualTo("bar")
}

companion object {
val BLINK_TIME = 5L
val CURSOR_STYLE = CursorStyle.UNDER_BAR
Expand Down

0 comments on commit 1943730

Please sign in to comment.