Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
16fcfcf
Add comprehensive progressive documentation
SCKelemen Nov 3, 2025
68f8c7c
Add animation asset structure and references
SCKelemen Nov 3, 2025
109182d
Add recording scripts and update quality settings for animations
SCKelemen Nov 3, 2025
199f397
Add comprehensive recording checklist
SCKelemen Nov 3, 2025
7ddb36f
Add standalone code examples for documentation
SCKelemen Nov 3, 2025
3d25bda
Reorganize examples into separate directories
SCKelemen Nov 3, 2025
db26cf2
Add go.mod setup for all example directories
SCKelemen Nov 3, 2025
7d2674a
Fix Makefile for go.mod setup
SCKelemen Nov 3, 2025
d766286
Add replace directives to all go.mod files
SCKelemen Nov 3, 2025
bf979a8
Fix replace path in go.mod files
SCKelemen Nov 3, 2025
f92bb33
Fix replace path to use relative path from code/ directory
SCKelemen Nov 3, 2025
c99a627
Fix go.mod replace paths with dynamic depth calculation
SCKelemen Nov 3, 2025
af3f186
Fix go.mod path depth calculation
SCKelemen Nov 3, 2025
85e0981
Fix app.Run() calls and create go.mod files
SCKelemen Nov 3, 2025
2168d87
Fix replace path to ../../../../ for all examples
SCKelemen Nov 3, 2025
b41aea5
Fix AddSubcommand to use Subcommands field directly
SCKelemen Nov 3, 2025
7afb33b
Add context import to example2_subcommands
SCKelemen Nov 3, 2025
9fa4745
Add comprehensive recording guide
SCKelemen Nov 3, 2025
aa32092
Enhance documentation to clearly show both API styles
SCKelemen Nov 3, 2025
75d6233
Fix compilation errors in documentation examples
SCKelemen Nov 3, 2025
68808c0
Add WebP animation files for documentation examples
SCKelemen Nov 3, 2025
6d6966e
Add minimal prompt to hide username/hostname in recordings
SCKelemen Nov 3, 2025
3958a93
Fix prompt override using asciinema -c flag
SCKelemen Nov 3, 2025
c7e3f62
Improve prompt handling in record script
SCKelemen Nov 3, 2025
6c65ddc
Add early styling documentation and fix prompt recording
SCKelemen Nov 3, 2025
9fce8c6
Refactor docs structure: combine docs and code in tutorial/ directories
SCKelemen Nov 3, 2025
ccb3a82
Fix go.mod files in tutorial directories
SCKelemen Nov 3, 2025
6398bff
Move webp files to their respective tutorial directories
SCKelemen Nov 3, 2025
45bcbc5
Fix broken image markdown syntax in tutorial READMEs
SCKelemen Nov 3, 2025
abb2731
Fix image markdown syntax - use correct format ![text](file.webp)
SCKelemen Nov 3, 2025
50299d2
Fix double parentheses in image links
SCKelemen Nov 3, 2025
4fb1e67
Populate empty tutorial directories with code examples
SCKelemen Nov 3, 2025
34441b6
Add main.go and go.mod to remaining tutorial directories
SCKelemen Nov 3, 2025
b43532b
Add main.go and go.mod to remaining tutorial directories
SCKelemen Nov 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 194 additions & 0 deletions docs/1.5_styling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
# 1.5. Styling with Lipgloss

CLIX supports beautiful terminal styling through `charmbracelet/lipgloss`. You can style your CLI output to make it more visually appealing and easier to read.

## Quick Start

Add lipgloss to your project:

```bash
go get github.com/charmbracelet/lipgloss
```

Then use `lipgloss.Style` directly - it implements CLIX's `TextStyle` interface, so no wrapping is needed!

