https://github.com/neandertech/cue4s
CLI prompts in Scala 3, available on JS, JVM, and Native platforms
https://github.com/neandertech/cue4s
cli prompts scala scala3 scalajs scalanative terminal tui
Last synced: 3 months ago
JSON representation
CLI prompts in Scala 3, available on JS, JVM, and Native platforms
- Host: GitHub
- URL: https://github.com/neandertech/cue4s
- Owner: neandertech
- License: apache-2.0
- Created: 2023-11-16T10:57:48.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2025-01-17T19:01:47.000Z (9 months ago)
- Last Synced: 2025-04-10T18:04:06.298Z (6 months ago)
- Topics: cli, prompts, scala, scala3, scalajs, scalanative, terminal, tui
- Language: Scala
- Homepage:
- Size: 252 KB
- Stars: 35
- Watchers: 1
- Forks: 3
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
- [Cue4s](#cue4s)
- [Installation](#installation)
- [Usage](#usage)
- [Auto-derivation for case classes](#auto-derivation-for-case-classes)
- [Cats Effect integration](#cats-effect-integration)
- [Platform support](#platform-support)## Cue4s
[](https://index.scala-lang.org/indoorvivants/cue4s/cue4s)
Scala 3 library for CLI prompts that works on JVM, JS, and Native.
The inspiration is taken from a JS library [prompts](https://github.com/terkelg/prompts#options), and the eventual goal is to have cue4s support all the same functionality.
https://github.com/user-attachments/assets/c762e557-26a2-4d24-bee2-23dd3443a21b
### Installation
- Scala CLI: `//> using dep tech.neander::cue4s::`
- SBT: `libraryDependencies += "tech.neander" %%% "cue4s" % ""`
-
### UsageThis example is runnable on both JVM and Native (note how we're using `sync`).
In fact, if you put into a file named `test.sc` you can run it with [Scala CLI](https://scala-cli.virtuslab.org/).```scala mdoc:compile-only
//> using dep tech.neander::cue4s::latest.releaseimport cue4s.*
Prompts.sync.use: prompts =>
val day = prompts
.singleChoice("How was your day?", List("great", "okay"))
.getOrThrowval work = prompts.text("Where do you work?").getOrThrow
val letters = prompts.multiChoiceAllSelected(
"What are your favourite letters?",
('A' to 'F').map(_.toString).toList
).getOrThrow
```For this to work on JS, you need to use the `Future`-based methods, example for that is provided in [examples folder](./modules/example/src/main/).
### Auto-derivation for case classes
cue4s includes an experimental auto-derivation for case classes (and only them, currently),
allowing you to create prompt chains:```scala mdoc:compile-only
//> using tech.neander::cue4s::latest.release
import cue4s.*
val validateName: String => Option[PromptError] = s =>
Option.when(s.trim.isEmpty)(PromptError("name cannot be empty!"))case class Attributes(
@cue(_.text("Your name").validate(validateName))
name: String,
@cue(_.text("Checklist").multi("Wake up" -> true, "Grub a brush" -> true, "Put a little makeup" -> false))
doneToday: Set[String],
@cue(_.text("What did you have for breakfast").options("eggs", "sadness"))
breakfast: String,
@cue(_.text("Do you want to build a snowman?"))
snowman: Boolean,
@cue(_.text("How old are you?"))
age: Int,
@cue(_.text("What is the value of PI?"))
pi: Float
) derives PromptChainval attributes: Attributes =
Prompts.sync.use: p =>
p.run(PromptChain[Attributes]).getOrThrow
```There is no generic mechanism to define how parameters of different types will be handled, just a set of
rules that felt right at the time of writing this library:1. If the type is `String`, and `.options(...)` is present in annotation, the prompt will become `SingleChoice`
2. If the type is `F[String]` where `F` is one of `List, Vector, Set`, and either `.options(...)` or `.multi(...)` are present,
then the prompt will become `MultipleChoice`
3. If the type is `Option[String]`, then _empty_ value will be turned into `None` (check for emptiness will be run before any validation)In the future more combinations can be added.
### Cats Effect integration
A simple Cats Effect integration is provided, which wraps the future-based implementation of terminal interactions.
The integration is available only for JVM and JS targets.
**Installation**
- Scala CLI: `//> using dep tech.neander::cue4s-cats-effect::`
- SBT: `libraryDependencies += "tech.neander" %%% "cue4s-cats-effect" % ""`**Usage**
```scala mdoc:compile-only
//> using dep tech.neander::cue4s-cats-effect::latest.releaseimport cue4s.catseffect.*
import cats.effect.*
import cats.syntax.all.*case class Info(
day: String,
work: String,
letters: List[String],
)object ioExample extends IOApp.Simple:
def run: IO[Unit] =
PromptsIO.make.use: prompts =>
for
_ <- IO.println("let's go")day = prompts
.singleChoice("How was your day?", List("great", "okay"))
.map(_.toEither)
.flatMap(IO.fromEither)work = prompts
.text("Where do you work?")
.map(_.toEither)
.flatMap(IO.fromEither)letter = prompts
.multiChoiceAllSelected(
"What are your favourite letters?",
('A' to 'F').map(_.toString).toList,
)
.map(_.toEither)
.flatMap(IO.fromEither)info <- (day, work, letter).mapN(Info.apply)
_ <- IO.println(info)
yield ()end ioExample
```### Platform support
On JS, we can only execute the prompts asynchronously, so the minimal
usable implementation of a prompt will always return `Future[Completion[Result]]`.On JVM and Native, we can execute prompts synchronously, so the simplest
implementation returns `Completion[Result]` - but methods wrapping the result in `Future` are provided for convenience.This is encoded in the availablity of `sync` and `async` methods on the `Prompts` object (e.g. only `Prompts.async` is available on JS).
This library is published for Scala.js 1.16.0+, Scala Native 0.5, and JVM.