tap

module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 21, 2025 License: MIT

README ΒΆ

πŸš€ Tap

Beautiful, interactive command-line prompts for Go - A Go port of the popular TypeScript Clack library.

Tap Demo

⚠️ Heavy Development: This project is currently in heavy development. APIs may change, and some features are still being implemented. Use with caution in production environments.

Why Tap?

Building interactive CLI applications shouldn't be complex. Tap brings the elegant, minimal design philosophy of Clack to the Go ecosystem, offering:

  • Event-driven architecture for responsive, race-condition-free prompts
  • Beautiful styling with consistent visual design and Unicode symbols
  • Type-safe APIs with generic support for strongly-typed selections
  • Comprehensive testing with built-in mock utilities
  • Minimal dependencies - Only essential terminal and keyboard libraries

Features

βœ… Available Now

Core Components:

  • Text Input - Single-line input with cursor navigation, validation, placeholders, and default values
  • Confirm - Yes/No prompts with customizable labels and keyboard navigation
  • Select - Single selection from typed options with hints and color-coded display
  • Progress Bar - Animated progress indicators with multiple styles (light, heavy, block)
  • Message Primitives - Intro, outro, cancel messages, and styled boxes
  • Event System - Race-condition-free event loop architecture

Developer Experience:

  • Mock Testing - Built-in utilities for reliable prompt testing
  • Type Safety - Generic APIs for strongly-typed selections
  • Terminal Management - Raw mode handling, keyboard input, and cursor control
πŸ”„ Coming Soon
  • Password Input - Masked text input for sensitive data
  • Multi-Select - Multiple selection from lists with checkboxes
  • Autocomplete - Text input with suggestion dropdown
  • Spinner - Loading indicators for long-running operations
  • Group - Grouped prompts for complex workflows

Installation

go get github.com/yarlson/tap@latest

Quick Start

package main

import (
    "fmt"
    "github.com/yarlson/tap/core"
    "github.com/yarlson/tap/prompts"
    "github.com/yarlson/tap/terminal"
)

func main() {
    // Initialize terminal
    term, err := terminal.New()
    if err != nil {
        panic(err)
    }
    defer term.Close()

    // Text input
    name := prompts.Text(prompts.TextOptions{
        Message: "What's your name?",
        Input:   term.Reader,
        Output:  term.Writer,
    })

    // Check for cancellation
    if core.IsCancel(name) {
        prompts.Cancel("Operation cancelled.", prompts.MessageOptions{Output: term.Writer})
        return
    }

    // Confirmation
    confirmed := prompts.Confirm(prompts.ConfirmOptions{
        Message: fmt.Sprintf("Hello %s! Continue?", name),
        Input:   term.Reader,
        Output:  term.Writer,
    })

    if core.IsCancel(confirmed) {
        prompts.Cancel("Operation cancelled.", prompts.MessageOptions{Output: term.Writer})
        return
    }

    if confirmed.(bool) {
        prompts.Outro("Let's go! πŸŽ‰", prompts.MessageOptions{Output: term.Writer})
    }
}

API Examples

Text Input with Validation
import "errors"

email := prompts.Text(prompts.TextOptions{
    Message:      "Enter your email:",
    Placeholder:  "user@example.com",
    DefaultValue: "anonymous@example.com",
    Validate: func(input string) error {
        if !strings.Contains(input, "@") {
            return errors.New("Please enter a valid email")
        }
        return nil
    },
    Input:  term.Reader,
    Output: term.Writer,
})
Confirmation with Custom Labels
proceed := prompts.Confirm(prompts.ConfirmOptions{
    Message:      "Deploy to production?",
    Active:       "Deploy",
    Inactive:     "Cancel",
    InitialValue: false,
    Input:        term.Reader,
    Output:       term.Writer,
})
Type-Safe Selection
type Environment string

envs := []prompts.SelectOption[Environment]{
    {Value: "dev", Label: "Development", Hint: "Local development"},
    {Value: "staging", Label: "Staging", Hint: "Pre-production testing"},
    {Value: "prod", Label: "Production", Hint: "Live environment"},
}