```go
package main

import (
"context"
"fmt"
"os"

"clix"
"github.com/charmbracelet/lipgloss"
)

func main() {
app := clix.NewApp("greet")
app.Out = os.Stdout
app.In = os.Stdin

// Create styled output
titleStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("213")).
Bold(true)

accentStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("212")).
Bold(true)

greetCmd := clix.NewCommand("greet")
greetCmd.Run = func(ctx *clix.Context) error {
fmt.Fprintln(ctx.App.Out, titleStyle.Render("Hello, World!"))
fmt.Fprintln(ctx.App.Out, accentStyle.Render("Welcome to CLIX"))
return nil
}

app.Root = greetCmd

if err := app.Run(context.Background(), nil); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
}
```

**Output:**
```
Hello, World! (in pink/bold)
Welcome to CLIX (in magenta/bold)
```

## Styling Help Output

You can customize how help text is displayed using CLIX's `Styles`:

```go
app := clix.NewApp("myapp")

// lipgloss.Style implements clix.TextStyle directly
styles := clix.DefaultStyles
styles.AppTitle = lipgloss.NewStyle().
Foreground(lipgloss.Color("213")).
Bold(true)
styles.SectionHeading = lipgloss.NewStyle().
Foreground(lipgloss.Color("212")).
Bold(true)
styles.FlagName = lipgloss.NewStyle().
Foreground(lipgloss.Color("51")).
Background(lipgloss.Color("236")).
Padding(0, 1)

app.Styles = styles
```

When users run `myapp --help`, they'll see styled output with colors and formatting.

## Styling Prompts

You can also style interactive prompts:

```go
theme := clix.DefaultPromptTheme
theme.Prefix = "➤ "
theme.PrefixStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("212")).
Bold(true)
theme.LabelStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("213")).
Bold(true)

app.DefaultTheme = theme
```

Now all prompts will use your custom styling.

## Common Style Patterns

### Titles and Headings
```go
titleStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("213")). // Magenta
Bold(true)
```

### Accent Text
```go
accentStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("212")). // Bright magenta
Bold(true)
```

### Code/Commands
```go
codeStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("51")). // Cyan
Background(lipgloss.Color("236")). // Dark gray
Padding(0, 1)
```

### Subtle Text
```go
subtitleStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("147")) // Light blue
```

## Complete Example

```go
package main

import (
"context"
"fmt"
"os"

"clix"
"github.com/charmbracelet/lipgloss"
)

var (
titleStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("213")).Bold(true)
accentStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("212")).Bold(true)
codeStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("51")).
Background(lipgloss.Color("236")).
Padding(0, 1)
)

func main() {
app := clix.NewApp("demo")
app.Out = os.Stdout
app.In = os.Stdin

// Style help output
styles := clix.DefaultStyles
styles.AppTitle = titleStyle
styles.SectionHeading = accentStyle
styles.FlagName = codeStyle
app.Styles = styles

cmd := clix.NewCommand("demo")
cmd.Run = func(ctx *clix.Context) error {
fmt.Fprintln(ctx.App.Out, titleStyle.Render("Welcome!"))
fmt.Fprintln(ctx.App.Out, accentStyle.Render("This is styled output"))
fmt.Fprintln(ctx.App.Out, "Command:", codeStyle.Render("demo"))
return nil
}

app.Root = cmd

if err := app.Run(context.Background(), nil); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
}
```

## Next Steps

