Clikt: Powerful CLI Framework for Kotlin
Clikt is a modern, lightweight framework for creating console (CLI) applications in Kotlin. Unlike many other libraries, Clikt uses a declarative approach, allowing you to describe the structure of commands and their parameters using simple annotations and lambda expressions. This makes the code clean, readable, and easily maintainable. The library is ideal for both small utilities and complex multi-level command-line interfaces.
Key Features of Clikt
- Declarative syntax: Define commands, options, and arguments via DSL (Domain Specific Language) or annotations.
- Automatic help generation: Clikt automatically creates a beautiful and structured
--helpmessage based on your definitions. - Nested command support: Create command hierarchies (e.g.,
git commit,git push) using a simple subcommand mechanism. - Value validation: Built-in mechanisms for checking types, ranges, formats, and custom conditions.
- Autocompletion: Native support for generating autocompletion scripts for Bash, Zsh, and Fish.
- Testability: Convenient tools for testing CLI applications without actually running them in the terminal.
Installation and Setup
To get started, add the dependency to your build.gradle.kts:
repositories { mavenCentral()}
dependencies { implementation("com.github.ajalt.clikt:clikt:4.4.0")}For Maven use:
<dependency> <groupId>com.github.ajalt.clikt</groupId> <artifactId>clikt</artifactId> <version>4.4.0</version></dependency>Basic Example: Greeting
Let's create a simple command that accepts a username and an optional flag for greeting in different languages.
import com.github.ajalt.clikt.core.CliktCommandimport com.github.ajalt.clikt.parameters.arguments.argumentimport com.github.ajalt.clikt.parameters.options.flagimport com.github.ajalt.clikt.parameters.options.option
class Greet : CliktCommand() { val name: String by argument(help = "Username") val formal: Boolean by option("--formal", "-f", help = "Formal greeting").flag()
override fun run() { val greeting = if (formal) "Hello" else "Hi" echo("$greeting, $name!") }}
fun main(args: Array<String>) = Greet().main(args)Running from the command line:
$ kotlin greet.kts IvanHi, Ivan!
$ kotlin greet.kts --formal IvanHello, Ivan!
$ kotlin greet.kts --helpUsage: greet [<options>] <name>
Username
Options: -f, --formal Formal greeting -h, --help Show this message and exitAdvanced Example: Working with Files and Subcommands
Let's consider a more complex scenario — a utility for working with text files that supports the count and search subcommands.
import com.github.ajalt.clikt.core.CliktCommandimport com.github.ajalt.clikt.core.subcommandsimport com.github.ajalt.clikt.parameters.arguments.argumentimport com.github.ajalt.clikt.parameters.options.defaultimport com.github.ajalt.clikt.parameters.options.optionimport java.io.File
class FileTool : CliktCommand() { override fun run() = Unit // Root command does nothing}
class Count : CliktCommand(help = "Count lines in a file") { val file: File by argument(help = "Path to file") .validate { require(it.exists()) { "File not found: $it" } }
override f