env := prompts.Select(prompts.SelectOptions[Environment]{
    Message: "Choose deployment target:",
    Options: envs,
    Input:   term.Reader,
    Output:  term.Writer,
})
Progress Bar
prog := prompts.NewProgress(prompts.ProgressOptions{
    Style:  "heavy",     // "light", "heavy", or "block"
    Max:    100,         // total units of work
    Size:   40,          // bar width in characters
    Output: term.Writer,
})

prog.Start("Processing...")
for i := 0; i <= 100; i += 10 {
    time.Sleep(200 * time.Millisecond)
    prog.Advance(10, fmt.Sprintf("Step %d/10", i/10+1))
}
prog.Stop("Complete!", 0) // 0=success, 1=cancel, 2=error

Architecture

Tap uses a clean, layered architecture designed for performance and reliability:

Package Structure
  • core - Core prompt engine with unstyled, functional prompts
  • prompts - Beautifully styled prompts built on top of core
  • terminal - Terminal management, keyboard input, and cursor control
Event-Driven Design

All prompts use a pure event loop architecture for race-condition-free operation:

// Single event loop processes all state changes
for event := range prompt.events {
    event(&state)                    // Update state
    prompt.render(&state)            // Render changes
    prompt.updateSnapshot(&state)    // Update atomic snapshot
}

This approach eliminates the need for mutexes while providing excellent performance and thread safety through atomic snapshots.

Testing

Tap includes comprehensive test coverage with built-in mock utilities:

# Run all tests
go test ./...

# Test with race detection
go test -race ./...

# Test specific packages
go test ./prompts -v
go test ./core -v
Mock Testing Example
func TestTextPrompt(t *testing.T) {
    mockInput := core.NewMockReader()
    mockOutput := core.NewMockWriter()

    // Simulate user typing "hello" and pressing enter
    mockInput.SendString("hello")
    mockInput.SendKey("return")

    result := prompts.Text(prompts.TextOptions{
        Message: "Enter text:",
        Input:   mockInput,
        Output:  mockOutput,
    })

    assert.Equal(t, "hello", result)
}

Examples

Explore working examples in the examples/ directory:

# Try different prompt types
go run examples/text/main.go      # Text input with validation
go run examples/confirm/main.go   # Yes/No confirmations
go run examples/select/main.go    # Single selection menus
go run examples/progress/main.go  # Progress bars and status
go run examples/multiple/main.go  # Complete workflow example

Each example demonstrates different features and can serve as starting points for your applications.

Development Status

Tap is in active development. Core functionality is stable and tested, but APIs may evolve. Current status:

  • βœ… Stable: Text, Confirm, Select prompts with full styling
  • βœ… Stable: Progress bars and message primitives
  • βœ… Stable: Event loop architecture and terminal management
  • πŸ”„ In Progress: Additional prompt types and enhanced styling
  • πŸ“‹ Planned: Documentation site, themes, and advanced features

Contributing

Contributions welcome! Areas where help is needed:

  • New Prompt Types - Multi-select, password, autocomplete
  • Enhanced Styling - Themes, custom symbols, color schemes
  • Documentation - API docs, tutorials, more examples
  • Testing - Cross-platform testing, edge cases, performance
  • Bug Reports - Issues with keyboard handling or rendering
Development Setup
git clone https://github.com/yarlson/tap.git
cd tap
go test ./...                    # Run tests
go run examples/text/main.go     # Try examples

Please follow Go best practices, maintain test coverage above 80%, and use the event-driven architecture patterns established in the codebase.

License

MIT License - see LICENSE file for details.

Acknowledgments

  • Clack - The original TypeScript library that inspired this project
  • @eiannone/keyboard - Cross-platform keyboard input for Go
  • The Go community for excellent tooling and libraries

Making interactive CLI development effortless in Go. πŸš€

Directories ΒΆ

Path Synopsis
examples
confirm command
multiple command
progress command
select command
text command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL