Promptberry

1.0.0

🍓 Beautiful, interactive CLI prompts for Swift
onmyway133/Promptberry

What's New

1.0.0

2026-04-07T19:23:59Z

Prompts

  • text — single-line text input with placeholder, default value, and validation
  • password — masked input
  • confirm — yes/no toggle
  • select — pick one from a list, with SelectOption, Promptable enum, or custom label support; allowOther for free-text entry
  • multiselect — pick multiple items, with enum and allowOther support
  • multiline — multi-line input, Ctrl+D to submit
  • autocomplete — searchable/filterable select

Feedback & Logging

  • spinner — animated spinner for async work
  • progress — progress bar for known-length operations
  • tasks — sequential async steps, each with its own spinner
  • note — bordered info box
  • intro / outro / cancel — session framing
  • log.info / log.success / log.warning / log.error / log.step

Other

  • Rainbow-style color chaining ("text".green.bold, .dim, .cyan, etc.)
  • Auto-disables colors for non-TTY, NO_COLOR, TERM=dumb
  • Swift 6 concurrency-safe

Promptberry

Promptberry logo

Beautiful, interactive CLI prompts for Swift

Promptberry demo

┌  My App v1.0
│
◆  What's your name?
│  ▌ Ada_
│
◆  Select language:
│  › ● Swift  (recommended)
│    ○ Kotlin
│    ○ Python
│
⠋  Installing...
◇  Done!
│
└  Happy coding, Ada.

Requirements

  • Swift 6.0+
  • macOS 13+

Installation

Add to your Package.swift:

dependencies: [
    .package(
        url: "https://github.com/onmyway133/Promptberry", 
        from: "1.0.0"
    )
],
targets: [
    .executableTarget(
        name: "MyApp",
        dependencies: [
            .product(name: "Promptberry", package: "Promptberry")
        ]
    )
]

Usage

import Promptberry

Promptberry.intro("My App v1.0")

let name = try Promptberry.text("What's your name?", placeholder: "e.g. Ada")
let pass = try Promptberry.password("Choose a password:")
let go   = try Promptberry.confirm("Continue?")

Promptberry.outro("All done, \(name)!")

Wrap everything in a do/catch to handle cancellation (Ctrl+C):

do {
    let name = try Promptberry.text("Name?")
} catch is PromptCancelled {
    Promptberry.cancel("Aborted.")
    exit(0)
}

Prompts

text

Single-line text input.

let name = try Promptberry.text(
    "What's your name?",
    placeholder: "e.g. Ada Lovelace",   // shown when empty
    defaultValue: "Anonymous",           // returned on empty Enter
    validate: { value in
        value.count < 2 ? "Too short." : nil
    }
)

password

Like text, but input is masked.

let secret = try Promptberry.password("Password:", mask: "")

confirm

Yes/No toggle. Use arrow keys, y/n, or Space to switch.

let ok = try Promptberry.confirm(
    "Continue?",
    active: "Yes",
    inactive: "No",
    initialValue: true
)

select

Pick one item from a list. Navigate with / or j/k.

Pass a plain [String] for quick use:

let choice = try Promptberry.select("Pick one:", options: ["a", "b", "c"])

Add allowOther: true to let the user type a custom value if none of the options fit:

let type_ = try Promptberry.select(
    "Project type:",
    options: ["Executable", "Library", "Plugin"],
    allowOther: true
)

Or use SelectOption for labels and hints:

let lang = try Promptberry.select(
    "Preferred language:",
    options: [
        SelectOption(value: "swift",  label: "Swift",  hint: "recommended"),
        SelectOption(value: "kotlin", label: "Kotlin"),
        SelectOption(value: "python", label: "Python"),
    ],
    initialValue: "swift",
    maxItems: 5          // how many options to show at once
)

Or pass your own enum — conform it to Promptable:

enum Language: String, CaseIterable, Promptable {
    case swift, kotlin, python, rust
}

let lang = try Promptberry.select("Language:", from: Language.self)
// returns Language.swift, .kotlin, etc.

Or select from any array of values with a custom label:

let server = try Promptberry.select(
    "Target server:",
    from: servers,
    label: { $0.hostname }
)

multiselect

Pick multiple items. Space to toggle, a to toggle all, Enter to confirm.

