0
# Core Commands
1
2
Foundation command classes and execution framework for building CLI applications. The CliktCommand class provides the base functionality for parameter registration, parsing, and execution.
3
4
## Capabilities
5
6
### CliktCommand
7
8
Abstract base class for all CLI commands. Provides parameter registration, parsing lifecycle, and execution framework.
9
10
```kotlin { .api }
11
/**
12
* Abstract base class for all CLI commands
13
* @param help Help text for the command
14
* @param epilog Text displayed at end of help output
15
* @param name Command name (inferred from class name if null)
16
* @param invokeWithoutSubcommand Allow execution without subcommands
17
* @param printHelpOnEmptyArgs Print help when no arguments given
18
* @param helpTags Extra help formatter information
19
*/
20
abstract class CliktCommand(
21
help: String = "",
22
epilog: String = "",
23
name: String? = null,
24
invokeWithoutSubcommand: Boolean = false,
25
printHelpOnEmptyArgs: Boolean = false,
26
helpTags: Map<String, String> = emptyMap()
27
) {
28
/** Main execution method - must be implemented by subclasses */
29
abstract fun run()
30
31
/** Parse and execute command with error handling */
32
fun main(argv: List<String>)
33
34
/** Parse command without error handling */
35
fun parse(argv: List<String>, parentContext: Context? = null)
36
37
/** Print output to terminal */
38
fun echo(message: Any?, trailingNewline: Boolean = true, err: Boolean = false)
39
40
/** Add message for later printing */
41
fun issueMessage(message: String)
42
43
/** Get formatted help text */
44
fun getFormattedHelp(error: CliktError? = null): String?
45
46
/** Print formatted help text */
47
fun echoFormattedHelp(error: CliktError? = null)
48
49
/** Get command aliases map */
50
fun aliases(): Map<String, List<String>>
51
52
/** Get all help parameters */
53
fun allHelpParams(): List<ParameterHelp>
54
55
/** Get registered subcommands */
56
fun registeredSubcommands(): List<CliktCommand>
57
58
/** Get registered options */
59
fun registeredOptions(): List<Option>
60
61
/** Get registered arguments */
62
fun registeredArguments(): List<Argument>
63
64
/** Get registered parameter groups */
65
fun registeredParameterGroups(): List<ParameterGroup>
66
67
/** Register an option */
68
fun registerOption(option: Option)
69
70
/** Register an argument */
71
fun registerArgument(argument: Argument)
72
73
/** Register a parameter group */
74
fun registerOptionGroup(group: ParameterGroup)
75
76
/** Get command help text */
77
fun commandHelp(context: Context): String
78
79
/** Get epilog text */
80
fun commandHelpEpilog(context: Context): String
81
82
/** The name of this command, used in help output */
83
val commandName: String
84
85
/** All messages issued during parsing */
86
val messages: List<String>
87
88
/** The names of all direct children of this command */
89
fun registeredSubcommandNames(): List<String>
90
91
/** Parse command line and throw exception if parsing fails */
92
fun parse(argv: Array<String>, parentContext: Context? = null)
93
94
/** Parse command line and print helpful output on errors */
95
fun main(argv: Array<out String>)
96
97
/** The help displayed in commands list when used as subcommand */
98
protected fun shortHelp(context: Context): String
99
}
100
```
101
102
**Usage Examples:**
103
104
```kotlin
105
import com.github.ajalt.clikt.core.CliktCommand
106
import com.github.ajalt.clikt.parameters.options.*
107
import com.github.ajalt.clikt.parameters.arguments.*
108
109
// Basic command
110
class GreetCommand : CliktCommand(name = "greet", help = "Greet a person") {
111
private val name by argument(help = "Name of person to greet")
112
private val greeting by option("-g", "--greeting", help = "Greeting to use").default("Hello")
113
114
override fun run() {
115
echo("$greeting $name!")
116
}
117
}
118
119
// Command with subcommands
120
class GitCommand : CliktCommand(name = "git") {
121
override fun run() = Unit
122
}
123
124
class CommitCommand : CliktCommand(name = "commit", help = "Record changes") {
125
private val message by option("-m", "--message", help = "Commit message").required()
126
127
override fun run() {
128
echo("Committing with message: $message")
129
}
130
}
131
132
fun main() {
133
GitCommand().subcommands(CommitCommand()).main()
134
}
135
```
136
137
### NoOpCliktCommand
138
139
Convenience base class with empty `run()` implementation for commands that only contain subcommands.
140
141
```kotlin { .api }
142
/**
143
* Convenience base class with empty run() implementation
144
* Useful for commands that only contain subcommands
145
*/
146
open class NoOpCliktCommand(
147
help: String = "",
148
epilog: String = "",
149
name: String? = null,
150
invokeWithoutSubcommand: Boolean = false,
151
printHelpOnEmptyArgs: Boolean = false,
152
helpTags: Map<String, String> = emptyMap()
153
) : CliktCommand(
154
help, epilog, name, invokeWithoutSubcommand, printHelpOnEmptyArgs, helpTags
155
) {
156
override fun run() = Unit
157
}
158
```
159
160
### Context
161
162
Manages parsing configuration and execution state. Provides context-aware error handling and configuration management.
163
164
```kotlin { .api }
165
/**
166
* Manages parsing configuration and execution state
167
* Context instances are created internally and configured via Context.Builder
168
*/
169
class Context private constructor(
170
val parent: Context?,
171
val command: CliktCommand,
172
val allowInterspersedArgs: Boolean,
173
val allowGroupedShortOptions: Boolean,
174
val autoEnvvarPrefix: String?,
175
val printExtraMessages: Boolean,
176
val helpOptionNames: Set<String>,
177
val helpFormatter: (Context) -> HelpFormatter,
178
val tokenTransformer: Context.(String) -> String,
179
val terminal: Terminal,
180
val argumentFileReader: ((filename: String) -> String)?,
181
val readEnvvarBeforeValueSource: Boolean,
182
val valueSource: ValueSource?,
183
val correctionSuggestor: TypoSuggestor,
184
val localization: Localization,
185
val readEnvvar: (String) -> String?,
186
var obj: Any?,
187
val originalArgv: List<String>
188
) {
189
/** If this command has subcommands and one was invoked, this is the subcommand */
190
var invokedSubcommand: CliktCommand?
191
192
/** If true, an error was encountered while parsing but parsing continues */
193
var errorEncountered: Boolean
194
195
/** Find context object by type */
196
inline fun <reified T : Any> findObject(): T?
197
198
/** Find or set context object */
199
inline fun <reified T : Any> findOrSetObject(defaultValue: () -> T): T
200
201
/** Get root context */
202
fun findRoot(): Context
203
204
/** Get parent command names */
205
fun parentNames(): List<String>
206
207
/** Get full command path */
208
fun commandNameWithParents(): List<String>
209
210
/** Throw UsageError */
211
fun fail(message: String = ""): Nothing
212
213
/** Register cleanup callback */
214
fun callOnClose(closeable: () -> Unit)
215
216
/** Execute cleanup callbacks */
217
fun close()
218
219
/** If true, arguments starting with @ will be expanded as argument files */
220
val expandArgumentFiles: Boolean
221
222
class Builder(command: CliktCommand, val parent: Context? = null) {
223
var allowInterspersedArgs: Boolean
224
var allowGroupedShortOptions: Boolean
225
var printExtraMessages: Boolean
226
var helpOptionNames: Iterable<String>
227
var helpFormatter: ((Context) -> HelpFormatter)?
228
var tokenTransformer: Context.(String) -> String
229
var autoEnvvarPrefix: String?
230
var terminal: Terminal
231
var expandArgumentFiles: Boolean
232
var argumentFileReader: ((filename: String) -> String)?
233
var readEnvvarBeforeValueSource: Boolean
234
var valueSource: ValueSource?
235
fun valueSources(vararg sources: ValueSource)
236
var correctionSuggestor: TypoSuggestor
237
var localization: Localization
238
var envvarReader: (key: String) -> String?
239
var obj: Any?
240
}
241
}
242
```
243
244
### Extension Functions
245
246
```kotlin { .api }
247
/**
248
* Add subcommands to a command
249
*/
250
fun <T : CliktCommand> T.subcommands(commands: Iterable<CliktCommand>): T
251
252
fun <T : CliktCommand> T.subcommands(vararg commands: CliktCommand): T
253
254
/**
255
* Configure command context
256
*/
257
fun <T : CliktCommand> T.context(block: Context.Builder.() -> Unit): T
258
259
/**
260
* Register an AutoCloseable to be closed when command finishes
261
*/
262
fun <T: AutoCloseable> Context.registerCloseable(closeable: T): T
263
264
/**
265
* Find the closest object of type T, or throw NullPointerException
266
*/
267
inline fun <reified T : Any> CliktCommand.requireObject(): ReadOnlyProperty<CliktCommand, T>
268
269
/**
270
* Find the closest object of type T, or null
271
*/
272
inline fun <reified T : Any> CliktCommand.findObject(): ReadOnlyProperty<CliktCommand, T?>
273
274
/**
275
* Find the closest object of type T, setting context.obj if not found
276
*/
277
inline fun <reified T : Any> CliktCommand.findOrSetObject(crossinline default: () -> T): ReadOnlyProperty<CliktCommand, T>
278
279
/**
280
* The current terminal's theme
281
*/
282
val Context.theme : Theme
283
284
/**
285
* Short for accessing the terminal from the currentContext
286
*/
287
val CliktCommand.terminal: Terminal
288
```
289
290
**Usage Examples:**
291
292
```kotlin
293
// Configure context
294
class MyCommand : CliktCommand() {
295
init {
296
context {
297
allowInterspersedArgs = false
298
helpOptionNames = setOf("--help")
299
}
300
}
301
302
override fun run() {
303
// Access context
304
val ctx = currentContext
305
echo("Command name: ${ctx.command.commandName}")
306
307
// Store data in context
308
ctx.obj = "shared data"
309
}
310
}
311
312
// Add subcommands
313
class MainCommand : NoOpCliktCommand() {
314
override fun run() = Unit
315
}
316
317
fun main() {
318
MainCommand()
319
.subcommands(
320
SubCommand1(),
321
SubCommand2(),
322
SubCommand3()
323
)
324
.main()
325
}
326
```
327
328
## Core Interfaces
329
330
```kotlin { .api }
331
/**
332
* DSL marker annotation for parameter holder interfaces
333
*/
334
@DslMarker
335
annotation class ParameterHolderDsl
336
337
/**
338
* Base interface for classes that hold parameters
339
*/
340
@ParameterHolderDsl
341
interface ParameterHolder {
342
/** Register an option with this command or group */
343
fun registerOption(option: GroupableOption)
344
}
345
346
/**
347
* Base interface for options with static group names
348
*/
349
interface StaticallyGroupedOption : Option {
350
/** The name of the group, or null if this option should not be grouped */
351
val groupName: String?
352
}
353
354
/**
355
* An option that can be added to a ParameterGroup
356
*/
357
interface GroupableOption : StaticallyGroupedOption {
358
/** The group that this option belongs to, or null. Set by the group */
359
var parameterGroup: ParameterGroup?
360
361
/** The name of the group, or null if this option should not be grouped */
362
override var groupName: String?
363
}
364
365
/**
366
* Marker interface for context-aware errors
367
*/
368
interface ContextCliktError {
369
/** The context of the command that raised this error */
370
var context: Context?
371
}
372
373
/**
374
* Type alias for typo correction functions
375
*/
376
typealias TypoSuggestor = (enteredValue: String, possibleValues: List<String>) -> List<String>
377
```