MyNixOS website logo
Description

Simple, beautiful CLI output for Haskell.

Build declarative and composable sections, trees, tables, dashboards for your Haskell applications. . Zero dependencies, rich text formatting with alignment, underlines, padding, margins. Features lists, trees, tables, charts, banners and more.

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

Metadata

Version

0.1.0.0

License

Platformsย (76)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-freebsd
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64-windows
  • aarch64_be-none
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-linux
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-windows