0
# Options
1
2
Declarative option parsing with type conversion, validation, and default values. Options are declared as delegated properties with a fluent API for configuration.
3
4
## Capabilities
5
6
### Option Declaration
7
8
Create options using the `option()` function with support for multiple names, help text, environment variables, and completion.
9
10
```kotlin { .api }
11
/**
12
* Create an option
13
* @param names Option names (e.g., "-v", "--verbose")
14
* @param help Help text for the option
15
* @param metavar Placeholder for option value in help
16
* @param hidden Hide option from help
17
* @param helpTags Extra help formatter information
18
* @param envvar Environment variable name
19
* @param valueSourceKey Key for value source lookup
20
* @param completionCandidates Completion candidates
21
*/
22
fun CliktCommand.option(
23
vararg names: String,
24
help: String = "",
25
metavar: String? = null,
26
hidden: Boolean = false,
27
helpTags: Map<String, String> = emptyMap(),
28
envvar: String? = null,
29
valueSourceKey: String? = null,
30
completionCandidates: CompletionCandidates? = null
31
): RawOption
32
```
33
34
**Usage Examples:**
35
36
```kotlin
37
class MyCommand : CliktCommand() {
38
// Basic option
39
private val verbose by option("-v", "--verbose", help = "Enable verbose output")
40
41
// Option with environment variable
42
private val apiKey by option("--api-key", envvar = "API_KEY", help = "API key")
43
44
// Hidden option
45
private val debug by option("--debug", hidden = true, help = "Debug mode")
46
}
47
```
48
49
### Type Conversion
50
51
Convert option values to specific types with built-in converters.
52
53
```kotlin { .api }
54
/**
55
* Convert option value using custom conversion function
56
*/
57
inline fun <InT : Any, ValueT : Any> NullableOption<InT, InT>.convert(
58
metavar: String,
59
completionCandidates: CompletionCandidates? = null,
60
crossinline conversion: ValueConverter<InT, ValueT>
61
): NullableOption<ValueT, ValueT>
62
63
inline fun <InT : Any, ValueT : Any> NullableOption<InT, InT>.convert(
64
crossinline metavar: (Context) -> String,
65
completionCandidates: CompletionCandidates? = null,
66
crossinline conversion: ValueConverter<InT, ValueT>
67
): NullableOption<ValueT, ValueT>
68
69
/** Convert to Int */
70
fun RawOption.int(): NullableOption<Int, Int>
71
72
/** Convert to Long */
73
fun RawOption.long(): NullableOption<Long, Long>
74
75
/** Convert to Float */
76
fun RawOption.float(): NullableOption<Float, Float>
77
78
/** Convert to Double */
79
fun RawOption.double(): NullableOption<Double, Double>
80
81
/** Convert to Boolean */
82
fun RawOption.boolean(): NullableOption<Boolean, Boolean>
83
84
/** Convert to Enum */
85
fun <T : Enum<T>> RawOption.enum(): NullableOption<T, T>
86
87
/** Convert using choice map */
88
fun <T : Any> RawOption.choice(choices: Map<String, T>): NullableOption<T, T>
89
90
/** Convert using string choices */
91
fun RawOption.choice(vararg choices: String): NullableOption<String, String>
92
```
93
94
**Usage Examples:**
95
96
```kotlin
97
class MyCommand : CliktCommand() {
98
// Numeric options
99
private val port by option("--port", help = "Port number").int().default(8080)
100
private val timeout by option("--timeout", help = "Timeout in seconds").double()
101
102
// Enum option
103
enum class LogLevel { DEBUG, INFO, WARN, ERROR }
104
private val logLevel by option("--log-level").enum<LogLevel>().default(LogLevel.INFO)
105
106
// Choice option
107
private val format by option("--format").choice("json", "xml", "yaml").default("json")
108
109
// Custom conversion
110
private val date by option("--date").convert("DATE") { LocalDate.parse(it) }
111
}
112
```
113
114
### Value Processing
115
116
Process option values with defaults, validation, and multiple value handling.
117
118
```kotlin { .api }
119
/** Provide default value */
120
fun <T : Any> NullableOption<T, T>.default(value: T): OptionDelegate<T>
121
122
/** Provide lazy default value */
123
fun <T : Any> NullableOption<T, T>.defaultLazy(value: () -> T): OptionDelegate<T>
124
125
/** Mark option as required */
126
fun <T : Any> NullableOption<T, T>.required(): OptionDelegate<T>
127
128
/** Accept multiple values */
129
fun <T : Any> NullableOption<T, T>.multiple(): OptionDelegate<List<T>>
130
131
/** Convert multiple values to Set */
132
fun <T : Any> OptionDelegate<List<T>>.unique(): OptionDelegate<Set<T>>
133
134
/** Accept exactly 2 values */
135
fun <T : Any> NullableOption<T, T>.pair(): NullableOption<Pair<T, T>, T>
136
137
/** Accept exactly 3 values */
138
fun <T : Any> NullableOption<T, T>.triple(): NullableOption<Triple<T, T, T>, T>
139
```
140
141
**Usage Examples:**
142
143
```kotlin
144
class MyCommand : CliktCommand() {
145
// Default values
146
private val host by option("--host").default("localhost")
147
private val port by option("--port").int().default(8080)
148
149
// Lazy default
150
private val timestamp by option("--timestamp").defaultLazy { Instant.now().toString() }
151
152
// Required option
153
private val apiKey by option("--api-key").required()
154
155
// Multiple values
156
private val includes by option("--include").multiple()
157
private val tags by option("--tag").multiple().unique()
158
159
// Paired values
160
private val coordinates by option("--coord").int().pair()
161
162
override fun run() {
163
echo("Host: $host:$port")
164
echo("Includes: $includes")
165
echo("Coordinates: $coordinates")
166
}
167
}
168
```
169
170
### Validation
171
172
Validate option values with custom validators and built-in checks.
173
174
```kotlin { .api }
175
/**
176
* Validate option value
177
* @param validator Custom validation function
178
*/
179
fun <T> NullableOption<T, T>.validate(validator: OptionValidator<T>): NullableOption<T, T>
180
181
/**
182
* Check option value with boolean condition
183
* @param message Error message if check fails
184
* @param validator Boolean check function
185
*/
186
fun <T> NullableOption<T, T>.check(
187
message: String,
188
validator: (T) -> Boolean
189
): NullableOption<T, T>
190
```
191
192
**Usage Examples:**
193
194
```kotlin
195
class MyCommand : CliktCommand() {
196
// Custom validation
197
private val port by option("--port").int().validate {
198
require(it in 1..65535) { "Port must be between 1 and 65535" }
199
}
200
201
// Boolean check
202
private val percentage by option("--percentage").int().check("Must be 0-100") {
203
it in 0..100
204
}
205
206
// Multiple validations
207
private val email by option("--email")
208
.check("Must contain @") { "@" in it }
209
.check("Must end with .com") { it.endsWith(".com") }
210
}
211
```
212
213
### Special Option Types
214
215
Special option types for common CLI patterns.
216
217
```kotlin { .api }
218
/** Boolean flag option (no value) */
219
fun RawOption.flag(default: Boolean = false): OptionDelegate<Boolean>
220
221
/** Count option occurrences */
222
fun RawOption.counted(): OptionDelegate<Int>
223
224
/** Switch option with choices */
225
fun <T> RawOption.switch(choices: Map<String, T>): OptionDelegate<T?>
226
227
/** Version option that prints version and exits */
228
fun CliktCommand.versionOption(
229
version: String,
230
names: Set<String> = setOf("-V", "--version"),
231
help: String = "Show the version and exit",
232
message: String = version
233
): Unit
234
```
235
236
**Usage Examples:**
237
238
```kotlin
239
class MyCommand : CliktCommand() {
240
// Flag option
241
private val verbose by option("-v", "--verbose", help = "Verbose output").flag()
242
243
// Counted option
244
private val verbosity by option("-v", "--verbose", help = "Increase verbosity").counted()
245
246
// Switch option
247
private val mode by option("--mode").switch(
248
mapOf(
249
"--dev" to "development",
250
"--prod" to "production",
251
"--test" to "testing"
252
)
253
)
254
255
// Version option
256
init {
257
versionOption("1.0.0")
258
}
259
260
override fun run() {
261
if (verbose) echo("Verbose mode enabled")
262
echo("Verbosity level: $verbosity")
263
echo("Mode: $mode")
264
}
265
}
266
```
267
268
### Eager Options
269
270
Options that are processed before normal parameter parsing.
271
272
```kotlin { .api }
273
/**
274
* Create eager option that processes before normal parsing
275
*/
276
fun CliktCommand.eagerOption(
277
vararg names: String,
278
help: String = "",
279
hidden: Boolean = false,
280
helpTags: Map<String, String> = emptyMap()
281
): EagerOption
282
283
abstract class EagerOption : Option {
284
/** Process the option value */
285
abstract fun process(context: Context, value: String)
286
}
287
```
288
289
## Option Interfaces
290
291
```kotlin { .api }
292
/**
293
* Base option interface
294
*/
295
interface Option {
296
/** A name representing the values for this option that can be displayed to the user */
297
fun metavar(context: Context): String?
298
299
/** The description of this option, usually a single line */
300
fun optionHelp(context: Context): String
301
302
/** The names that can be used to invoke this option */
303
val names: Set<String>
304
305
/** Names that can be used for a secondary purpose, like disabling flag options */
306
val secondaryNames: Set<String>
307
308
/** The min and max number of values that must be given to this option */
309
val nvalues: IntRange
310
311
/** If true, this option should not appear in help output */
312
val hidden: Boolean
313
314
/** Extra information about this option to pass to the help formatter */
315
val helpTags: Map<String, String>
316
317
/** Optional set of strings to use when the user invokes shell autocomplete */
318
val completionCandidates: CompletionCandidates
319
320
/** Optional explicit key to use when looking this option up from a ValueSource */
321
val valueSourceKey: String?
322
323
/** If true, this option can be specified without a name e.g. `-2` instead of `-o2` */
324
val acceptsNumberValueWithoutName: Boolean
325
326
/** If true, the presence of this option will halt parsing immediately */
327
val eager: Boolean
328
329
/** If false, invocations must be of the form `--foo=1` or `-f1` */
330
val acceptsUnattachedValue: Boolean
331
332
/** Information about this option for the help output */
333
fun parameterHelp(context: Context): HelpFormatter.ParameterHelp.Option?
334
335
/** Called after this command's argv is parsed to transform and store the option's value */
336
fun finalize(context: Context, invocations: List<Invocation>)
337
338
/** Called after all parameters have been finalized to perform validation */
339
fun postValidate(context: Context)
340
}
341
342
/**
343
* Option property delegate interface
344
*/
345
interface OptionDelegate<T> : GroupableOption, ReadOnlyProperty<ParameterHolder, T>, PropertyDelegateProvider<ParameterHolder, ReadOnlyProperty<ParameterHolder, T>> {
346
/** The value for this option */
347
val value: T
348
349
/** Implementations must call ParameterHolder.registerOption */
350
override operator fun provideDelegate(
351
thisRef: ParameterHolder,
352
property: KProperty<*>
353
): ReadOnlyProperty<ParameterHolder, T>
354
355
override fun getValue(thisRef: ParameterHolder, property: KProperty<*>): T = value
356
}
357
358
/**
359
* Raw unprocessed option
360
*/
361
interface RawOption : Option
362
363
/**
364
* Option that may have null value
365
*/
366
interface NullableOption<out T, ValueT> : Option
367
368
/**
369
* Option with processed values
370
*/
371
interface OptionWithValues<ValueT, EachT, AllT> : Option
372
373
/**
374
* Flag option for boolean values
375
*/
376
interface FlagOption : Option
377
378
/**
379
* Eager option processed before normal parsing
380
*/
381
abstract class EagerOption : Option {
382
abstract fun process(context: Context, value: String)
383
}
384
```
385
386
## Type Aliases
387
388
```kotlin { .api }
389
typealias ValueConverter<InT, ValueT> = OptionTransformContext.(InT) -> ValueT
390
typealias OptionValidator<T> = OptionTransformContext.(T) -> Unit
391
```