mtlstats/src/Mtlstats/Format.hs

150 lines
3.4 KiB
Haskell
Raw Normal View History

2019-09-01 22:50:56 -04:00
{- |
mtlstats
Copyright (C) 2019 Rhéal Lamothe
<rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
-}
2019-09-02 09:30:49 -04:00
module Mtlstats.Format
( padNum
, left
2019-09-02 09:40:57 -04:00
, right
2019-09-02 09:54:04 -04:00
, centre
2019-09-02 22:56:29 -04:00
, overlay
2019-09-02 10:29:32 -04:00
, month
2019-11-18 21:36:36 -05:00
, labelTable
, numTable
, tableWith
2019-09-02 09:30:49 -04:00
) where
2019-09-01 22:50:56 -04:00
2019-11-18 21:36:36 -05:00
import Data.List (transpose)
2019-09-01 22:50:56 -04:00
-- | Pad an 'Int' with leading zeroes to fit a certain character width
padNum
:: Int
-- ^ The width in characters
-> Int
-- ^ The value to format
-> String
padNum size n
| n < 0 = '-' : padNum (pred size) (-n)
| otherwise = let
str = show n
sLen = length str
pLen = size - sLen
pad = replicate pLen '0'
in pad ++ str
2019-09-02 09:30:49 -04:00
-- | Aligns text to the left within a field (clipping if necessary)
left
:: Int
-- ^ The width of the field
-> String
-- ^ The text to align
-> String
left n str = take n $ str ++ repeat ' '
2019-09-02 09:40:57 -04:00
-- | Aligns text to the right within a field (clipping if necessary)
right
:: Int
-- ^ The width of the field
-> String
-- ^ The text to align
-> String
right n str = reverse $ left n $ reverse str
2019-09-02 09:54:04 -04:00
-- | Aligns text to the centre within a field (clipping if necessary)
centre
:: Int
-- ^ The width of the field
-> String
-- ^ The text to align
-> String
centre n str = let
sLen = length str
pLen = (n - sLen) `div` 2
pad = replicate pLen ' '
in take n $ pad ++ str ++ repeat ' '
2019-09-02 10:29:32 -04:00
2019-09-02 22:56:29 -04:00
-- | Overlays one string on top of another
overlay
:: String
-- ^ The string on the top
-> String
-- ^ The string on the bottom
-> String
overlay (x:xs) (_:ys) = x : overlay xs ys
overlay xs [] = xs
overlay [] ys = ys
2019-09-02 10:29:32 -04:00
-- | Converts a number to a three character month (e.g. @"JAN"@)
month :: Int -> String
month 1 = "JAN"
month 2 = "FEB"
month 3 = "MAR"
month 4 = "APR"
month 5 = "MAY"
month 6 = "JUN"
month 7 = "JUL"
month 8 = "AUG"
month 9 = "SEP"
month 10 = "OCT"
month 11 = "NOV"
month 12 = "DEC"
month _ = ""
2019-11-18 21:36:36 -05:00
-- | Creates a two-column table with labels
labelTable :: [(String, String)] -> [String]
labelTable xs = let
labelWidth = maximum $ map (length . fst) xs
in map
(\(label, val) -> right labelWidth label ++ ": " ++ val)
xs
-- | Creates a variable column table of numbers with two axes
numTable
:: [String]
-- ^ The top column labels
-> [(String, [Int])]
-- ^ The rows with their labels
-> [String]
numTable headers rows = tableWith right $ header : body
where
header = "" : headers
body = map
(\(label, row) ->
label : map show row)
rows
-- | Creates a table from a two-dimensional list with a specified
-- padding function
tableWith
:: (Int -> String -> String)
-- ^ The padding function
-> [[String]]
-- ^ The cells
-> [String]
tableWith func tdata = let
widths = map (map length) tdata
colWidths = map maximum $ transpose widths
fitted = map
(\row -> map
(\(str, len) -> func len str) $
zip row colWidths)
tdata
in map unwords fitted