Skip to content

Commit

Permalink
Update help formatter to leverage Kotter styles
Browse files Browse the repository at this point in the history
  • Loading branch information
bitspittle committed Oct 4, 2024
1 parent fe505b7 commit acd3973
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 2 deletions.
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ freemarker = "2.3.31"
jreleaser = "1.14.0"
kobweb-cli = "0.9.17-SNAPSHOT"
kobweb-libs = "0.19.1"
kotter = "1.1.2"
kotter = "1.2.0-SNAPSHOT"
kotlin = "2.0.20"
kotlinx-coroutines = "1.8.1"
okhttp = "4.12.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package com.varabyte.kobweb.cli.help

import com.github.ajalt.clikt.core.Context
import com.github.ajalt.clikt.core.UsageError
import com.github.ajalt.clikt.output.AbstractHelpFormatter
import com.github.ajalt.clikt.output.HelpFormatter
import com.varabyte.kotter.foundation.render.offscreen
import com.varabyte.kotter.foundation.text.black
import com.varabyte.kotter.foundation.text.blue
import com.varabyte.kotter.foundation.text.bold
import com.varabyte.kotter.foundation.text.green
import com.varabyte.kotter.foundation.text.red
import com.varabyte.kotter.foundation.text.text
import com.varabyte.kotter.runtime.render.RenderScope
import com.varabyte.kotterx.text.shiftRight
import com.varabyte.kotterx.util.consoleOutputFor
import kotlinx.coroutines.runBlocking

class KotterHelpFormatter(
/**
* The current command's context.
*/
context: Context,
/**
* The string to show before the names of required options, or null to not show a mark.
*/
requiredOptionMarker: String? = null,
/**
* If true, the default values will be shown in the help text for parameters that have them.
*/
showDefaultValues: Boolean = false,
/**
* If true, a tag indicating the parameter is required will be shown after the description of
* required parameters.
*/
showRequiredTag: Boolean = false,
) : AbstractHelpFormatter<String>(
context,
requiredOptionMarker,
showDefaultValues,
showRequiredTag
) {
override fun formatHelp(
error: UsageError?,
prolog: String,
epilog: String,
parameters: List<HelpFormatter.ParameterHelp>,
programName: String,
): String {
val parts = collectHelpParts(error, prolog, epilog, parameters, programName)
return parts.joinToString("\n\n") { it.removeSuffix("\n") }
}

private fun RenderScope.styleTitle(block: RenderScope.() -> Unit) = block()
private fun RenderScope.styleProgramName(block: RenderScope.() -> Unit) = bold { blue(scopedBlock = block) }
private fun RenderScope.styleParams(block: RenderScope.() -> Unit) = green(scopedBlock = block)
private fun RenderScope.styleError(block: RenderScope.() -> Unit) = red(scopedBlock = block)
private fun RenderScope.styleProlog(block: RenderScope.() -> Unit) = block()
private fun RenderScope.styleEpilog(block: RenderScope.() -> Unit) = block()
private fun RenderScope.styleOptional(block: RenderScope.() -> Unit) = black(isBright = false, scopedBlock = block)

override fun renderError(
parameters: List<HelpFormatter.ParameterHelp>,
error: UsageError,
) = consoleOutputFor {
styleError { text(renderErrorString(parameters, error)) }
}

override fun renderUsage(
parameters: List<HelpFormatter.ParameterHelp>,
programName: String,
) = consoleOutputFor {
val params = renderUsageParametersString(parameters)
val title = localization.usageTitle()

styleTitle { text(title) }
text(" ")
styleProgramName { text(programName) }
if (params.isNotEmpty()) {
text(" ")
styleParams { text(params) }
}
}

override fun renderProlog(prolog: String): String {
return consoleOutputFor {
shiftRight(2) {
styleProlog {
text(prolog)
}
}
}
}

override fun renderEpilog(epilog: String): String {
return consoleOutputFor {
styleEpilog { text(epilog) }
}
}

override fun renderParameters(parameters: List<HelpFormatter.ParameterHelp>): String {
return collectParameterSections(parameters).joinToString("\n\n") { (title, content) ->
"$title\n$content"
}
}

override fun renderOptionGroup(
help: String?,
parameters: List<HelpFormatter.ParameterHelp.Option>,
): String = buildString {
if (help != null) {
appendLine()
appendLine(help)
appendLine()
}
val options = parameters.map { renderOptionDefinition(it) }
append(buildParameterList(options))
}

override fun renderDefinitionTerm(row: DefinitionRow): String {
val rowMarker = row.marker
val termPrefix = when {
rowMarker.isNullOrEmpty() -> " "
else -> rowMarker + " ".drop(rowMarker.length).ifEmpty { " " }
}
return termPrefix + row.term
}

override fun renderDefinitionDescription(row: DefinitionRow): String = row.description

override fun buildParameterList(rows: List<DefinitionRow>): String {
val termLength = (rows.maxOfOrNull { it.term.length } ?: 0) + 4
return rows.joinToString("\n") {
val term = renderDefinitionTerm(it)
val definition = renderDefinitionDescription(it).ifBlank { null }
val separator = " ".repeat(termLength - term.length)
listOfNotNull(term, definition).joinToString(separator)
}
}
}
3 changes: 2 additions & 1 deletion kobweb/src/main/kotlin/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import com.varabyte.kobweb.cli.common.version.reportUpdateAvailable
import com.varabyte.kobweb.cli.conf.handleConf
import com.varabyte.kobweb.cli.create.handleCreate
import com.varabyte.kobweb.cli.export.handleExport
import com.varabyte.kobweb.cli.help.KotterHelpFormatter
import com.varabyte.kobweb.cli.list.handleList
import com.varabyte.kobweb.cli.run.handleRun
import com.varabyte.kobweb.cli.stop.handleStop
Expand Down Expand Up @@ -185,7 +186,7 @@ fun main(args: Array<String>) {
init {
context {
helpFormatter = { context ->
PlaintextHelpFormatter(
KotterHelpFormatter(
context = context,
showDefaultValues = true,
)
Expand Down

0 comments on commit acd3973

Please sign in to comment.