table-layout
Format tabular data as grid or table.
https://github.com/muesli4/table-layout
Stackage Nightly 2025-05-19: | 1.0.0.2 |
Latest on Hackage: | 1.0.0.2 |
table-layout-1.0.0.2@sha256:d1d7fb2afb618bed9c749c0873011f746f2448c3cd45b704380f8768b449af29,7880
Module documentation for 1.0.0.2
- Text
- Text.Layout
- Text.Layout.Table
- Text.Layout.Table.Cell
- Text.Layout.Table.Justify
- Text.Layout.Table.LineStyle
- Text.Layout.Table.Pandoc
- Text.Layout.Table.Primitives
- Text.Layout.Table.Spec
- Text.Layout.Table.Spec.AlignSpec
- Text.Layout.Table.Spec.ColSpec
- Text.Layout.Table.Spec.CutMark
- Text.Layout.Table.Spec.HeaderColSpec
- Text.Layout.Table.Spec.HeaderSpec
- Text.Layout.Table.Spec.LenSpec
- Text.Layout.Table.Spec.OccSpec
- Text.Layout.Table.Spec.Position
- Text.Layout.Table.Spec.RowGroup
- Text.Layout.Table.Spec.TableSpec
- Text.Layout.Table.Spec.Util
- Text.Layout.Table.StringBuilder
- Text.Layout.Table.Style
- Text.Layout.Table.Vertical
- Text.Layout.Table
- Text.Layout
table-layout 
This package can be used to render character-based table layouts which should be displayed with monospace fonts.
Purpose
The focus of this library lies on rendering cells with different styles per column:
- Columns can be fixed in size or expanding to make content fit.
- Whenever content has to be cut, it is possible to indicate this with special strings, which are called cut marks.
- Columns can be positionally aligned as
left
,right
orcenter
. - Columns may also be aligned at certain character occurence with respect to the other cells of that column. One such purpose is to display floating point numbers.
Those specifications are then applied to a list of rows. A row is simply a list of a cell. A cell is a type that implements the Cell
type class.
Typically cells are rendered as a grid, but it is also possible to render tables with simulated lines, including styling support. Such tables can use optional headers and multiple lines per cell. Multi-line content can be aligned vertically, with respect to the other horizontally adjacent cells, and text can be rendered justified.
Tutorial
Grids
Render some text rows as grid:
> let g = [["top left", "top right"], ["bottom left", "bottom right"]]
> putStrLn $ gridString [column expand left def def, column expand right def def] g
gridString
will join cells with a whitespace and rows with a newline character. The result is not spectacular but does look as expected:
top left top right
bottom left bottom right
There are sensible default values for all column specification types, even for columns. We could have used just def
for the first column.
Number Columns
Additionally some common types are provided. A particularly useful one is numCol
:
> import Numeric
> let toRow d = [showFFloat Nothing d ""]
> mapM_ putStrLn $ gridLines [numCol] $ toRow <$> [1.2, 100.5, 0.037, 5000.00001]
This will display the given numbers as a dot-aligned single column:
1.2
100.5
0.037
5000.00001
Improving Readability of Grids
Big grids are usually not that readable. To improve their readability, two functions are provided:
altLines
will apply the given function in an alternating pattern. E.g., color every second row grey.checkeredCells
will checker cells with 2 different functions.
A good way to use this would be the ansi-terminal package, provided you are using a terminal to output your text. Another way to introduce color into cells is the Formatted
type:
> :set -XOverloadedStrings
> import Text.Layout.Table.Cell.Formatted
> import System.Console.ANSI.Codes
> let red s = formatted (setSGRCode [SetColor Foreground Dull Red]) (plain s) (setSGRCode [Reset])
> let g = [["Jim", "1203"], ["Jane", "523"], ["Jack", red "-959000"]]
> putStrLn $ gridString [def, numCol] g
This way the color can depend on the cell content.
Tables
For more complex data, grids do not offer as much visibility. Sometimes we want to explicitly display a table, for example, as output in a database application. tableLines
and tableString
are used to create a table.
> let t = headerlessTableS [def , numCol] unicodeRoundS [rowG ["Jack", "184.74"], rowG ["Jane", "162.2"]]
> putStrLn $ tableString t
A row group is a group of rows which are not visually separated from each other. Thus multiple rows form one cell.
In addition we specify the style and an optional header. By default the header is not visible. This will yield the following result:
╭──────┬────────╮
│ Jack │ 184.74 │
├──────┼────────┤
│ Jane │ 162.2 │
╰──────┴────────╯
Table Headers
Optionally we can use table headers. titlesH
will center titles, whereas fullH
allows more control:
> let cs = [fixedLeftCol 10, column (fixed 10) center dotAlign def]
> let h = (titlesH ["Text", "Number"])
> let rgs = [rowG ["A very long text", "0.42000000"], rowG ["Short text", "100200.5"]]
> let t = columnHeaderTableS cs unicodeS h rgs
> putStrLn $ tableString t
Headers are always displayed with a different style than the other columns (centered by default). A maximum column width is respected, otherwise a header may acquire additional space.
┌────────────┬────────────┐
│ Text │ Number │
╞════════════╪════════════╡
│ A very lo… │ 0.42000… │
├────────────┼────────────┤
│ Short text │ …00.5 │
└────────────┴────────────┘
Vertical positioning and justified text
Because a row group consists of multiple lines, we may also want to align the content of cells vertically, especially when we do not know how many lines there will be. The following piece of code will display a left-justified text alongside the length of the text:
> let txt = "Lorem ipsum ..."
> let rgs = [colsAllG center [justifyText 50 txt, [show $ length txt]]]
> let cs = [fixedLeftCol 50, numCol]
> let h = titlesH ["Text", "Length"]
> let t = columnHeaderTableS cs asciiS h rgs
> putStrLn $ tableString t
colsAllG
will merge the given columns into a row group with the given positioning:
+----------------------------------------------------+--------+
| Text | Length |
+----------------------------------------------------+--------+
| Lorem ipsum dolor sit amet, consectetur adipisici | |
| elit, sed eiusmod tempor incidunt ut labore et | |
| dolore magna aliqua. Ut enim ad minim veniam, quis | |
| nostrud exercitation ullamco laboris nisi ut | |
| aliquid ex ea commodi consequat. Quis aute iure | 429 |
| reprehenderit in voluptate velit esse cillum | |
| dolore eu fugiat nulla pariatur. Excepteur sint | |
| obcaecat cupiditat non proident, sunt in culpa qui | |
| officia deserunt mollit anim id est laborum. | |
+----------------------------------------------------+--------+
Additionally, the positioning can be specified for each column with colsG
. For grids colsAsRows
and colsAsRowsAll
are provided.
Contact
- Please report issues and suggestions to the GitHub page.
- Any kind of feedback is welcome.
- Contributions are much appreciated. Contact me first for bigger changes.
Changes
The format is based on Keep a Changelog.
[Unreleased]
Changed
[1.0.0.2] - 2025-05-18
- Change version bounds of
base
,data-default-class
anddoclayout
.
[1.0.0.1] - 2024-07-20
Changed
- Changed version bounds of
base
andQuickCheck
.
[1.0.0.0] - 2023-11-17
This release would not have been possible without the tireless work of Stephen Morgan.
Added
- Add
asciiDoubleS
table style. - Add combinators for removing outer borders of tables.
- Provide general versions of grid and table functions that generate output for
StringBuilder
instances. - Add dependency to
doclayout
andtext
. - Add
WideString
andWideText
to support multi-width character input. (#8) - Custom vertical separators can now be specified in the table header specification in a hierarchic manner.
- Add simplified table style specification with
LineStyle
and many new combinators. - Add
Cell
instance forData.Text
,Data.Either
,Data.Maybe
. - Add versions of functions for tables and grids that return
ColModInfo
s. - Provide functions to work with
Formatted
. - Add safe versions of the
trim
function. (#35) - Add
expandBetween
LenSpec
which provides a lower and an upper bound for the width of a column. (#35) - Add explicit defaults for data types (#26).
- Provide more functions to derive
ColModInfo
. - Add
TableSpec
to specify tables.
Changed
- Changed version bounds of
base
,QuickCheck
, anddata-default-class
. - Remove dependency on
data-default-instances-base
. - Improve performance of Cell and StringBuilder instances
- Generalize
Formatted
to provide nested color formatting. (#11) - Change
TableStyle
to useString
as basic building blocks of tables. (#17) - Add more separator types to
TableStyle
. - Accept arbitrary instances of
Cell
as header titles. - Lower requirements for
Cell
instances: Cells no longer need to be able to drop characters. - Drop
Monoid
requirement for vertical alignment. - Rendering functions for tables now use
TableSpec
. - Renamed functions to derive
ColModInfo
.
Fixed
- Fix recently introduced errors which made text justification completely unusable. Add test coverage for relevant functions. (#15)
[0.9.0.2] - 2020-12-20
Fixed
- Fix error in
fitWords
that was reversing the word order. This also affectsjustify
andjustifyWords
. (#14)
[0.9.0.1] - 2020-06-14
Added
- Provide functions for concatenation
concatRow
,concatLines
, andconcatGrid
. (#10)
Fixed
- Fix an error with
applyCutInfo
that created a string of wrong length in case the cut mark was of unequal length and the view was outside of the cell.
[0.9.0.0] - 2020-04-10
Added
- Add
Text.Layout.Table.Cell.Formatted
. ACell
instance is provided that enables formatting text correctly with inline text formatting commands. - Add helpers to generate tables for Pandoc in the module
Text.Layout.Table.Pandoc
. - Add
Cell
type class: This enables using different input string types. - Add
StringBuilder
type class. This enables generating output in different ways. - Add test case for left-biased trim.
Changed
- Change input type of a lot of functions to use the
Cell
type class. This might break some code but will require only a type annotation to fix. - Rework and simplify formatting functions with
Cell
andStringBuilder
. This includes improvements in test coverage. - Reorganize module structure:
- Modules of types used for specification do now start with
Text.Layout.Table.Spec.
. - Move a lot of the code in
Text.Layout.Table
into sub-modules.
- Modules of types used for specification do now start with
Fixed
- Fix an error with text justification for lines that contain only one word and add a test case. (#6)
- Fix an error where cut marks where applied wrongly on the right side.