https://github.com/mattlianje/layoutz
Simple, beautiful CLI output
https://github.com/mattlianje/layoutz
cli dsl functional-programming scala tui
Last synced: 5 months ago
JSON representation
Simple, beautiful CLI output
- Host: GitHub
- URL: https://github.com/mattlianje/layoutz
- Owner: mattlianje
- License: apache-2.0
- Created: 2025-07-05T21:46:18.000Z (12 months ago)
- Default Branch: master
- Last Pushed: 2025-12-31T23:33:18.000Z (6 months ago)
- Last Synced: 2026-01-03T14:54:16.805Z (5 months ago)
- Topics: cli, dsl, functional-programming, scala, tui
- Language: Scala
- Homepage:
- Size: 117 MB
- Stars: 217
- Watchers: 2
- Forks: 6
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
#
layoutz
**Simple, beautiful CLI output πͺΆ**
Build declarative and composable sections, trees, tables and dashboards for your consoles. Part of [d4](https://github.com/mattlianje/d4)
## Features
- Zero dependencies, use **Layoutz.scala** like a header-file
- Effortless composition of elements
- Thread-safe, purely functional rendering
## Installation
**layoutz** is on MavenCentral and cross-built for Scala, 2.12, 2.13, 3.x
```scala
"xyz.matthieucourt" %% "layoutz" % "0.1.0"
```
Or try in REPL:
```bash
scala-cli repl --scala 3 --dep xyz.matthieucourt:layoutz_3:0.1.0
```
All you need:
```scala
import layoutz._
```
## Quickstart
```scala
import layoutz._
val dashboard = layout(
section("System Status")(
row(
statusCard("CPU", "45%"),
statusCard("Memory", "78%"),
statusCard("Disk", "23%")
)
),
box("Recent Activity")(
bullets(
"User alice logged in",
"Database backup completed",
"3 new deployments"
)
)
)
println(dashboard.render)
```
yields:
```
=== System Status ===
βββββββββ ββββββββββββ ββββββββββ
β CPU β β Memory β β Disk β
β 45% β β 78% β β 23% β
βββββββββ ββββββββββββ ββββββββββ
ββββββββRecent Activityββββββββ
β β’ User alice logged in β
β β’ Database backup completed β
β β’ 3 new deployments β
βββββββββββββββββββββββββββββββ
```
## Motivation
- We have `s"..."`, and full-blown TUI libraries - but there is a gap in-between.
- With LLM's, boilerplate code that formats & "pretty-prints" is **_cheaper than ever_**...
- Thus, **_more than ever_**, "string formatting code" is spawning, and polluting domain logic
- Utlimately, **layoutz** is just a tiny, declarative DSL to combat this
## Core concepts
- Every piece of content is an `Element`
- Elements are **immutable** and **composable** - you build complex layouts by combining simple elements.
- A `layout` is just a special element that arranges other elements **vertically** with consistent spacing:
```scala
layout(elem1, elem2, elem3) /* Joins with "\n\n" */
```
Call `.render` on an element to get a String
The power comes from **uniform composition**, since everything is an `Element`, everything can be combined with everything else.
## Elements
All components implementing the Element interface you can use in your layouts...
### Text: `Text`
**layoutz** implicitly converts Strings to `Text` element
```scala
"Simple text" // <- valid Element
Text("Simple text") // <- you don't need to do this
```
this lets you splice strings into layouts as you build them with var-arg shorthand
### Line Break: `br`
Add extra line-break "\n" with `br`:
```scala
layout("Line 1", br, "Line 2")
```
### Section: `section`
```scala
section("Config")(kv("env" -> "prod"))
```
```
=== Config ===
env : prod
```
### Layout (vertical): `layout`
```scala
layout("First", "Second", "Third")
```
```
First
Second
Third
```
### Row (horizontal): `row`
```scala
row("Left", "Middle", "Right")
```
```
Left Middle Right
```
### Horizontal rule: `hr`
```scala
hr
hr("~", 10)
```
```
ββββββββββββββββββββββββββββββββββββββββββββββββββ
~~~~~~~~~
```
### Key-value pairs: `kv`
```scala
kv("name" -> "Alice", "role" -> "admin")
```
```
name : Alice
role : admin
```
### Table: `table`
```scala
table(
headers = Seq("Name", "Status"),
rows = Seq(Seq("Alice", "Online"), Seq("Bob", "Away"))
)
```
```
βββββββββ¬βββββββββ
β Name β Status β
βββββββββΌβββββββββ€
β Alice β Online β
β Bob β Away β
βββββββββ΄βββββββββ
```
### Bullets: `bullets`/`bullet`
Simple bullet list
```scala
bullets("Task 1", "Task 2", "Task 3")
```
```
β’ Task 1
β’ Task 2
β’ Task 3
```
Single bullet with nested children
```scala
bullet("Backend",
bullet("API"),
bullet("Database")
)
```
```
β’ Backend
β’ API
β’ Database
```
Complex nesting
```scala
bullets(
bullet("Frontend",
bullet("Components",
bullet("Header"),
bullet("Footer")
),
bullet("Styles")
),
bullet("Backend",
bullet("API"),
bullet("Database")
)
)
```
```
β’ Frontend
β’ Components
β’ Header
β’ Footer
β’ Styles
β’ Backend
β’ API
β’ Database
```
Mix bullets with other elements
```scala
bullet("Status",
"System online",
inlineBar("Health", 0.95),
"All services running"
)
```
```
β’ Status
β’ System online
β’ Health [ββββββββββββββββββββ] 95%
β’ All services running
```
### Box: `box`
```scala
box("Summary")(kv("total" -> "42"))
```
```
βββSummaryββββ
β total : 42 β
ββββββββββββββ
```
### Status card: `statusCard`
```scala
statusCard("CPU", "45%")
```
```
βββββββββ
β CPU β
β 45% β
βββββββββ
```
### Progress bar: `inlineBar`
```scala
inlineBar("Download", 0.75)
```
```
Download [ββββββββββββββββββββ] 75%
```
### Diff block: `diffBlock`
```scala
diffBlock(
added = Seq("new feature"),
removed = Seq("old code")
)
```
```
Changes:
- old code
+ new feature
```
### Tree: `tree`/`branch`/`leaf`
```scala
tree("Project")(
branch("src",
branch("main", leaf("App.scala")),
branch("test", leaf("AppSpec.scala"))
)
)
```
```
Project
βββ src/
βββ main/
β βββ App.scala
βββ test/
βββ AppSpec.scala
```
## Working with collections
The full power of Scala functional collections is at your fingertips to render your strings with **layoutz**
```scala
case class User(name: String, role: String)
val users = Seq(User("Alice", "Admin"), User("Bob", "User"), User("Tom", "User"))
val usersByRole = users.groupBy(_.role)
section("Users by Role")(
layout(
usersByRole.map { case (role, roleUsers) =>
box(role)(
bullets(roleUsers.map(_.name): _*)
)
}.toSeq: _*
)
)
```
```
=== Users by Role ===
βββAdminβββ
β β’ Alice β
βββββββββββ
βββUserβββ
β β’ Bob β
β β’ Tom β
ββββββββββ
```
## Inspiration
- [ScalaTags](https://github.com/com-lihaoyi/scalatags) by Li Haoyi
- Countless templating libraries via osmosis ...