Clikt: Мощный CLI фреймворк для Kotlin с декларативным синтаксисом

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Clikt: Мощный CLI фреймворк для Kotlin

Clikt — это современный, легковесный фреймворк для создания консольных (CLI) приложений на языке Kotlin. В отличие от многих других библиотек, Clikt использует декларативный подход, позволяя описывать структуру команд и их параметры с помощью простых аннотаций и лямбда-выражений. Это делает код чистым, читаемым и легко поддерживаемым. Библиотека идеально подходит как для небольших утилит, так и для сложных многоуровневых интерфейсов командной строки.

Ключевые возможности Clikt

  • Декларативный синтаксис: Определение команд, опций и аргументов через DSL (Domain Specific Language) или аннотации.
  • Автоматическая генерация справки: Clikt автоматически создает красивое и структурированное сообщение --help на основе ваших определений.
  • Поддержка вложенных команд: Создавайте иерархии команд (например, git commit, git push) с помощью простого механизма подкоманд.
  • Валидация значений: Встроенные механизмы для проверки типов, диапазонов, форматов и пользовательских условий.
  • Автодополнение: Нативная поддержка генерации скриптов автодополнения для Bash, Zsh и Fish.
  • Тестируемость: Удобные инструменты для тестирования CLI-приложений без реального запуска в терминале.

Установка и подключение

Для начала работы добавьте зависимость в ваш build.gradle.kts:

repositories {
    mavenCentral()
}

dependencies {
    implementation("com.github.ajalt.clikt:clikt:4.4.0")
}

Для Maven используйте:

<dependency>
    <groupId>com.github.ajalt.clikt</groupId>
    <artifactId>clikt</artifactId>
    <version>4.4.0</version>
</dependency>

Базовый пример: приветствие

Создадим простую команду, которая принимает имя пользователя и опциональный флаг для приветствия на разных языках.

import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.parameters.arguments.argument
import com.github.ajalt.clikt.parameters.options.flag
import com.github.ajalt.clikt.parameters.options.option

class Greet : CliktCommand() {
    val name: String by argument(help = "Имя пользователя")
    val formal: Boolean by option("--formal", "-f", help = "Формальное приветствие").flag()

    override fun run() {
        val greeting = if (formal) "Здравствуйте" else "Привет"
        echo("$greeting, $name!")
    }
}

fun main(args: Array<String>) = Greet().main(args)

Запуск из командной строки:

$ kotlin greet.kts Иван
Привет, Иван!

$ kotlin greet.kts --formal Иван
Здравствуйте, Иван!

$ kotlin greet.kts --help
Usage: greet [<options>] <name>

  Имя пользователя

Options:
  -f, --formal  Формальное приветствие
  -h, --help    Show this message and exit

Продвинутый пример: работа с файлами и подкомандами

Рассмотрим более сложный сценарий — утилиту для работы с текстовыми файлами с поддержкой подкоманд count и search.

import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.subcommands
import com.github.ajalt.clikt.parameters.arguments.argument
import com.github.ajalt.clikt.parameters.options.default
import com.github.ajalt.clikt.parameters.options.option
import java.io.File

class FileTool : CliktCommand() {
    override fun run() = Unit // Корневая команда ничего не делает
}

class Count : CliktCommand(help = "Подсчитать строки в файле") {
    val file: File by argument(help = "Путь к файлу")
        .validate { require(it.exists()) { "Файл не найден: $it" } }

    override fun run() {
        val lines = file.readLines().size
        echo("Количество строк: $lines")
    }
}

class Search : CliktCommand(help = "Поиск подстроки в файле") {
    val file: File by argument(help = "Путь к файлу")
    val pattern: String by option("--pattern", "-p", help = "Искомая строка").default("")

    override fun run() {
        val found = file.readLines().filter { it.contains(pattern) }
        if (found.isEmpty()) {
            echo("Совпадений не найдено.")
        } else {
            found.forEach {                    

Рекомендаций