This page collects common layouts you can paste into a REPL and adapt.
(require '[clj-string-layout.core :refer [layout layout-seq layout-str]]
'[clj-string-layout.escape :as escape]
'[clj-string-layout.layout :as layouts]
'[clj-string-layout.predicates :as pred])
Use [L], [C], and [R] for left, center, and right alignment.
(layout [["name" "qty" "price"]
["apple" "12" "$1.50"]
["pear" "4" "$2.00"]]
{:layout {:cols ["[L] [R] [R]"]}})
;; => ["name qty price"
;; "apple 12 $1.50"
;; "pear 4 $2.00"]
Use f where extra width should be distributed.
(layout [["left" "right"]]
{:width 24
:fill-char \.
:layout {:cols ["[L]f[R]"]}})
;; => ["left...............right"]
Multiple fill markers split the extra width.
(layout [["x" "y"]]
{:width 9
:fill-char \-
:layout {:cols ["f[L]f[R]f"]}})
;; => ["--x--y---"]
Repeat groups let one layout handle any number of columns.
(layout [["a" "b" "c"]
["10" "200" "3"]]
{:layout {:cols ["|{ [R] |}" :repeat-for [pred/all-cols?]]}})
;; => ["| a | b | c |"
;; "| 10 | 200 | 3 |"]
Use multiple repeat groups when the first, interior, and last columns need different delimiters.
(layout [["a" "b" "c"]]
{:layout {:cols ["{[L]}{, [L]}"
:repeat-for [pred/first-col? pred/not-first-col?]]}})
;; => ["a, b, c"]
Use a built-in preset when you want a complete table shape.
(layout [["name" "qty"]
["apple" "12"]]
layouts/layout-ascii-box-left)
;; => ["┌───────┬─────┐"
;; "│ name │ qty │"
;; "├───────┼─────┤"
;; "│ apple │ 12 │"
;; "└───────┴─────┘"]
The *-fill-* presets consume :width.
(layout [["name" "qty"]
["apple" "12"]]
(assoc layouts/layout-ascii-box-fill-center :width 30))
Markdown cells are emitted verbatim, so escape data first when values may
contain |, backslashes, or line breaks.
(layout (escape/map-cells escape/markdown-cell
[["name" "notes"]
["apple" "red|green"]])
layouts/layout-markdown-left)
;; => ["| name | notes |"
;; "|:----- |:---------- |"
;; "| apple | red\\|green |"]
HTML cells are emitted verbatim by design. Escape user-provided values first.
(layout (escape/map-cells escape/html
[["<Alice>" "tea & cake"]])
layouts/layout-html-table)
;; => ["<table>"
;; " <tr><td><Alice></td><td>tea & cake</td></tr>"
;; "</table>"]
By default, widths use count. Pass :display-width when terminal display
width differs from string length.
(defn demo-width [s]
(reduce + (map #(if (= \界 %) 2 1) s)))
(layout [["界" "x"]
["ab" "yy"]]
{:display-width demo-width
:layout {:cols ["[R] [L]"]}})
;; => ["界 x "
;; "ab yy"]
Use :raw? true to get row pieces before they are joined. This is useful when a
later step needs to color cells or otherwise decorate pieces.
(layout [["a" "b"]]
{:raw? true
:layout {:cols ["| [L] | [R] |"]}})
;; => [["| " "a" " | " "b" " |"]]
Exact automatic widths require a full scan of the data. If your data set is
large and the schema widths are known, use layout-seq with :col-widths so
output can be consumed row-by-row. If you need escaping for a large lazy input,
use escape/map-cell-seq rather than escape/map-cells.
(def huge-rows
(map (fn [n] [(str "item-" n) (str n)])
(range)))
(take 3
(layout-seq huge-rows
{:col-widths [12 8]
:layout {:cols ["[L] [R]"]}}))
;; => ("item-0 0"
;; "item-1 1"
;; "item-2 2")
When row layouts are present, pass :row-count for finite data so predicates
can identify the last virtual row without counting the input.
(layout-seq (map vector ["a" "bb"])
{:col-widths [3]
:row-count 2
:layout {:cols ["[L]"]
:rows [["[-]" :apply-for layouts/all-rows?]]}})
;; => ("---" "a " "---" "bb " "---")
String input is split by :row-split-char and :word-split-char.
(layout "name|qty;apple|12"
{:word-split-char \|
:row-split-char \;
:layout {:cols ["[L] [R]"]}})
;; => ["name qty"
;; "apple 12"]
Use diagnostics while writing custom layout strings.
(clj-string-layout.core/parse-layout "[L]f[R]")
(clj-string-layout.core/explain-layout "[x]")
;; => {:valid? false, :message "...", :data {:type :layout-parse-error, ...}}
Use layout-str when the consumer wants one newline-delimited string.
(layout-str [["a" "b"]
["aa" "bb"]]
{:layout {:cols ["[L] [R]"]}})
;; => "a b\naa bb"
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |