layoutz
Simple, beautiful CLI output for Haskell ๐ชถ
Build declarative and composable sections, trees, tables, dashboards for your Haskell applications.
Features
- Zero dependencies, use
Layoutz.hs
like a header file
- Rich text formatting: alignment, underlines, padding, margins
- Lists, trees, tables, charts, banners...
Installation
Add to your package.yaml
or .cabal
file:
dependencies:
- layoutz
Or install directly:
cabal install layoutz
All you need:
import Layoutz
Quickstart
Beautiful, compositional text layouts:
import Layoutz
demo = layout
[ center $ row [text "Layoutz", underline' "ห" $ text "DEMO"]
, br
, row
[ statusCard "Users" "1.2K"
, statusCard' DoubleBorder "API" "UP"
, statusCard' ThickBorder "CPU" "23%"
, table' RoundBorder ["Name", "Role", "Status"]
[ [text "Alice", text "Engineer", text "Online"]
, [text "Eve", text "QA", text "Away"]
]
, section "Pugilists" [kv [("Kazushi", "Sakuraba"), ("Jet", "Li")]]
]
]
putStrLn $ render demo
Layoutz DEMO
หหหห
โโโโโโโโโโโ โโโโโโโโโ โโโโโโโโโ โญโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโฎ === Pugilists ===
โ Users โ โ API โ โ CPU โ โ Name โ Role โ Status โ Kazushi: Sakuraba
โ 1.2K โ โ UP โ โ 23% โ โโโโโโโโโผโโโโโโโโโโโผโโโโโโโโโค Jet: Li
โโโโโโโโโโโ โโโโโโโโโ โโโโโโโโโ โ Alice โ Engineer โ Online โ
โ Eve โ QA โ Away โ
โฐโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโฏ
Core concepts
- Every piece of content is an
Element
- Elements are immutable and composable - build complex layouts by combining simple elements
- A
layout
arranges elements vertically:
layout [elem1, elem2, elem3] -- Joins with "\n"
Call render
on any element to get a string
The power comes from uniform composition - since everything has the Element
typeclass, everything can be combined.
Elements
Text
text "Simple text"
Simple text
Line Break
Add line breaks with br
:
layout [text "Line 1", br, text "Line 2"]
Line 1
Line 2
Section: section
section "Config" [kv [("env", "prod")]]
section' "-" "Status" [kv [("health", "ok")]]
section'' "#" "Report" 5 [kv [("items", "42")]]
=== Config ===
env: prod
--- Status ---
health: ok
##### Report #####
items: 42
Layout (vertical): layout
layout [text "First", text "Second", text "Third"]
First
Second
Third
Row (horizontal): row
row [text "Left", text "Middle", text "Right"]
Left Middle Right
Horizontal rule: hr
hr
hr' "~"
hr'' "-" 10
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
----------
Key-value pairs: kv
kv [("name", "Alice"), ("role", "admin")]
name: Alice
role: admin
Table: table
Tables automatically handle alignment and borders:
table ["Name", "Age", "City"]
[ [text "Alice", text "30", text "New York"]
, [text "Bob", text "25", text ""] -- Missing values handled
, [text "Charlie", text "35", text "London"]
]
โโโโโโโโโโโฌโโโโโโฌโโโโโโโโโโ
โ Name โ Age โ City โ
โโโโโโโโโโโผโโโโโโผโโโโโโโโโโค
โ Alice โ 30 โ New Yorkโ
โ Bob โ 25 โ โ
โ Charlie โ 35 โ London โ
โโโโโโโโโโโดโโโโโโดโโโโโโโโโโ
Unordered Lists: ul
Clean unordered lists with automatic nesting:
ul [text "Feature A", text "Feature B", text "Feature C"]
โข Feature A
โข Feature B
โข Feature C
Nested lists with auto-styling:
ul [ text "Backend"
, ul [text "API", text "Database"]
, text "Frontend"
, ul [text "Components", ul [text "Header", ul [text "Footer"]]]
]
โข Backend
โฆ API
โฆ Database
โข Frontend
โฆ Components
โช Header
โข Footer
Underline: underline
Add underlines to any element:
underline $ text "Important Title"
underline' "=" $ text "Custom"
Important Title
โโโโโโโโโโโโโโโ
Custom
โโโโโโ
Box: box
With title:
box "Summary" [kv [("total", "42")]]
โโโSummaryโโโโ
โ total: 42 โ
โโโโโโโโโโโโโโ
Without title:
box "" [kv [("total", "42")]]
โโโโโโโโโโโโโโ
โ total: 42 โ
โโโโโโโโโโโโโโ
Status card: statusCard
statusCard "CPU" "45%"
โโโโโโโโโ
โ CPU โ
โ 45% โ
โโโโโโโโโ
Progress bar: inlineBar
inlineBar "Download" 0.75
Download [โโโโโโโโโโโโโโโโโโโโ] 75%
Tree: tree
tree "Project"
[ branch "src"
[ leaf "main.hs"
, leaf "test.hs"
]
, branch "docs"
[ leaf "README.md"
]
]
Project
โโโ src
โ โโโ main.hs
โ โโโ test.hs
โโโ docs
โโโ README.md
Chart: chart
chart [("Web", 10), ("Mobile", 20), ("API", 15)]
Web โโโโโโโโโโโโโโโโโโโโโ 10
Mobile โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 20
API โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 15
Padding: pad
Add uniform padding around any element:
pad 2 $ text "content"
content
Centering: center
Smart auto-centering and manual width:
center $ text "Auto-centered" -- Uses layout context
center' 20 $ text "Manual width" -- Fixed width
Auto-centered
Manual width
Margin: margin
Use margin
for colorful "compiler-style" prefixes:
layout
[ marginError [text "Type error: expected Int, got String"]
, marginWarn [text "Unused variable 'temp'"]
, marginSuccess [text "Build completed successfully"]
, marginInfo [text "Pro tip: Use layoutz for beautiful output"]
]
[error] Type error: expected Int, got String
[warn] Unused variable 'temp'
[success] Build completed successfully
[info] Pro tip: Use layoutz for beautiful output
Border Styles
Elements like box
, table
, and statusCard
support different border styles:
NormalBorder (default):
box "Title" [text "content"]
โโโTitleโโโ
โ content โ
โโโโโโโโโโโ
DoubleBorder:
statusCard' DoubleBorder "API" "UP"
โโโโโโโโโ
โ API โ
โ UP โ
โโโโโโโโโ
ThickBorder:
table' ThickBorder ["Name"] [[text "Alice"]]
โโโโโโโโโ
โ Name โ
โฃโโโโโโโโซ
โ Alice โ
โโโโโโโโโ
RoundBorder:
box' RoundBorder "Info" [text "content"]
โญโโInfoโโโโฎ
โ content โ
โฐโโโโโโโโโโฏ
REPL Usage
Drop into GHCi to experiment:
cabal repl
ฮป> import Layoutz
ฮป> putStrLn $ render $ center $ box "Hello" [text "World!"]
โโโHelloโโโ
โ World! โ
โโโโโโโโโโโ
ฮป> putStrLn $ render $ table ["A", "B"] [[text "1", text "2"]]
โโโโโฌโโโโ
โ A โ B โ
โโโโโผโโโโค
โ 1 โ 2 โ
โโโโโดโโโโ
Inspiration