An open API service indexing awesome lists of open source software.

https://github.com/marcoroth/lipgloss-ruby

Style Definitions for Nice Terminal Layouts for Ruby, based on Charm's lipgloss.
https://github.com/marcoroth/lipgloss-ruby

charm charmbracelet cli go lipgloss native-extension ruby

Last synced: 5 days ago
JSON representation

Style Definitions for Nice Terminal Layouts for Ruby, based on Charm's lipgloss.

Awesome Lists containing this project

README

          


Lipgloss for Ruby


Style Definitions for Nice Terminal Layouts


Gem Version
License

Ruby bindings for charmbracelet/lipgloss.
Style definitions for nice terminal layouts. Built with TUIs in mind.


## Installation

**Add to your Gemfile:**

```ruby
gem "lipgloss"
```

**Or install directly:**

```bash
gem install lipgloss
```

## Usage

### Basic Styling

**Create and render styled text:**

```ruby
require "lipgloss"

style = Lipgloss::Style.new
.bold(true)
.foreground("#FAFAFA")
.background("#7D56F4")
.padding(1, 2)

puts style.render("Hello, Lipgloss!")
```

**Reusable styles:**

```ruby
heading = Lipgloss::Style.new
.bold(true)
.foreground("#FF6B6B")
.margin_bottom(1)

body = Lipgloss::Style.new
.width(40)
.align(:center)

puts heading.render("Welcome")
puts body.render("Styled terminal output")
```

### Borders

**Add borders to your content:**

```ruby
box = Lipgloss::Style.new
.border(:rounded)
.border_foreground("#874BFD")
.padding(1, 2)

puts box.render("Boxed content")
```

**Available border styles:**

| Style | Description |
|------------|-----------------------------------|
| `:normal` | Standard box drawing characters |
| `:rounded` | Rounded corners |
| `:thick` | Thick lines |
| `:double` | Double lines |
| `:hidden` | Hidden (spacing only) |
| `:block` | Block characters |
| `:ascii` | ASCII characters (`+`, `-`, `\|`) |

**Custom borders:**

```ruby
style = Lipgloss::Style.new
.border_custom(
top: "~", bottom: "~",
left: "|", right: "|",
top_left: "+", top_right: "+",
bottom_left: "+", bottom_right: "+"
)

puts style.render("Custom border!")
```

**Per-side border colors:**

```ruby
style = Lipgloss::Style.new
.border(:rounded)
.border_top_foreground("#FF0000")
.border_right_foreground("#00FF00")
.border_bottom_foreground("#0000FF")
.border_left_foreground("#FFFF00")

puts style.render("Rainbow border!")
```

### Layout

**Join content horizontally:**

```ruby
left = box.render("Left")
right = box.render("Right")

puts Lipgloss.join_horizontal(:top, left, right)
```

**Join content vertically:**

```ruby
puts Lipgloss.join_vertical(:center, left, right)
```

**Place content in whitespace:**

```ruby
puts Lipgloss.place(40, 10, :center, :center, "Centered")
```

**Position symbols:** `:top`, `:bottom`, `:left`, `:right`, `:center` (or numeric 0.0-1.0)

### Colors

**Simple hex colors:**

```ruby
style = Lipgloss::Style.new
.foreground("#FF0000")
.background("#0000FF")
```

**Adaptive colors (auto-detect light/dark terminal):**

```ruby
style = Lipgloss::Style.new
.foreground(Lipgloss::AdaptiveColor.new(light: "#000", dark: "#FFF"))
```

**Complete colors with fallbacks:**

```ruby
color = Lipgloss::CompleteColor.new(
true_color: "#FF6B6B", # 24-bit color
ansi256: 196, # 256-color fallback (integer)
ansi: :bright_red # 16-color fallback (symbol)
)

style = Lipgloss::Style.new.foreground(color)
```

**ANSI color symbols:** `:black`, `:red`, `:green`, `:yellow`, `:blue`, `:magenta`, `:cyan`, `:white`, and bright variants (`:bright_red`, etc.)

**Complete adaptive colors:**

```ruby
light = Lipgloss::CompleteColor.new(true_color: "#000", ansi256: :black, ansi: :black)
dark = Lipgloss::CompleteColor.new(true_color: "#FFF", ansi256: :bright_white, ansi: :bright_white)
color = Lipgloss::CompleteAdaptiveColor.new(light: light, dark: dark)

style = Lipgloss::Style.new.foreground(color)
```

### Style Inheritance

**Inherit styles from a parent:**