// Simple string array
let features = try Promptberry.multiselect(
    "Features:",
    options: ["tests", "ci", "docs"],
    initialValues: ["tests"]   // pre-selected
)

Use allowOther: true to let the user append a custom entry:

let extras = try Promptberry.multiselect(
    "Include extras:",
    options: ["Tests", "CI workflow", "README", "SwiftLint"],
    allowOther: true
)

// Or with SelectOption for hints
let tools = try Promptberry.multiselect(
    "Build tools:",
    options: [
        SelectOption(value: "spm",   label: "Swift Package Manager"),
        SelectOption(value: "cmake", label: "CMake"),
        SelectOption(value: "bazel", label: "Bazel", hint: "large-scale"),
    ],
    initialValues: ["spm"],
    required: true       // at least one must be selected
)
// returns [String]

Or with a Promptable enum:

enum Feature: String, CaseIterable, Promptable {
    case tests, ci, docs, linting
}

let features = try Promptberry.multiselect("Features:", from: Feature.self)
// returns [Feature]

multiline

Multi-line text input. Press Enter for new lines, Ctrl+D to submit.

let description = try Promptberry.multiline(
    "Describe your project:",
    placeholder: "What does it do?",
    validate: { $0.isEmpty ? "Description required." : nil }
)

autocomplete

Searchable select — filters options as you type. Tab or Enter to confirm.

let pkg = try Promptberry.autocomplete(
    "Find package:",
    options: ["ArgumentParser", "AsyncHTTPClient", "Crypto", "NIO", "Vapor"],
    placeholder: "Type to filter..."
)

Also works with SelectOption for typed values:

let server = try Promptberry.autocomplete(
    "Select server:",
    options: servers.map { SelectOption(value: $0, label: $0.hostname) }
)

spinner

Show an animated spinner while doing async work.

let s = Promptberry.spinner()
await s.start("Installing packages...")

try await installPackages()    // your async work runs concurrently

await s.stop("Packages installed!")    // or s.error("Failed.")

Update the message while it's running:

await s.update("Almost there...")

progress

Progress bar for known-length operations.

let p = Promptberry.progress(total: files.count, message: "Copying files...")
for file in files {
    try await copy(file)
    await p.advance()
}
await p.complete("All files copied!")

You can also jump to an absolute value:

await p.update(42, message: "Step 42...")

Call p.error("message") to abort with error styling.

tasks

Run a sequence of async operations sequentially, each with its own spinner.

try await tasks([
    PromptTask("Scaffolding project structure") {
        try await scaffold()
    },
    PromptTask("Writing Package.swift") {
        try await writeManifest()
    },
    PromptTask("Installing dependencies") {
        try await installDeps()
    },
])

If any task throws, its spinner shows an error and the error propagates.t

Info & Logging

// Bordered info box
Promptberry.note("Line 1\nLine 2", title: "Important")

// Cancellation message
Promptberry.cancel("Setup aborted.")

// Semantic log lines (non-interactive)
log.info("Reading config...")
log.success("Build passed in 1.2s")
log.warning("Deprecated API used")
log.step("Running post-install hooks")
log.error("Connection refused (non-fatal)")

Group

Sequence multiple prompts with a shared cancellation handler:

let profile = try Promptberry.group(
    onCancel: { _ in
        Promptberry.cancel("Cancelled.")
        exit(0)
    }
) {
    let email = try Promptberry.text("Email?")
    let age   = try Promptberry.text("Age?",
        validate: { Int($0) == nil ? "Enter a number." : nil })
    return (email: email, age: age)
}

Colors

All strings support Rainbow-style chaining:

"success".green.bold
"warning".yellow
"error".red
"hint".dim
"label".cyan.underline
"bg".onBlue

Disable colors globally (e.g. for piped output):

ColorSupport.enabled = false

Colors are also auto-disabled when:

  • NO_COLOR environment variable is set
  • stdout is not a TTY (piped to a file)
  • TERM=dumb

Force colors on even in non-TTY contexts:

ColorSupport.enabled = true
// or set FORCE_COLOR=1 in the environment

Reference

License

Promptberry is available under the MIT license. Copyright (c) 2026 Khoa Pham.

Description

  • Swift Tools 6.0.0
View More Packages from this Author

Dependencies

  • None
Last updated: Wed Apr 08 2026 14:47:20 GMT-0900 (Hawaii-Aleutian Daylight Time)