table-layout 0.5.2.0 → 0.6.0.0
raw patch · 8 files changed
+226/−123 lines, 8 filesdep ~basePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base
API changes (from Hackage documentation)
- Text.Layout.Table: columnsAsGrid :: Position V -> [Col [a]] -> [Row [a]]
- Text.Layout.Table: justifyTextsAsGrid :: [(Int, String)] -> [Row String]
- Text.Layout.Table: justifyWordListsAsGrid :: [(Int, [String])] -> [Row String]
- Text.Layout.Table: rowGroup :: [Row String] -> RowGroup
- Text.Layout.Table.Internal: rowGroup :: [Row String] -> RowGroup
- Text.Layout.Table.Justify: columnsAsGrid :: Position V -> [Col [a]] -> [Row [a]]
- Text.Layout.Table.Justify: justifyTextsAsGrid :: [(Int, String)] -> [Row String]
- Text.Layout.Table.Justify: justifyWordListsAsGrid :: [(Int, [String])] -> [Row String]
- Text.Layout.Table.Justify: vpadCols :: Position V -> a -> [[a]] -> [[a]]
+ Text.Layout.Table: colsAllG :: Position V -> [Col String] -> RowGroup
+ Text.Layout.Table: colsAsRows :: [Position V] -> [Col [a]] -> [Row [a]]
+ Text.Layout.Table: colsAsRowsAll :: Position V -> [Col [a]] -> [Row [a]]
+ Text.Layout.Table: colsG :: [Position V] -> [Col String] -> RowGroup
+ Text.Layout.Table: rowG :: Row String -> RowGroup
+ Text.Layout.Table: rowsG :: [Row String] -> RowGroup
+ Text.Layout.Table.Internal: rowG :: Row String -> RowGroup
+ Text.Layout.Table.Internal: rowsG :: [Row String] -> RowGroup
+ Text.Layout.Table.Vertical: colsAsRows :: [Position V] -> [Col [a]] -> [Row [a]]
+ Text.Layout.Table.Vertical: colsAsRowsAll :: Position V -> [Col [a]] -> [Row [a]]
+ Text.Layout.Table.Vertical: vPad :: a -> [Position V] -> [Col a] -> [Col a]
+ Text.Layout.Table.Vertical: vPadAll :: a -> Position V -> [Col a] -> [Col a]
Files
- README.md +122/−0
- src/Test.hs +8/−8
- src/Text/Layout/Table.hs +20/−55
- src/Text/Layout/Table/Internal.hs +12/−7
- src/Text/Layout/Table/Justify.hs +4/−43
- src/Text/Layout/Table/Primitives/Basic.hs +1/−1
- src/Text/Layout/Table/Vertical.hs +51/−0
- table-layout.cabal +8/−9
+ README.md view
@@ -0,0 +1,122 @@+# 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 (these are called cut marks). Columns can be positionally aligned as left, right or center and additionally aligned at certain character occurences, e.g. to display floating point numbers. Those specifications are then applied to a list of rows (currently only `String` is supported).++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 and text can be rendered justified.++## Tutorial++### Basic grid layout++Render some text rows as grid:+``` hs+putStrLn $ layoutToString [ ["top left", "top right"]+ , ["bottom left", "bottom right"]+ ]+ [column expand left def def, column expand right def def]+```+`layoutToString` 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`:+``` hs+mapM_ putStrLn $ layoutToLines (map ((: []) . show) [1.2, 100.5, 0.037, 5000.00001]) [numCol]+```+We simply display the given numbers as a dot-aligned single column:+```+ 1.2 + 100.5 + 3.7e-2 +5000.00001+```++### Improving readability of grids++Big grids are usually not that readable, so to improve their readability two functions are provided:++- `altLines` will alternate functions applied to lines.+- `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.++### Table layout++Grids are fine, but sometimes we want to explicitly display a table, e.g. as output in a database application. This is where ```layoutTableToString``` comes in handy:++``` hs+putStrLn $ layoutTableToString [ rowG ["Jack", "184.74"]+ , rowG ["Jane", "162.2"]+ ]+ def+ [def , numCol] unicodeRoundS+```+A row group is a group of rows which form one cell, meaning that each line of a group is not visually seperated from the other ones. The second argument specifies an optional header, the third the column specifications and the style. This will yield the following result:++```+╭──────┬────────╮+│ Jack │ 184.74 │+├──────┼────────┤+│ Jane │ 162.2 │+╰──────┴────────╯+```++### Table headers++The same is possible with headers:++``` hs+putStrLn $ layoutTableToString [ rowG ["A very long text", "0.42000000"]+ , rowG ["Short text", "100200.5"]+ ]+ (Just (["Title", "Length"], repeat def))+ [fixedLeftCol 10, column (fixed 10) center dotAlign def]+ unicodeS+```+Some fixed length columns are used this time and the header is displayed with a different style (additionally the header column will be specified differently):+```+┌────────────┬────────────┐+│ Title │ Length │+╞════════════╪════════════╡+│ 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 don't know how many lines will be there. Display a left-justified text alongside the length of the text:+``` hs+let txt = "Lorem ipsum ..." +in putStrLn $ layoutTableToString [colsAllG center [ justifyText 50 txt+ , [show $ length txt]+ ]+ ]+ (Just (["Text", "Length"], repeat def))+ [fixedLeftCol 50, numCol]+ asciiS+```+`colsAllG` will merge the given columns into a row group with the given positioning:+```++----------------------------------------------------+--------++| Text | Length |++----------------------------------------------------+--------++| Lorem ipsum dolor sit amet, consetetur sadipscing | |+| elitr, sed diam nonumy eirmod tempor invidunt ut | |+| labore et dolore magna aliquyam erat, sed diam | |+| voluptua. At vero eos et accusam et justo duo | 295 |+| dolores et ea rebum. Stet clita kasd gubergren, no | |+| sea takimata sanctus est Lorem ipsum dolor sit | |+| amet. | |++----------------------------------------------------+--------++```++[ansi-terminal package]: http://hackage.haskell.org/package/ansi-terminal
src/Test.hs view
@@ -7,19 +7,19 @@ main :: IO () main = putStrLn $ layoutTableToString rowGroups (Just (["Layout", "Result"], repeat def))- [ column (expandUntil 30) left (charAlign ':') ellipsisCutMark+ [ column (expandUntil 30) left (charAlign ':') def , column expand center noAlign noCutMark ] unicodeRoundS where rowGroups = flip concatMap styles $ \style -> flip map columTs $ \(cSpec, is) ->- rowGroup $ columnsAsGrid center [ is- , genTable cSpec style- ]- genTable c s = layoutTableToLines [ rowGroup [ [longText, smallNum, "foo"]- , [shortText, bigNum, "bar"]- ]+ colsAllG center [ is+ , genTable cSpec style+ ]+ genTable c s = layoutTableToLines [ rowsG [ [longText, smallNum, "foo"]+ , [shortText, bigNum, "bar"]+ ] ] (Just (["Some text", "Some numbers", "X"], repeat def)) (repeat c)@@ -36,7 +36,7 @@ , unicodeBoldStripedS , unicodeBoldHeaderS ]- columTs = [ ( column l p a ellipsisCutMark+ columTs = [ ( column l p a def , ["len spec: " ++ dL, "position: " ++ pL, "alignment: " ++ aL] ) | (l, dL) <- zip [expand, fixed 10, expandUntil 10, fixedUntil 10]
src/Text/Layout/Table.hs view
@@ -3,55 +3,6 @@ -- and length restriction it also provides advanced features like justifying -- text and fancy tables with styling support. ----- == Some examples--- Layouting text as a plain grid (given a list of rows):------ >>> putStrLn $ layoutToString [["a", "b"], ["c", "d"]] (repeat def)--- a b--- c d------ Fancy table without header:------ >>> putStrLn $ layoutTableToString [rowGroup [["Jack", "184.74"]], rowGroup [["Jane", "162.2"]]] def [def , numCol] unicodeRoundS--- ╭──────┬────────╮--- │ Jack │ 184.74 │--- ├──────┼────────┤--- │ Jane │ 162.2 │--- ╰──────┴────────╯------ Fancy table with header:------ >>> putStrLn $ layoutTableToString [ rowGroup [["A very long text", "0.42000000"]]--- , rowGroup [["Short text", "100200.5"]]--- ]--- (Just (["Title", "Length"], repeat def))--- [fixedLeftCol 20, column (fixed 10) center dotAlign def]--- unicodeRoundS--- ╭──────────────────────┬────────────╮--- │ Title │ Length │--- ╞══════════════════════╪════════════╡--- │ A very long text │ 0.4200… │--- ├──────────────────────┼────────────┤--- │ Short text │ …200.5 │--- ╰──────────────────────┴────────────╯------ Using justified text and 'RowGroup's to group multiple rows together to form one cell:------ >>> putStrLn $ layoutTableToString [rowGroup $ columnsAsGrid center [justifyText 50 txt, [show $ length txt]]]--- (Just (["Text", "Length"], repeat def))--- [fixedLeftCol 50, numCol]--- asciiS--- +----------------------------------------------------+--------+--- | Text | Length |--- +----------------------------------------------------+--------+--- | Lorem ipsum dolor sit amet, consetetur sadipscing | |--- | elitr, sed diam nonumy eirmod tempor invidunt ut | |--- | labore et dolore magna aliquyam erat, sed diam | |--- | voluptua. At vero eos et accusam et justo duo | 295 |--- | dolores et ea rebum. Stet clita kasd gubergren, no | |--- | sea takimata sanctus est Lorem ipsum dolor sit | |--- | amet. | |--- +----------------------------------------------------+--------+ {-# LANGUAGE RecordWildCards #-} module Text.Layout.Table ( -- * Layout combinators@@ -103,7 +54,10 @@ -- * Advanced table layout , RowGroup- , rowGroup+ , rowsG+ , rowG+ , colsG+ , colsAllG , HeaderColSpec , headerColumn , layoutTableToLines@@ -113,13 +67,14 @@ -- $justify , justify , justifyText++ -- * Vertical column positioning , Col- , columnsAsGrid+ , colsAsRowsAll+ , colsAsRows , top , bottom , V- , justifyTextsAsGrid- , justifyWordListsAsGrid -- * Table styles , module Text.Layout.Table.Style@@ -167,6 +122,7 @@ import Text.Layout.Table.Primitives.LenSpec.Internal import Text.Layout.Table.Primitives.Occurence import Text.Layout.Table.Internal+import Text.Layout.Table.Vertical ------------------------------------------------------------------------------- -- Layout types and combinators@@ -230,7 +186,7 @@ align oS (AlignInfo l r) s = case splitAtOcc oS s of (ls, rs) -> fillLeft l ls ++ case rs of -- No alignment character found.- [] -> (if r == 0 then "" else spaces r)+ [] -> spaces r _ -> fillRight r rs -- | Aligns a column using a fixed width, fitting it to the width by either@@ -494,6 +450,16 @@ -- Advanced layout ------------------------------------------------------------------------------- +-- | Uses the columns to create a row group, using the given vertical+-- positionings.+colsG :: [Position V] -> [Col String] -> RowGroup+colsG ps = rowsG . colsAsRows ps++-- | Uses the columns to create a row group, using the given vertical+-- positioning.+colsAllG :: Position V -> [Col String] -> RowGroup+colsAllG p = rowsG . colsAsRowsAll p+ -- | Layouts a good-looking table with a optional header. Note that specifying -- fewer layout specifications than columns or vice versa will result in not -- showing them.@@ -572,4 +538,3 @@ -- $justify -- Text can easily be justified and distributed over multiple lines. Such -- columns can easily be combined with other columns.---
src/Text/Layout/Table/Internal.hs view
@@ -6,20 +6,25 @@ import Text.Layout.Table.Position import Text.Layout.Table.Primitives.Basic --- | Groups rows together, which are not seperated from each other.+-- | Groups rows together, which should not be visually seperated from each other. newtype RowGroup = RowGroup { rows :: [[String]] } --- | Construct a row group from a list of rows.-rowGroup :: [Row String] -> RowGroup-rowGroup = RowGroup+-- | Group the given rows together.+rowsG :: [Row String] -> RowGroup+rowsG = RowGroup --- | Specifies how a header is layout, by omitting the cut mark it will use the--- one specified in the 'Text.Layout.Primitives.Column.ColSpec' like the other--- cells in that column.+-- | Make a group of a single row.+rowG :: Row String -> RowGroup+rowG = RowGroup . (: [])++-- | Specifies how a header is rendered. data HeaderColSpec = HeaderColSpec (Position H) (Maybe CutMark) +-- | Smart constructor for 'HeaderColSpec'. By omitting the cut mark it will use+-- the one specified in the 'Text.Layout.Primitives.Column.ColSpec' like the+-- other cells in that column. headerColumn :: Position H -> Maybe CutMark -> HeaderColSpec headerColumn = HeaderColSpec
src/Text/Layout/Table/Justify.hs view
@@ -3,16 +3,11 @@ -- is best suited. {-# LANGUAGE MultiWayIf #-} module Text.Layout.Table.Justify- ( justifyTextsAsGrid- , justifyWordListsAsGrid+ ( -- * Justification of text.+ justify , justifyText- , justify - -- * Vertical alignment of whole columns- , columnsAsGrid- , vpadCols-- -- * Helpers+ -- * Helpers , dimorphicSummands , dimorphicSummandsBy ) where@@ -23,41 +18,7 @@ import Text.Layout.Table.Internal import Text.Layout.Table.Primitives.Basic import Text.Layout.Table.Position.Internal---- | Justifies texts and presents the resulting lines in a grid structure (each--- text in one column).-justifyTextsAsGrid :: [(Int, String)] -> [Row String]-justifyTextsAsGrid = justifyWordListsAsGrid . fmap (second words)---- | Justifies lists of words and presents the resulting lines in a grid--- structure (each list of words in one column). This is useful if you don't--- want to split just at whitespaces.-justifyWordListsAsGrid :: [(Int, [String])] -> [Row String]-justifyWordListsAsGrid = columnsAsGrid top . fmap (uncurry justify)---- TODO put in fitting module-{- | Merges multiple columns together and merges them to a valid grid without- holes. The following example clarifies this:-->>> columnsAsGrid top [justifyText 10 "This text will not fit on one line.", ["42", "23"]]-[["This text","42"],["will not","23"],["fit on one",""],["line.",""]]--The result is intended to be used with 'Text.Layout.Table.layoutToCells' or with-'Text.Layout.Table.rowGroup'.--}-columnsAsGrid :: Position V -> [Col [a]] -> [Row [a]]-columnsAsGrid vPos = transpose . vpadCols vPos []---- | Fill all columns to the same length by aligning at the given position.-vpadCols :: Position V -> a -> [[a]] -> [[a]]-vpadCols vPos x l = fmap fillToMax l- where- fillToMax = fillTo $ maximum $ 0 : fmap length l- fillTo = let f = case vPos of- Start -> fillEnd- Center -> fillBoth- End -> fillStart- in f x+import Text.Layout.Table.Vertical -- | Uses 'words' to split the text into words and justifies it with 'justify'. --
src/Text/Layout/Table/Primitives/Basic.hs view
@@ -65,7 +65,7 @@ noCutMark :: CutMark noCutMark = singleCutMark "" --- | A single unicode character showing three dots is used as cut mark.+{-# DEPRECATED ellipsisCutMark "Use def instead." #-} ellipsisCutMark :: CutMark ellipsisCutMark = singleCutMark "…"
+ src/Text/Layout/Table/Vertical.hs view
@@ -0,0 +1,51 @@+-- | This module provides functions for vertical alginment of columns.+module Text.Layout.Table.Vertical+ ( -- * Vertical padding of columns+ vPad+ , vPadAll+ , -- * Converting columns to rows with positioning+ colsAsRowsAll+ , colsAsRows+ ) where++import Data.List++import Text.Layout.Table.Internal+import Text.Layout.Table.Position.Internal+import Text.Layout.Table.Primitives.Basic++{- | Merges multiple columns together and merges them to a valid grid without+ holes. The following example clarifies this:++>>> colsAsRowsAll top [justifyText 10 "This text will not fit on one line.", ["42", "23"]]+[["This text","42"],["will not","23"],["fit on one",""],["line.",""]]++The result is intended to be used with 'Text.Layout.Table.layoutToCells' or with+'Text.Layout.Table.rowsG'.+-}+colsAsRowsAll :: Position V -> [Col [a]] -> [Row [a]]+colsAsRowsAll ps = transpose . vPadAll [] ps++{- | Works like 'columnsAsRowsAll', but every position can be specified on its+ own:++>>> colsAsRows [top, center, bottom] [["a1"], ["b1", "b2", "b3"], ["d3"]]+[["a1","b1",""],["","b2",""],["","b3","d3"]]+-}+colsAsRows :: [Position V] -> [Col [a]] -> [Row [a]]+colsAsRows ps = transpose . vPad [] ps++-- | Fill all columns to the same length by aligning at the given position.+vPadAll :: a -> Position V -> [Col a] -> [Col a]+vPadAll x = vPad x . repeat++-- | Fill all columns to the same length by aligning at the given positions.+vPad :: a -> [Position V] -> [Col a] -> [Col a]+vPad x vs l = zipWith fillToMax vs l+ where+ fillToMax vPos = fillTo vPos $ maximum $ 0 : fmap length l+ fillTo vPos = let f = case vPos of+ Start -> fillEnd+ Center -> fillBoth+ End -> fillStart+ in f x
table-layout.cabal view
@@ -6,7 +6,7 @@ -- PVP summary: +-+------- breaking API changes -- | | +----- non-breaking API additions -- | | | +--- code changes with no API change-version: 0.5.2.0+version: 0.6.0.0 synopsis: Layout text as grid or table. @@ -27,8 +27,7 @@ . * Justified text layout over multiple rows .- /Note:/ This package is currently under development and may not be suited for- productive use.+ A small tutorial is provided in the `README.md` file. -- URL for the project homepage or repository. homepage: https://github.com/muesli4/table-layout@@ -40,7 +39,7 @@ build-type: Simple -- Extra files to be distributed with the package, such as examples or a -- README.--- extra-source-files: +extra-source-files: README.md -- Constraint on the version of Cabal needed to build this package. cabal-version: >=1.10@@ -60,7 +59,8 @@ Text.Layout.Table.Primitives.Column, Text.Layout.Table.Primitives.LenSpec, Text.Layout.Table.Primitives.Occurence,- Text.Layout.Table.Internal+ Text.Layout.Table.Internal,+ Text.Layout.Table.Vertical other-modules: Text.Layout.Table.Primitives.AlignSpec.Internal,@@ -72,7 +72,7 @@ other-extensions: RecordWildCards -- Other library packages from which modules are imported.- build-depends: base >=4.8 && <4.9,+ build-depends: base >=4.8 && <4.10, data-default-class ==0.0.*, data-default-instances-base ==0.1.* @@ -83,7 +83,7 @@ executable table-layout-test-styles main-is: Test.hs- build-depends: base >=4.8 && <4.9,+ build-depends: base >=4.8 && <4.10, data-default-class ==0.0.*, data-default-instances-base ==0.1.* hs-source-dirs: src@@ -94,8 +94,7 @@ type: exitcode-stdio-1.0 hs-source-dirs: test-suite, src main-is: Spec.hs- build-depends: base,- --Cabal,+ build-depends: base >=4.8 && <4.10, QuickCheck >=2.8 && < 2.9, HUnit ==1.3.*, data-default-class ==0.0.*,