```ruby
base = Lipgloss::Style.new
.foreground("#FF0000")
.bold(true)

child = Lipgloss::Style.new
.padding(1)
.inherit(base) # Inherits foreground and bold

puts child.render("Inherited style!")
```

**Unset specific properties:**

```ruby
style = Lipgloss::Style.new
.bold(true)
.foreground("#FF0000")
.unset_bold # Remove bold
.unset_foreground # Remove foreground color
```

### SetString

**Set default text for a style:**

```ruby
style = Lipgloss::Style.new
.bold(true)
.foreground("#7D56F4")
.set_string("Hello!")

puts style.to_s # Renders "Hello!" with the style
```

### Tables

**Create styled tables:**

```ruby
table = Lipgloss::Table.new
.headers(["Language", "Greeting"])
.rows([
["English", "Hello"],
["Spanish", "Hola"],
["Japanese", "こんにちは"]
])
.border(:rounded)

puts table.render
```

**Style cells with StyleFunc:**

```ruby
header_style = Lipgloss::Style.new.bold(true).background("#5A56E0")
even_style = Lipgloss::Style.new.background("#3C3C3C")
odd_style = Lipgloss::Style.new.background("#4A4A4A")

table = Lipgloss::Table.new
.headers(["Name", "Role"])
.rows([["Alice", "Engineer"], ["Bob", "Designer"]])
.border(:rounded)
.style_func(rows: 2, columns: 2) do |row, column|
if row == Lipgloss::Table::HEADER_ROW
header_style
elsif row.even?
even_style
else
odd_style
end
end

puts table.render
```

### Lists

**Create styled lists:**

```ruby
list = Lipgloss::List.new
.items(["First item", "Second item", "Third item"])
.enumerator(:bullet)

puts list.render
```

**Available enumerators:**

| Enumerator | Output |
|-------------|--------------------|
| `:bullet` | `•` |
| `:dash` | `-` |
| `:asterisk` | `*` |
| `:arabic` | `1.`, `2.`, `3.` |
| `:alphabet` | `A.`, `B.`, `C.` |
| `:roman` | `I.`, `II.`, `III.` |

**Styled list items:**

```ruby
list = Lipgloss::List.new
.items(["Red", "Green", "Blue"])
.enumerator(:bullet)
.enumerator_style(Lipgloss::Style.new.foreground("#FF0000"))
.item_style(Lipgloss::Style.new.bold(true))

puts list.render
```

### Trees

**Create tree structures:**

```ruby
tree = Lipgloss::Tree.root("Project")
.child("src")
.child("lib")
.child("test")

puts tree.render
```

**Nested trees:**

```ruby
src = Lipgloss::Tree.root("src").child("main.rb").child("helper.rb")
test = Lipgloss::Tree.root("test").child("test_main.rb")

tree = Lipgloss::Tree.root("Project")
.child(src)
.child(test)

puts tree.render
```

## Style Methods

### Text Formatting

| Method | Description |
|-----------------------|-------------------------------|
| `bold(bool)` | Bold text |
| `italic(bool)` | Italic text |
| `underline(bool)` | Underlined text |
| `strikethrough(bool)` | Strikethrough text |
| `reverse(bool)` | Reverse foreground/background |
| `blink(bool)` | Blinking text |
| `faint(bool)` | Dimmed text |

### Colors

| Method | Description |
|----------------------------|-------------------------|
| `foreground(color)` | Text color |
| `background(color)` | Background color |
| `margin_background(color)` | Margin background color |

### Dimensions

| Method | Description |
|------------------|----------------|
| `width(int)` | Set width |
| `height(int)` | Set height |
| `max_width(int)` | Maximum width |
| `max_height(int)`| Maximum height |

### Spacing

| Method | Description |
|------------------------------------------------|-----------------------|
| `padding(top, right, bottom, left)` | Padding (CSS shorthand) |
| `padding_top(int)`, `padding_right(int)`, etc. | Individual padding |
| `margin(top, right, bottom, left)` | Margin (CSS shorthand) |
| `margin_top(int)`, `margin_right(int)`, etc. | Individual margin |

### Borders

| Method | Description |
|------------------------------------------------|-----------------------------|
| `border(type, *sides)` | Set border type and sides |
| `border_style(type)` | Set border type only |
| `border_foreground(color)` | Border color (all sides) |
| `border_background(color)` | Border background (all sides) |
| `border_top_foreground(color)`, etc. | Per-side border colors |
| `border_top_background(color)`, etc. | Per-side border backgrounds |
| `border_top(bool)`, `border_right(bool)`, etc. | Enable/disable sides |
| `border_custom(**opts)` | Custom border characters |