- Learn about [Arguments](2_arguments.md) to handle user input
- See [Terminal Prompts](8_terminal_prompts.md) for styled interactive prompts
- Check out the [Lipgloss documentation](https://github.com/charmbracelet/lipgloss) for more styling options

179 changes: 179 additions & 0 deletions docs/10_extensions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
# 10. Extensions

CLIX uses an extension system inspired by [goldmark](https://github.com/yuin/goldmark) to provide optional "batteries-included" features without polluting the core library.

## Philosophy

**Simple by default, powerful when needed.** CLIX starts with minimal overhead:
- Core command/flag/argument parsing
- Flag-based help (`-h`, `--help`) - always available
- Basic text prompting (`TextPrompter`)
- Configuration management (API only)

Everything else is opt-in via extensions.

## Using Extensions

Add extensions to your app before calling `Run()`:

```go
import (
"clix"
"clix/ext/help"
"clix/ext/config"
"clix/ext/autocomplete"
"clix/ext/version"
"clix/ext/prompt"
"clix/ext/survey"
"clix/ext/validation"
)

app := clix.NewApp("myapp")

// Add extensions
app.AddExtension(help.Extension{})
app.AddExtension(config.Extension{})
app.AddExtension(autocomplete.Extension{})
app.AddExtension(version.Extension{
Version: "1.0.0",
Commit: "abc123", // optional
Date: "2024-01-01", // optional
})
app.AddExtension(prompt.Extension{})
app.AddExtension(survey.Extension{})
app.AddExtension(validation.Extension{})

// Apply extensions (required before Run)
if err := app.ApplyExtensions(); err != nil {
return err
}

// Now Run
if err := app.Run(); err != nil {
return err
}
```

## Available Extensions

### Help Extension (`clix/ext/help`)

Adds command-based help similar to man pages:
- `cli help` - Show help for root command
- `cli help [command]` - Show help for specific command

**Note:** Flag-based help (`-h`, `--help`) works without this extension.

### Config Extension (`clix/ext/config`)

Adds configuration management commands:
- `cli config` - Show config help
- `cli config list` - List all config values
- `cli config get <key>` - Get a config value
- `cli config set <key> <value>` - Set a config value
- `cli config unset <key>` - Remove a config value

### Autocomplete Extension (`clix/ext/autocomplete`)

Adds shell completion:
- `cli autocomplete bash` - Install bash completion
- `cli autocomplete zsh` - Install zsh completion
- `cli autocomplete fish` - Install fish completion

### Version Extension (`clix/ext/version`)

Adds version information:
- `cli version` - Show version information
- `cli --version` - Global flag (also works)

Also provides `app.Version` field access.

### Prompt Extension (`clix/ext/prompt`)

Replaces `TextPrompter` with `TerminalPrompter`, enabling:
- Select prompts (single choice from list)
- Multi-select prompts (multiple choices)
- Enhanced text input with tab completion
- Raw terminal mode support

**Note:** Basic text prompts and confirm work without this extension.

### Survey Extension (`clix/ext/survey`)

Enables chaining prompts together:
- Dynamic question flows
- Static survey definitions
- Conditional branches
- Undo/back functionality
- End card summaries

### Validation Extension (`clix/ext/validation`)

Provides common validators:
- `Email()` - Email validation
- `URL()` - URL validation
- `CIDR()` - CIDR notation
- `IP()` - IP address validation
- `E164()` - Phone number validation
- `MinLength(n)` - Minimum length
- `MaxLength(n)` - Maximum length
- `Regex(re)` - Regex validation
- `All(...)` - All validators must pass
- `Any(...)` - Any validator can pass

## Extension Order

Extensions are applied in the order they're added. Most extensions don't depend on order, but it's good practice to add them in logical groups:

1. Core functionality (help, config, version)
2. Enhanced prompting (prompt, validation)
3. Advanced features (survey)

## Creating Custom Extensions

You can create custom extensions by implementing the `Extension` interface:

```go
type Extension interface {
Extend(app *App) error
}
```

Example:

```go
type MyExtension struct{}

func (MyExtension) Extend(app *clix.App) error {
// Modify app, add commands, replace components, etc.

// Example: Add a custom command
customCmd := clix.NewCommand("custom")
customCmd.Run = func(ctx *clix.Context) error {
fmt.Fprintln(ctx.App.Out, "Custom extension command")
return nil
}

if app.Root == nil {
app.Root = customCmd
} else {
app.Root.AddSubcommand(customCmd)
}

return nil
}
```

## Extension Best Practices

1. **Don't break core behavior**: Extensions should enhance, not replace core functionality
2. **Make features opt-in**: Don't assume all users want advanced features
3. **Follow extension patterns**: Look at existing extensions for patterns
4. **Document your extension**: Provide clear examples and usage

## Summary

The extension system allows CLIX to remain simple for basic use cases while providing powerful features when needed. Use only the extensions you need for your application.

For a complete example using multiple extensions, see the [examples](../examples/) directory.

Loading
Loading