### Alignment

| Method | Description |
|-------------------------------|----------------------|
| `align(horizontal, vertical)` | Set alignment |
| `align_horizontal(position)` | Horizontal alignment |
| `align_vertical(position)` | Vertical alignment |

**Position symbols:** `:top`, `:bottom`, `:left`, `:right`, `:center` (or numeric 0.0-1.0)

### Other

| Method | Description |
|--------------------|-------------------------------------------|
| `inline(bool)` | Render inline (no margins/padding/borders) |
| `tab_width(int)` | Tab character width (-1 to disable) |
| `set_string(text)` | Set default text |
| `inherit(style)` | Inherit from another style |
| `to_s` | Render with default text |

### Unset Methods

| Method | Description |
|----------------------------------------|----------------------|
| `unset_bold`, `unset_italic`, etc. | Clear text formatting |
| `unset_foreground`, `unset_background` | Clear colors |
| `unset_width`, `unset_height` | Clear dimensions |
| `unset_padding_top`, etc. | Clear padding |
| `unset_margin_top`, etc. | Clear margin |
| `unset_border_style` | Clear border |
| `unset_inline` | Clear inline |

## Module Methods

| Method | Description |
|-----------------------------------------------------------|---------------------------|
| `Lipgloss.join_horizontal(position, *strings)` | Join strings horizontally |
| `Lipgloss.join_vertical(position, *strings)` | Join strings vertically |
| `Lipgloss.width(string)` | Get rendered width |
| `Lipgloss.height(string)` | Get rendered height |
| `Lipgloss.size(string)` | Get `[width, height]` |
| `Lipgloss.place(width, height, h_pos, v_pos, string)` | Place in whitespace |
| `Lipgloss.place_horizontal(width, position, string)` | Place horizontally |
| `Lipgloss.place_vertical(height, position, string)` | Place vertically |
| `Lipgloss.has_dark_background?` | Check terminal background |

### Color Blending

| Method | Description |
|----------------------------------------------------------------|--------------------------------|
| `Lipgloss::ColorBlend.blend(c1, c2, t, mode:)` | Blend two colors (0.0-1.0) |
| `Lipgloss::ColorBlend.blends(c1, c2, steps, mode:)` | Generate color gradient array |
| `Lipgloss::ColorBlend.grid(c1, c2, c3, c4, x, y, mode:)` | Generate 2D color grid |

**Blend modes:** `:luv` (default, perceptually uniform), `:rgb`, `:hcl`

#### Generate a 5-color gradient

```ruby
colors = Lipgloss::ColorBlend.blends("#FF0000", "#0000FF", 5)
# => ["#ff0000", "#c1007f", "#7a00c1", "#0000ff", ...]
```

#### Blend two colors at 50%

```ruby
mid = Lipgloss::ColorBlend.blend("#FF0000", "#00FF00", 0.5)
# => "#b5b500"
```

## Development

**Requirements:**
- Go 1.23+
- Ruby 3.2+

**Install dependencies:**

```bash
bundle install
```

**Build the Go library and compile the extension:**

```bash
bundle exec rake compile
```

**Run tests:**

```bash
bundle exec rake test
```

**Run demos:**

```bash
./demo/basic
./demo/colors
./demo/layout
./demo/table
./demo/list
./demo/tree
```

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/marcoroth/lipgloss-ruby.

## License

The gem is available as open source under the terms of the MIT License.

## Acknowledgments

This gem wraps [charmbracelet/lipgloss](https://github.com/charmbracelet/lipgloss), part of the excellent [Charm](https://charm.sh) ecosystem. Charm Ruby is not affiliated with or endorsed by Charmbracelet, Inc.

---

Part of [Charm Ruby](https://charm-ruby.dev).

Charm Ruby

[Lipgloss](https://github.com/marcoroth/lipgloss-ruby) • [Bubble Tea](https://github.com/marcoroth/bubbletea-ruby) • [Bubbles](https://github.com/marcoroth/bubbles-ruby) • [Glamour](https://github.com/marcoroth/glamour-ruby) • [Huh?](https://github.com/marcoroth/huh-ruby) • [Harmonica](https://github.com/marcoroth/harmonica-ruby) • [Bubblezone](https://github.com/marcoroth/bubblezone-ruby) • [Gum](https://github.com/marcoroth/gum-ruby) • [ntcharts](https://github.com/marcoroth/ntcharts-ruby)

The terminal doesn't have to be boring.